libreboot-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libreboot-dev] [PATCH] Coreboot update, depthcharge menus improvement


From: Paul Kocialkowski
Subject: [Libreboot-dev] [PATCH] Coreboot update, depthcharge menus improvement
Date: Fri, 30 Oct 2015 17:17:42 +0100

Signed-off-by: Paul Kocialkowski <address@hidden>
---
 ...ay-callbacks-for-developer-and-recovery-m.patch |    35 +-
 .../config/depthcharge/veyron_speedy/config        |     9 +-
 ...sized-half-word-sized-memory-operations-f.patch |    89 -
 ...low-disabling-vboot-firmware-verification.patch |    98 +
 ...low-disabling-vboot-firmware-verification.patch |    84 -
 ...-w83795-Add-full-support-for-fan-control-.patch |   710 -
 ...-amd-sb700-Allow-use-of-auxiliary-SMBUS-c.patch |   142 +-
 ...-w83795-Add-full-support-for-core-functio.patch |   725 +
 ...-w83795-Add-option-to-use-auxiliary-SMBUS.patch |    62 -
 ...eed-Add-native-text-mode-VGA-support-for-.patch |  3675 -----
 ...-w83795-Add-option-to-use-auxiliary-SMBUS.patch |    68 +
 ...pdate-mainboards-using-the-w83795-sensor-.patch |   323 +
 ...-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch |   642 -
 ...eed-Add-native-text-mode-VGA-support-for-.patch |  3675 +++++
 ...-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch |   621 -
 ...-initial-support-for-AMD-Socket-G34-proce.patch |   832 -
 ...-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch |   619 +
 ...-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch |  3463 ----
 ...-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch |   621 +
 ...-initial-support-for-AMD-Socket-G34-proce.patch |   832 +
 ...-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch |    95 -
 ...-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch |   121 -
 ...-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch |  3454 ++++
 ...thbridge-amd-amdfam10-Fix-typo-in-comment.patch |    27 -
 ...-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch |    95 +
 ...ypertransport-Add-additional-debug-output.patch |    35 -
 ...-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch |   121 +
 ...ypertransport-Add-additional-debug-output.patch |    35 +
 ...sus-kgpe-d16-Add-initial-support-for-the-.patch |  3221 ----
 ...sus-kgpe-d16-Add-initial-support-for-the-.patch |  3222 ++++
 ...sus-kgpe-d16-Add-nvram-option-to-enable-d.patch |    72 -
 ...model_10xxx-Clean-up-debugging-statements.patch |   116 -
 ...sus-kgpe-d16-Add-nvram-option-to-enable-d.patch |    72 +
 ...model_10xxx-Clean-up-debugging-statements.patch |   108 +
 ...e-amd-sb700-Add-Suspend-to-RAM-S3-support.patch |   367 -
 ...e-amd-sb700-Add-Suspend-to-RAM-S3-support.patch |   367 +
 ...oton-nct5572d-Enable-power-state-after-po.patch |    82 -
 ...-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch |   135 -
 ...oton-nct5572d-Enable-power-state-after-po.patch |    80 +
 ...srock-e350m1-Update-CMOS-layout-to-match-.patch |    38 +
 ...-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch |  1007 --
 ...car-Add-initial-Suspend-to-RAM-S3-support.patch |    56 -
 ...-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch |   135 +
 ...sus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch |   832 -
 ...-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch |  1017 ++
 ...car-Add-initial-Suspend-to-RAM-S3-support.patch |    56 +
 ...ios-Update-SMBIOS-memory-structures-to-ve.patch |    33 -
 ...sus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch |   832 +
 ...-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch |   198 -
 ...ios-Update-SMBIOS-memory-structures-to-ve.patch |    33 +
 ...sus-kgpe-d16-Set-DDR3-memory-voltage-base.patch |   166 -
 ...-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch |   198 +
 ...-console-Add-x86-romstage-spinlock-option.patch |   100 -
 ...sus-kgpe-d16-Set-DDR3-memory-voltage-base.patch |   166 +
 ...-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch |    51 -
 ...-amd-amdmct-mct_ddr3-Fix-failing-S3-resum.patch |    53 -
 ...-Add-x86-romstage-spinlock-option-and-pri.patch |   193 +
 ...-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch |    51 +
 ...c-console-Add-x86-printk-spinlock-support.patch |   149 -
 ...029-lib-stack-Add-stack-overrun-detection.patch |     8 +-
 ...cpu-x86-lapic-Add-stack-overrun-detection.patch |     8 +-
 ...-amd-sr5650-Add-AMD-Family-15h-CPU-suppor.patch |     8 +-
 ...Move-model_10xxx-to-family_10h-family_15h.patch |    24 +-
 ...pu-amd-Add-initial-AMD-Family-15h-support.patch | 16206 ------------------
 ...ily_10h-family_15h-Use-correct-label-for-.patch |    28 +
 ...pu-amd-Add-initial-AMD-Family-15h-support.patch | 16249 +++++++++++++++++++
 ...sus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch |   565 -
 ...ily_10h-family_15h-Add-Family-15h-microco.patch |    28 -
 ...sus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch |   556 +
 ...ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch |    38 -
 ...ily_10h-family_15h-Add-Family-15h-microco.patch |    28 +
 ...ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch |    38 +
 ...-Add-romstage-BSP-stack-overrun-detection.patch |    58 -
 ...-Add-romstage-BSP-stack-overrun-detection.patch |    59 +
 ...-Increase-Family-10h-CAR-size-limit-to-12.patch |    31 -
 ...-Increase-Family-10h-CAR-size-limit-to-12.patch |    31 +
 ...-Move-AP-stacks-below-the-BSP-stack-to-fr.patch |    33 -
 ...-Move-AP-stacks-below-the-BSP-stack-to-fr.patch |    33 +
 ...-amd-amdmct-Read-SPD-data-into-cache-to-d.patch |   461 -
 ...-Initialize-entire-CAR-space-instead-of-o.patch |    34 -
 ...-amd-amdmct-Read-SPD-data-into-cache-to-d.patch |   461 +
 ...mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch |    49 -
 ...-Initialize-entire-CAR-space-instead-of-o.patch |    34 +
 ...mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch |    49 +
 ...mct_ddr3-Use-training-values-from-previou.patch |   781 -
 ...mct_ddr3-Use-training-values-from-previou.patch |   781 +
 ...-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch |   261 -
 .../0045-mainboard-asus-kgpe-d16-Enable-CC6.patch  |    70 -
 ...-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch |   261 +
 .../kgpe-d16/0046-cpu-amd-Add-CC6-support.patch    |  1307 --
 .../0046-mainboard-asus-kgpe-d16-Enable-CC6.patch  |    70 +
 .../kgpe-d16/0047-cpu-amd-Add-CC6-support.patch    |  1318 ++
 ...-amd-amdmct-Skip-DCT-config-write-to-Flas.patch |   103 -
 ...-amd-amdmct-Skip-DCT-config-write-to-Flas.patch |   103 +
 ...48-southbridge-amd-sb700-Add-AHCI-support.patch |   656 -
 ...sus-kgpe-d16-Properly-initialize-SB700-SA.patch |    49 -
 ...49-southbridge-amd-sb700-Add-AHCI-support.patch |   656 +
 ...sus-kgpe-d16-Properly-initialize-SB700-SA.patch |    49 +
 ...-amd-sb700-Disable-broken-SATA-MSI-functi.patch |    41 -
 ...-amd-sb700-Disable-broken-SATA-MSI-functi.patch |    41 +
 ...-amd-sb700-Indicate-iSATA-eSATA-port-type.patch |    93 -
 ...-amd-amdfam10-Add-ability-to-set-maximum-.patch |    84 -
 ...-amd-sb700-Indicate-iSATA-eSATA-port-type.patch |    94 +
 ...-amd-amdfam10-Add-ability-to-set-maximum-.patch |    84 +
 ...-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch |   149 -
 ...-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch |   149 +
 ...idge-amd-amdmct-Add-option-to-override-ba.patch |   104 -
 ...sus-kgpe-d16-Add-missing-IRQ-routing-for-.patch |   209 -
 ...idge-amd-amdmct-Add-option-to-override-ba.patch |   102 +
 ...sus-kgpe-d16-Add-missing-IRQ-routing-for-.patch |   209 +
 ...-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch |    37 -
 ...-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch |    37 +
 ...-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch |    85 -
 ...-amd-sr5650-Add-optional-delay-after-link.patch |    71 -
 ...-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch |    85 +
 ...sus-kgpe-d16-Properly-configure-SR5690-so.patch |    32 -
 ...-amd-sr5650-Add-optional-delay-after-link.patch |    71 +
 ...sus-kgpe-d16-Properly-configure-SR5690-so.patch |    32 +
 ...-amd-sb700-Add-option-to-disable-SATA-ALP.patch |    86 -
 ...ainboard-asus-kgpe-d16-Set-SP5100-subtype.patch |    26 -
 ...-amd-sb700-Add-option-to-disable-SATA-ALP.patch |    84 +
 ...ainboard-asus-kgpe-d16-Set-SP5100-subtype.patch |    26 +
 ...-amd-amdmct-Fix-crash-on-startup-due-to-N.patch |    33 -
 ...-amd-amdmct-Clear-memory-before-enabling-.patch |   185 -
 ...-amd-amdmct-Fix-crash-on-startup-due-to-N.patch |    33 +
 ...-amd-amdmct-Clear-memory-before-enabling-.patch |   185 +
 ...-amd-sb700-Do-drive-detection-even-in-AHC.patch |   142 -
 ...-amd-sb700-Do-drive-detection-even-in-AHC.patch |   142 +
 ...idge-amd-sb700-Reset-SATA-controller-in-A.patch |    96 -
 ...-amd-sb700-Recover-if-AHCI-disk-detection.patch |   163 -
 ...idge-amd-sb700-Reset-SATA-controller-in-A.patch |    96 +
 ...-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch |    97 -
 ...-amd-sb700-Recover-if-AHCI-disk-detection.patch |   163 +
 ...-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch |    97 +
 ...-amd-sb700-Fix-random-persistent-SATA-AHC.patch |   165 -
 ...-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch |   407 -
 ...-amd-sb700-Fix-random-persistent-SATA-AHC.patch |   165 +
 ...-AMD-Family-15h-ECC-initialization-reliab.patch |   474 -
 ...-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch |   409 +
 ...-AMD-Family-15h-ECC-initialization-reliab.patch |   474 +
 ...-amd-amdfam10-Properly-indicate-node-and-.patch |   120 -
 ...mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch |   508 -
 ...-amd-amdfam10-Properly-indicate-node-and-.patch |   120 +
 ...mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch |   508 +
 ...-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch |   256 -
 ...-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch |   256 +
 ...-amd-amdmct-mct_ddr3-Work-around-strange-.patch |    42 -
 ...-amd-amdmct-mct_ddr3-Add-additional-debug.patch |   120 -
 ...-amd-amdmct-mct_ddr3-Work-around-strange-.patch |    42 +
 ...-amd-amdmct-mct_ddr3-Add-additional-debug.patch |   120 +
 ...-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch |   240 -
 ...-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch |   268 -
 ...-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch |   240 +
 ...-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch |   268 +
 ...-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch |   114 -
 ...-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch |    58 -
 ...-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch |   114 +
 ...-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch |   100 -
 ...-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch |    58 +
 ...-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch |   100 +
 ...idge-amd-sr5650-Always-configure-lane-dir.patch |    51 -
 ...ily_10h-family_15h-Fix-BSP-stack-corrupti.patch |    28 -
 ...idge-amd-sr5650-Always-configure-lane-dir.patch |    51 +
 ...ily_10h-family_15h-Fix-BSP-stack-corrupti.patch |    40 +
 ...-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch |   330 -
 ...mct_ddr3-Partially-fix-up-registered-DIMM.patch |   960 --
 ...-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch |   304 +
 ...mct_ddr3-Partially-fix-up-registered-DIMM.patch |   960 ++
 ...ridge-amd-amdmct-Fix-Family-15h-detection.patch |    49 -
 ...ridge-amd-amdmct-Fix-Family-15h-detection.patch |    49 +
 ...-amd-amdmct-mct_ddr3-Add-registered-and-x.patch |  1887 ---
 ...ily_10h-family_15h-Fix-Family-15h-multipl.patch |  1931 ---
 ...-amd-amdmct-Reduce-maximum-number-of-DDR3.patch |    41 +
 ...dge-amd-amdfam10-Add-probe-filter-support.patch |   214 -
 ...-amd-amdmct-mct_ddr3-Add-registered-and-x.patch |  1887 +++
 ...ily_10h-family_15h-Bring-initial-HT-regis.patch |   248 -
 ...ily_10h-family_15h-Fix-Family-15h-multipl.patch |  1244 ++
 ...dge-amd-amdfam10-Add-probe-filter-support.patch |   282 +
 ...-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch |   338 -
 ...ily_10h-family_15h-Bring-initial-HT-regis.patch |   248 +
 ...oard-asus-kgpe-d16-Fix-I-O-link-detection.patch |    28 -
 ...ily_10h-family_15h-Set-northbridge-thrott.patch |   139 -
 ...-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch |   336 +
 ...ily_10h-family_15h-Fix-incorrect-revision.patch |    64 -
 ...oard-asus-kgpe-d16-Fix-I-O-link-detection.patch |    28 +
 ...ily_10h-family_15h-Set-northbridge-thrott.patch |   110 +
 ...-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch |   561 -
 ...10h-family_15h-Fix-poor-performance-on-Fa.patch |   124 -
 ...ily_10h-family_15h-Fix-incorrect-revision.patch |    64 +
 ...mct_ddr3-Fix-poor-performance-on-Family-1.patch |  1089 --
 ...-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch |   532 +
 ...10h-family_15h-Fix-poor-performance-on-Fa.patch |   124 +
 ...-amd-amdht-Fix-poor-performance-on-Family.patch |    30 -
 ...mct_ddr3-Fix-poor-performance-on-Family-1.patch |  1089 ++
 ...-amd-amdfam10-Fix-poor-performance-on-Fam.patch |    72 -
 ...ily_10h-family_15h-Configure-NB-register-.patch |    34 -
 ...-amd-amdht-Fix-poor-performance-on-Family.patch |    30 +
 ...ily_10h-family_15h-Set-up-link-XCS-token-.patch |   344 -
 ...-amd-amdfam10-Fix-poor-performance-on-Fam.patch |    72 +
 ...ily_10h-family_15h-Configure-NB-register-.patch |    34 +
 ...-amd-amdmct-mct_ddr3-Force-retraining-on-.patch |    36 -
 ...ily_10h-family_15h-Set-up-link-XCS-token-.patch |   344 +
 ...ridge-amd-amdfam10-Fix-invalid-NUMA-table.patch |    28 -
 ...-amd-amdfam10-Add-Family-15h-cache-partit.patch |   123 -
 ...-amd-amdmct-mct_ddr3-Force-retraining-on-.patch |    36 +
 ...mct_ddr3-Set-prefetch-double-stride-to-im.patch |    27 -
 ...ridge-amd-amdfam10-Fix-invalid-NUMA-table.patch |    28 +
 ...ily_10h-family_15h-Set-up-Family-15h-Link.patch |   192 -
 ...-amd-amdfam10-Add-Family-15h-cache-partit.patch |   123 +
 ...mct_ddr3-Set-prefetch-double-stride-to-im.patch |    27 +
 ...ily_10h-family_15h-Set-up-cache-controls-.patch |    43 -
 ...ily_10h-family_15h-Set-up-Family-15h-Link.patch |   192 +
 ...ily_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch |    66 -
 ...0-Control-Family-15h-cache-partitioning-a.patch |   177 -
 ...ily_10h-family_15h-Set-up-cache-controls-.patch |    43 +
 ...ily_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch |    66 +
 ...-amd-amdht-Add-isochronous-setup-support-.patch |   272 -
 ...0-Control-Family-15h-cache-partitioning-a.patch |   190 +
 ...6-acpi-Add-IVRS-table-generation-routines.patch |   121 -
 ...-amd-amdht-Add-isochronous-setup-support-.patch |   279 +
 ...-southbridge-amd-sr5650-Add-IOMMU-support.patch |   711 -
 ...6-acpi-Add-IVRS-table-generation-routines.patch |   121 +
 ...-amd-sr5650-Hide-clock-configuration-devi.patch |    57 -
 ...-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch |    55 -
 ...-southbridge-amd-sr5650-Add-IOMMU-support.patch |   804 +
 ...-amd-amdfam10-Fix-gart-setup-not-working-.patch |    96 -
 ...-amd-sr5650-Hide-clock-configuration-devi.patch |    57 +
 ...sus-kgpe-d16-Add-several-nvram-configurat.patch |   129 -
 ...-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch |    55 +
 ...-amd-amdfam10-Fix-gart-setup-not-working-.patch |    96 +
 ...-amd-sr5650-Use-correct-PCI-configuration.patch |    30 -
 ...sus-kgpe-d16-Add-several-nvram-configurat.patch |    82 +
 ...ge-amd-sr5650-Add-MCFG-ACPI-table-support.patch |   119 -
 ...dge-amd-sb700-Fix-mismatched-FADT-entries.patch |    36 -
 ...-amd-sr5650-Use-correct-PCI-configuration.patch |    30 +
 ...ridge-amd-sb700-Fix-drifting-system-clock.patch |    47 -
 ...ge-amd-sr5650-Add-MCFG-ACPI-table-support.patch |   121 +
 ...-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch |    58 -
 ...dge-amd-sb700-Fix-mismatched-FADT-entries.patch |    36 +
 ...-amd-amdfam10-Work-around-sporadic-lockup.patch |    40 -
 ...ridge-amd-sb700-Fix-drifting-system-clock.patch |    47 +
 ...-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch |    58 +
 ...-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch |   115 -
 ...-amd-amdfam10-Work-around-sporadic-lockup.patch |    40 +
 ...-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch |    36 -
 ...-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch |   115 +
 ...-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch |    37 -
 ...-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch |    36 +
 ...-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch |    65 -
 ...-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch |    37 +
 ...-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch |   157 -
 ...-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch |   602 -
 ...-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch |    65 +
 ...0-Add-optional-spinlock-for-nvram-CBFS-ac.patch |   175 -
 ...-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch |   157 +
 ...board-asus-kgpe-d16-Enable-CBFS-spinlocks.patch |    68 -
 ...-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch |   602 +
 ...rocode-Introduce-CBFS-access-spinlock-to-.patch |   155 -
 ...0-Add-optional-spinlock-for-nvram-CBFS-ac.patch |   175 +
 ...board-asus-kgpe-d16-Enable-CBFS-spinlocks.patch |    61 +
 ...rd-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch |    41 -
 ...ily_10h-family_15h-Apply-missing-Family-1.patch |    70 -
 ...rocode-Introduce-CBFS-access-spinlock-to-.patch |   155 +
 ...rd-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch |    41 +
 ...-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch |   231 -
 ...ily_10h-family_15h-Apply-missing-Family-1.patch |    70 +
 ...oard-asus-kgpe-d16-Enable-GART-by-default.patch |    27 -
 ...-amd-amdfam10-Fix-incorrect-channel-buffe.patch |    42 -
 ...-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch |   231 +
 ...ily_10h-family_15h-Force-iolink-detect-to.patch |    37 -
 ...oard-asus-kgpe-d16-Enable-GART-by-default.patch |    27 +
 ...-amd-amdfam10-Fix-incorrect-channel-buffe.patch |    42 +
 ...-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch |   144 -
 ...ily_10h-family_15h-Fix-link-type-detectio.patch |   158 -
 ...ily_10h-family_15h-Force-iolink-detect-to.patch |    37 +
 ...ily_10h-family_15h-Enable-DFE-on-Family-1.patch |    32 -
 ...-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch |   144 +
 ...ily_10h-family_15h-Fix-link-type-detectio.patch |   158 +
 ...ily_10h-family_15h-Enable-DFE-on-Family-1.patch |    32 +
 ...ily_10h-family_15h-Fix-build-when-microco.patch |    28 +
 ...s-Avoid-infinite-loop-if-i2c-device-has-w.patch |    39 +
 ...low-disabling-vboot-firmware-verification.patch |    68 -
 resources/scripts/helpers/download/coreboot        |     5 +-
 283 files changed, 55428 insertions(+), 55778 deletions(-)
 delete mode 100644 
resources/libreboot/patch/chromebook/0001-armv7-Word-sized-half-word-sized-memory-operations-f.patch
 create mode 100644 
resources/libreboot/patch/chromebook/0001-chromeos-Allow-disabling-vboot-firmware-verification.patch
 delete mode 100644 
resources/libreboot/patch/chromebook/0002-chromeos-Allow-disabling-vboot-firmware-verification.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0001-drivers-i2c-w83795-Add-full-support-for-fan-control-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-full-support-for-core-functio.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0004-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0004-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0005-mainboard-Update-mainboards-using-the-w83795-sensor-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0005-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0006-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0006-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0007-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0007-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0008-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0008-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0009-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0009-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdfam10-Fix-typo-in-comment.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0012-device-hypertransport-Add-additional-debug-output.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0012-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0013-device-hypertransport-Add-additional-debug-output.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0013-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0015-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0015-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0016-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0016-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0017-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0017-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0018-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0018-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0019-mainboard-asrock-e350m1-Update-CMOS-layout-to-match-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0019-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0020-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0020-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0021-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0021-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0022-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0022-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0023-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0023-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0024-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0024-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0025-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0025-src-console-Add-x86-romstage-spinlock-option.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0026-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0026-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0027-northbridge-amd-amdmct-mct_ddr3-Fix-failing-S3-resum.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0027-src-console-Add-x86-romstage-spinlock-option-and-pri.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0028-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0028-src-console-Add-x86-printk-spinlock-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0033-cpu-amd-Add-initial-AMD-Family-15h-support.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0033-cpu-amd-family_10h-family_15h-Use-correct-label-for-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0034-cpu-amd-Add-initial-AMD-Family-15h-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0034-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0035-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0035-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0036-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0036-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0037-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0037-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0040-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0040-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0041-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0042-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0042-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0044-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0044-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0045-mainboard-asus-kgpe-d16-Enable-CC6.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0045-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0046-mainboard-asus-kgpe-d16-Enable-CC6.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0047-cpu-amd-Add-CC6-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0047-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0048-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0048-southbridge-amd-sb700-Add-AHCI-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0049-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0049-southbridge-amd-sb700-Add-AHCI-support.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0050-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0050-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0052-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0052-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0054-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0054-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0055-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0055-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0056-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0056-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0057-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0057-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0059-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0059-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0060-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0060-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0061-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0061-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0062-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0062-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0064-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0064-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0065-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0065-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0066-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0066-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0069-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0069-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0070-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0070-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0071-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0071-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0072-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0072-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0073-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0073-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0081-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0081-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0082-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0082-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0083-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0083-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0084-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0084-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0085-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0085-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0087-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0087-northbridge-amd-amdmct-Reduce-maximum-number-of-DDR3.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdfam10-Add-probe-filter-support.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdfam10-Add-probe-filter-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0091-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0091-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0092-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0092-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0093-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0093-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0094-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0094-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0095-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0095-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0096-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0096-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0097-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0097-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0098-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0098-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0099-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0099-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0100-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0100-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0101-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0101-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0102-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0102-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0104-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0104-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0105-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0105-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0106-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0106-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0108-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0108-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0109-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0109-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0110-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0110-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0111-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0112-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0112-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0113-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0113-southbridge-amd-sr5650-Add-IOMMU-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0114-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0114-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0115-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0115-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0116-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0116-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0117-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0117-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sb700-Fix-drifting-system-clock.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0120-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0120-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0121-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0121-southbridge-amd-sb700-Fix-drifting-system-clock.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0128-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0128-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0129-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0130-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0130-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0132-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0132-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0133-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0133-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0134-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0134-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0136-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0136-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
 delete mode 100644 
resources/libreboot/patch/kgpe-d16/0139-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0139-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0140-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0141-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0142-cpu-amd-family_10h-family_15h-Fix-build-when-microco.patch
 create mode 100644 
resources/libreboot/patch/kgpe-d16/0143-device-smbus-Avoid-infinite-loop-if-i2c-device-has-w.patch
 delete mode 100644 
resources/libreboot/patch/misc/0009-chromeos-Allow-disabling-vboot-firmware-verification.patch

diff --git 
a/resources/depthcharge/patch/0007-vboot-Display-callbacks-for-developer-and-recovery-m.patch
 
b/resources/depthcharge/patch/0007-vboot-Display-callbacks-for-developer-and-recovery-m.patch
index 4de5a67..ea06121 100644
--- 
a/resources/depthcharge/patch/0007-vboot-Display-callbacks-for-developer-and-recovery-m.patch
+++ 
b/resources/depthcharge/patch/0007-vboot-Display-callbacks-for-developer-and-recovery-m.patch
@@ -1,4 +1,4 @@
-From dc7421b033667ccbad3429e6ed118c849f3b05ca Mon Sep 17 00:00:00 2001
+From 541a3f09ecb062e3f0778eb9846732cfabcbfbba Mon Sep 17 00:00:00 2001
 From: Paul Kocialkowski <address@hidden>
 Date: Tue, 11 Aug 2015 11:22:54 +0200
 Subject: [PATCH 7/7] vboot: Display callbacks for developer and recovery mode
@@ -9,14 +9,14 @@ free software (Chrome OS), so this implements a text-based 
interface instead.
 
 Signed-off-by: Paul Kocialkowski <address@hidden>
 ---
- src/vboot/callbacks/display.c | 157 ++++++++++++++++++++++++++++++++++++++----
- 1 file changed, 145 insertions(+), 12 deletions(-)
+ src/vboot/callbacks/display.c | 168 +++++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 156 insertions(+), 12 deletions(-)
 
 diff --git a/src/vboot/callbacks/display.c b/src/vboot/callbacks/display.c
-index efa0691..2341621 100644
+index efa0691..b659f7b 100644
 --- a/src/vboot/callbacks/display.c
 +++ b/src/vboot/callbacks/display.c
-@@ -84,9 +84,16 @@ void print_on_center(const char *msg)
+@@ -84,9 +84,17 @@ void print_on_center(const char *msg)
        print_string(msg);
  }
  
@@ -27,6 +27,7 @@ index efa0691..2341621 100644
 +      unsigned int rows, cols;
 +      uint32_t boot_signed_only = 0;
 +      uint32_t boot_usb = 0;
++      uint32_t boot_legacy = 0;
 +      const char *fw_id;
 +      int fw_index;
 +      void *blob = NULL;
@@ -35,7 +36,7 @@ index efa0691..2341621 100644
  
        /*
         * Show the debug messages for development. It is a backup method
-@@ -98,31 +105,157 @@ VbError_t VbExDisplayScreen(uint32_t screen_type)
+@@ -98,31 +106,167 @@ VbError_t VbExDisplayScreen(uint32_t screen_type)
                video_console_clear();
                break;
        case VB_SCREEN_DEVELOPER_WARNING:
@@ -48,34 +49,44 @@ index efa0691..2341621 100644
 +                              &boot_signed_only);
 +
 +                      VbNvGet(vnc, VBNV_DEV_BOOT_USB, &boot_usb);
++                      VbNvGet(vnc, VBNV_DEV_BOOT_LEGACY, &boot_legacy);
 +              }
 +
 +              print_string(
 +                      "Welcome to developer mode!\n\n"
 +                      "Useful key combinations:\n"
 +                      "- Ctrl + H: Hold developer mode\n"
-+                      "- Ctrl + D: Continue booting\n");
++                      "- Ctrl + D: Boot from internal storage\n");
 +
 +              if (boot_usb)
 +                      print_string("- Ctrl + U: Boot from external media\n");
 +
++              if (boot_legacy)
++                      print_string("- Ctrl + L: Boot from legacy payload\n");
++
 +              print_string(
-+                      "- Ctrl + L: Boot from legacy media\n"
 +                      "- Ctrl + I: Show device information\n"
 +                      "- Space: Disable developer mode\n\n"
-+                      "This screen is shown for 3 seconds (if not 
held).\n\n");
++                      "This screen is shown for 3 seconds (if not held)."
++                      "\n\n");
 +
 +              if (vnc != NULL) {
 +                      if (!boot_signed_only)
 +                              print_string(
-+                                      "Warning: this device will boot "
-+                                      "unsigned kernels!\n");
++                                      "Warning: this device will boot kernels"
++                                      " without verifying their signature!"
++                                      "\n");
 +
 +                      if (boot_usb)
 +                              print_string(
 +                                      "Warning: this device will boot from "
 +                                      "external media!\n");
 +
++                      if (boot_legacy)
++                              print_string(
++                                      "Warning: this device will boot legacy "
++                                      "payloads!\n");
++
 +                      if (!boot_signed_only || boot_usb)
 +                              print_string("\n");
 +              }
@@ -130,7 +141,7 @@ index efa0691..2341621 100644
 +              print_string(
 +                      "Welcome to recovery mode!\n\n"
 +                      "Useful key combinations:\n"
-+                      "- Ctrl + D: Enable developer mode\n\n");
++                      "- Ctrl + D: Enable developer mode (if possible)\n\n");
 +
 +              if (screen_type == VB_SCREEN_RECOVERY_NO_GOOD)
 +                      print_on_center(
diff --git a/resources/libreboot/config/depthcharge/veyron_speedy/config 
b/resources/libreboot/config/depthcharge/veyron_speedy/config
index 9647cff..4abf201 100644
--- a/resources/libreboot/config/depthcharge/veyron_speedy/config
+++ b/resources/libreboot/config/depthcharge/veyron_speedy/config
@@ -206,6 +206,7 @@ CONFIG_HEAP_SIZE=0x4000
 # CONFIG_SOC_NVIDIA_TEGRA210 is not set
 # CONFIG_SOC_QC_IPQ806X is not set
 CONFIG_SOC_ROCKCHIP_RK3288=y
+# CONFIG_VBOOT_VERIFY_FIRMWARE is not set
 # CONFIG_CPU_SAMSUNG_EXYNOS5250 is not set
 # CONFIG_CPU_SAMSUNG_EXYNOS5420 is not set
 # CONFIG_SOC_UCB_RISCV is not set
@@ -285,14 +286,10 @@ CONFIG_CHROMEOS_RAMOOPS_RAM_SIZE=0x00100000
 CONFIG_EC_SOFTWARE_SYNC=y
 # CONFIG_VBOOT_EC_SLOW_UPDATE is not set
 CONFIG_VIRTUAL_DEV_SWITCH=y
-# CONFIG_VBOOT_VERIFY_FIRMWARE is not set
 # CONFIG_NO_TPM_RESUME is not set
 # CONFIG_PHYSICAL_REC_SWITCH is not set
 # CONFIG_LID_SWITCH is not set
 # CONFIG_WIPEOUT_SUPPORTED is not set
-CONFIG_VBOOT_STARTS_IN_BOOTBLOCK=y
-CONFIG_SEPARATE_VERSTAGE=y
-CONFIG_RETURN_FROM_VERSTAGE=y
 # CONFIG_UEFI_2_4_BINDING is not set
 CONFIG_ARCH_ARM=y
 CONFIG_ARCH_BOOTBLOCK_ARM=y
@@ -356,7 +353,6 @@ CONFIG_MAINBOARD_HAS_NATIVE_VGA_INIT=y
 CONFIG_NATIVE_VGA_INIT_USE_EDID=y
 # CONFIG_MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG is not set
 # CONFIG_MULTIPLE_VGA_ADAPTERS is not set
-# CONFIG_SMBUS_HAS_AUX is not set
 # CONFIG_SPD_CACHE is not set
 # CONFIG_PCI is not set
 # CONFIG_PXE_ROM is not set
@@ -457,9 +453,6 @@ CONFIG_POST_DEVICE_NONE=y
 # CONFIG_POST_DEVICE_PCI_PCIE is not set
 # CONFIG_HAVE_ACPI_RESUME is not set
 CONFIG_HAVE_HARD_RESET=y
-# CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK is not set
-# CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK is not set
-# CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK is not set
 CONFIG_HAVE_MONOTONIC_TIMER=y
 CONFIG_GENERIC_UDELAY=y
 # CONFIG_TIMER_QUEUE is not set
diff --git 
a/resources/libreboot/patch/chromebook/0001-armv7-Word-sized-half-word-sized-memory-operations-f.patch
 
b/resources/libreboot/patch/chromebook/0001-armv7-Word-sized-half-word-sized-memory-operations-f.patch
deleted file mode 100644
index f89b160..0000000
--- 
a/resources/libreboot/patch/chromebook/0001-armv7-Word-sized-half-word-sized-memory-operations-f.patch
+++ /dev/null
@@ -1,89 +0,0 @@
-From 9746b7bf27d4a3c7c0de78b26ec9f217887f4e7d Mon Sep 17 00:00:00 2001
-From: Paul Kocialkowski <address@hidden>
-Date: Tue, 22 Sep 2015 22:16:33 +0200
-Subject: [PATCH 1/2] armv7: Word-sized/half-word-sized memory operations for
- 32/16 bit read/write
-
-Some registers only allow word-sized or half-word-sized operations and will
-cause a data fault when accessed with byte-sized operations.
-However, the compiler may or may not break such an operation into smaller
-(byte-sized) chunks. Thus, we need to reliably perform word-sized operations 
for
-32 bit read/write and half-word-sized operations for 16 bit read/write.
-
-This is particularly the case on the rk3288 SRAM registers, where the watchdog
-tombstone is stored. Moving to GCC 5.2.0 introduced a change of strategy in the
-compiler, where a 32 bit read would be broken into byte-sized chunks, which
-caused a data fault when accessing the watchdog tombstone register.
-
-The definitions for byte-sized memory operations are also adapted to stay
-consistent with the rest.
-
-Change-Id: I1fb3fc139e0a813acf9d70f14386a9603c9f9ede
-Signed-off-by: Paul Kocialkowski <address@hidden>
----
- src/arch/arm/include/armv7/arch/io.h | 21 +++++++++++++++------
- 1 file changed, 15 insertions(+), 6 deletions(-)
-
-diff --git a/src/arch/arm/include/armv7/arch/io.h 
b/src/arch/arm/include/armv7/arch/io.h
-index 9d06003..94cb131 100644
---- a/src/arch/arm/include/armv7/arch/io.h
-+++ b/src/arch/arm/include/armv7/arch/io.h
-@@ -29,40 +29,49 @@
- 
- static inline uint8_t read8(const void *addr)
- {
-+      uint8_t val;
-+
-       dmb();
--      return *(volatile uint8_t *)addr;
-+      asm volatile ("ldrb %0, [%1]" : "=r" (val) : "r" (addr) : "memory");
-+      return val;
- }
- 
- static inline uint16_t read16(const void *addr)
- {
-+      uint16_t val;
-+
-       dmb();
--      return *(volatile uint16_t *)addr;
-+      asm volatile ("ldrh %0, [%1]" : "=r" (val) : "r" (addr) : "memory");
-+      return val;
- }
- 
- static inline uint32_t read32(const void *addr)
- {
-+      uint32_t val;
-+
-       dmb();
--      return *(volatile uint32_t *)addr;
-+      asm volatile ("ldr %0, [%1]" : "=r" (val) : "r" (addr) : "memory");
-+      return val;
- }
- 
- static inline void write8(void *addr, uint8_t val)
- {
-       dmb();
--      *(volatile uint8_t *)addr = val;
-+      asm volatile ("strb %0, [%1]" : : "r" (val), "r" (addr) : "memory");
-       dmb();
- }
- 
- static inline void write16(void *addr, uint16_t val)
- {
-       dmb();
--      *(volatile uint16_t *)addr = val;
-+      asm volatile ("strh %0, [%1]" : : "r" (val), "r" (addr) : "memory");
-       dmb();
- }
- 
- static inline void write32(void *addr, uint32_t val)
- {
-       dmb();
--      *(volatile uint32_t *)addr = val;
-+      asm volatile ("str %0, [%1]" : : "r" (val), "r" (addr) : "memory");
-       dmb();
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/chromebook/0001-chromeos-Allow-disabling-vboot-firmware-verification.patch
 
b/resources/libreboot/patch/chromebook/0001-chromeos-Allow-disabling-vboot-firmware-verification.patch
new file mode 100644
index 0000000..f268922
--- /dev/null
+++ 
b/resources/libreboot/patch/chromebook/0001-chromeos-Allow-disabling-vboot-firmware-verification.patch
@@ -0,0 +1,98 @@
+From 2178bea1fbef28afbb9ffa2d95673407fac1907e Mon Sep 17 00:00:00 2001
+From: Paul Kocialkowski <address@hidden>
+Date: Sun, 9 Aug 2015 10:23:38 +0200
+Subject: [PATCH] chromeos: Allow disabling vboot firmware verification when
+ ChromeOS is enabled
+
+Some ChromeOS bindings might be wanted without using vboot verification, for
+instance to boot up depthcharge from the version of Coreboot installed in the
+write-protected part of the SPI flash (without jumping to a RW firmware).
+
+Vboot firmware verification is still selected by default when ChromeOS is
+enabled, but this allows more flexibility since vboot firmware verification is
+no longer a hard requirement for ChromeOS (that this particular use case still
+allows booting ChromeOS).
+
+In the future, it would make sense to have all the separate components that
+CONFIG_CHROMEOS enables have their own config options, so that they can be
+enabled separately.
+
+Change-Id: Ia4057a56838aa05dcf3cb250ae1a27fd91402ddb
+Signed-off-by: Paul Kocialkowski <address@hidden>
+---
+ src/lib/bootmode.c                            | 2 ++
+ src/soc/rockchip/rk3288/Kconfig               | 2 +-
+ src/vendorcode/google/chromeos/Kconfig        | 2 +-
+ src/vendorcode/google/chromeos/vboot2/Kconfig | 4 ++++
+ 4 files changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/src/lib/bootmode.c b/src/lib/bootmode.c
+index f2ff72a..13c0130 100644
+--- a/src/lib/bootmode.c
++++ b/src/lib/bootmode.c
+@@ -80,8 +80,10 @@ void gfx_set_init_done(int done)
+ int display_init_required(void)
+ {
+       /* For Chrome OS always honor vboot_skip_display_init(). */
++#if CONFIG_VBOOT_VERIFY_FIRMWARE
+       if (IS_ENABLED(CONFIG_CHROMEOS))
+               return !vboot_skip_display_init();
++#endif
+ 
+       /* By default always initialize display. */
+       return 1;
+diff --git a/src/soc/rockchip/rk3288/Kconfig b/src/soc/rockchip/rk3288/Kconfig
+index bc484e3..74a63e7 100644
+--- a/src/soc/rockchip/rk3288/Kconfig
++++ b/src/soc/rockchip/rk3288/Kconfig
+@@ -35,7 +35,7 @@ config SOC_ROCKCHIP_RK3288
+ 
+ if SOC_ROCKCHIP_RK3288
+ 
+-config CHROMEOS
++config VBOOT_VERIFY_FIRMWARE
+       select VBOOT_STARTS_IN_BOOTBLOCK
+       select SEPARATE_VERSTAGE
+       select RETURN_FROM_VERSTAGE
+diff --git a/src/vendorcode/google/chromeos/Kconfig 
b/src/vendorcode/google/chromeos/Kconfig
+index 8309d19..694e0d7 100644
+--- a/src/vendorcode/google/chromeos/Kconfig
++++ b/src/vendorcode/google/chromeos/Kconfig
+@@ -31,7 +31,6 @@ config CHROMEOS
+       select BOOTMODE_STRAPS
+       select ELOG
+       select COLLECT_TIMESTAMPS
+-      select VBOOT_VERIFY_FIRMWARE
+       help
+         Enable ChromeOS specific features like the GPIO sub table in
+         the coreboot table. NOTE: Enabling this option on an unsupported
+@@ -129,6 +128,7 @@ config VIRTUAL_DEV_SWITCH
+ 
+ config VBOOT_VERIFY_FIRMWARE
+       bool "Verify firmware with vboot."
++      default y if CHROMEOS
+       default n
+       depends on HAVE_HARD_RESET
+       help
+diff --git a/src/vendorcode/google/chromeos/vboot2/Kconfig 
b/src/vendorcode/google/chromeos/vboot2/Kconfig
+index 930b009..610a847 100644
+--- a/src/vendorcode/google/chromeos/vboot2/Kconfig
++++ b/src/vendorcode/google/chromeos/vboot2/Kconfig
+@@ -16,6 +16,8 @@
+ ## Foundation, Inc.
+ ##
+ 
++if VBOOT_VERIFY_FIRMWARE
++
+ config VBOOT_STARTS_IN_BOOTBLOCK
+       bool "Vboot starts verifying in bootblock"
+       default n
+@@ -133,3 +135,5 @@ config VBOOT_DYNAMIC_WORK_BUFFER
+         ram to allocate the vboot work buffer. That means vboot verification
+         is after memory init and requires main memory to back the work
+         buffer.
++
++endif # VBOOT_VERIFY_FIRMWARE
+-- 
+1.9.1
+
diff --git 
a/resources/libreboot/patch/chromebook/0002-chromeos-Allow-disabling-vboot-firmware-verification.patch
 
b/resources/libreboot/patch/chromebook/0002-chromeos-Allow-disabling-vboot-firmware-verification.patch
deleted file mode 100644
index bed24b1..0000000
--- 
a/resources/libreboot/patch/chromebook/0002-chromeos-Allow-disabling-vboot-firmware-verification.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From d0e6324693214c51e707928e26571ecc9ab8ee03 Mon Sep 17 00:00:00 2001
-From: Paul Kocialkowski <address@hidden>
-Date: Sun, 9 Aug 2015 10:23:38 +0200
-Subject: [PATCH 2/2] chromeos: Allow disabling vboot firmware verification
- when ChromeOS is enabled
-
-Some ChromeOS bindings might be wanted without using vboot verification, for
-instance to boot up depthcharge from the version of Coreboot installed in the
-write-protected part of the SPI flash (without jumping to a RW firmware).
-
-Vboot firmware verification is still selected by default when ChromeOS is
-enabled, but this allows more flexibility since vboot firmware verification is
-no longer a hard requirement for ChromeOS (that this particular use case still
-allows booting ChromeOS).
-
-In the future, it would make sense to have all the separate components that
-CONFIG_CHROMEOS enables have their own config options, so that they can be
-enabled separately.
-
-Change-Id: Ia4057a56838aa05dcf3cb250ae1a27fd91402ddb
-Signed-off-by: Paul Kocialkowski <address@hidden>
----
- src/lib/bootmode.c                            | 2 ++
- src/vendorcode/google/chromeos/Kconfig        | 2 +-
- src/vendorcode/google/chromeos/vboot2/Kconfig | 4 ++++
- 3 files changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/src/lib/bootmode.c b/src/lib/bootmode.c
-index f2ff72a..13c0130 100644
---- a/src/lib/bootmode.c
-+++ b/src/lib/bootmode.c
-@@ -80,8 +80,10 @@ void gfx_set_init_done(int done)
- int display_init_required(void)
- {
-       /* For Chrome OS always honor vboot_skip_display_init(). */
-+#if CONFIG_VBOOT_VERIFY_FIRMWARE
-       if (IS_ENABLED(CONFIG_CHROMEOS))
-               return !vboot_skip_display_init();
-+#endif
- 
-       /* By default always initialize display. */
-       return 1;
-diff --git a/src/vendorcode/google/chromeos/Kconfig 
b/src/vendorcode/google/chromeos/Kconfig
-index 8309d19..694e0d7 100644
---- a/src/vendorcode/google/chromeos/Kconfig
-+++ b/src/vendorcode/google/chromeos/Kconfig
-@@ -31,7 +31,6 @@ config CHROMEOS
-       select BOOTMODE_STRAPS
-       select ELOG
-       select COLLECT_TIMESTAMPS
--      select VBOOT_VERIFY_FIRMWARE
-       help
-         Enable ChromeOS specific features like the GPIO sub table in
-         the coreboot table. NOTE: Enabling this option on an unsupported
-@@ -129,6 +128,7 @@ config VIRTUAL_DEV_SWITCH
- 
- config VBOOT_VERIFY_FIRMWARE
-       bool "Verify firmware with vboot."
-+      default y if CHROMEOS
-       default n
-       depends on HAVE_HARD_RESET
-       help
-diff --git a/src/vendorcode/google/chromeos/vboot2/Kconfig 
b/src/vendorcode/google/chromeos/vboot2/Kconfig
-index 33c33a5..5bd8b54 100644
---- a/src/vendorcode/google/chromeos/vboot2/Kconfig
-+++ b/src/vendorcode/google/chromeos/vboot2/Kconfig
-@@ -16,6 +16,8 @@
- ## Foundation, Inc.
- ##
- 
-+if VBOOT_VERIFY_FIRMWARE
-+
- config VBOOT_STARTS_IN_BOOTBLOCK
-       bool "Vboot starts verifying in bootblock"
-       default n
-@@ -133,3 +135,5 @@ config VBOOT_DYNAMIC_WORK_BUFFER
-         ram to allocate the vboot work buffer. That means vboot verification
-         is after memory init and requires main memory to back the work
-         buffer.
-+
-+endif # VBOOT_VERIFY_FIRMWARE
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0001-drivers-i2c-w83795-Add-full-support-for-fan-control-.patch
 
b/resources/libreboot/patch/kgpe-d16/0001-drivers-i2c-w83795-Add-full-support-for-fan-control-.patch
deleted file mode 100644
index 0dc1606..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0001-drivers-i2c-w83795-Add-full-support-for-fan-control-.patch
+++ /dev/null
@@ -1,710 +0,0 @@
-From f7b8be27ea159845a982c310799a5896865016cd Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 17:53:20 -0500
-Subject: [PATCH 001/139] drivers/i2c/w83795: Add full support for fan control,
- fan monitoring, and voltage monitoring
-
-Change-Id: I3e246af0e398d65ee43ea708060885c67fd7d202
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/drivers/i2c/w83795/chip.h   | 142 +++++++++++++++++
- src/drivers/i2c/w83795/w83795.c | 334 ++++++++++++++++++++++++++--------------
- src/drivers/i2c/w83795/w83795.h |  52 +++++--
- 3 files changed, 399 insertions(+), 129 deletions(-)
- create mode 100644 src/drivers/i2c/w83795/chip.h
-
-diff --git a/src/drivers/i2c/w83795/chip.h b/src/drivers/i2c/w83795/chip.h
-new file mode 100644
-index 0000000..effe119
---- /dev/null
-+++ b/src/drivers/i2c/w83795/chip.h
-@@ -0,0 +1,142 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc.
-+ */
-+
-+struct drivers_i2c_w83795_config {
-+      uint8_t fanin_ctl1;
-+      uint8_t fanin_ctl2;
-+
-+      uint8_t temp_ctl1;
-+      uint8_t temp_ctl2;
-+      uint8_t temp_dtse;
-+
-+      uint8_t volt_ctl1;
-+      uint8_t volt_ctl2;
-+
-+      uint8_t temp1_fan_select;
-+      uint8_t temp2_fan_select;
-+      uint8_t temp3_fan_select;
-+      uint8_t temp4_fan_select;
-+      uint8_t temp5_fan_select;
-+      uint8_t temp6_fan_select;
-+
-+      uint8_t temp1_source_select;
-+      uint8_t temp2_source_select;
-+      uint8_t temp3_source_select;
-+      uint8_t temp4_source_select;
-+      uint8_t temp5_source_select;
-+      uint8_t temp6_source_select;
-+
-+      uint32_t vcore1_high_limit_mv;          /* mV */
-+      uint32_t vcore1_low_limit_mv;           /* mV */
-+      uint32_t vcore2_high_limit_mv;          /* mV */
-+      uint32_t vcore2_low_limit_mv;           /* mV */
-+      uint32_t vtt_high_limit_mv;             /* mV */
-+      uint32_t vtt_low_limit_mv;              /* mV */
-+      uint32_t vsen3_high_limit_mv;           /* mV */
-+      uint32_t vsen3_low_limit_mv;            /* mV */
-+      uint32_t vsen4_high_limit_mv;           /* mV */
-+      uint32_t vsen4_low_limit_mv;            /* mV */
-+      uint32_t vsen5_high_limit_mv;           /* mV */
-+      uint32_t vsen5_low_limit_mv;            /* mV */
-+      uint32_t vsen6_high_limit_mv;           /* mV */
-+      uint32_t vsen6_low_limit_mv;            /* mV */
-+      uint32_t vsen7_high_limit_mv;           /* mV */
-+      uint32_t vsen7_low_limit_mv;            /* mV */
-+      uint32_t vsen8_high_limit_mv;           /* mV */
-+      uint32_t vsen8_low_limit_mv;            /* mV */
-+      uint32_t vsen9_high_limit_mv;           /* mV */
-+      uint32_t vsen9_low_limit_mv;            /* mV */
-+      uint32_t vsen10_high_limit_mv;          /* mV */
-+      uint32_t vsen10_low_limit_mv;           /* mV */
-+      uint32_t vsen11_high_limit_mv;          /* mV */
-+      uint32_t vsen11_low_limit_mv;           /* mV */
-+      uint32_t vsen12_high_limit_mv;          /* mV */
-+      uint32_t vsen12_low_limit_mv;           /* mV */
-+      uint32_t vsen13_high_limit_mv;          /* mV */
-+      uint32_t vsen13_low_limit_mv;           /* mV */
-+      uint32_t vdd_high_limit_mv;             /* mV */
-+      uint32_t vdd_low_limit_mv;              /* mV */
-+      uint32_t vsb_high_limit_mv;             /* mV */
-+      uint32_t vsb_low_limit_mv;              /* mV */
-+      uint32_t vbat_high_limit_mv;            /* mV */
-+      uint32_t vbat_low_limit_mv;             /* mV */
-+
-+      int8_t tr1_critical_temperature;        /* °C */
-+      int8_t tr1_critical_hysteresis;         /* °C */
-+      int8_t tr1_warning_temperature;         /* °C */
-+      int8_t tr1_warning_hysteresis;          /* °C */
-+      int8_t tr2_critical_temperature;        /* °C */
-+      int8_t tr2_critical_hysteresis;         /* °C */
-+      int8_t tr2_warning_temperature;         /* °C */
-+      int8_t tr2_warning_hysteresis;          /* °C */
-+      int8_t tr3_critical_temperature;        /* °C */
-+      int8_t tr3_critical_hysteresis;         /* °C */
-+      int8_t tr3_warning_temperature;         /* °C */
-+      int8_t tr3_warning_hysteresis;          /* °C */
-+      int8_t tr4_critical_temperature;        /* °C */
-+      int8_t tr4_critical_hysteresis;         /* °C */
-+      int8_t tr4_warning_temperature;         /* °C */
-+      int8_t tr4_warning_hysteresis;          /* °C */
-+      int8_t tr5_critical_temperature;        /* °C */
-+      int8_t tr5_critical_hysteresis;         /* °C */
-+      int8_t tr5_warning_temperature;         /* °C */
-+      int8_t tr5_warning_hysteresis;          /* °C */
-+      int8_t tr6_critical_temperature;        /* °C */
-+      int8_t tr6_critical_hysteresis;         /* °C */
-+      int8_t tr6_warning_temperature;         /* °C */
-+      int8_t tr6_warning_hysteresis;          /* °C */
-+      int8_t dts_critical_temperature;        /* °C */
-+      int8_t dts_critical_hysteresis;         /* °C */
-+      int8_t dts_warning_temperature;         /* °C */
-+      int8_t dts_warning_hysteresis;          /* °C */
-+
-+      int8_t temp1_critical_temperature;      /* °C */
-+      int8_t temp2_critical_temperature;      /* °C */
-+      int8_t temp3_critical_temperature;      /* °C */
-+      int8_t temp4_critical_temperature;      /* °C */
-+      int8_t temp5_critical_temperature;      /* °C */
-+      int8_t temp6_critical_temperature;      /* °C */
-+
-+      int8_t temp1_target_temperature;        /* °C */
-+      int8_t temp2_target_temperature;        /* °C */
-+      int8_t temp3_target_temperature;        /* °C */
-+      int8_t temp4_target_temperature;        /* °C */
-+      int8_t temp5_target_temperature;        /* °C */
-+      int8_t temp6_target_temperature;        /* °C */
-+
-+      uint8_t fan1_nonstop;                   /* % of full speed (0-100) */
-+      uint8_t fan2_nonstop;                   /* % of full speed (0-100) */
-+      uint8_t fan3_nonstop;                   /* % of full speed (0-100) */
-+      uint8_t fan4_nonstop;                   /* % of full speed (0-100) */
-+      uint8_t fan5_nonstop;                   /* % of full speed (0-100) */
-+      uint8_t fan6_nonstop;                   /* % of full speed (0-100) */
-+      uint8_t fan7_nonstop;                   /* % of full speed (0-100) */
-+      uint8_t fan8_nonstop;                   /* % of full speed (0-100) */
-+
-+      uint8_t default_speed;                  /* % of full speed (0-100) */
-+
-+      uint8_t fan1_duty;                      /* % of full speed (0-100) */
-+      uint8_t fan2_duty;                      /* % of full speed (0-100) */
-+      uint8_t fan3_duty;                      /* % of full speed (0-100) */
-+      uint8_t fan4_duty;                      /* % of full speed (0-100) */
-+      uint8_t fan5_duty;                      /* % of full speed (0-100) */
-+      uint8_t fan6_duty;                      /* % of full speed (0-100) */
-+      uint8_t fan7_duty;                      /* % of full speed (0-100) */
-+      uint8_t fan8_duty;                      /* % of full speed (0-100) */
-+};
-diff --git a/src/drivers/i2c/w83795/w83795.c b/src/drivers/i2c/w83795/w83795.c
-index 2bbe0be..cf0cf2f 100644
---- a/src/drivers/i2c/w83795/w83795.c
-+++ b/src/drivers/i2c/w83795/w83795.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2012 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -21,106 +22,68 @@
- #include <arch/cpu.h>
- #include <console/console.h>
- #include <device/device.h>
--#include "southbridge/amd/cimx/sb700/smbus.h" /*SMBUS_IO_BASE*/
- #include "w83795.h"
-+#include <device/smbus.h>
-+#include "chip.h"
- 
--static int w83795_set_bank(u8 bank)
-+static int w83795_set_bank(struct device *dev, uint8_t bank)
- {
--      return do_smbus_write_byte(SMBUS_IO_BASE, W83795_DEV, 
W83795_REG_BANKSEL, bank);
-+      return smbus_write_byte(dev, W83795_REG_BANKSEL, bank);
- }
- 
--static u8 w83795_read(u16 reg)
-+static uint8_t w83795_read(struct device *dev, uint16_t reg)
- {
-       int ret;
- 
--      ret = w83795_set_bank(reg >> 8);
-+      ret = w83795_set_bank(dev, reg >> 8);
-       if (ret < 0) {
--              printk(BIOS_DEBUG, "read faild to set bank %x\n", reg >> 8);
-+              printk(BIOS_DEBUG, "read failed to set bank %x\n", reg >> 8);
-               return -1;
-       }
- 
--      ret = do_smbus_read_byte(SMBUS_IO_BASE, W83795_DEV, reg & 0xff);
-+      ret = smbus_read_byte(dev, reg & 0xff);
-       return ret;
- }
- 
--static u8 w83795_write(u16 reg, u8 value)
-+static uint8_t w83795_write(struct device *dev, uint16_t reg, uint8_t value)
- {
-       int err;
- 
--      err = w83795_set_bank(reg >> 8);
-+      err = w83795_set_bank(dev, reg >> 8);
-       if (err < 0) {
--              printk(BIOS_DEBUG, "write faild to set bank %x\n", reg >> 8);
-+              printk(BIOS_DEBUG, "write failed to set bank %x\n", reg >> 8);
-               return -1;
-       }
- 
--      err = do_smbus_write_byte(SMBUS_IO_BASE, W83795_DEV, reg & 0xff, value);
-+      err = smbus_write_byte(dev, reg & 0xff, value);
-       return err;
- }
- 
- /*
-- * Enable Digital Temperature Sensor
-+ * Configure Digital Temperature Sensor
-  */
--static void w83795_dts_enable(u8 dts_src)
-+static void w83795_dts_configure(struct device *dev, uint8_t dts_src)
- {
-       u8 val;
- 
-       /* DIS */
--      val = w83795_read(W83795_REG_DTSC);
-+      val = w83795_read(dev, W83795_REG_DTSC);
-       val |= (dts_src & 0x01);
--      w83795_write(W83795_REG_DTSC, val);
--
--      /* DTSE */
--      val = w83795_read(W83795_REG_DTSE);
--      val |= 0xFF;
--      w83795_write(W83795_REG_DTSE, val);
--
--      /* store bank3 regs first before enable DTS */
--
--      /*
--       * TD/TR1-4 thermal diode by default
--       *  0x00 Disable
--       *  0x01 thermistors on motherboard
--       *  0x10 different mode voltage
--       *  0x11 CPU internal thermal diode output
--       *
--       * TR5-6 thermistors by default  TRn
--       */
--      val = 0x55; /* thermal diode */
--      w83795_write(W83795_REG_TEMP_CTRL2, val);
--
--      /* Enable Digital Temperature Sensor */
--      val = w83795_read(W83795_REG_TEMP_CTRL1);
--      val |= W83795_REG_TEMP_CTRL1_EN_DTS; /* EN_DTS */
--      w83795_write(W83795_REG_TEMP_CTRL1, val);
-+      w83795_write(dev, W83795_REG_DTSC, val);
- }
- 
--static void w83795_set_tfmr(w83795_fan_mode_t mode)
--{
--      u8 val;
--      u8 i;
--
--      if ((mode == SMART_FAN_MODE) || (mode == THERMAL_CRUISE_MODE)) {
--              val = 0xFF;
--      } else {
--              val = 0x00;
--      }
--
--      for (i = 0; i < 6; i++)
--              w83795_write(W83795_REG_TFMR(i), val);
--}
--
--static u32 w83795_set_fan_mode(w83795_fan_mode_t mode)
-+static u32 w83795_set_fan_mode(struct device *dev, w83795_fan_mode_t mode)
- {
-       if (mode == SPEED_CRUISE_MODE) {
--              w83795_write(W83795_REG_FCMS1, 0xFF);
-+              w83795_write(dev, W83795_REG_FCMS1, 0xFF);
-               printk(BIOS_INFO, "W83795G/ADG work in Speed Cruise Mode\n");
-       }  else {
--              w83795_write(W83795_REG_FCMS1, 0x00);
-+              w83795_write(dev, W83795_REG_FCMS1, 0x00);
-               if (mode == THERMAL_CRUISE_MODE) {
--                      w83795_write(W83795_REG_FCMS2, 0x00);
-+                      w83795_write(dev, W83795_REG_FCMS2, 0x00);
-                       printk(BIOS_INFO, "W83795G/ADG work in Thermal Cruise 
Mode\n");
-               } else if (mode == SMART_FAN_MODE) {
--                      w83795_write(W83795_REG_FCMS2, 0x3F);
-+                      w83795_write(dev, W83795_REG_FCMS2, 0x3F);
-                       printk(BIOS_INFO, "W83795G/ADG work in Smart Fan 
Mode\n");
-               } else {
-                       printk(BIOS_INFO, "W83795G/ADG work in Manual Mode\n");
-@@ -131,40 +94,12 @@ static u32 w83795_set_fan_mode(w83795_fan_mode_t mode)
-       return 0;
- }
- 
--static void w83795_set_tss(void)
--{
--      u8 val;
--
--      val = 0x00;
--      w83795_write(W83795_REG_TSS(0), val); /* Temp1, 2 */
--      w83795_write(W83795_REG_TSS(1), val); /* Temp3, 4 */
--      w83795_write(W83795_REG_TSS(2), val); /* Temp5, 6 */
--}
--
--static void w83795_set_fan(w83795_fan_mode_t mode)
-+static void w83795_set_fan(struct device *dev, w83795_fan_mode_t mode)
- {
--      u8 i;
--
--      /* select temperature sensor (TSS)*/
--      w83795_set_tss();
--
--      /* select Temperature to Fan mapping Relationships (TFMR)*/
--      w83795_set_tfmr(mode);
--
-       /* set fan output controlled mode (FCMS)*/
--      w83795_set_fan_mode(mode);
-+      w83795_set_fan_mode(dev, mode);
- 
--      /* Set Critical Temperature to Full Speed all fan (CTFS) */
--      for (i = 0; i < 6; i++) {
--              w83795_write(W83795_REG_CTFS(i), 0x50); /* default 80 celsius 
degree */
--      }
--
--      if (mode == THERMAL_CRUISE_MODE) {
--              /* Set Target Temperature of Temperature Inputs (TTTI) */
--              for (i = 0; i < 6; i++) {
--                      w83795_write(W83795_REG_TTTI(i), 0x28); /* default 40 
celsius degree */
--              }
--      } else if (mode == SMART_FAN_MODE) {
-+      if (mode == SMART_FAN_MODE) {
-               /* Set the Relative Register-at SMART FAN IV Control Mode Table 
*/
-               //SFIV TODO
-       }
-@@ -173,16 +108,44 @@ static void w83795_set_fan(w83795_fan_mode_t mode)
-       //TODO
- }
- 
--static void w83795_init(w83795_fan_mode_t mode, u8 dts_src)
-+static uint8_t fan_pct_to_cfg_val(uint8_t percent)
- {
--      u8 i;
--      u8 val;
-+      uint16_t cfg = (((unsigned int)percent * 10000) / 3922);
-+      if (cfg > 0xff)
-+              cfg = 0xff;
-+      return cfg;
-+}
-+
-+static uint8_t millivolts_to_limit_value_type1(int millivolts)
-+{
-+      /* Datasheet v1.41 page 44 (VSEN1 - VSEN13, VTT) */
-+      return ((millivolts / 2) >> 2);
-+}
- 
--      if (do_smbus_read_byte(SMBUS_IO_BASE, W83795_DEV, 0x00) < 0) {
-+static uint8_t millivolts_to_limit_value_type2(int millivolts)
-+{
-+      /* Datasheet v1.41 page 44 (3VSB, 3VDD, VBAT) */
-+      return ((millivolts / 6) >> 2);
-+}
-+
-+static uint16_t millivolts_to_limit_value_type3(int millivolts)
-+{
-+      /* Datasheet v1.41 page 44 (VDSEN14 - VDSEN17) */
-+      return (millivolts / 2);
-+}
-+
-+static void w83795_init(struct device *dev, w83795_fan_mode_t mode, u8 
dts_src)
-+{
-+      struct drivers_i2c_w83795_config *config = dev->chip_info;
-+      uint8_t i;
-+      uint8_t val;
-+      uint16_t limit_value;
-+
-+      if (smbus_read_byte(dev, 0x00) < 0) {
-               printk(BIOS_ERR, "W83795G/ADG Nuvoton H/W Monitor not found\n");
-               return;
-       }
--      val = w83795_read(W83795_REG_CONFIG);
-+      val = w83795_read(dev, W83795_REG_CONFIG);
-       if ((val & W83795_REG_CONFIG_CONFIG48) == 0)
-               printk(BIOS_INFO, "Found 64 pin W83795G Nuvoton H/W Monitor\n");
-       else if ((val & W83795_REG_CONFIG_CONFIG48) == 1)
-@@ -190,35 +153,178 @@ static void w83795_init(w83795_fan_mode_t mode, u8 
dts_src)
- 
-       /* Reset */
-       val |= W83795_REG_CONFIG_INIT;
--      w83795_write(W83795_REG_CONFIG, val);
-+      w83795_write(dev, W83795_REG_CONFIG, val);
-+
-+      /* Fan monitor settings */
-+      w83795_write(dev, W83795_REG_FANIN_CTRL1, config->fanin_ctl1);
-+      w83795_write(dev, W83795_REG_FANIN_CTRL2, config->fanin_ctl2);
-+
-+      /* Temperature thresholds */
-+      w83795_write(dev, W83795_REG_TEMP_CRIT(0), 
config->tr1_critical_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(0), 
config->tr1_critical_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_WARN(0), 
config->tr1_warning_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(0), 
config->tr1_warning_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT(1), 
config->tr2_critical_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(1), 
config->tr2_critical_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_WARN(1), 
config->tr2_warning_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(1), 
config->tr2_warning_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT(2), 
config->tr3_critical_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(2), 
config->tr3_critical_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_WARN(2), 
config->tr3_warning_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(2), 
config->tr3_warning_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT(3), 
config->tr4_critical_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(3), 
config->tr4_critical_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_WARN(3), 
config->tr4_warning_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(3), 
config->tr4_warning_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT(4), 
config->tr5_critical_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(4), 
config->tr5_critical_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_WARN(4), 
config->tr5_warning_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(4), 
config->tr5_warning_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT(5), 
config->tr6_critical_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(5), 
config->tr6_critical_hysteresis);
-+      w83795_write(dev, W83795_REG_TEMP_WARN(5), 
config->tr6_warning_temperature);
-+      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(5), 
config->tr6_warning_hysteresis);
-+
-+      /* DTS enable */
-+      w83795_write(dev, W83795_REG_DTSE, config->temp_dtse);
-+
-+      /* DTS temperature thresholds */
-+      w83795_write(dev, W83795_REG_DTS_CRIT, 
config->dts_critical_temperature);
-+      w83795_write(dev, W83795_REG_DTS_CRIT_HYSTER, 
config->dts_critical_hysteresis);
-+      w83795_write(dev, W83795_REG_DTS_WARN, config->dts_warning_temperature);
-+      w83795_write(dev, W83795_REG_DTS_WARN_HYSTER, 
config->dts_warning_hysteresis);
-+
-+      /* Configure DTS registers in bank3 before enabling DTS */
-+      w83795_dts_configure(dev, dts_src);
-+
-+      /* Temperature monitor settings */
-+      w83795_write(dev, W83795_REG_TEMP_CTRL1, config->temp_ctl1);
-+      w83795_write(dev, W83795_REG_TEMP_CTRL2, config->temp_ctl2);
-+
-+      /* Temperature to fan mappings */
-+      w83795_write(dev, W83795_REG_TFMR(0), config->temp1_fan_select);
-+      w83795_write(dev, W83795_REG_TFMR(1), config->temp2_fan_select);
-+      w83795_write(dev, W83795_REG_TFMR(2), config->temp3_fan_select);
-+      w83795_write(dev, W83795_REG_TFMR(3), config->temp4_fan_select);
-+      w83795_write(dev, W83795_REG_TFMR(4), config->temp5_fan_select);
-+      w83795_write(dev, W83795_REG_TFMR(5), config->temp6_fan_select);
-+
-+      /* Temperature data source to temperature mappings */
-+      w83795_write(dev, W83795_REG_T12TSS, ((config->temp2_source_select & 
0xff) << 8) | (config->temp1_source_select & 0xff));
-+      w83795_write(dev, W83795_REG_T34TSS, ((config->temp4_source_select & 
0xff) << 8) | (config->temp3_source_select & 0xff));
-+      w83795_write(dev, W83795_REG_T56TSS, ((config->temp6_source_select & 
0xff) << 8) | (config->temp5_source_select & 0xff));
- 
--      /* Fan monitoring setting */
--      val = 0xFF; /* FAN1-FAN8 */
--      w83795_write(W83795_REG_FANIN_CTRL1, val);
--      val = 0x3F; /* FAN9-FAN14 */
--      w83795_write(W83795_REG_FANIN_CTRL2, val);
--
--      /* enable monitoring operations */
--      val = w83795_read(W83795_REG_CONFIG);
--      val |= W83795_REG_CONFIG_START;
--      w83795_write(W83795_REG_CONFIG, val);
--
--      w83795_dts_enable(dts_src);
--      w83795_set_fan(mode);
-+      /* Set Critical Temperature to Full Speed all fan (CTFS) */
-+      w83795_write(dev, W83795_REG_CTFS(0), 
config->temp1_critical_temperature);
-+      w83795_write(dev, W83795_REG_CTFS(1), 
config->temp2_critical_temperature);
-+      w83795_write(dev, W83795_REG_CTFS(2), 
config->temp3_critical_temperature);
-+      w83795_write(dev, W83795_REG_CTFS(3), 
config->temp4_critical_temperature);
-+      w83795_write(dev, W83795_REG_CTFS(4), 
config->temp5_critical_temperature);
-+      w83795_write(dev, W83795_REG_CTFS(5), 
config->temp6_critical_temperature);
-+
-+      /* Set fan control target temperatures */
-+      w83795_write(dev, W83795_REG_TTTI(0), config->temp1_target_temperature);
-+      w83795_write(dev, W83795_REG_TTTI(1), config->temp2_target_temperature);
-+      w83795_write(dev, W83795_REG_TTTI(2), config->temp3_target_temperature);
-+      w83795_write(dev, W83795_REG_TTTI(3), config->temp4_target_temperature);
-+      w83795_write(dev, W83795_REG_TTTI(4), config->temp5_target_temperature);
-+      w83795_write(dev, W83795_REG_TTTI(5), config->temp6_target_temperature);
-+
-+      /* Set fan stall prevention parameters */
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(0), config->fan1_nonstop);
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(1), config->fan2_nonstop);
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(2), config->fan3_nonstop);
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(3), config->fan4_nonstop);
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(4), config->fan5_nonstop);
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(5), config->fan6_nonstop);
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(6), config->fan7_nonstop);
-+      w83795_write(dev, W83795_REG_FAN_NONSTOP(7), config->fan8_nonstop);
-+
-+      /* Set fan default speed */
-+      w83795_write(dev, W83795_REG_DFSP, 
fan_pct_to_cfg_val(config->default_speed));
-+
-+      /* Set initial fan speeds */
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(0), 
fan_pct_to_cfg_val(config->fan1_duty));
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(1), 
fan_pct_to_cfg_val(config->fan2_duty));
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(2), 
fan_pct_to_cfg_val(config->fan3_duty));
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(3), 
fan_pct_to_cfg_val(config->fan4_duty));
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(4), 
fan_pct_to_cfg_val(config->fan5_duty));
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(5), 
fan_pct_to_cfg_val(config->fan6_duty));
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(6), 
fan_pct_to_cfg_val(config->fan7_duty));
-+      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(7), 
fan_pct_to_cfg_val(config->fan8_duty));
-+
-+      /* Voltage monitor settings */
-+      w83795_write(dev, W83795_REG_VOLT_CTRL1, config->volt_ctl1);
-+      w83795_write(dev, W83795_REG_VOLT_CTRL2, config->volt_ctl2);
-+
-+      /* Voltage high/low limits */
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(0), 
millivolts_to_limit_value_type1(config->vcore1_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(0), 
millivolts_to_limit_value_type1(config->vcore1_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(1), 
millivolts_to_limit_value_type1(config->vcore2_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(1), 
millivolts_to_limit_value_type1(config->vcore2_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(2), 
millivolts_to_limit_value_type1(config->vsen3_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(2), 
millivolts_to_limit_value_type1(config->vsen3_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(3), 
millivolts_to_limit_value_type1(config->vsen4_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(3), 
millivolts_to_limit_value_type1(config->vsen4_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(4), 
millivolts_to_limit_value_type1(config->vsen5_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(4), 
millivolts_to_limit_value_type1(config->vsen5_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(5), 
millivolts_to_limit_value_type1(config->vsen6_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(5), 
millivolts_to_limit_value_type1(config->vsen6_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(6), 
millivolts_to_limit_value_type1(config->vsen7_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(6), 
millivolts_to_limit_value_type1(config->vsen7_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(7), 
millivolts_to_limit_value_type1(config->vsen8_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(7), 
millivolts_to_limit_value_type1(config->vsen8_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(8), 
millivolts_to_limit_value_type1(config->vsen9_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(8), 
millivolts_to_limit_value_type1(config->vsen9_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(9), 
millivolts_to_limit_value_type1(config->vsen10_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(9), 
millivolts_to_limit_value_type1(config->vsen10_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(10), 
millivolts_to_limit_value_type1(config->vsen11_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(10), 
millivolts_to_limit_value_type1(config->vsen11_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(11), 
millivolts_to_limit_value_type1(config->vtt_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(11), 
millivolts_to_limit_value_type1(config->vtt_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(12), 
millivolts_to_limit_value_type2(config->vdd_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(12), 
millivolts_to_limit_value_type2(config->vdd_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(13), 
millivolts_to_limit_value_type2(config->vsb_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(13), 
millivolts_to_limit_value_type2(config->vsb_low_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(14), 
millivolts_to_limit_value_type2(config->vbat_high_limit_mv));
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(14), 
millivolts_to_limit_value_type2(config->vbat_low_limit_mv));
-+
-+      /* VSEN12 limits */
-+      limit_value = 
millivolts_to_limit_value_type3(config->vsen12_high_limit_mv);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_M(4), limit_value >> 2);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_L(4), limit_value & 0x3);
-+      limit_value = 
millivolts_to_limit_value_type3(config->vsen12_low_limit_mv);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_M(4), limit_value >> 2);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_L(4), limit_value & 0x3);
-+
-+      /* VSEN13 limits */
-+      limit_value = 
millivolts_to_limit_value_type3(config->vsen13_high_limit_mv);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_M(5), limit_value >> 2);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_L(5), limit_value & 0x3);
-+      limit_value = 
millivolts_to_limit_value_type3(config->vsen13_low_limit_mv);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_M(5), limit_value >> 2);
-+      w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_L(5), limit_value & 0x3);
-+
-+      w83795_set_fan(dev, mode);
- 
-       printk(BIOS_INFO, "Fan   CTFS(celsius)  TTTI(celsius)\n");
-       for (i = 0; i < 6; i++) {
--              val = w83795_read(W83795_REG_CTFS(i));
-+              val = w83795_read(dev, W83795_REG_CTFS(i));
-               printk(BIOS_INFO, " %x     %d", i, val);
--              val = w83795_read(W83795_REG_TTTI(i));
-+              val = w83795_read(dev, W83795_REG_TTTI(i));
-               printk(BIOS_INFO, "             %d\n", val);
-       }
- 
-       /* Temperature ReadOut */
-       for (i = 0; i < 9; i++) {
--              val = w83795_read(W83795_REG_DTS(i));
-+              val = w83795_read(dev, W83795_REG_DTS(i));
-               printk(BIOS_DEBUG, "DTS%x ReadOut=%x\n", i, val);
-       }
-+
-+      /* start monitoring operation */
-+      val = w83795_read(dev, W83795_REG_CONFIG);
-+      val |= W83795_REG_CONFIG_START;
-+      w83795_write(dev, W83795_REG_CONFIG, val);
- }
- 
- static void w83795_hwm_init(struct device *dev)
-@@ -232,9 +338,9 @@ static void w83795_hwm_init(struct device *dev)
-               die("CPU: missing cpu device structure");
- 
-       if (cpu->vendor == X86_VENDOR_AMD)
--              w83795_init(THERMAL_CRUISE_MODE, DTS_SRC_AMD_SBTSI);
-+              w83795_init(dev, THERMAL_CRUISE_MODE, DTS_SRC_AMD_SBTSI);
-       else if (cpu->vendor == X86_VENDOR_INTEL)
--              w83795_init(THERMAL_CRUISE_MODE, DTS_SRC_INTEL_PECI);
-+              w83795_init(dev, THERMAL_CRUISE_MODE, DTS_SRC_INTEL_PECI);
-       else
-               printk(BIOS_ERR, "Neither AMD nor INTEL CPU detected\n");
- }
-diff --git a/src/drivers/i2c/w83795/w83795.h b/src/drivers/i2c/w83795/w83795.h
-index cac4d5f..0727dc5 100644
---- a/src/drivers/i2c/w83795/w83795.h
-+++ b/src/drivers/i2c/w83795/w83795.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2012 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -20,8 +21,6 @@
- #ifndef _W83795_H_
- #define _W83795_H_
- 
--#define W83795_DEV                    0x2F /* Host I2c Addr (strap to addr1 
addr0 1 1, 0x5E) */
--
- #define W83795_REG_I2C_ADDR           0xFC
- #define W83795_REG_BANKSEL            0x00
- #define W83795_REG_CONFIG             0x01
-@@ -29,6 +28,8 @@
- #define W83795_REG_CONFIG_CONFIG48    0x04
- #define W83795_REG_CONFIG_INIT                0x80
- 
-+#define W83795_REG_VOLT_CTRL1         0x02
-+#define W83795_REG_VOLT_CTRL2         0x03
- #define W83795_REG_TEMP_CTRL1         0x04 /* Temperature Monitoring Control 
Register */
- #define W83795_REG_TEMP_CTRL2         0x05 /* Temperature Monitoring Control 
Register */
- #define W83795_REG_FANIN_CTRL1                0x06
-@@ -37,37 +38,58 @@
- #define DTS_SRC_INTEL_PECI            (0 << 0)
- #define DTS_SRC_AMD_SBTSI             (1 << 0)
- 
--#define W83795_REG_TSS(n)             (0x209 + (n)) /* Temperature Source 
Selection Register */
- #define W83795_REG_TTTI(n)            (0x260 + (n)) /* Target temperature 
W83795G/ADG will try to tune the fan output to keep */
- #define W83795_REG_CTFS(n)            (0x268 + (n)) /* Critical Temperature 
to Full Speed all fan */
--#define W83795_REG_HT(n)              (0x270 + (n)) /* Hysteresis of 
Temperature */
- #define W83795_REG_DTSC                       0x301 /* Digital Temperature 
Sensor Configuration */
- 
- #define W83795_REG_DTSE                       0x302 /* Digital Temperature 
Sensor Enable */
- #define W83795_REG_DTS(n)             (0x26 + (n))
- #define W83795_REG_VRLSB              0x3C
- 
--#define W83795_TEMP_REG_TR1           0x21
--#define W83795_TEMP_REG_TR2           0x22
--#define W83795_TEMP_REG_TR3           0x23
--#define W83795_TEMP_REG_TR4           0x24
--#define W83795_TEMP_REG_TR5           0x1F
--#define W83795_TEMP_REG_TR6           0x20
-+#define W83795_REG_TEMP_TR1           0x21
-+#define W83795_REG_TEMP_TR2           0x22
-+#define W83795_REG_TEMP_TR3           0x23
-+#define W83795_REG_TEMP_TR4           0x24
-+#define W83795_REG_TEMP_TR5           0x1F
-+#define W83795_REG_TEMP_TR6           0x20
-+
-+#define W83795_REG_VOLT_LIM_HIGH(n)   (0x70 + (n * 2))        /* Voltage high 
limit (0 == VSEN1) */
-+#define W83795_REG_VOLT_LIM_LOW(n)    (0x71 + (n * 2))        /* Voltage low 
limit (0 == VSEN1) */
-+#define W83795_REG_VOLT_LIM_HIGH_2_M(n)       (0x96 + (n * 4))        /* 
Voltage high limit MSB (0 == VDSEN14) */
-+#define W83795_REG_VOLT_LIM_LOW_2_M(n)        (0x97 + (n * 4))        /* 
Voltage low limit MSB (0 == VDSEN14)  */
-+#define W83795_REG_VOLT_LIM_HIGH_2_L(n)       (0x98 + (n * 4))        /* 
Voltage high limit LSB (0 == VDSEN14) */
-+#define W83795_REG_VOLT_LIM_LOW_2_L(n)        (0x99 + (n * 4))        /* 
Voltage low limit LSB (0 == VDSEN14)  */
-+
-+#define W83795_REG_TEMP_CRIT(n)               (0x96 + (n * 4))        /* 
Temperature critical limit */
-+#define W83795_REG_TEMP_CRIT_HYSTER(n)        (0x97 + (n * 4))        /* 
Temperature critical limit hysteresis */
-+#define W83795_REG_TEMP_WARN(n)               (0x98 + (n * 4))        /* 
Temperature warning limit */
-+#define W83795_REG_TEMP_WARN_HYSTER(n)        (0x99 + (n * 4))        /* 
Temperature warning limit hysteresis */
-+
-+#define W83795_REG_DTS_CRIT           0xB2                    /* Temperature 
critical limit */
-+#define W83795_REG_DTS_CRIT_HYSTER    0xB3                    /* Temperature 
critical limit hysteresis */
-+#define W83795_REG_DTS_WARN           0xB4                    /* Temperature 
warning limit */
-+#define W83795_REG_DTS_WARN_HYSTER    0xB5                    /* Temperature 
warning limit hysteresis */
- 
- #define W83795_REG_FCMS1              0x201
- #define W83795_REG_FCMS2              0x208
--#define W83795_REG_TFMR(n)            (0x202 + (n)) /*temperature to fam 
mappig*/
-+#define W83795_REG_TFMR(n)            (0x202 + (n))           /* Temperature 
to fan mapping */
-+#define W83795_REG_T12TSS             0x209                   /* Temperature 
Source Selection Register 1 */
-+#define W83795_REG_T34TSS             0x20A                   /* Temperature 
Source Selection Register 2 */
-+#define W83795_REG_T56TSS             0x20B                   /* Temperature 
Source Selection Register 3 */
-+#define W83795_REG_FAN_MANUAL_SPEED(n)        (0x210 + n)
- #define W83795_REG_DFSP                       0x20C
- 
-+#define W83795_REG_FAN_NONSTOP(n)     (0x228 + (n))   /* Fan Nonstop Value */
-+
- #define W83795_REG_FTSH(n)            (0x240 + (n) * 2)
- #define W83795_REG_FTSL(n)            (0x241 + (n) * 2)
- #define W83795_REG_TFTS                       0x250
- 
- typedef enum w83795_fan_mode {
--      SPEED_CRUISE_MODE,      ///< Fan Speed Cruise mode keeps the fan speed 
in a specified range
--      THERMAL_CRUISE_MODE,    ///< Thermal Cruise mode is an algorithm to 
control the fan speed to keep the temperature source around the TTTI
--      SMART_FAN_MODE,         ///< Smart Fan mode offers 6 slopes to control 
the fan speed
--      MANUAL_MODE,            ///< control manually
-+      SPEED_CRUISE_MODE = 0,          ///< Fan Speed Cruise mode keeps the 
fan speed in a specified range
-+      THERMAL_CRUISE_MODE = 1,        ///< Thermal Cruise mode is an 
algorithm to control the fan speed to keep the temperature source around the 
TTTI
-+      SMART_FAN_MODE = 2,             ///< Smart Fan mode offers 6 slopes to 
control the fan speed
-+      MANUAL_MODE = 3,                ///< control manually
- } w83795_fan_mode_t;
- 
- #endif
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0002-southbridge-amd-sb700-Allow-use-of-auxiliary-SMBUS-c.patch
 
b/resources/libreboot/patch/kgpe-d16/0002-southbridge-amd-sb700-Allow-use-of-auxiliary-SMBUS-c.patch
index 651c973..b5f03eb 100644
--- 
a/resources/libreboot/patch/kgpe-d16/0002-southbridge-amd-sb700-Allow-use-of-auxiliary-SMBUS-c.patch
+++ 
b/resources/libreboot/patch/kgpe-d16/0002-southbridge-amd-sb700-Allow-use-of-auxiliary-SMBUS-c.patch
@@ -1,28 +1,29 @@
-From 6ae8695f880a4a15672eda801226b4b1c83aa1a8 Mon Sep 17 00:00:00 2001
+From c3691fe7c155d63baedbb1836e6ccf9c1fcb5846 Mon Sep 17 00:00:00 2001
 From: Timothy Pearson <address@hidden>
 Date: Sat, 17 Oct 2015 04:36:47 -0500
-Subject: [PATCH 002/139] southbridge/amd/sb700: Allow use of auxiliary SMBUS
+Subject: [PATCH 002/143] southbridge/amd/sb700: Allow use of auxiliary SMBUS
  controller
 
 Change-Id: I29ece10eeefc2c75a3829c169f1e1aede7194ec2
 Signed-off-by: Timothy Pearson <address@hidden>
 ---
- src/device/Kconfig                |  4 ++++
- src/include/device/smbus.h        |  5 +++++
- src/southbridge/amd/sb700/Kconfig |  1 +
- src/southbridge/amd/sb700/sm.c    | 36 +++++++++++++++++++++++++++++++-----
- src/southbridge/amd/sb700/smbus.c | 15 +++++++++++++++
- 5 files changed, 56 insertions(+), 5 deletions(-)
+ src/device/Kconfig                |    4 ++++
+ src/include/device/smbus.h        |    5 ++++
+ src/southbridge/amd/sb700/Kconfig |    1 +
+ src/southbridge/amd/sb700/sm.c    |   47 ++++++++++++++++++++++++++++++-------
+ src/southbridge/amd/sb700/smbus.c |   15 ++++++++++++
+ src/southbridge/amd/sb700/smbus.h |    5 ++--
+ 6 files changed, 66 insertions(+), 11 deletions(-)
 
 diff --git a/src/device/Kconfig b/src/device/Kconfig
-index 613461b..3dd2b61 100644
+index 613461b..bcf7dad 100644
 --- a/src/device/Kconfig
 +++ b/src/device/Kconfig
 @@ -192,6 +192,10 @@ config MULTIPLE_VGA_ADAPTERS
        bool
        default n
  
-+config SMBUS_HAS_AUX
++config SMBUS_HAS_AUX_CHANNELS
 +      bool
 +      default n
 +
@@ -30,129 +31,133 @@ index 613461b..3dd2b61 100644
        bool
        default n
 diff --git a/src/include/device/smbus.h b/src/include/device/smbus.h
-index 073d7e2..53e90fb 100644
+index 073d7e2..a838f55 100644
 --- a/src/include/device/smbus.h
 +++ b/src/include/device/smbus.h
 @@ -47,4 +47,9 @@ int smbus_process_call(device_t dev, u8 cmd, u16 data);
  int smbus_block_read(device_t dev, u8 cmd, u8 bytes, u8 *buffer);
  int smbus_block_write(device_t dev, u8 cmd, u8 bytes, const u8 *buffer);
  
-+#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX)
-+void smbus_switch_to_aux(uint8_t enable_aux);
-+uint8_t smbus_switched_to_aux(void);
++#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX_CHANNELS)
++void smbus_switch_to_aux_channel(uint8_t aux_channel_number);
++uint8_t smbus_current_aux_channel(void);
 +#endif
 +
  #endif /* DEVICE_SMBUS_H */
 diff --git a/src/southbridge/amd/sb700/Kconfig 
b/src/southbridge/amd/sb700/Kconfig
-index 42ca2bb..a5dfe07 100644
+index 42ca2bb..0761934 100644
 --- a/src/southbridge/amd/sb700/Kconfig
 +++ b/src/southbridge/amd/sb700/Kconfig
 @@ -27,6 +27,7 @@ config SOUTHBRIDGE_SPECIFIC_OPTIONS # dummy
        select IOAPIC
        select HAVE_USBDEBUG_OPTIONS
        select HAVE_HARD_RESET
-+      select SMBUS_HAS_AUX
++      select SMBUS_HAS_AUX_CHANNELS
  
  # Set for southbridge SP5100 which also uses SB700 driver
  config SOUTHBRIDGE_AMD_SUBTYPE_SP5100
 diff --git a/src/southbridge/amd/sb700/sm.c b/src/southbridge/amd/sb700/sm.c
-index f544c88..c216e1f 100644
+index f544c88..598ebec 100644
 --- a/src/southbridge/amd/sb700/sm.c
 +++ b/src/southbridge/amd/sb700/sm.c
-@@ -40,6 +40,8 @@
+@@ -40,6 +40,11 @@
  #define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
  #endif
  
++#define PRIMARY_SMBUS_RESOURCE_NUMBER 0x90
++#define AUXILIARY_SMBUS_RESOURCE_NUMBER 0x58
++
 +uint8_t smbus_use_aux = 0;
 +
  /*
  * SB700 enables all USB controllers by default in SMBUS Control.
  * SB700 enables SATA by default in SMBUS Control.
-@@ -312,7 +314,10 @@ static int lsmbus_recv_byte(device_t dev)
+@@ -312,7 +317,10 @@ static int lsmbus_recv_byte(device_t dev)
        device = dev->path.i2c.device;
        pbus = get_pbus_smbus(dev);
  
 -      res = find_resource(pbus->dev, 0x90);
 +      if (!smbus_use_aux)
-+              res = find_resource(pbus->dev, 0x90);
++              res = find_resource(pbus->dev, PRIMARY_SMBUS_RESOURCE_NUMBER);
 +      else
-+              res = find_resource(pbus->dev, 0x58);
++              res = find_resource(pbus->dev, AUXILIARY_SMBUS_RESOURCE_NUMBER);
  
        return do_smbus_recv_byte(res->base, device);
  }
-@@ -326,7 +331,10 @@ static int lsmbus_send_byte(device_t dev, u8 val)
+@@ -326,7 +334,10 @@ static int lsmbus_send_byte(device_t dev, u8 val)
        device = dev->path.i2c.device;
        pbus = get_pbus_smbus(dev);
  
 -      res = find_resource(pbus->dev, 0x90);
 +      if (!smbus_use_aux)
-+              res = find_resource(pbus->dev, 0x90);
++              res = find_resource(pbus->dev, PRIMARY_SMBUS_RESOURCE_NUMBER);
 +      else
-+              res = find_resource(pbus->dev, 0x58);
++              res = find_resource(pbus->dev, AUXILIARY_SMBUS_RESOURCE_NUMBER);
  
        return do_smbus_send_byte(res->base, device, val);
  }
-@@ -340,7 +348,10 @@ static int lsmbus_read_byte(device_t dev, u8 address)
+@@ -340,7 +351,10 @@ static int lsmbus_read_byte(device_t dev, u8 address)
        device = dev->path.i2c.device;
        pbus = get_pbus_smbus(dev);
  
 -      res = find_resource(pbus->dev, 0x90);
 +      if (!smbus_use_aux)
-+              res = find_resource(pbus->dev, 0x90);
++              res = find_resource(pbus->dev, PRIMARY_SMBUS_RESOURCE_NUMBER);
 +      else
-+              res = find_resource(pbus->dev, 0x58);
++              res = find_resource(pbus->dev, AUXILIARY_SMBUS_RESOURCE_NUMBER);
  
        return do_smbus_read_byte(res->base, device, address);
  }
-@@ -354,7 +365,10 @@ static int lsmbus_write_byte(device_t dev, u8 address, u8 
val)
+@@ -354,7 +368,10 @@ static int lsmbus_write_byte(device_t dev, u8 address, u8 
val)
        device = dev->path.i2c.device;
        pbus = get_pbus_smbus(dev);
  
 -      res = find_resource(pbus->dev, 0x90);
 +      if (!smbus_use_aux)
-+              res = find_resource(pbus->dev, 0x90);
++              res = find_resource(pbus->dev, PRIMARY_SMBUS_RESOURCE_NUMBER);
 +      else
-+              res = find_resource(pbus->dev, 0x58);
++              res = find_resource(pbus->dev, AUXILIARY_SMBUS_RESOURCE_NUMBER);
  
        return do_smbus_write_byte(res->base, device, address, val);
  }
-@@ -393,7 +407,7 @@ static void sb700_sm_read_resources(device_t dev)
+@@ -393,9 +410,18 @@ static void sb700_sm_read_resources(device_t dev)
  
        /* dev->command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; */
  
 -      /* smbus */
+-      res = new_resource(dev, 0x90);
+-      res->base  = 0xB00;
 +      /* primary smbus */
-       res = new_resource(dev, 0x90);
-       res->base  = 0xB00;
-       res->size = 0x10;
-@@ -402,6 +416,15 @@ static void sb700_sm_read_resources(device_t dev)
-       res->gran = 8;
-       res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_RESERVE | 
IORESOURCE_ASSIGNED;
- 
-+      /* auxiliary smbus */
-+      res = new_resource(dev, 0x58);
-+      res->base  = 0xB20;
++      res = new_resource(dev, PRIMARY_SMBUS_RESOURCE_NUMBER);
++      res->base  = SMBUS_IO_BASE;
 +      res->size = 0x10;
 +      res->limit = 0xFFFFUL;  /* res->base + res->size -1; */
 +      res->align = 8;
 +      res->gran = 8;
 +      res->flags = IORESOURCE_IO | IORESOURCE_FIXED | IORESOURCE_RESERVE | 
IORESOURCE_ASSIGNED;
 +
-       compact_resources(dev);
- }
- 
-@@ -441,6 +464,9 @@ static void sb700_sm_set_resources(struct device *dev)
- 
-       res = find_resource(dev, 0x90);
-       pci_write_config32(dev, 0x90, res->base | 1);
++      /* auxiliary smbus */
++      res = new_resource(dev, AUXILIARY_SMBUS_RESOURCE_NUMBER);
++      res->base  = SMBUS_AUX_IO_BASE;
+       res->size = 0x10;
+       res->limit = 0xFFFFUL;  /* res->base + res->size -1; */
+       res->align = 8;
+@@ -439,8 +465,11 @@ static void sb700_sm_set_resources(struct device *dev)
+       pci_write_config8(dev, 0x65, byte);
+       /* TODO: End of test hpet */
+ 
+-      res = find_resource(dev, 0x90);
+-      pci_write_config32(dev, 0x90, res->base | 1);
++      res = find_resource(dev, PRIMARY_SMBUS_RESOURCE_NUMBER);
++      pci_write_config32(dev, PRIMARY_SMBUS_RESOURCE_NUMBER, res->base | 1);
 +
-+      res = find_resource(dev, 0x58);
-+      pci_write_config32(dev, 0x58, res->base | 1);
++      res = find_resource(dev, AUXILIARY_SMBUS_RESOURCE_NUMBER);
++      pci_write_config32(dev, AUXILIARY_SMBUS_RESOURCE_NUMBER, res->base | 1);
  }
  
  static struct pci_operations lops_pci = {
 diff --git a/src/southbridge/amd/sb700/smbus.c 
b/src/southbridge/amd/sb700/smbus.c
-index 94f5e24..a89e830 100644
+index 94f5e24..e1cfe6b 100644
 --- a/src/southbridge/amd/sb700/smbus.c
 +++ b/src/southbridge/amd/sb700/smbus.c
 @@ -22,6 +22,11 @@
@@ -161,8 +166,8 @@ index 94f5e24..a89e830 100644
  
 +extern uint8_t smbus_use_aux;
 +
-+void smbus_switch_to_aux(uint8_t enable_aux);
-+uint8_t smbus_switched_to_aux(void);
++void smbus_switch_to_aux_channel(uint8_t aux_channel_number);
++uint8_t smbus_current_aux_channel(void);
 +
  void alink_ab_indx(u32 reg_space, u32 reg_addr, u32 mask, u32 val)
  {
@@ -171,17 +176,40 @@ index 94f5e24..a89e830 100644
        return 0;
  }
  
-+void smbus_switch_to_aux(uint8_t enable_aux)
++void smbus_switch_to_aux_channel(uint8_t aux_channel_number)
 +{
-+      smbus_use_aux = enable_aux;
++      smbus_use_aux = (aux_channel_number != 0);
 +}
 +
-+uint8_t smbus_switched_to_aux(void)
++uint8_t smbus_current_aux_channel(void)
 +{
 +      return smbus_use_aux;
 +}
 +
  #endif
+diff --git a/src/southbridge/amd/sb700/smbus.h 
b/src/southbridge/amd/sb700/smbus.h
+index d223fe7..34b4098 100644
+--- a/src/southbridge/amd/sb700/smbus.h
++++ b/src/southbridge/amd/sb700/smbus.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -24,8 +25,8 @@
+ #include "stddef.h"
+ #include <arch/io.h>
+ 
+-#define SMBUS_IO_BASE 0x6000  /* Is it a temporary SMBus I/O base address? */
+-                              /*SIZE 0x40 */
++#define SMBUS_IO_BASE 0xb00
++#define SMBUS_AUX_IO_BASE 0xb20
+ 
+ #define SMBHSTSTAT 0x0
+ #define SMBSLVSTAT 0x1
 -- 
-1.9.1
+1.7.9.5
 
diff --git 
a/resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-full-support-for-core-functio.patch
 
b/resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-full-support-for-core-functio.patch
new file mode 100644
index 0000000..0cbdaf6
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-full-support-for-core-functio.patch
@@ -0,0 +1,725 @@
+From 72d183bad6db0f2f91b991710d1c0a8113a071f3 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 17:53:20 -0500
+Subject: [PATCH 003/143] drivers/i2c/w83795: Add full support for core
+ functions
+
+Add full support for fan control, fan monitoring, and voltage
+monitoring.  Fan speeds and functions are configurable via
+each mainboard's devicetree.cb file.
+
+NOTE: This patch effectively rewrites large portions of
+the original driver.  You may need to re-verify correct
+operation on your hardware if you were using the old
+driver code.
+
+Change-Id: I3e246af0e398d65ee43ea708060885c67fd7d202
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/drivers/i2c/w83795/chip.h   |  142 ++++++++++++++++
+ src/drivers/i2c/w83795/w83795.c |  339 ++++++++++++++++++++++++++-------------
+ src/drivers/i2c/w83795/w83795.h |   52 ++++--
+ 3 files changed, 405 insertions(+), 128 deletions(-)
+ create mode 100644 src/drivers/i2c/w83795/chip.h
+
+diff --git a/src/drivers/i2c/w83795/chip.h b/src/drivers/i2c/w83795/chip.h
+new file mode 100644
+index 0000000..c8a42ea
+--- /dev/null
++++ b/src/drivers/i2c/w83795/chip.h
+@@ -0,0 +1,142 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc.
++ */
++
++struct drivers_i2c_w83795_config {
++      uint8_t fanin_ctl1;
++      uint8_t fanin_ctl2;
++
++      uint8_t temp_ctl1;
++      uint8_t temp_ctl2;
++      uint8_t temp_dtse;
++
++      uint8_t volt_ctl1;
++      uint8_t volt_ctl2;
++
++      uint8_t temp1_fan_select;
++      uint8_t temp2_fan_select;
++      uint8_t temp3_fan_select;
++      uint8_t temp4_fan_select;
++      uint8_t temp5_fan_select;
++      uint8_t temp6_fan_select;
++
++      uint8_t temp1_source_select;
++      uint8_t temp2_source_select;
++      uint8_t temp3_source_select;
++      uint8_t temp4_source_select;
++      uint8_t temp5_source_select;
++      uint8_t temp6_source_select;
++
++      uint32_t vcore1_high_limit_mv;          /* mV */
++      uint32_t vcore1_low_limit_mv;           /* mV */
++      uint32_t vcore2_high_limit_mv;          /* mV */
++      uint32_t vcore2_low_limit_mv;           /* mV */
++      uint32_t vtt_high_limit_mv;             /* mV */
++      uint32_t vtt_low_limit_mv;              /* mV */
++      uint32_t vsen3_high_limit_mv;           /* mV */
++      uint32_t vsen3_low_limit_mv;            /* mV */
++      uint32_t vsen4_high_limit_mv;           /* mV */
++      uint32_t vsen4_low_limit_mv;            /* mV */
++      uint32_t vsen5_high_limit_mv;           /* mV */
++      uint32_t vsen5_low_limit_mv;            /* mV */
++      uint32_t vsen6_high_limit_mv;           /* mV */
++      uint32_t vsen6_low_limit_mv;            /* mV */
++      uint32_t vsen7_high_limit_mv;           /* mV */
++      uint32_t vsen7_low_limit_mv;            /* mV */
++      uint32_t vsen8_high_limit_mv;           /* mV */
++      uint32_t vsen8_low_limit_mv;            /* mV */
++      uint32_t vsen9_high_limit_mv;           /* mV */
++      uint32_t vsen9_low_limit_mv;            /* mV */
++      uint32_t vsen10_high_limit_mv;          /* mV */
++      uint32_t vsen10_low_limit_mv;           /* mV */
++      uint32_t vsen11_high_limit_mv;          /* mV */
++      uint32_t vsen11_low_limit_mv;           /* mV */
++      uint32_t vsen12_high_limit_mv;          /* mV */
++      uint32_t vsen12_low_limit_mv;           /* mV */
++      uint32_t vsen13_high_limit_mv;          /* mV */
++      uint32_t vsen13_low_limit_mv;           /* mV */
++      uint32_t vdd_high_limit_mv;             /* mV */
++      uint32_t vdd_low_limit_mv;              /* mV */
++      uint32_t vsb_high_limit_mv;             /* mV */
++      uint32_t vsb_low_limit_mv;              /* mV */
++      uint32_t vbat_high_limit_mv;            /* mV */
++      uint32_t vbat_low_limit_mv;             /* mV */
++
++      int8_t tr1_critical_temperature;        /* °C */
++      int8_t tr1_critical_hysteresis;         /* °C */
++      int8_t tr1_warning_temperature;         /* °C */
++      int8_t tr1_warning_hysteresis;          /* °C */
++      int8_t tr2_critical_temperature;        /* °C */
++      int8_t tr2_critical_hysteresis;         /* °C */
++      int8_t tr2_warning_temperature;         /* °C */
++      int8_t tr2_warning_hysteresis;          /* °C */
++      int8_t tr3_critical_temperature;        /* °C */
++      int8_t tr3_critical_hysteresis;         /* °C */
++      int8_t tr3_warning_temperature;         /* °C */
++      int8_t tr3_warning_hysteresis;          /* °C */
++      int8_t tr4_critical_temperature;        /* °C */
++      int8_t tr4_critical_hysteresis;         /* °C */
++      int8_t tr4_warning_temperature;         /* °C */
++      int8_t tr4_warning_hysteresis;          /* °C */
++      int8_t tr5_critical_temperature;        /* °C */
++      int8_t tr5_critical_hysteresis;         /* °C */
++      int8_t tr5_warning_temperature;         /* °C */
++      int8_t tr5_warning_hysteresis;          /* °C */
++      int8_t tr6_critical_temperature;        /* °C */
++      int8_t tr6_critical_hysteresis;         /* °C */
++      int8_t tr6_warning_temperature;         /* °C */
++      int8_t tr6_warning_hysteresis;          /* °C */
++      int8_t dts_critical_temperature;        /* °C */
++      int8_t dts_critical_hysteresis;         /* °C */
++      int8_t dts_warning_temperature;         /* °C */
++      int8_t dts_warning_hysteresis;          /* °C */
++
++      int8_t temp1_critical_temperature;      /* °C */
++      int8_t temp2_critical_temperature;      /* °C */
++      int8_t temp3_critical_temperature;      /* °C */
++      int8_t temp4_critical_temperature;      /* °C */
++      int8_t temp5_critical_temperature;      /* °C */
++      int8_t temp6_critical_temperature;      /* °C */
++
++      int8_t temp1_target_temperature;        /* °C */
++      int8_t temp2_target_temperature;        /* °C */
++      int8_t temp3_target_temperature;        /* °C */
++      int8_t temp4_target_temperature;        /* °C */
++      int8_t temp5_target_temperature;        /* °C */
++      int8_t temp6_target_temperature;        /* °C */
++
++      uint8_t fan1_nonstop;                   /* % of full speed (0-100) */
++      uint8_t fan2_nonstop;                   /* % of full speed (0-100) */
++      uint8_t fan3_nonstop;                   /* % of full speed (0-100) */
++      uint8_t fan4_nonstop;                   /* % of full speed (0-100) */
++      uint8_t fan5_nonstop;                   /* % of full speed (0-100) */
++      uint8_t fan6_nonstop;                   /* % of full speed (0-100) */
++      uint8_t fan7_nonstop;                   /* % of full speed (0-100) */
++      uint8_t fan8_nonstop;                   /* % of full speed (0-100) */
++
++      uint8_t default_speed;                  /* % of full speed (0-100) */
++
++      uint8_t fan1_duty;                      /* % of full speed (0-100) */
++      uint8_t fan2_duty;                      /* % of full speed (0-100) */
++      uint8_t fan3_duty;                      /* % of full speed (0-100) */
++      uint8_t fan4_duty;                      /* % of full speed (0-100) */
++      uint8_t fan5_duty;                      /* % of full speed (0-100) */
++      uint8_t fan6_duty;                      /* % of full speed (0-100) */
++      uint8_t fan7_duty;                      /* % of full speed (0-100) */
++      uint8_t fan8_duty;                      /* % of full speed (0-100) */
++};
+diff --git a/src/drivers/i2c/w83795/w83795.c b/src/drivers/i2c/w83795/w83795.c
+index 2bbe0be..0af272f 100644
+--- a/src/drivers/i2c/w83795/w83795.c
++++ b/src/drivers/i2c/w83795/w83795.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2012 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -21,106 +22,68 @@
+ #include <arch/cpu.h>
+ #include <console/console.h>
+ #include <device/device.h>
+-#include "southbridge/amd/cimx/sb700/smbus.h" /*SMBUS_IO_BASE*/
+ #include "w83795.h"
++#include <device/smbus.h>
++#include "chip.h"
+ 
+-static int w83795_set_bank(u8 bank)
++static int w83795_set_bank(struct device *dev, uint8_t bank)
+ {
+-      return do_smbus_write_byte(SMBUS_IO_BASE, W83795_DEV, 
W83795_REG_BANKSEL, bank);
++      return smbus_write_byte(dev, W83795_REG_BANKSEL, bank);
+ }
+ 
+-static u8 w83795_read(u16 reg)
++static uint8_t w83795_read(struct device *dev, uint16_t reg)
+ {
+       int ret;
+ 
+-      ret = w83795_set_bank(reg >> 8);
++      ret = w83795_set_bank(dev, reg >> 8);
+       if (ret < 0) {
+-              printk(BIOS_DEBUG, "read faild to set bank %x\n", reg >> 8);
++              printk(BIOS_DEBUG, "read failed to set bank %x\n", reg >> 8);
+               return -1;
+       }
+ 
+-      ret = do_smbus_read_byte(SMBUS_IO_BASE, W83795_DEV, reg & 0xff);
++      ret = smbus_read_byte(dev, reg & 0xff);
+       return ret;
+ }
+ 
+-static u8 w83795_write(u16 reg, u8 value)
++static uint8_t w83795_write(struct device *dev, uint16_t reg, uint8_t value)
+ {
+       int err;
+ 
+-      err = w83795_set_bank(reg >> 8);
++      err = w83795_set_bank(dev, reg >> 8);
+       if (err < 0) {
+-              printk(BIOS_DEBUG, "write faild to set bank %x\n", reg >> 8);
++              printk(BIOS_DEBUG, "write failed to set bank %x\n", reg >> 8);
+               return -1;
+       }
+ 
+-      err = do_smbus_write_byte(SMBUS_IO_BASE, W83795_DEV, reg & 0xff, value);
++      err = smbus_write_byte(dev, reg & 0xff, value);
+       return err;
+ }
+ 
+ /*
+- * Enable Digital Temperature Sensor
++ * Configure Digital Temperature Sensor
+  */
+-static void w83795_dts_enable(u8 dts_src)
++static void w83795_dts_configure(struct device *dev, uint8_t dts_src)
+ {
+       u8 val;
+ 
+       /* DIS */
+-      val = w83795_read(W83795_REG_DTSC);
++      val = w83795_read(dev, W83795_REG_DTSC);
+       val |= (dts_src & 0x01);
+-      w83795_write(W83795_REG_DTSC, val);
+-
+-      /* DTSE */
+-      val = w83795_read(W83795_REG_DTSE);
+-      val |= 0xFF;
+-      w83795_write(W83795_REG_DTSE, val);
+-
+-      /* store bank3 regs first before enable DTS */
+-
+-      /*
+-       * TD/TR1-4 thermal diode by default
+-       *  0x00 Disable
+-       *  0x01 thermistors on motherboard
+-       *  0x10 different mode voltage
+-       *  0x11 CPU internal thermal diode output
+-       *
+-       * TR5-6 thermistors by default  TRn
+-       */
+-      val = 0x55; /* thermal diode */
+-      w83795_write(W83795_REG_TEMP_CTRL2, val);
+-
+-      /* Enable Digital Temperature Sensor */
+-      val = w83795_read(W83795_REG_TEMP_CTRL1);
+-      val |= W83795_REG_TEMP_CTRL1_EN_DTS; /* EN_DTS */
+-      w83795_write(W83795_REG_TEMP_CTRL1, val);
++      w83795_write(dev, W83795_REG_DTSC, val);
+ }
+ 
+-static void w83795_set_tfmr(w83795_fan_mode_t mode)
+-{
+-      u8 val;
+-      u8 i;
+-
+-      if ((mode == SMART_FAN_MODE) || (mode == THERMAL_CRUISE_MODE)) {
+-              val = 0xFF;
+-      } else {
+-              val = 0x00;
+-      }
+-
+-      for (i = 0; i < 6; i++)
+-              w83795_write(W83795_REG_TFMR(i), val);
+-}
+-
+-static u32 w83795_set_fan_mode(w83795_fan_mode_t mode)
++static u32 w83795_set_fan_mode(struct device *dev, w83795_fan_mode_t mode)
+ {
+       if (mode == SPEED_CRUISE_MODE) {
+-              w83795_write(W83795_REG_FCMS1, 0xFF);
++              w83795_write(dev, W83795_REG_FCMS1, 0xFF);
+               printk(BIOS_INFO, "W83795G/ADG work in Speed Cruise Mode\n");
+       }  else {
+-              w83795_write(W83795_REG_FCMS1, 0x00);
++              w83795_write(dev, W83795_REG_FCMS1, 0x00);
+               if (mode == THERMAL_CRUISE_MODE) {
+-                      w83795_write(W83795_REG_FCMS2, 0x00);
++                      w83795_write(dev, W83795_REG_FCMS2, 0x00);
+                       printk(BIOS_INFO, "W83795G/ADG work in Thermal Cruise 
Mode\n");
+               } else if (mode == SMART_FAN_MODE) {
+-                      w83795_write(W83795_REG_FCMS2, 0x3F);
++                      w83795_write(dev, W83795_REG_FCMS2, 0x3F);
+                       printk(BIOS_INFO, "W83795G/ADG work in Smart Fan 
Mode\n");
+               } else {
+                       printk(BIOS_INFO, "W83795G/ADG work in Manual Mode\n");
+@@ -131,40 +94,12 @@ static u32 w83795_set_fan_mode(w83795_fan_mode_t mode)
+       return 0;
+ }
+ 
+-static void w83795_set_tss(void)
++static void w83795_set_fan(struct device *dev, w83795_fan_mode_t mode)
+ {
+-      u8 val;
+-
+-      val = 0x00;
+-      w83795_write(W83795_REG_TSS(0), val); /* Temp1, 2 */
+-      w83795_write(W83795_REG_TSS(1), val); /* Temp3, 4 */
+-      w83795_write(W83795_REG_TSS(2), val); /* Temp5, 6 */
+-}
+-
+-static void w83795_set_fan(w83795_fan_mode_t mode)
+-{
+-      u8 i;
+-
+-      /* select temperature sensor (TSS)*/
+-      w83795_set_tss();
+-
+-      /* select Temperature to Fan mapping Relationships (TFMR)*/
+-      w83795_set_tfmr(mode);
+-
+       /* set fan output controlled mode (FCMS)*/
+-      w83795_set_fan_mode(mode);
++      w83795_set_fan_mode(dev, mode);
+ 
+-      /* Set Critical Temperature to Full Speed all fan (CTFS) */
+-      for (i = 0; i < 6; i++) {
+-              w83795_write(W83795_REG_CTFS(i), 0x50); /* default 80 celsius 
degree */
+-      }
+-
+-      if (mode == THERMAL_CRUISE_MODE) {
+-              /* Set Target Temperature of Temperature Inputs (TTTI) */
+-              for (i = 0; i < 6; i++) {
+-                      w83795_write(W83795_REG_TTTI(i), 0x28); /* default 40 
celsius degree */
+-              }
+-      } else if (mode == SMART_FAN_MODE) {
++      if (mode == SMART_FAN_MODE) {
+               /* Set the Relative Register-at SMART FAN IV Control Mode Table 
*/
+               //SFIV TODO
+       }
+@@ -173,16 +108,44 @@ static void w83795_set_fan(w83795_fan_mode_t mode)
+       //TODO
+ }
+ 
+-static void w83795_init(w83795_fan_mode_t mode, u8 dts_src)
++static uint8_t fan_pct_to_cfg_val(uint8_t percent)
+ {
+-      u8 i;
+-      u8 val;
++      uint16_t cfg = (((unsigned int)percent * 10000) / 3922);
++      if (cfg > 0xff)
++              cfg = 0xff;
++      return cfg;
++}
++
++static uint8_t millivolts_to_limit_value_type1(int millivolts)
++{
++      /* Datasheet v1.41 page 44 (VSEN1 - VSEN13, VTT) */
++      return ((millivolts / 2) >> 2);
++}
++
++static uint8_t millivolts_to_limit_value_type2(int millivolts)
++{
++      /* Datasheet v1.41 page 44 (3VSB, 3VDD, VBAT) */
++      return ((millivolts / 6) >> 2);
++}
++
++static uint16_t millivolts_to_limit_value_type3(int millivolts)
++{
++      /* Datasheet v1.41 page 44 (VDSEN14 - VDSEN17) */
++      return (millivolts / 2);
++}
++
++static void w83795_init(struct device *dev, w83795_fan_mode_t mode, u8 
dts_src)
++{
++      struct drivers_i2c_w83795_config *config = dev->chip_info;
++      uint8_t i;
++      uint8_t val;
++      uint16_t limit_value;
+ 
+-      if (do_smbus_read_byte(SMBUS_IO_BASE, W83795_DEV, 0x00) < 0) {
++      if (smbus_read_byte(dev, 0x00) < 0) {
+               printk(BIOS_ERR, "W83795G/ADG Nuvoton H/W Monitor not found\n");
+               return;
+       }
+-      val = w83795_read(W83795_REG_CONFIG);
++      val = w83795_read(dev, W83795_REG_CONFIG);
+       if ((val & W83795_REG_CONFIG_CONFIG48) == 0)
+               printk(BIOS_INFO, "Found 64 pin W83795G Nuvoton H/W Monitor\n");
+       else if ((val & W83795_REG_CONFIG_CONFIG48) == 1)
+@@ -190,35 +153,185 @@ static void w83795_init(w83795_fan_mode_t mode, u8 
dts_src)
+ 
+       /* Reset */
+       val |= W83795_REG_CONFIG_INIT;
+-      w83795_write(W83795_REG_CONFIG, val);
+-
+-      /* Fan monitoring setting */
+-      val = 0xFF; /* FAN1-FAN8 */
+-      w83795_write(W83795_REG_FANIN_CTRL1, val);
+-      val = 0x3F; /* FAN9-FAN14 */
+-      w83795_write(W83795_REG_FANIN_CTRL2, val);
++      w83795_write(dev, W83795_REG_CONFIG, val);
++
++      /* Fan monitor settings */
++      w83795_write(dev, W83795_REG_FANIN_CTRL1, config->fanin_ctl1);
++      w83795_write(dev, W83795_REG_FANIN_CTRL2, config->fanin_ctl2);
++
++      /* Temperature thresholds */
++      w83795_write(dev, W83795_REG_TEMP_CRIT(0), 
config->tr1_critical_temperature);
++      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(0), 
config->tr1_critical_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_WARN(0), 
config->tr1_warning_temperature);
++      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(0), 
config->tr1_warning_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_CRIT(1), 
config->tr2_critical_temperature);
++      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(1), 
config->tr2_critical_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_WARN(1), 
config->tr2_warning_temperature);
++      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(1), 
config->tr2_warning_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_CRIT(2), 
config->tr3_critical_temperature);
++      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(2), 
config->tr3_critical_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_WARN(2), 
config->tr3_warning_temperature);
++      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(2), 
config->tr3_warning_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_CRIT(3), 
config->tr4_critical_temperature);
++      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(3), 
config->tr4_critical_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_WARN(3), 
config->tr4_warning_temperature);
++      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(3), 
config->tr4_warning_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_CRIT(4), 
config->tr5_critical_temperature);
++      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(4), 
config->tr5_critical_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_WARN(4), 
config->tr5_warning_temperature);
++      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(4), 
config->tr5_warning_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_CRIT(5), 
config->tr6_critical_temperature);
++      w83795_write(dev, W83795_REG_TEMP_CRIT_HYSTER(5), 
config->tr6_critical_hysteresis);
++      w83795_write(dev, W83795_REG_TEMP_WARN(5), 
config->tr6_warning_temperature);
++      w83795_write(dev, W83795_REG_TEMP_WARN_HYSTER(5), 
config->tr6_warning_hysteresis);
++
++      /* DTS enable */
++      w83795_write(dev, W83795_REG_DTSE, config->temp_dtse);
++
++      /* DTS temperature thresholds */
++      w83795_write(dev, W83795_REG_DTS_CRIT, 
config->dts_critical_temperature);
++      w83795_write(dev, W83795_REG_DTS_CRIT_HYSTER, 
config->dts_critical_hysteresis);
++      w83795_write(dev, W83795_REG_DTS_WARN, config->dts_warning_temperature);
++      w83795_write(dev, W83795_REG_DTS_WARN_HYSTER, 
config->dts_warning_hysteresis);
++
++      /* Configure DTS registers in bank3 before enabling DTS */
++      w83795_dts_configure(dev, dts_src);
++
++      /* Temperature monitor settings */
++      w83795_write(dev, W83795_REG_TEMP_CTRL1, config->temp_ctl1);
++      w83795_write(dev, W83795_REG_TEMP_CTRL2, config->temp_ctl2);
++
++      /* Temperature to fan mappings */
++      w83795_write(dev, W83795_REG_TFMR(0), config->temp1_fan_select);
++      w83795_write(dev, W83795_REG_TFMR(1), config->temp2_fan_select);
++      w83795_write(dev, W83795_REG_TFMR(2), config->temp3_fan_select);
++      w83795_write(dev, W83795_REG_TFMR(3), config->temp4_fan_select);
++      w83795_write(dev, W83795_REG_TFMR(4), config->temp5_fan_select);
++      w83795_write(dev, W83795_REG_TFMR(5), config->temp6_fan_select);
++
++      /* Temperature data source to temperature mappings */
++      w83795_write(dev, W83795_REG_T12TSS, ((config->temp2_source_select & 
0xff) << 8) | (config->temp1_source_select & 0xff));
++      w83795_write(dev, W83795_REG_T34TSS, ((config->temp4_source_select & 
0xff) << 8) | (config->temp3_source_select & 0xff));
++      w83795_write(dev, W83795_REG_T56TSS, ((config->temp6_source_select & 
0xff) << 8) | (config->temp5_source_select & 0xff));
++
++      /* Set critical temperatures
++       * If any sensor exceeds the associated critical temperature,
++       * all fans will be forced to full speed.
++       */
++      w83795_write(dev, W83795_REG_CTFS(0), 
config->temp1_critical_temperature);
++      w83795_write(dev, W83795_REG_CTFS(1), 
config->temp2_critical_temperature);
++      w83795_write(dev, W83795_REG_CTFS(2), 
config->temp3_critical_temperature);
++      w83795_write(dev, W83795_REG_CTFS(3), 
config->temp4_critical_temperature);
++      w83795_write(dev, W83795_REG_CTFS(4), 
config->temp5_critical_temperature);
++      w83795_write(dev, W83795_REG_CTFS(5), 
config->temp6_critical_temperature);
++
++      /* Set fan control target temperatures */
++      w83795_write(dev, W83795_REG_TTTI(0), config->temp1_target_temperature);
++      w83795_write(dev, W83795_REG_TTTI(1), config->temp2_target_temperature);
++      w83795_write(dev, W83795_REG_TTTI(2), config->temp3_target_temperature);
++      w83795_write(dev, W83795_REG_TTTI(3), config->temp4_target_temperature);
++      w83795_write(dev, W83795_REG_TTTI(4), config->temp5_target_temperature);
++      w83795_write(dev, W83795_REG_TTTI(5), config->temp6_target_temperature);
++
++      /* Set fan stall prevention parameters */
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(0), config->fan1_nonstop);
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(1), config->fan2_nonstop);
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(2), config->fan3_nonstop);
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(3), config->fan4_nonstop);
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(4), config->fan5_nonstop);
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(5), config->fan6_nonstop);
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(6), config->fan7_nonstop);
++      w83795_write(dev, W83795_REG_FAN_NONSTOP(7), config->fan8_nonstop);
++
++      /* Set fan default speed */
++      w83795_write(dev, W83795_REG_DFSP, 
fan_pct_to_cfg_val(config->default_speed));
++
++      /* Set initial fan speeds */
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(0), 
fan_pct_to_cfg_val(config->fan1_duty));
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(1), 
fan_pct_to_cfg_val(config->fan2_duty));
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(2), 
fan_pct_to_cfg_val(config->fan3_duty));
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(3), 
fan_pct_to_cfg_val(config->fan4_duty));
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(4), 
fan_pct_to_cfg_val(config->fan5_duty));
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(5), 
fan_pct_to_cfg_val(config->fan6_duty));
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(6), 
fan_pct_to_cfg_val(config->fan7_duty));
++      w83795_write(dev, W83795_REG_FAN_MANUAL_SPEED(7), 
fan_pct_to_cfg_val(config->fan8_duty));
++
++      /* Voltage monitor settings */
++      w83795_write(dev, W83795_REG_VOLT_CTRL1, config->volt_ctl1);
++      w83795_write(dev, W83795_REG_VOLT_CTRL2, config->volt_ctl2);
++
++      /* Voltage high/low limits */
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(0), 
millivolts_to_limit_value_type1(config->vcore1_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(0), 
millivolts_to_limit_value_type1(config->vcore1_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(1), 
millivolts_to_limit_value_type1(config->vcore2_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(1), 
millivolts_to_limit_value_type1(config->vcore2_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(2), 
millivolts_to_limit_value_type1(config->vsen3_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(2), 
millivolts_to_limit_value_type1(config->vsen3_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(3), 
millivolts_to_limit_value_type1(config->vsen4_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(3), 
millivolts_to_limit_value_type1(config->vsen4_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(4), 
millivolts_to_limit_value_type1(config->vsen5_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(4), 
millivolts_to_limit_value_type1(config->vsen5_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(5), 
millivolts_to_limit_value_type1(config->vsen6_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(5), 
millivolts_to_limit_value_type1(config->vsen6_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(6), 
millivolts_to_limit_value_type1(config->vsen7_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(6), 
millivolts_to_limit_value_type1(config->vsen7_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(7), 
millivolts_to_limit_value_type1(config->vsen8_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(7), 
millivolts_to_limit_value_type1(config->vsen8_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(8), 
millivolts_to_limit_value_type1(config->vsen9_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(8), 
millivolts_to_limit_value_type1(config->vsen9_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(9), 
millivolts_to_limit_value_type1(config->vsen10_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(9), 
millivolts_to_limit_value_type1(config->vsen10_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(10), 
millivolts_to_limit_value_type1(config->vsen11_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(10), 
millivolts_to_limit_value_type1(config->vsen11_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(11), 
millivolts_to_limit_value_type1(config->vtt_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(11), 
millivolts_to_limit_value_type1(config->vtt_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(12), 
millivolts_to_limit_value_type2(config->vdd_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(12), 
millivolts_to_limit_value_type2(config->vdd_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(13), 
millivolts_to_limit_value_type2(config->vsb_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(13), 
millivolts_to_limit_value_type2(config->vsb_low_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_HIGH(14), 
millivolts_to_limit_value_type2(config->vbat_high_limit_mv));
++      w83795_write(dev, W83795_REG_VOLT_LIM_LOW(14), 
millivolts_to_limit_value_type2(config->vbat_low_limit_mv));
++
++      /* VSEN12 limits */
++      if (config->temp_ctl1 & 0x2) {
++              limit_value = 
millivolts_to_limit_value_type3(config->vsen12_high_limit_mv);
++              w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_M(4), limit_value 
>> 2);
++              w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_L(4), limit_value 
& 0x3);
++              limit_value = 
millivolts_to_limit_value_type3(config->vsen12_low_limit_mv);
++              w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_M(4), limit_value 
>> 2);
++              w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_L(4), limit_value & 
0x3);
++      }
+ 
+-      /* enable monitoring operations */
+-      val = w83795_read(W83795_REG_CONFIG);
+-      val |= W83795_REG_CONFIG_START;
+-      w83795_write(W83795_REG_CONFIG, val);
++      /* VSEN13 limits */
++      if (config->temp_ctl1 & 0x8) {
++              limit_value = 
millivolts_to_limit_value_type3(config->vsen13_high_limit_mv);
++              w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_M(5), limit_value 
>> 2);
++              w83795_write(dev, W83795_REG_VOLT_LIM_HIGH_2_L(5), limit_value 
& 0x3);
++              limit_value = 
millivolts_to_limit_value_type3(config->vsen13_low_limit_mv);
++              w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_M(5), limit_value 
>> 2);
++              w83795_write(dev, W83795_REG_VOLT_LIM_LOW_2_L(5), limit_value & 
0x3);
++      }
+ 
+-      w83795_dts_enable(dts_src);
+-      w83795_set_fan(mode);
++      w83795_set_fan(dev, mode);
+ 
+       printk(BIOS_INFO, "Fan   CTFS(celsius)  TTTI(celsius)\n");
+       for (i = 0; i < 6; i++) {
+-              val = w83795_read(W83795_REG_CTFS(i));
++              val = w83795_read(dev, W83795_REG_CTFS(i));
+               printk(BIOS_INFO, " %x     %d", i, val);
+-              val = w83795_read(W83795_REG_TTTI(i));
++              val = w83795_read(dev, W83795_REG_TTTI(i));
+               printk(BIOS_INFO, "             %d\n", val);
+       }
+ 
+       /* Temperature ReadOut */
+       for (i = 0; i < 9; i++) {
+-              val = w83795_read(W83795_REG_DTS(i));
++              val = w83795_read(dev, W83795_REG_DTS(i));
+               printk(BIOS_DEBUG, "DTS%x ReadOut=%x\n", i, val);
+       }
++
++      /* start monitoring operation */
++      val = w83795_read(dev, W83795_REG_CONFIG);
++      val |= W83795_REG_CONFIG_START;
++      w83795_write(dev, W83795_REG_CONFIG, val);
+ }
+ 
+ static void w83795_hwm_init(struct device *dev)
+@@ -232,9 +345,9 @@ static void w83795_hwm_init(struct device *dev)
+               die("CPU: missing cpu device structure");
+ 
+       if (cpu->vendor == X86_VENDOR_AMD)
+-              w83795_init(THERMAL_CRUISE_MODE, DTS_SRC_AMD_SBTSI);
++              w83795_init(dev, THERMAL_CRUISE_MODE, DTS_SRC_AMD_SBTSI);
+       else if (cpu->vendor == X86_VENDOR_INTEL)
+-              w83795_init(THERMAL_CRUISE_MODE, DTS_SRC_INTEL_PECI);
++              w83795_init(dev, THERMAL_CRUISE_MODE, DTS_SRC_INTEL_PECI);
+       else
+               printk(BIOS_ERR, "Neither AMD nor INTEL CPU detected\n");
+ }
+diff --git a/src/drivers/i2c/w83795/w83795.h b/src/drivers/i2c/w83795/w83795.h
+index cac4d5f..ef603f5 100644
+--- a/src/drivers/i2c/w83795/w83795.h
++++ b/src/drivers/i2c/w83795/w83795.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2012 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -20,8 +21,6 @@
+ #ifndef _W83795_H_
+ #define _W83795_H_
+ 
+-#define W83795_DEV                    0x2F /* Host I2c Addr (strap to addr1 
addr0 1 1, 0x5E) */
+-
+ #define W83795_REG_I2C_ADDR           0xFC
+ #define W83795_REG_BANKSEL            0x00
+ #define W83795_REG_CONFIG             0x01
+@@ -29,6 +28,8 @@
+ #define W83795_REG_CONFIG_CONFIG48    0x04
+ #define W83795_REG_CONFIG_INIT                0x80
+ 
++#define W83795_REG_VOLT_CTRL1         0x02
++#define W83795_REG_VOLT_CTRL2         0x03
+ #define W83795_REG_TEMP_CTRL1         0x04 /* Temperature Monitoring Control 
Register */
+ #define W83795_REG_TEMP_CTRL2         0x05 /* Temperature Monitoring Control 
Register */
+ #define W83795_REG_FANIN_CTRL1                0x06
+@@ -37,37 +38,58 @@
+ #define DTS_SRC_INTEL_PECI            (0 << 0)
+ #define DTS_SRC_AMD_SBTSI             (1 << 0)
+ 
+-#define W83795_REG_TSS(n)             (0x209 + (n)) /* Temperature Source 
Selection Register */
+ #define W83795_REG_TTTI(n)            (0x260 + (n)) /* Target temperature 
W83795G/ADG will try to tune the fan output to keep */
+ #define W83795_REG_CTFS(n)            (0x268 + (n)) /* Critical Temperature 
to Full Speed all fan */
+-#define W83795_REG_HT(n)              (0x270 + (n)) /* Hysteresis of 
Temperature */
+ #define W83795_REG_DTSC                       0x301 /* Digital Temperature 
Sensor Configuration */
+ 
+ #define W83795_REG_DTSE                       0x302 /* Digital Temperature 
Sensor Enable */
+ #define W83795_REG_DTS(n)             (0x26 + (n))
+ #define W83795_REG_VRLSB              0x3C
+ 
+-#define W83795_TEMP_REG_TR1           0x21
+-#define W83795_TEMP_REG_TR2           0x22
+-#define W83795_TEMP_REG_TR3           0x23
+-#define W83795_TEMP_REG_TR4           0x24
+-#define W83795_TEMP_REG_TR5           0x1F
+-#define W83795_TEMP_REG_TR6           0x20
++#define W83795_REG_TEMP_TR1           0x21
++#define W83795_REG_TEMP_TR2           0x22
++#define W83795_REG_TEMP_TR3           0x23
++#define W83795_REG_TEMP_TR4           0x24
++#define W83795_REG_TEMP_TR5           0x1F
++#define W83795_REG_TEMP_TR6           0x20
++
++#define W83795_REG_VOLT_LIM_HIGH(n)   (0x70 + (n * 2))        /* Voltage high 
limit (0 == VSEN1) */
++#define W83795_REG_VOLT_LIM_LOW(n)    (0x71 + (n * 2))        /* Voltage low 
limit (0 == VSEN1) */
++#define W83795_REG_VOLT_LIM_HIGH_2_M(n)       (0x96 + (n * 4))        /* 
Voltage high limit MSB (0 == VDSEN14) */
++#define W83795_REG_VOLT_LIM_LOW_2_M(n)        (0x97 + (n * 4))        /* 
Voltage low limit MSB (0 == VDSEN14)  */
++#define W83795_REG_VOLT_LIM_HIGH_2_L(n)       (0x98 + (n * 4))        /* 
Voltage high limit LSB (0 == VDSEN14) */
++#define W83795_REG_VOLT_LIM_LOW_2_L(n)        (0x99 + (n * 4))        /* 
Voltage low limit LSB (0 == VDSEN14)  */
++
++#define W83795_REG_TEMP_CRIT(n)               (0x96 + (n * 4))        /* 
Temperature critical limit */
++#define W83795_REG_TEMP_CRIT_HYSTER(n)        (0x97 + (n * 4))        /* 
Temperature critical limit hysteresis */
++#define W83795_REG_TEMP_WARN(n)               (0x98 + (n * 4))        /* 
Temperature warning limit */
++#define W83795_REG_TEMP_WARN_HYSTER(n)        (0x99 + (n * 4))        /* 
Temperature warning limit hysteresis */
++
++#define W83795_REG_DTS_CRIT           0xB2                    /* Temperature 
critical limit */
++#define W83795_REG_DTS_CRIT_HYSTER    0xB3                    /* Temperature 
critical limit hysteresis */
++#define W83795_REG_DTS_WARN           0xB4                    /* Temperature 
warning limit */
++#define W83795_REG_DTS_WARN_HYSTER    0xB5                    /* Temperature 
warning limit hysteresis */
+ 
+ #define W83795_REG_FCMS1              0x201
+ #define W83795_REG_FCMS2              0x208
+-#define W83795_REG_TFMR(n)            (0x202 + (n)) /*temperature to fam 
mappig*/
++#define W83795_REG_TFMR(n)            (0x202 + (n))           /* Temperature 
to fan mapping */
++#define W83795_REG_T12TSS             0x209                   /* Temperature 
Source Selection Register 1 */
++#define W83795_REG_T34TSS             0x20A                   /* Temperature 
Source Selection Register 2 */
++#define W83795_REG_T56TSS             0x20B                   /* Temperature 
Source Selection Register 3 */
++#define W83795_REG_FAN_MANUAL_SPEED(n)        (0x210 + n)
+ #define W83795_REG_DFSP                       0x20C
+ 
++#define W83795_REG_FAN_NONSTOP(n)     (0x228 + (n))   /* Fan Nonstop Value */
++
+ #define W83795_REG_FTSH(n)            (0x240 + (n) * 2)
+ #define W83795_REG_FTSL(n)            (0x241 + (n) * 2)
+ #define W83795_REG_TFTS                       0x250
+ 
+ typedef enum w83795_fan_mode {
+-      SPEED_CRUISE_MODE,      ///< Fan Speed Cruise mode keeps the fan speed 
in a specified range
+-      THERMAL_CRUISE_MODE,    ///< Thermal Cruise mode is an algorithm to 
control the fan speed to keep the temperature source around the TTTI
+-      SMART_FAN_MODE,         ///< Smart Fan mode offers 6 slopes to control 
the fan speed
+-      MANUAL_MODE,            ///< control manually
++      SPEED_CRUISE_MODE = 0,          ///< Fan Speed Cruise mode keeps the 
fan speed in a specified range
++      THERMAL_CRUISE_MODE = 1,        ///< Thermal Cruise mode is an 
algorithm to control the fan speed to keep the temperature source around the 
TTTI
++      SMART_FAN_MODE = 2,             ///< Smart Fan mode offers 6 slopes to 
control the fan speed
++      MANUAL_MODE = 3,                ///< control manually
+ } w83795_fan_mode_t;
+ 
+ #endif
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
 
b/resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
deleted file mode 100644
index b984f28..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0003-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From 3e2be2d88101331eedb59c1459630b553c7cb660 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 17 Oct 2015 04:37:10 -0500
-Subject: [PATCH 003/139] drivers/i2c/w83795: Add option to use auxiliary SMBUS
- controller
-
-Change-Id: I5a9b5eba992853b84b0cb6c3a1764edf42ac49b2
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/drivers/i2c/w83795/chip.h   |  4 ++++
- src/drivers/i2c/w83795/w83795.c | 14 ++++++++++++++
- 2 files changed, 18 insertions(+)
-
-diff --git a/src/drivers/i2c/w83795/chip.h b/src/drivers/i2c/w83795/chip.h
-index effe119..413ea87 100644
---- a/src/drivers/i2c/w83795/chip.h
-+++ b/src/drivers/i2c/w83795/chip.h
-@@ -139,4 +139,8 @@ struct drivers_i2c_w83795_config {
-       uint8_t fan6_duty;                      /* % of full speed (0-100) */
-       uint8_t fan7_duty;                      /* % of full speed (0-100) */
-       uint8_t fan8_duty;                      /* % of full speed (0-100) */
-+
-+      uint8_t smbus_aux;                      /* 0 == device located on first 
SMBUS,
-+                                               * 1 == device located on 
auxiliary SMBUS
-+                                               */
- };
-diff --git a/src/drivers/i2c/w83795/w83795.c b/src/drivers/i2c/w83795/w83795.c
-index cf0cf2f..453e0af 100644
---- a/src/drivers/i2c/w83795/w83795.c
-+++ b/src/drivers/i2c/w83795/w83795.c
-@@ -141,7 +141,16 @@ static void w83795_init(struct device *dev, 
w83795_fan_mode_t mode, u8 dts_src)
-       uint8_t val;
-       uint16_t limit_value;
- 
-+#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX)
-+      uint8_t smbus_aux_prev = smbus_switched_to_aux();
-+      smbus_switch_to_aux(config->smbus_aux);
-+#endif
-+
-       if (smbus_read_byte(dev, 0x00) < 0) {
-+#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX)
-+              /* Restore SMBUS channel setting */
-+              smbus_switch_to_aux(smbus_aux_prev);
-+#endif
-               printk(BIOS_ERR, "W83795G/ADG Nuvoton H/W Monitor not found\n");
-               return;
-       }
-@@ -325,6 +334,11 @@ static void w83795_init(struct device *dev, 
w83795_fan_mode_t mode, u8 dts_src)
-       val = w83795_read(dev, W83795_REG_CONFIG);
-       val |= W83795_REG_CONFIG_START;
-       w83795_write(dev, W83795_REG_CONFIG, val);
-+
-+#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX)
-+      /* Restore SMBUS channel setting */
-+      smbus_switch_to_aux(smbus_aux_prev);
-+#endif
- }
- 
- static void w83795_hwm_init(struct device *dev)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0004-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
 
b/resources/libreboot/patch/kgpe-d16/0004-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
deleted file mode 100644
index 3d9c5c8..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0004-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
+++ /dev/null
@@ -1,3675 +0,0 @@
-From 7075bbddd264958b80ea4831b602b6fbfaf60b0d Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 17:38:09 -0500
-Subject: [PATCH 004/139] drivers/aspeed: Add native text mode VGA support for
- the AST2050
-
-Change-Id: I37763a59d2546cd0c0e57b31fdb7aa77c2c50bee
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/drivers/aspeed/Kconfig                  |    2 +
- src/drivers/aspeed/Makefile.inc             |    1 +
- src/drivers/aspeed/ast2050/Kconfig          |   14 +
- src/drivers/aspeed/ast2050/Makefile.inc     |    1 +
- src/drivers/aspeed/ast2050/ast2050.c        |   83 ++
- src/drivers/aspeed/common/Kconfig           |   10 +
- src/drivers/aspeed/common/Makefile.inc      |    1 +
- src/drivers/aspeed/common/aspeed_coreboot.h |  210 ++++
- src/drivers/aspeed/common/ast_dp501.c       |  443 +++++++
- src/drivers/aspeed/common/ast_dram_tables.h |  165 +++
- src/drivers/aspeed/common/ast_drv.h         |  223 ++++
- src/drivers/aspeed/common/ast_main.c        |  393 +++++++
- src/drivers/aspeed/common/ast_post.c        | 1679 +++++++++++++++++++++++++++
- src/drivers/aspeed/common/ast_tables.h      |  305 +++++
- src/include/device/pci_ids.h                |    3 +
- 15 files changed, 3533 insertions(+)
- create mode 100644 src/drivers/aspeed/Kconfig
- create mode 100644 src/drivers/aspeed/Makefile.inc
- create mode 100644 src/drivers/aspeed/ast2050/Kconfig
- create mode 100644 src/drivers/aspeed/ast2050/Makefile.inc
- create mode 100644 src/drivers/aspeed/ast2050/ast2050.c
- create mode 100644 src/drivers/aspeed/common/Kconfig
- create mode 100644 src/drivers/aspeed/common/Makefile.inc
- create mode 100644 src/drivers/aspeed/common/aspeed_coreboot.h
- create mode 100644 src/drivers/aspeed/common/ast_dp501.c
- create mode 100644 src/drivers/aspeed/common/ast_dram_tables.h
- create mode 100644 src/drivers/aspeed/common/ast_drv.h
- create mode 100644 src/drivers/aspeed/common/ast_main.c
- create mode 100644 src/drivers/aspeed/common/ast_post.c
- create mode 100644 src/drivers/aspeed/common/ast_tables.h
-
-diff --git a/src/drivers/aspeed/Kconfig b/src/drivers/aspeed/Kconfig
-new file mode 100644
-index 0000000..27469b5
---- /dev/null
-+++ b/src/drivers/aspeed/Kconfig
-@@ -0,0 +1,2 @@
-+source src/drivers/aspeed/common/Kconfig
-+source src/drivers/aspeed/ast2050/Kconfig
-\ No newline at end of file
-diff --git a/src/drivers/aspeed/Makefile.inc b/src/drivers/aspeed/Makefile.inc
-new file mode 100644
-index 0000000..955a213
---- /dev/null
-+++ b/src/drivers/aspeed/Makefile.inc
-@@ -0,0 +1 @@
-+subdirs-y += common ast2050
-\ No newline at end of file
-diff --git a/src/drivers/aspeed/ast2050/Kconfig 
b/src/drivers/aspeed/ast2050/Kconfig
-new file mode 100644
-index 0000000..f110d58
---- /dev/null
-+++ b/src/drivers/aspeed/ast2050/Kconfig
-@@ -0,0 +1,14 @@
-+config DRIVERS_ASPEED_AST2050
-+      bool
-+
-+if DRIVERS_ASPEED_AST2050
-+
-+config DEVICE_SPECIFIC_OPTIONS # dummy
-+      def_bool y
-+      select DRIVERS_ASPEED_AST_COMMON
-+
-+config NATIVE_VGA_INIT_USE_EDID
-+      bool
-+      default n
-+
-+endif # DRIVERS_ASPEED_AST2050
-diff --git a/src/drivers/aspeed/ast2050/Makefile.inc 
b/src/drivers/aspeed/ast2050/Makefile.inc
-new file mode 100644
-index 0000000..3ba9dde
---- /dev/null
-+++ b/src/drivers/aspeed/ast2050/Makefile.inc
-@@ -0,0 +1 @@
-+ramstage-$(CONFIG_DRIVERS_ASPEED_AST2050) += ast2050.c
-\ No newline at end of file
-diff --git a/src/drivers/aspeed/ast2050/ast2050.c 
b/src/drivers/aspeed/ast2050/ast2050.c
-new file mode 100644
-index 0000000..809e9de
---- /dev/null
-+++ b/src/drivers/aspeed/ast2050/ast2050.c
-@@ -0,0 +1,83 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+#include <delay.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <arch/io.h>
-+#include <edid.h>
-+
-+#include <console/console.h>
-+#include <device/device.h>
-+#include <device/pci.h>
-+#include <device/pci_ids.h>
-+#include <device/pci_ops.h>
-+
-+#include <pc80/vga.h>
-+
-+#include "../common/aspeed_coreboot.h"
-+#include "../common/ast_drv.h"
-+
-+static void aspeed_ast2050_set_resources(device_t dev)
-+{
-+      /* Reserve VGA regions */
-+      mmio_resource(dev, 3, 0xa0000 >> 10, 0x1ffff >> 10);
-+
-+      /* Run standard resource set routine */
-+      pci_dev_set_resources(dev);
-+}
-+
-+static void aspeed_ast2050_init(struct device *dev)
-+{
-+      u8 ret;
-+      struct drm_device drm_dev;
-+
-+      drm_dev.pdev = dev;
-+
-+      printk(BIOS_INFO, "ASpeed AST2050: initializing video device\n");
-+      ret = ast_driver_load(&drm_dev, 0);
-+
-+      /* Unlock extended configuration registers */
-+      outb(0x80, 0x3d4); outb(0xa8, 0x3d5);
-+
-+      /* Set CRT Request Threshold */
-+      outb(0xa6, 0x3d4); outb(0x2f, 0x3d5);
-+      outb(0xa7, 0x3d4); outb(0x3f, 0x3d5);
-+
-+      /* Initialize standard VGA text mode */
-+      vga_io_init();
-+      vga_textmode_init();
-+      printk(BIOS_INFO, "ASpeed VGA text mode initialized\n");
-+
-+      /* if we don't have console, at least print something... */
-+      vga_line_write(0, "ASpeed VGA text mode initialized");
-+}
-+
-+static struct device_operations aspeed_ast2050_ops  = {
-+      .read_resources   = pci_dev_read_resources,
-+      .set_resources    = aspeed_ast2050_set_resources,
-+      .enable_resources = pci_dev_enable_resources,
-+      .init             = aspeed_ast2050_init,
-+      .scan_bus         = 0,
-+};
-+
-+static const struct pci_driver aspeed_ast2050_driver __pci_driver = {
-+        .ops    = &aspeed_ast2050_ops,
-+        .vendor = PCI_VENDOR_ID_ASPEED,
-+        .device = PCI_DEVICE_ID_ASPEED_AST2050_VGA,
-+};
-diff --git a/src/drivers/aspeed/common/Kconfig 
b/src/drivers/aspeed/common/Kconfig
-new file mode 100644
-index 0000000..0f7056b
---- /dev/null
-+++ b/src/drivers/aspeed/common/Kconfig
-@@ -0,0 +1,10 @@
-+config DRIVERS_ASPEED_AST_COMMON
-+      bool
-+
-+if !MAINBOARD_DO_NATIVE_VGA_INIT
-+
-+config DEVICE_SPECIFIC_OPTIONS # dummy
-+      def_bool y
-+      select VGA
-+
-+endif # MAINBOARD_DO_NATIVE_VGA_INIT
-diff --git a/src/drivers/aspeed/common/Makefile.inc 
b/src/drivers/aspeed/common/Makefile.inc
-new file mode 100644
-index 0000000..75f8b48
---- /dev/null
-+++ b/src/drivers/aspeed/common/Makefile.inc
-@@ -0,0 +1 @@
-+ramstage-$(CONFIG_DRIVERS_ASPEED_AST_COMMON) += ast_dp501.c ast_main.c 
ast_post.c
-diff --git a/src/drivers/aspeed/common/aspeed_coreboot.h 
b/src/drivers/aspeed/common/aspeed_coreboot.h
-new file mode 100644
-index 0000000..237c23f
---- /dev/null
-+++ b/src/drivers/aspeed/common/aspeed_coreboot.h
-@@ -0,0 +1,210 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#ifndef _ASPEED_COREBOOT_
-+#define _ASPEED_COREBOOT_
-+
-+#include <delay.h>
-+#include <stdlib.h>
-+#include <stdint.h>
-+#include <string.h>
-+#include <arch/io.h>
-+
-+#include <console/console.h>
-+#include <device/device.h>
-+#include <device/pci.h>
-+#include <device/pci_ids.h>
-+#include <device/pci_ops.h>
-+
-+/* coreboot <--> kernel code interface */
-+#define __iomem
-+typedef u64 phys_addr_t;
-+#define pci_dev device
-+
-+#define SZ_16M 0x01000000
-+
-+#define min_t(type, x, y) ({                  \
-+      type __min1 = (x);                      \
-+      type __min2 = (y);                      \
-+      __min1 < __min2 ? __min1 : __min2; })
-+
-+#define dev_info(dev, format, arg...) printk(BIOS_INFO, "ASpeed VGA: " 
format, ##arg)
-+#define dev_dbg(dev, format, arg...) printk(BIOS_DEBUG, "ASpeed VGA: " 
format, ##arg)
-+#define dev_err(dev, format, arg...) printk(BIOS_ERR, "ASpeed VGA: " format, 
##arg)
-+
-+#define pr_info(format, arg...) printk(BIOS_INFO, "ASpeed VGA: " format, 
##arg)
-+#define pr_debug(format, arg...) printk(BIOS_INFO, "ASpeed VGA: " format, 
##arg)
-+#define pr_err(format, arg...) printk(BIOS_ERR, "ASpeed VGA: " format, ##arg)
-+
-+#define DRM_INFO pr_info
-+
-+#define GFP_KERNEL 0
-+#define GFP_ATOMIC 1
-+#define kfree(address) free(address)
-+
-+#define EIO 5
-+#define ENOMEM 12
-+
-+struct firmware {
-+      size_t size;
-+      const u8 *data;
-+      struct page **pages;
-+
-+      /* firmware loader private fields */
-+      void *priv;
-+};
-+
-+struct drm_device {
-+      struct pci_dev *pdev;
-+      void *dev_private;
-+};
-+
-+static inline void *kzalloc(size_t size, int flags) {
-+      void* ptr = malloc(size);
-+      memset(ptr, 0, size);
-+      return ptr;
-+}
-+
-+static inline void writel(u32 val, volatile void *addr) {
-+      *(u32*)addr = val;
-+}
-+
-+static inline u32 readl(const volatile void *addr) {
-+      return *(u32*)addr;
-+}
-+
-+static inline void writew(u16 val, volatile void *addr) {
-+      *(u16*)addr = val;
-+}
-+
-+static inline u16 readw(const volatile void *addr) {
-+      return *(u16*)addr;
-+}
-+
-+static inline void writeb(u8 val, volatile void *addr) {
-+      *(u8*)addr = val;
-+}
-+
-+static inline u8 readb(const volatile void *addr) {
-+      return *(u8*)addr;
-+}
-+
-+static inline int pci_read_config_dword(struct pci_dev *dev, int where,
-+      u32 *val)
-+{
-+      *val = pci_read_config32(dev, where);
-+      return 0;
-+}
-+
-+static inline int pci_write_config_dword(struct pci_dev *dev, int where,
-+      u32 val)
-+{
-+      pci_write_config32(dev, where, val);
-+      return 0;
-+}
-+
-+static inline int pci_read_config_byte(struct pci_dev *dev, int where,
-+      u8 *val)
-+{
-+      *val = pci_read_config8(dev, where);
-+      return 0;
-+}
-+
-+static inline struct resource* resource_at_bar(struct pci_dev *dev, u8 bar) {
-+      struct resource *res = dev->resource_list;
-+      int i;
-+      for (i = 0; i < bar; i++) {
-+              res = res->next;
-+              if (res == NULL)
-+                      return NULL;
-+      }
-+
-+      return res;
-+}
-+
-+static inline resource_t pci_resource_len(struct pci_dev *dev, u8 bar) {
-+      struct resource *res = resource_at_bar(dev, bar);
-+      if (res)
-+              return res->size;
-+      else
-+              return 0;
-+}
-+
-+static inline resource_t pci_resource_start(struct pci_dev *dev, u8 bar) {
-+      struct resource *res = resource_at_bar(dev, bar);
-+      if (res)
-+              return res->base;
-+      else
-+              return 0;
-+}
-+
-+static inline unsigned int ioread32(void __iomem *p) {
-+      return readl(p);
-+}
-+
-+static inline void iowrite32(u32 val, void __iomem *p) {
-+      writel(val, p);
-+}
-+
-+static inline unsigned int ioread16(void __iomem *p) {
-+      return readw(p);
-+}
-+
-+static inline void iowrite16(u16 val, void __iomem *p) {
-+      writew(val, p);
-+}
-+
-+static inline unsigned int ioread8(void __iomem *p) {
-+      return readb(p);
-+}
-+
-+static inline void iowrite8(u8 val, void __iomem *p) {
-+      writeb(val, p);
-+}
-+
-+static inline unsigned int ioread_cbio32(void __iomem *p) {
-+      return inl((uint16_t)((intptr_t)p));
-+}
-+
-+static inline void iowrite_cbio32(u32 val, void __iomem *p) {
-+      outl(val, (uint16_t)((intptr_t)p));
-+}
-+
-+static inline unsigned int ioread_cbio16(void __iomem *p) {
-+      return inw((uint16_t)((intptr_t)p));
-+}
-+
-+static inline void iowrite_cbio16(u16 val, void __iomem *p) {
-+      outw(val, (uint16_t)((intptr_t)p));
-+}
-+
-+static inline unsigned int ioread_cbio8(void __iomem *p) {
-+      return inb((uint16_t)((intptr_t)p));
-+}
-+
-+static inline void iowrite_cbio8(u8 val, void __iomem *p) {
-+      outb(val, (uint16_t)((intptr_t)p));
-+}
-+
-+static inline void msleep(unsigned int msecs) {
-+      udelay(msecs * 1000);
-+}
-+
-+#endif
-\ No newline at end of file
-diff --git a/src/drivers/aspeed/common/ast_dp501.c 
b/src/drivers/aspeed/common/ast_dp501.c
-new file mode 100644
-index 0000000..5be8ec3
---- /dev/null
-+++ b/src/drivers/aspeed/common/ast_dp501.c
-@@ -0,0 +1,443 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * File taken from the Linux ast driver (v3.18.5)
-+ * Coreboot-specific includes added at top and/or contents modified
-+ * as needed to function within the coreboot environment.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc.
-+ */
-+
-+#include "ast_drv.h"
-+
-+static void send_ack(struct ast_private *ast)
-+{
-+      u8 sendack;
-+      sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
-+      sendack |= 0x80;
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
-+}
-+
-+static void send_nack(struct ast_private *ast)
-+{
-+      u8 sendack;
-+      sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
-+      sendack &= ~0x80;
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
-+}
-+
-+static bool wait_ack(struct ast_private *ast)
-+{
-+      u8 waitack;
-+      u32 retry = 0;
-+      do {
-+              waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 
0xff);
-+              waitack &= 0x80;
-+              udelay(100);
-+      } while ((!waitack) && (retry++ < 1000));
-+
-+      if (retry < 1000)
-+              return true;
-+      else
-+              return false;
-+}
-+
-+static bool wait_nack(struct ast_private *ast)
-+{
-+      u8 waitack;
-+      u32 retry = 0;
-+      do {
-+              waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 
0xff);
-+              waitack &= 0x80;
-+              udelay(100);
-+      } while ((waitack) && (retry++ < 1000));
-+
-+      if (retry < 1000)
-+              return true;
-+      else
-+              return false;
-+}
-+
-+static void set_cmd_trigger(struct ast_private *ast)
-+{
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x40);
-+}
-+
-+static void clear_cmd_trigger(struct ast_private *ast)
-+{
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x00);
-+}
-+
-+#if 0
-+static bool wait_fw_ready(struct ast_private *ast)
-+{
-+      u8 waitready;
-+      u32 retry = 0;
-+      do {
-+              waitready = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 
0xff);
-+              waitready &= 0x40;
-+              udelay(100);
-+      } while ((!waitready) && (retry++ < 1000));
-+
-+      if (retry < 1000)
-+              return true;
-+      else
-+              return false;
-+}
-+#endif
-+
-+static bool ast_write_cmd(struct drm_device *dev, u8 data)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      int retry = 0;
-+      if (wait_nack(ast)) {
-+              send_nack(ast);
-+              ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
-+              send_ack(ast);
-+              set_cmd_trigger(ast);
-+              do {
-+                      if (wait_ack(ast)) {
-+                              clear_cmd_trigger(ast);
-+                              send_nack(ast);
-+                              return true;
-+                      }
-+              } while (retry++ < 100);
-+      }
-+      clear_cmd_trigger(ast);
-+      send_nack(ast);
-+      return false;
-+}
-+
-+static bool ast_write_data(struct drm_device *dev, u8 data)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+
-+      if (wait_nack(ast)) {
-+              send_nack(ast);
-+              ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
-+              send_ack(ast);
-+              if (wait_ack(ast)) {
-+                      send_nack(ast);
-+                      return true;
-+              }
-+      }
-+      send_nack(ast);
-+      return false;
-+}
-+
-+#if 0
-+static bool ast_read_data(struct drm_device *dev, u8 *data)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u8 tmp;
-+
-+      *data = 0;
-+
-+      if (wait_ack(ast) == false)
-+              return false;
-+      tmp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd3, 0xff);
-+      *data = tmp;
-+      if (wait_nack(ast) == false) {
-+              send_nack(ast);
-+              return false;
-+      }
-+      send_nack(ast);
-+      return true;
-+}
-+
-+static void clear_cmd(struct ast_private *ast)
-+{
-+      send_nack(ast);
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, 0x00);
-+}
-+#endif
-+
-+void ast_set_dp501_video_output(struct drm_device *dev, u8 mode)
-+{
-+      ast_write_cmd(dev, 0x40);
-+      ast_write_data(dev, mode);
-+
-+      msleep(10);
-+}
-+
-+static u32 get_fw_base(struct ast_private *ast)
-+{
-+      return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff;
-+}
-+
-+bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u32 i, data;
-+      u32 boot_address;
-+
-+      data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
-+      if (data) {
-+              boot_address = get_fw_base(ast);
-+              for (i = 0; i < size; i += 4)
-+                      *(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i);
-+              return true;
-+      }
-+      return false;
-+}
-+
-+bool ast_launch_m68k(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u32 i, data, len = 0;
-+      u32 boot_address;
-+      u8 *fw_addr = NULL;
-+      u8 jreg;
-+
-+      data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
-+      if (!data) {
-+
-+              if (ast->dp501_fw_addr) {
-+                      fw_addr = ast->dp501_fw_addr;
-+                      len = 32*1024;
-+              } else if (ast->dp501_fw) {
-+                      fw_addr = (u8 *)ast->dp501_fw->data;
-+                      len = ast->dp501_fw->size;
-+              }
-+              /* Get BootAddress */
-+              ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
-+              data = ast_mindwm(ast, 0x1e6e0004);
-+              switch (data & 0x03) {
-+              case 0:
-+                      boot_address = 0x44000000;
-+                      break;
-+              default:
-+              case 1:
-+                      boot_address = 0x48000000;
-+                      break;
-+              case 2:
-+                      boot_address = 0x50000000;
-+                      break;
-+              case 3:
-+                      boot_address = 0x60000000;
-+                      break;
-+              }
-+              boot_address -= 0x200000; /* -2MB */
-+
-+              /* copy image to buffer */
-+              for (i = 0; i < len; i += 4) {
-+                      data = *(u32 *)(fw_addr + i);
-+                      ast_moutdwm(ast, boot_address + i, data);
-+              }
-+
-+              /* Init SCU */
-+              ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
-+
-+              /* Launch FW */
-+              ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address);
-+              ast_moutdwm(ast, 0x1e6e2100, 1);
-+
-+              /* Update Scratch */
-+              data = ast_mindwm(ast, 0x1e6e2040) & 0xfffff1ff;                
/* D[11:9] = 100b: UEFI handling */
-+              data |= 0x800;
-+              ast_moutdwm(ast, 0x1e6e2040, data);
-+
-+              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 
0xfc); /* D[1:0]: Reserved Video Buffer */
-+              jreg |= 0x02;
-+              ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x99, jreg);
-+      }
-+      return true;
-+}
-+
-+u8 ast_get_dp501_max_clk(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u32 boot_address, offset, data;
-+      u8 linkcap[4], linkrate, linklanes, maxclk = 0xff;
-+
-+      boot_address = get_fw_base(ast);
-+
-+      /* validate FW version */
-+      offset = 0xf000;
-+      data = ast_mindwm(ast, boot_address + offset);
-+      if ((data & 0xf0) != 0x10) /* version: 1x */
-+              return maxclk;
-+
-+      /* Read Link Capability */
-+      offset  = 0xf014;
-+      data = ast_mindwm(ast, boot_address + offset);
-+      linkcap[0] = (data & 0xff000000) >> 24;
-+      linkcap[1] = (data & 0x00ff0000) >> 16;
-+      linkcap[2] = (data & 0x0000ff00) >> 8;
-+      linkcap[3] = (data & 0x000000ff);
-+      if (linkcap[2] == 0) {
-+              linkrate = linkcap[0];
-+              linklanes = linkcap[1];
-+              data = (linkrate == 0x0a) ? (90 * linklanes) : (54 * linklanes);
-+              if (data > 0xff)
-+                      data = 0xff;
-+              maxclk = (u8)data;
-+      }
-+      return maxclk;
-+}
-+
-+bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u32 i, boot_address, offset, data;
-+
-+      boot_address = get_fw_base(ast);
-+
-+      /* validate FW version */
-+      offset = 0xf000;
-+      data = ast_mindwm(ast, boot_address + offset);
-+      if ((data & 0xf0) != 0x10)
-+              return false;
-+
-+      /* validate PnP Monitor */
-+      offset = 0xf010;
-+      data = ast_mindwm(ast, boot_address + offset);
-+      if (!(data & 0x01))
-+              return false;
-+
-+      /* Read EDID */
-+      offset = 0xf020;
-+      for (i = 0; i < 128; i += 4) {
-+              data = ast_mindwm(ast, boot_address + offset + i);
-+              *(u32 *)(ediddata + i) = data;
-+      }
-+
-+      return true;
-+}
-+
-+static bool ast_init_dvo(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u8 jreg;
-+      u32 data;
-+      ast_write32(ast, 0xf004, 0x1e6e0000);
-+      ast_write32(ast, 0xf000, 0x1);
-+      ast_write32(ast, 0x12000, 0x1688a8a8);
-+
-+      jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
-+      if (!(jreg & 0x80)) {
-+              /* Init SCU DVO Settings */
-+              data = ast_read32(ast, 0x12008);
-+              /* delay phase */
-+              data &= 0xfffff8ff;
-+              data |= 0x00000500;
-+              ast_write32(ast, 0x12008, data);
-+
-+              if (ast->chip == AST2300) {
-+                      data = ast_read32(ast, 0x12084);
-+                      /* multi-pins for DVO single-edge */
-+                      data |= 0xfffe0000;
-+                      ast_write32(ast, 0x12084, data);
-+
-+                      data = ast_read32(ast, 0x12088);
-+                      /* multi-pins for DVO single-edge */
-+                      data |= 0x000fffff;
-+                      ast_write32(ast, 0x12088, data);
-+
-+                      data = ast_read32(ast, 0x12090);
-+                      /* multi-pins for DVO single-edge */
-+                      data &= 0xffffffcf;
-+                      data |= 0x00000020;
-+                      ast_write32(ast, 0x12090, data);
-+              } else { /* AST2400 */
-+                      data = ast_read32(ast, 0x12088);
-+                      /* multi-pins for DVO single-edge */
-+                      data |= 0x30000000;
-+                      ast_write32(ast, 0x12088, data);
-+
-+                      data = ast_read32(ast, 0x1208c);
-+                      /* multi-pins for DVO single-edge */
-+                      data |= 0x000000cf;
-+                      ast_write32(ast, 0x1208c, data);
-+
-+                      data = ast_read32(ast, 0x120a4);
-+                      /* multi-pins for DVO single-edge */
-+                      data |= 0xffff0000;
-+                      ast_write32(ast, 0x120a4, data);
-+
-+                      data = ast_read32(ast, 0x120a8);
-+                      /* multi-pins for DVO single-edge */
-+                      data |= 0x0000000f;
-+                      ast_write32(ast, 0x120a8, data);
-+
-+                      data = ast_read32(ast, 0x12094);
-+                      /* multi-pins for DVO single-edge */
-+                      data |= 0x00000002;
-+                      ast_write32(ast, 0x12094, data);
-+              }
-+      }
-+
-+      /* Force to DVO */
-+      data = ast_read32(ast, 0x1202c);
-+      data &= 0xfffbffff;
-+      ast_write32(ast, 0x1202c, data);
-+
-+      /* Init VGA DVO Settings */
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80);
-+      return true;
-+}
-+
-+
-+static void ast_init_analog(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u32 data;
-+
-+      /*
-+       * Set DAC source to VGA mode in SCU2C via the P2A
-+       * bridge. First configure the P2U to target the SCU
-+       * in case it isn't at this stage.
-+       */
-+      ast_write32(ast, 0xf004, 0x1e6e0000);
-+      ast_write32(ast, 0xf000, 0x1);
-+
-+      /* Then unlock the SCU with the magic password */
-+      ast_write32(ast, 0x12000, 0x1688a8a8);
-+      ast_write32(ast, 0x12000, 0x1688a8a8);
-+      ast_write32(ast, 0x12000, 0x1688a8a8);
-+
-+      /* Finally, clear bits [17:16] of SCU2c */
-+      data = ast_read32(ast, 0x1202c);
-+      data &= 0xfffcffff;
-+      ast_write32(ast, 0, data);
-+
-+      /* Disable DVO */
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00);
-+}
-+
-+void ast_init_3rdtx(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u8 jreg;
-+
-+      if (ast->chip == AST2300 || ast->chip == AST2400) {
-+              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 
0xff);
-+              switch (jreg & 0x0e) {
-+              case 0x04:
-+                      ast_init_dvo(dev);
-+                      break;
-+              case 0x08:
-+                      ast_launch_m68k(dev);
-+                      break;
-+              case 0x0c:
-+                      ast_init_dvo(dev);
-+                      break;
-+              default:
-+                      if (ast->tx_chip_type == AST_TX_SIL164)
-+                              ast_init_dvo(dev);
-+                      else
-+                              ast_init_analog(dev);
-+              }
-+      }
-+}
-diff --git a/src/drivers/aspeed/common/ast_dram_tables.h 
b/src/drivers/aspeed/common/ast_dram_tables.h
-new file mode 100644
-index 0000000..4884cba
---- /dev/null
-+++ b/src/drivers/aspeed/common/ast_dram_tables.h
-@@ -0,0 +1,165 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * File taken from the Linux ast driver (v3.18.5)
-+ * Coreboot-specific includes added at top and/or contents modified
-+ * as needed to function within the coreboot environment.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc.
-+ */
-+
-+#ifndef AST_DRAM_TABLES_H
-+#define AST_DRAM_TABLES_H
-+
-+/* DRAM timing tables */
-+struct ast_dramstruct {
-+      u16 index;
-+      u32 data;
-+};
-+
-+static const struct ast_dramstruct ast2000_dram_table_data[] = {
-+      { 0x0108, 0x00000000 },
-+      { 0x0120, 0x00004a21 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x0000, 0xFFFFFFFF },
-+      { 0x0004, 0x00000089 },
-+      { 0x0008, 0x22331353 },
-+      { 0x000C, 0x0d07000b },
-+      { 0x0010, 0x11113333 },
-+      { 0x0020, 0x00110350 },
-+      { 0x0028, 0x1e0828f0 },
-+      { 0x0024, 0x00000001 },
-+      { 0x001C, 0x00000000 },
-+      { 0x0014, 0x00000003 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x0018, 0x00000131 },
-+      { 0x0014, 0x00000001 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x0018, 0x00000031 },
-+      { 0x0014, 0x00000001 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x0028, 0x1e0828f1 },
-+      { 0x0024, 0x00000003 },
-+      { 0x002C, 0x1f0f28fb },
-+      { 0x0030, 0xFFFFFE01 },
-+      { 0xFFFF, 0xFFFFFFFF }
-+};
-+
-+static const struct ast_dramstruct ast1100_dram_table_data[] = {
-+      { 0x2000, 0x1688a8a8 },
-+      { 0x2020, 0x000041f0 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x0000, 0xfc600309 },
-+      { 0x006C, 0x00909090 },
-+      { 0x0064, 0x00050000 },
-+      { 0x0004, 0x00000585 },
-+      { 0x0008, 0x0011030f },
-+      { 0x0010, 0x22201724 },
-+      { 0x0018, 0x1e29011a },
-+      { 0x0020, 0x00c82222 },
-+      { 0x0014, 0x01001523 },
-+      { 0x001C, 0x1024010d },
-+      { 0x0024, 0x00cb2522 },
-+      { 0x0038, 0xffffff82 },
-+      { 0x003C, 0x00000000 },
-+      { 0x0040, 0x00000000 },
-+      { 0x0044, 0x00000000 },
-+      { 0x0048, 0x00000000 },
-+      { 0x004C, 0x00000000 },
-+      { 0x0050, 0x00000000 },
-+      { 0x0054, 0x00000000 },
-+      { 0x0058, 0x00000000 },
-+      { 0x005C, 0x00000000 },
-+      { 0x0060, 0x032aa02a },
-+      { 0x0064, 0x002d3000 },
-+      { 0x0068, 0x00000000 },
-+      { 0x0070, 0x00000000 },
-+      { 0x0074, 0x00000000 },
-+      { 0x0078, 0x00000000 },
-+      { 0x007C, 0x00000000 },
-+      { 0x0034, 0x00000001 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x002C, 0x00000732 },
-+      { 0x0030, 0x00000040 },
-+      { 0x0028, 0x00000005 },
-+      { 0x0028, 0x00000007 },
-+      { 0x0028, 0x00000003 },
-+      { 0x0028, 0x00000001 },
-+      { 0x000C, 0x00005a08 },
-+      { 0x002C, 0x00000632 },
-+      { 0x0028, 0x00000001 },
-+      { 0x0030, 0x000003c0 },
-+      { 0x0028, 0x00000003 },
-+      { 0x0030, 0x00000040 },
-+      { 0x0028, 0x00000003 },
-+      { 0x000C, 0x00005a21 },
-+      { 0x0034, 0x00007c03 },
-+      { 0x0120, 0x00004c41 },
-+      { 0xffff, 0xffffffff },
-+};
-+
-+static const struct ast_dramstruct ast2100_dram_table_data[] = {
-+      { 0x2000, 0x1688a8a8 },
-+      { 0x2020, 0x00004120 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x0000, 0xfc600309 },
-+      { 0x006C, 0x00909090 },
-+      { 0x0064, 0x00070000 },
-+      { 0x0004, 0x00000489 },
-+      { 0x0008, 0x0011030f },
-+      { 0x0010, 0x32302926 },
-+      { 0x0018, 0x274c0122 },
-+      { 0x0020, 0x00ce2222 },
-+      { 0x0014, 0x01001523 },
-+      { 0x001C, 0x1024010d },
-+      { 0x0024, 0x00cb2522 },
-+      { 0x0038, 0xffffff82 },
-+      { 0x003C, 0x00000000 },
-+      { 0x0040, 0x00000000 },
-+      { 0x0044, 0x00000000 },
-+      { 0x0048, 0x00000000 },
-+      { 0x004C, 0x00000000 },
-+      { 0x0050, 0x00000000 },
-+      { 0x0054, 0x00000000 },
-+      { 0x0058, 0x00000000 },
-+      { 0x005C, 0x00000000 },
-+      { 0x0060, 0x0f2aa02a },
-+      { 0x0064, 0x003f3005 },
-+      { 0x0068, 0x02020202 },
-+      { 0x0070, 0x00000000 },
-+      { 0x0074, 0x00000000 },
-+      { 0x0078, 0x00000000 },
-+      { 0x007C, 0x00000000 },
-+      { 0x0034, 0x00000001 },
-+      { 0xFF00, 0x00000043 },
-+      { 0x002C, 0x00000942 },
-+      { 0x0030, 0x00000040 },
-+      { 0x0028, 0x00000005 },
-+      { 0x0028, 0x00000007 },
-+      { 0x0028, 0x00000003 },
-+      { 0x0028, 0x00000001 },
-+      { 0x000C, 0x00005a08 },
-+      { 0x002C, 0x00000842 },
-+      { 0x0028, 0x00000001 },
-+      { 0x0030, 0x000003c0 },
-+      { 0x0028, 0x00000003 },
-+      { 0x0030, 0x00000040 },
-+      { 0x0028, 0x00000003 },
-+      { 0x000C, 0x00005a21 },
-+      { 0x0034, 0x00007c03 },
-+      { 0x0120, 0x00005061 },
-+      { 0xffff, 0xffffffff },
-+};
-+
-+#endif
-diff --git a/src/drivers/aspeed/common/ast_drv.h 
b/src/drivers/aspeed/common/ast_drv.h
-new file mode 100644
-index 0000000..53640f1
---- /dev/null
-+++ b/src/drivers/aspeed/common/ast_drv.h
-@@ -0,0 +1,223 @@
-+/*
-+ * Copyright 2012 Red Hat Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY 
CLAIM,
-+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ */
-+/*
-+ * Authors: Dave Airlie <address@hidden>
-+ */
-+#ifndef __AST_DRV_H__
-+#define __AST_DRV_H__
-+
-+#include "aspeed_coreboot.h"
-+
-+#define PCI_CHIP_AST2000 0x2000
-+#define PCI_CHIP_AST2100 0x2010
-+#define PCI_CHIP_AST1180 0x1180
-+
-+
-+enum ast_chip {
-+      AST2000,
-+      AST2100,
-+      AST1100,
-+      AST2200,
-+      AST2150,
-+      AST2300,
-+      AST2400,
-+      AST1180,
-+};
-+
-+enum ast_tx_chip {
-+      AST_TX_NONE,
-+      AST_TX_SIL164,
-+      AST_TX_ITE66121,
-+      AST_TX_DP501,
-+};
-+
-+#define AST_DRAM_512Mx16 0
-+#define AST_DRAM_1Gx16   1
-+#define AST_DRAM_512Mx32 2
-+#define AST_DRAM_1Gx32   3
-+#define AST_DRAM_2Gx16   6
-+#define AST_DRAM_4Gx16   7
-+
-+struct ast_fbdev;
-+
-+struct ast_private {
-+      struct drm_device *dev;
-+
-+      void __iomem *regs;
-+      void __iomem *ioregs;
-+      bool io_space_uses_mmap;
-+
-+      enum ast_chip chip;
-+      bool vga2_clone;
-+      uint32_t dram_bus_width;
-+      uint32_t dram_type;
-+      uint32_t mclk;
-+      uint32_t vram_size;
-+
-+      struct ast_fbdev *fbdev;
-+
-+      int fb_mtrr;
-+
-+      struct drm_gem_object *cursor_cache;
-+      uint64_t cursor_cache_gpu_addr;
-+
-+      int next_cursor;
-+      bool support_wide_screen;
-+
-+      enum ast_tx_chip tx_chip_type;
-+      u8 dp501_maxclk;
-+      u8 *dp501_fw_addr;
-+      const struct firmware *dp501_fw;        /* dp501 fw */
-+};
-+
-+int ast_driver_load(struct drm_device *dev, unsigned long flags);
-+int ast_driver_unload(struct drm_device *dev);
-+
-+#define AST_IO_AR_PORT_WRITE          (0x40)
-+#define AST_IO_MISC_PORT_WRITE                (0x42)
-+#define AST_IO_VGA_ENABLE_PORT                (0x43)
-+#define AST_IO_SEQ_PORT                       (0x44)
-+#define AST_IO_DAC_INDEX_READ         (0x47)
-+#define AST_IO_DAC_INDEX_WRITE                (0x48)
-+#define AST_IO_DAC_DATA                       (0x49)
-+#define AST_IO_GR_PORT                        (0x4E)
-+#define AST_IO_CRTC_PORT              (0x54)
-+#define AST_IO_INPUT_STATUS1_READ     (0x5A)
-+#define AST_IO_MISC_PORT_READ         (0x4C)
-+
-+#define AST_IO_MM_OFFSET              (0x380)
-+
-+#define __ast_read(x) \
-+static inline u##x ast_read##x(struct ast_private *ast, u32 reg) { \
-+u##x val = 0;\
-+val = ioread##x(ast->regs + reg); \
-+return val;\
-+}
-+
-+__ast_read(8);
-+__ast_read(16);
-+__ast_read(32)
-+
-+#define __ast_io_read(x) \
-+static inline u##x ast_io_read##x(struct ast_private *ast, u32 reg) { \
-+u##x val = 0;\
-+if (ast->io_space_uses_mmap) \
-+val = ioread##x(ast->regs + reg); \
-+else \
-+val = ioread_cbio##x(ast->ioregs + reg); \
-+return val;\
-+}
-+
-+__ast_io_read(8);
-+__ast_io_read(16);
-+__ast_io_read(32);
-+
-+#define __ast_write(x) \
-+static inline void ast_write##x(struct ast_private *ast, u32 reg, u##x val) {\
-+      iowrite##x(val, ast->regs + reg);\
-+      }
-+
-+__ast_write(8);
-+__ast_write(16);
-+__ast_write(32);
-+
-+#define __ast_io_write(x) \
-+static inline void ast_io_write##x(struct ast_private *ast, u32 reg, u##x 
val) {\
-+      if (ast->io_space_uses_mmap) \
-+      iowrite##x(val, ast->regs + reg);\
-+      else \
-+      iowrite_cbio##x(val, ast->ioregs + reg);\
-+      }
-+
-+__ast_io_write(8);
-+__ast_io_write(16);
-+#undef __ast_io_write
-+
-+static inline void ast_set_index_reg(struct ast_private *ast,
-+                                   uint32_t base, uint8_t index,
-+                                   uint8_t val)
-+{
-+      ast_io_write16(ast, base, ((u16)val << 8) | index);
-+}
-+
-+void ast_set_index_reg_mask(struct ast_private *ast,
-+                          uint32_t base, uint8_t index,
-+                          uint8_t mask, uint8_t val);
-+uint8_t ast_get_index_reg(struct ast_private *ast,
-+                        uint32_t base, uint8_t index);
-+uint8_t ast_get_index_reg_mask(struct ast_private *ast,
-+                             uint32_t base, uint8_t index, uint8_t mask);
-+
-+static inline void ast_open_key(struct ast_private *ast)
-+{
-+      ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x80, 0xA8);
-+}
-+
-+#define AST_VIDMEM_SIZE_8M    0x00800000
-+#define AST_VIDMEM_SIZE_16M   0x01000000
-+#define AST_VIDMEM_SIZE_32M   0x02000000
-+#define AST_VIDMEM_SIZE_64M   0x04000000
-+#define AST_VIDMEM_SIZE_128M  0x08000000
-+
-+#define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M
-+
-+#define AST_MAX_HWC_WIDTH 64
-+#define AST_MAX_HWC_HEIGHT 64
-+
-+#define AST_HWC_SIZE                (AST_MAX_HWC_WIDTH*AST_MAX_HWC_HEIGHT*2)
-+#define AST_HWC_SIGNATURE_SIZE      32
-+
-+#define AST_DEFAULT_HWC_NUM 2
-+/* define for signature structure */
-+#define AST_HWC_SIGNATURE_CHECKSUM  0x00
-+#define AST_HWC_SIGNATURE_SizeX     0x04
-+#define AST_HWC_SIGNATURE_SizeY     0x08
-+#define AST_HWC_SIGNATURE_X         0x0C
-+#define AST_HWC_SIGNATURE_Y         0x10
-+#define AST_HWC_SIGNATURE_HOTSPOTX  0x14
-+#define AST_HWC_SIGNATURE_HOTSPOTY  0x18
-+
-+#define AST_MM_ALIGN_SHIFT 4
-+#define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1)
-+
-+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
-+
-+/* ast post */
-+void ast_enable_vga(struct drm_device *dev);
-+void ast_enable_mmio(struct drm_device *dev);
-+bool ast_is_vga_enabled(struct drm_device *dev);
-+void ast_post_gpu(struct drm_device *dev);
-+u32 ast_mindwm(struct ast_private *ast, u32 r);
-+void ast_moutdwm(struct ast_private *ast, u32 r, u32 v);
-+/* ast dp501 */
-+int ast_load_dp501_microcode(struct drm_device *dev);
-+void ast_set_dp501_video_output(struct drm_device *dev, u8 mode);
-+bool ast_launch_m68k(struct drm_device *dev);
-+bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);
-+bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
-+u8 ast_get_dp501_max_clk(struct drm_device *dev);
-+void ast_init_3rdtx(struct drm_device *dev);
-+#endif
-diff --git a/src/drivers/aspeed/common/ast_main.c 
b/src/drivers/aspeed/common/ast_main.c
-new file mode 100644
-index 0000000..2939442
---- /dev/null
-+++ b/src/drivers/aspeed/common/ast_main.c
-@@ -0,0 +1,393 @@
-+/*
-+ * Copyright 2012 Red Hat Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY 
CLAIM,
-+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ */
-+/*
-+ * Authors: Dave Airlie <address@hidden>
-+ */
-+#include "ast_drv.h"
-+
-+#include "ast_dram_tables.h"
-+
-+void ast_set_index_reg_mask(struct ast_private *ast,
-+                          uint32_t base, uint8_t index,
-+                          uint8_t mask, uint8_t val)
-+{
-+      u8 tmp;
-+      ast_io_write8(ast, base, index);
-+      tmp = (ast_io_read8(ast, base + 1) & mask) | val;
-+      ast_set_index_reg(ast, base, index, tmp);
-+}
-+
-+uint8_t ast_get_index_reg(struct ast_private *ast,
-+                        uint32_t base, uint8_t index)
-+{
-+      uint8_t ret;
-+      ast_io_write8(ast, base, index);
-+      ret = ast_io_read8(ast, base + 1);
-+      return ret;
-+}
-+
-+uint8_t ast_get_index_reg_mask(struct ast_private *ast,
-+                             uint32_t base, uint8_t index, uint8_t mask)
-+{
-+      uint8_t ret;
-+      ast_io_write8(ast, base, index);
-+      ret = ast_io_read8(ast, base + 1) & mask;
-+      return ret;
-+}
-+
-+
-+static int ast_detect_chip(struct drm_device *dev, bool *need_post)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      uint32_t data, jreg;
-+      ast_open_key(ast);
-+
-+      if (dev->pdev->device == PCI_CHIP_AST1180) {
-+              ast->chip = AST1100;
-+              DRM_INFO("AST 1180 detected\n");
-+      } else {
-+              pci_read_config_dword(ast->dev->pdev, 0x08, &data);
-+              uint8_t revision = data & 0xff;
-+
-+              if (revision >= 0x30) {
-+                      ast->chip = AST2400;
-+                      DRM_INFO("AST 2400 detected\n");
-+              } else if (revision >= 0x20) {
-+                      ast->chip = AST2300;
-+                      DRM_INFO("AST 2300 detected\n");
-+              } else if (revision >= 0x10) {
-+                      ast_write32(ast, 0xf004, 0x1e6e0000);
-+                      ast_write32(ast, 0xf000, 0x1);
-+
-+                      data = ast_read32(ast, 0x1207c);
-+                      switch (data & 0x0300) {
-+                      case 0x0200:
-+                              ast->chip = AST1100;
-+                              DRM_INFO("AST 1100 detected\n");
-+                              break;
-+                      case 0x0100:
-+                              ast->chip = AST2200;
-+                              DRM_INFO("AST 2200 detected\n");
-+                              break;
-+                      case 0x0000:
-+                              ast->chip = AST2150;
-+                              DRM_INFO("AST 2150 detected\n");
-+                              break;
-+                      default:
-+                              ast->chip = AST2100;
-+                              DRM_INFO("AST 2100 detected\n");
-+                              break;
-+                      }
-+                      ast->vga2_clone = false;
-+              } else {
-+                      ast->chip = AST2000;
-+                      DRM_INFO("AST 2000 detected\n");
-+              }
-+      }
-+
-+      /*
-+       * If VGA isn't enabled, we need to enable now or subsequent
-+       * access to the scratch registers will fail. We also inform
-+       * our caller that it needs to POST the chip
-+       * (Assumption: VGA not enabled -> need to POST)
-+       */
-+      if (!ast_is_vga_enabled(dev)) {
-+              ast_enable_vga(dev);
-+              ast_enable_mmio(dev);
-+              DRM_INFO("VGA not enabled on entry, requesting chip POST\n");
-+              *need_post = true;
-+      } else
-+              *need_post = false;
-+
-+      /* Check if we support wide screen */
-+      switch (ast->chip) {
-+      case AST1180:
-+              ast->support_wide_screen = true;
-+              break;
-+      case AST2000:
-+              ast->support_wide_screen = false;
-+              break;
-+      default:
-+              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 
0xff);
-+              if (!(jreg & 0x80))
-+                      ast->support_wide_screen = true;
-+              else if (jreg & 0x01)
-+                      ast->support_wide_screen = true;
-+              else {
-+                      ast->support_wide_screen = false;
-+                      /* Read SCU7c (silicon revision register) */
-+                      ast_write32(ast, 0xf004, 0x1e6e0000);
-+                      ast_write32(ast, 0xf000, 0x1);
-+                      data = ast_read32(ast, 0x1207c);
-+                      data &= 0x300;
-+                      if (ast->chip == AST2300 && data == 0x0) /* ast1300 */
-+                              ast->support_wide_screen = true;
-+                      if (ast->chip == AST2400 && data == 0x100) /* ast1400 */
-+                              ast->support_wide_screen = true;
-+              }
-+              break;
-+      }
-+
-+      /* Check 3rd Tx option (digital output afaik) */
-+      ast->tx_chip_type = AST_TX_NONE;
-+
-+      /*
-+       * VGACRA3 Enhanced Color Mode Register, check if DVO is already
-+       * enabled, in that case, assume we have a SIL164 TMDS transmitter
-+       *
-+       * Don't make that assumption if we the chip wasn't enabled and
-+       * is at power-on reset, otherwise we'll incorrectly "detect" a
-+       * SIL164 when there is none.
-+       */
-+      if (!*need_post) {
-+              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 
0xff);
-+              if (jreg & 0x80)
-+                      ast->tx_chip_type = AST_TX_SIL164;
-+      }
-+
-+      if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
-+              /*
-+               * On AST2300 and 2400, look the configuration set by the SoC in
-+               * the SOC scratch register #1 bits 11:8 (interestingly marked
-+               * as "reserved" in the spec)
-+               */
-+              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 
0xff);
-+              switch (jreg) {
-+              case 0x04:
-+                      ast->tx_chip_type = AST_TX_SIL164;
-+                      break;
-+              case 0x08:
-+                      ast->dp501_fw_addr = kzalloc(32*1024, GFP_KERNEL);
-+                      if (ast->dp501_fw_addr) {
-+                              /* backup firmware */
-+                              if (ast_backup_fw(dev, ast->dp501_fw_addr, 
32*1024)) {
-+                                      kfree(ast->dp501_fw_addr);
-+                                      ast->dp501_fw_addr = NULL;
-+                              }
-+                      }
-+                      /* fallthrough */
-+              case 0x0c:
-+                      ast->tx_chip_type = AST_TX_DP501;
-+              }
-+      }
-+
-+      /* Print stuff for diagnostic purposes */
-+      switch(ast->tx_chip_type) {
-+      case AST_TX_SIL164:
-+              DRM_INFO("Using Sil164 TMDS transmitter\n");
-+              break;
-+      case AST_TX_DP501:
-+              DRM_INFO("Using DP501 DisplayPort transmitter\n");
-+              break;
-+      default:
-+              DRM_INFO("Analog VGA only\n");
-+      }
-+      return 0;
-+}
-+
-+static int ast_get_dram_info(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      uint8_t i;
-+      uint32_t data, data2;
-+      uint32_t denum, num, div, ref_pll;
-+
-+      ast_write32(ast, 0xf004, 0x1e6e0000);
-+      ast_write32(ast, 0xf000, 0x1);
-+
-+
-+      ast_write32(ast, 0x10000, 0xfc600309);
-+
-+      /* Wait up to 2.5 seconds for device initialization / register unlock */
-+      for (i = 0; i < 250; i++) {
-+              if (ast_read32(ast, 0x10000) == 0x01)
-+                      break;
-+              mdelay(10);
-+      }
-+      if (ast_read32(ast, 0x10000) != 0x01)
-+              dev_err(dev->pdev, "Unable to unlock SDRAM control 
registers\n");
-+
-+      data = ast_read32(ast, 0x10004);
-+
-+      if (data & 0x400)
-+              ast->dram_bus_width = 16;
-+      else
-+              ast->dram_bus_width = 32;
-+
-+      if (ast->chip == AST2300 || ast->chip == AST2400) {
-+              switch (data & 0x03) {
-+              case 0:
-+                      ast->dram_type = AST_DRAM_512Mx16;
-+                      break;
-+              default:
-+              case 1:
-+                      ast->dram_type = AST_DRAM_1Gx16;
-+                      break;
-+              case 2:
-+                      ast->dram_type = AST_DRAM_2Gx16;
-+                      break;
-+              case 3:
-+                      ast->dram_type = AST_DRAM_4Gx16;
-+                      break;
-+              }
-+      } else {
-+              switch (data & 0x0c) {
-+              case 0:
-+              case 4:
-+                      ast->dram_type = AST_DRAM_512Mx16;
-+                      break;
-+              case 8:
-+                      if (data & 0x40)
-+                              ast->dram_type = AST_DRAM_1Gx16;
-+                      else
-+                              ast->dram_type = AST_DRAM_512Mx32;
-+                      break;
-+              case 0xc:
-+                      ast->dram_type = AST_DRAM_1Gx32;
-+                      break;
-+              }
-+      }
-+
-+      data = ast_read32(ast, 0x10120);
-+      data2 = ast_read32(ast, 0x10170);
-+      if (data2 & 0x2000)
-+              ref_pll = 14318;
-+      else
-+              ref_pll = 12000;
-+
-+      denum = data & 0x1f;
-+      num = (data & 0x3fe0) >> 5;
-+      data = (data & 0xc000) >> 14;
-+      switch (data) {
-+      case 3:
-+              div = 0x4;
-+              break;
-+      case 2:
-+      case 1:
-+              div = 0x2;
-+              break;
-+      default:
-+              div = 0x1;
-+              break;
-+      }
-+      ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
-+      return 0;
-+}
-+
-+static u32 ast_get_vram_info(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u8 jreg;
-+      u32 vram_size;
-+      ast_open_key(ast);
-+
-+      vram_size = AST_VIDMEM_DEFAULT_SIZE;
-+      jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
-+      switch (jreg & 3) {
-+      case 0: vram_size = AST_VIDMEM_SIZE_8M; break;
-+      case 1: vram_size = AST_VIDMEM_SIZE_16M; break;
-+      case 2: vram_size = AST_VIDMEM_SIZE_32M; break;
-+      case 3: vram_size = AST_VIDMEM_SIZE_64M; break;
-+      }
-+
-+      return vram_size;
-+}
-+
-+int ast_driver_load(struct drm_device *dev, unsigned long flags)
-+{
-+      struct ast_private *ast;
-+      bool need_post;
-+      int ret = 0;
-+      struct resource *res;
-+
-+      ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
-+      if (!ast)
-+              return -ENOMEM;
-+
-+      dev->dev_private = ast;
-+      ast->dev = dev;
-+
-+      /* PCI BAR 1 */
-+        res = find_resource(dev->pdev, 0x14);
-+      if (!res) {
-+              dev_err(dev->pdev, "BAR1 resource not found.\n");
-+              ret = -EIO;
-+              goto out_free;
-+      }
-+      ast->regs = res2mmio(res, 0, 0);
-+      if (!ast->regs) {
-+              ret = -EIO;
-+              goto out_free;
-+      }
-+
-+      /* PCI BAR 2 */
-+      ast->io_space_uses_mmap = false;
-+      res = find_resource(dev->pdev, 0x18);
-+      if (!res) {
-+              dev_err(dev->pdev, "BAR2 resource not found.\n");
-+              ret = -EIO;
-+              goto out_free;
-+      }
-+
-+      /*
-+       * If we don't have IO space at all, use MMIO now and
-+       * assume the chip has MMIO enabled by default (rev 0x20
-+       * and higher).
-+       */
-+      if (!(res->flags & IORESOURCE_IO)) {
-+              DRM_INFO("platform has no IO space, trying MMIO\n");
-+              ast->ioregs = ast->regs + AST_IO_MM_OFFSET;
-+              ast->io_space_uses_mmap = true;
-+      }
-+
-+      /* "map" IO regs if the above hasn't done so already */
-+      if (!ast->ioregs) {
-+              ast->ioregs = res2mmio(res, 0, 0);
-+              if (!ast->ioregs) {
-+                      ret = -EIO;
-+                      goto out_free;
-+              }
-+              /* Adjust the I/O space location to match expectations (the 
code expects offset 0x0 to be I/O location 0x380) */
-+              ast->ioregs = (void *)AST_IO_MM_OFFSET;
-+      }
-+
-+      ast_detect_chip(dev, &need_post);
-+
-+      if (ast->chip != AST1180) {
-+              ast_get_dram_info(dev);
-+              ast->vram_size = ast_get_vram_info(dev);
-+              DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, 
ast->dram_bus_width, ast->vram_size);
-+      }
-+
-+      if (need_post)
-+              ast_post_gpu(dev);
-+
-+      return 0;
-+out_free:
-+      kfree(ast);
-+      dev->dev_private = NULL;
-+      return ret;
-+}
-diff --git a/src/drivers/aspeed/common/ast_post.c 
b/src/drivers/aspeed/common/ast_post.c
-new file mode 100644
-index 0000000..7d31845
---- /dev/null
-+++ b/src/drivers/aspeed/common/ast_post.c
-@@ -0,0 +1,1679 @@
-+/*
-+ * Copyright 2012 Red Hat Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a
-+ * copy of this software and associated documentation files (the
-+ * "Software"), to deal in the Software without restriction, including
-+ * without limitation the rights to use, copy, modify, merge, publish,
-+ * distribute, sub license, and/or sell copies of the Software, and to
-+ * permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
-+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY 
CLAIM,
-+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
-+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
-+ *
-+ * The above copyright notice and this permission notice (including the
-+ * next paragraph) shall be included in all copies or substantial portions
-+ * of the Software.
-+ *
-+ */
-+/*
-+ * Authors: Dave Airlie <address@hidden>
-+ */
-+
-+#include "ast_drv.h"
-+
-+#include "ast_dram_tables.h"
-+
-+static void ast_init_dram_2300(struct drm_device *dev);
-+
-+void ast_enable_vga(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+
-+      ast_io_write8(ast, AST_IO_VGA_ENABLE_PORT, 0x01);
-+      ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, 0x01);
-+}
-+
-+void ast_enable_mmio(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04);
-+}
-+
-+
-+bool ast_is_vga_enabled(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u8 ch;
-+
-+      if (ast->chip == AST1180) {
-+              /* TODO 1180 */
-+      } else {
-+              ch = ast_io_read8(ast, AST_IO_VGA_ENABLE_PORT);
-+              if (ch) {
-+                      ast_open_key(ast);
-+                      ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 
0xb6, 0xff);
-+                      return ch & 0x04;
-+              }
-+      }
-+      return 0;
-+}
-+
-+static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
-+static const u8 extreginfo_ast2300a0[] = { 0x0f, 0x04, 0x1c, 0xff };
-+static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff };
-+
-+static void
-+ast_set_def_ext_reg(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u8 i, index, reg;
-+      uint32_t data;
-+      const u8 *ext_reg_info;
-+
-+      pci_read_config_dword(ast->dev->pdev, 0x08, &data);
-+      uint8_t revision = data & 0xff;
-+
-+      /* reset scratch */
-+      for (i = 0x81; i <= 0x8f; i++)
-+              ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, 0x00);
-+
-+      if (ast->chip == AST2300 || ast->chip == AST2400) {
-+              if (revision >= 0x20)
-+                      ext_reg_info = extreginfo_ast2300;
-+              else
-+                      ext_reg_info = extreginfo_ast2300a0;
-+      } else
-+              ext_reg_info = extreginfo;
-+
-+      index = 0xa0;
-+      while (*ext_reg_info != 0xff) {
-+              ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, index, 0x00, 
*ext_reg_info);
-+              index++;
-+              ext_reg_info++;
-+      }
-+
-+      /* disable standard IO/MEM decode if secondary */
-+      /* ast_set_index_reg-mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x3); */
-+
-+      /* Set Ext. Default */
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x8c, 0x00, 0x01);
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x00, 0x00);
-+
-+      /* Enable RAMDAC for A1 */
-+      reg = 0x04;
-+      if (ast->chip == AST2300 || ast->chip == AST2400)
-+              reg |= 0x20;
-+      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff, reg);
-+}
-+
-+u32 ast_mindwm(struct ast_private *ast, u32 r)
-+{
-+      uint32_t data;
-+
-+      ast_write32(ast, 0xf004, r & 0xffff0000);
-+      ast_write32(ast, 0xf000, 0x1);
-+
-+      do {
-+              data = ast_read32(ast, 0xf004) & 0xffff0000;
-+      } while (data != (r & 0xffff0000));
-+      return ast_read32(ast, 0x10000 + (r & 0x0000ffff));
-+}
-+
-+void ast_moutdwm(struct ast_private *ast, u32 r, u32 v)
-+{
-+      uint32_t data;
-+      ast_write32(ast, 0xf004, r & 0xffff0000);
-+      ast_write32(ast, 0xf000, 0x1);
-+      do {
-+              data = ast_read32(ast, 0xf004) & 0xffff0000;
-+      } while (data != (r & 0xffff0000));
-+      ast_write32(ast, 0x10000 + (r & 0x0000ffff), v);
-+}
-+
-+/*
-+ * AST2100/2150 DLL CBR Setting
-+ */
-+#define CBR_SIZE_AST2150           ((16 << 10) - 1)
-+#define CBR_PASSNUM_AST2150          5
-+#define CBR_THRESHOLD_AST2150        10
-+#define CBR_THRESHOLD2_AST2150       10
-+#define TIMEOUT_AST2150              5000000
-+
-+#define CBR_PATNUM_AST2150           8
-+
-+static const u32 pattern_AST2150[14] = {
-+      0xFF00FF00,
-+      0xCC33CC33,
-+      0xAA55AA55,
-+      0xFFFE0001,
-+      0x683501FE,
-+      0x0F1929B0,
-+      0x2D0B4346,
-+      0x60767F02,
-+      0x6FBE36A6,
-+      0x3A253035,
-+      0x3019686D,
-+      0x41C6167E,
-+      0x620152BF,
-+      0x20F050E0
-+};
-+
-+static u32 mmctestburst2_ast2150(struct ast_private *ast, u32 datagen)
-+{
-+      u32 data, timeout;
-+
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3));
-+      timeout = 0;
-+      do {
-+              data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
-+              if (++timeout > TIMEOUT_AST2150) {
-+                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+                      return 0xffffffff;
-+              }
-+      } while (!data);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3));
-+      timeout = 0;
-+      do {
-+              data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
-+              if (++timeout > TIMEOUT_AST2150) {
-+                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+                      return 0xffffffff;
-+              }
-+      } while (!data);
-+      data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      return data;
-+}
-+
-+#if 0 /* unused in DDX driver - here for completeness */
-+static u32 mmctestsingle2_ast2150(struct ast_private *ast, u32 datagen)
-+{
-+      u32 data, timeout;
-+
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
-+      timeout = 0;
-+      do {
-+              data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
-+              if (++timeout > TIMEOUT_AST2150) {
-+                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+                      return 0xffffffff;
-+              }
-+      } while (!data);
-+      data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      return data;
-+}
-+#endif
-+
-+static int cbrtest_ast2150(struct ast_private *ast)
-+{
-+      int i;
-+
-+      for (i = 0; i < 8; i++)
-+              if (mmctestburst2_ast2150(ast, i))
-+                      return 0;
-+      return 1;
-+}
-+
-+static int cbrscan_ast2150(struct ast_private *ast, int busw)
-+{
-+      u32 patcnt, loop;
-+
-+      for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) {
-+              ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]);
-+              for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) {
-+                      if (cbrtest_ast2150(ast))
-+                              break;
-+              }
-+              if (loop == CBR_PASSNUM_AST2150)
-+                      return 0;
-+      }
-+      return 1;
-+}
-+
-+
-+static void cbrdlli_ast2150(struct ast_private *ast, int busw)
-+{
-+      u32 dll_min[4], dll_max[4], dlli, data, passcnt;
-+
-+cbr_start:
-+      dll_min[0] = dll_min[1] = dll_min[2] = dll_min[3] = 0xff;
-+      dll_max[0] = dll_max[1] = dll_max[2] = dll_max[3] = 0x0;
-+      passcnt = 0;
-+
-+      for (dlli = 0; dlli < 100; dlli++) {
-+              ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) 
| (dlli << 24));
-+              data = cbrscan_ast2150(ast, busw);
-+              if (data != 0) {
-+                      if (data & 0x1) {
-+                              if (dll_min[0] > dlli)
-+                                      dll_min[0] = dlli;
-+                              if (dll_max[0] < dlli)
-+                                      dll_max[0] = dlli;
-+                      }
-+                      passcnt++;
-+              } else if (passcnt >= CBR_THRESHOLD_AST2150)
-+                      goto cbr_start;
-+      }
-+      if (dll_max[0] == 0 || (dll_max[0]-dll_min[0]) < CBR_THRESHOLD_AST2150)
-+              goto cbr_start;
-+
-+      dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4);
-+      ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli 
<< 24));
-+}
-+
-+
-+
-+static void ast_init_dram_reg(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      u8 j;
-+      u32 data, temp, i;
-+      const struct ast_dramstruct *dram_reg_info;
-+
-+      j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
-+
-+      if ((j & 0x80) == 0) { /* VGA only */
-+              if (ast->chip == AST2000) {
-+                      dram_reg_info = ast2000_dram_table_data;
-+                      ast_write32(ast, 0xf004, 0x1e6e0000);
-+                      ast_write32(ast, 0xf000, 0x1);
-+                      ast_write32(ast, 0x10100, 0xa8);
-+
-+                      do {
-+                              ;
-+                      } while (ast_read32(ast, 0x10100) != 0xa8);
-+              } else {/* AST2100/1100 */
-+                      if (ast->chip == AST2100 || ast->chip == 2200)
-+                              dram_reg_info = ast2100_dram_table_data;
-+                      else
-+                              dram_reg_info = ast1100_dram_table_data;
-+
-+                      ast_write32(ast, 0xf004, 0x1e6e0000);
-+                      ast_write32(ast, 0xf000, 0x1);
-+                      ast_write32(ast, 0x12000, 0x1688A8A8);
-+
-+                      /* Wait up to 2.5 seconds for device initialization / 
register unlock */
-+                      for (i = 0; i < 250; i++) {
-+                              if (ast_read32(ast, 0x12000) == 0x01)
-+                                      break;
-+                              mdelay(10);
-+                      }
-+                      if (ast_read32(ast, 0x12000) != 0x01)
-+                              dev_err(dev->pdev, "Unable to unlock SCU 
registers\n");
-+
-+                      ast_write32(ast, 0x10000, 0xfc600309);
-+
-+                      /* Wait up to 2.5 seconds for device initialization / 
register unlock */
-+                      for (i = 0; i < 250; i++) {
-+                              if (ast_read32(ast, 0x10000) == 0x01)
-+                                      break;
-+                              mdelay(10);
-+                      }
-+                      if (ast_read32(ast, 0x10000) != 0x01)
-+                              dev_err(dev->pdev, "Unable to unlock SDRAM 
control registers\n");
-+              }
-+
-+              while (dram_reg_info->index != 0xffff) {
-+                      if (dram_reg_info->index == 0xff00) {/* delay fn */
-+                              for (i = 0; i < 15; i++)
-+                                      udelay(dram_reg_info->data);
-+                      } else if (dram_reg_info->index == 0x4 && ast->chip != 
AST2000) {
-+                              data = dram_reg_info->data;
-+                              if (ast->dram_type == AST_DRAM_1Gx16)
-+                                      data = 0x00000d89;
-+                              else if (ast->dram_type == AST_DRAM_1Gx32)
-+                                      data = 0x00000c8d;
-+
-+                              temp = ast_read32(ast, 0x12070);
-+                              temp &= 0xc;
-+                              temp <<= 2;
-+                              ast_write32(ast, 0x10000 + 
dram_reg_info->index, data | temp);
-+                      } else
-+                              ast_write32(ast, 0x10000 + 
dram_reg_info->index, dram_reg_info->data);
-+                      dram_reg_info++;
-+              }
-+
-+              /* AST 2100/2150 DRAM calibration */
-+              data = ast_read32(ast, 0x10120);
-+              if (data == 0x5061) { /* 266Mhz */
-+                      data = ast_read32(ast, 0x10004);
-+                      if (data & 0x40)
-+                              cbrdlli_ast2150(ast, 16); /* 16 bits */
-+                      else
-+                              cbrdlli_ast2150(ast, 32); /* 32 bits */
-+              }
-+
-+              switch (ast->chip) {
-+              case AST2000:
-+                      temp = ast_read32(ast, 0x10140);
-+                      ast_write32(ast, 0x10140, temp | 0x40);
-+                      break;
-+              case AST1100:
-+              case AST2100:
-+              case AST2200:
-+              case AST2150:
-+                      temp = ast_read32(ast, 0x1200c);
-+                      ast_write32(ast, 0x1200c, temp & 0xfffffffd);
-+                      temp = ast_read32(ast, 0x12040);
-+                      ast_write32(ast, 0x12040, temp | 0x40);
-+                      break;
-+              default:
-+                      break;
-+              }
-+      }
-+
-+      /* wait ready */
-+      /* Wait up to 2.5 seconds for device to become ready */
-+      for (i = 0; i < 250; i++) {
-+              j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
-+              mdelay(10);
-+              if ((j & 0x40) != 0)
-+                      break;
-+      }
-+      if ((j & 0x40) == 0)
-+              dev_err(dev->pdev, "Timeout while waiting for device to signal 
ready\n");
-+}
-+
-+void ast_post_gpu(struct drm_device *dev)
-+{
-+      u32 reg;
-+      struct ast_private *ast = dev->dev_private;
-+
-+      pci_read_config_dword(ast->dev->pdev, 0x04, &reg);
-+      reg |= 0x3;
-+      pci_write_config_dword(ast->dev->pdev, 0x04, reg);
-+
-+      ast_enable_vga(dev);
-+      ast_enable_mmio(dev);
-+      ast_open_key(ast);
-+      ast_set_def_ext_reg(dev);
-+
-+      if (ast->chip == AST2300 || ast->chip == AST2400)
-+              ast_init_dram_2300(dev);
-+      else
-+              ast_init_dram_reg(dev);
-+
-+      ast_init_3rdtx(dev);
-+}
-+
-+/* AST 2300 DRAM settings */
-+#define AST_DDR3 0
-+#define AST_DDR2 1
-+
-+struct ast2300_dram_param {
-+      u32 dram_type;
-+      u32 dram_chipid;
-+      u32 dram_freq;
-+      u32 vram_size;
-+      u32 odt;
-+      u32 wodt;
-+      u32 rodt;
-+      u32 dram_config;
-+      u32 reg_PERIOD;
-+      u32 reg_MADJ;
-+      u32 reg_SADJ;
-+      u32 reg_MRS;
-+      u32 reg_EMRS;
-+      u32 reg_AC1;
-+      u32 reg_AC2;
-+      u32 reg_DQSIC;
-+      u32 reg_DRV;
-+      u32 reg_IOZ;
-+      u32 reg_DQIDLY;
-+      u32 reg_FREQ;
-+      u32 madj_max;
-+      u32 dll2_finetune_step;
-+};
-+
-+/*
-+ * DQSI DLL CBR Setting
-+ */
-+#define CBR_SIZE0            ((1  << 10) - 1)
-+#define CBR_SIZE1            ((4  << 10) - 1)
-+#define CBR_SIZE2            ((64 << 10) - 1)
-+#define CBR_PASSNUM          5
-+#define CBR_PASSNUM2         5
-+#define CBR_THRESHOLD        10
-+#define CBR_THRESHOLD2       10
-+#define TIMEOUT              5000000
-+#define CBR_PATNUM           8
-+
-+static const u32 pattern[8] = {
-+      0xFF00FF00,
-+      0xCC33CC33,
-+      0xAA55AA55,
-+      0x88778877,
-+      0x92CC4D6E,
-+      0x543D3CDE,
-+      0xF1E843C7,
-+      0x7C61D253
-+};
-+
-+static int mmc_test_burst(struct ast_private *ast, u32 datagen)
-+{
-+      u32 data, timeout;
-+
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x000000c1 | (datagen << 3));
-+      timeout = 0;
-+      do {
-+              data = ast_mindwm(ast, 0x1e6e0070) & 0x3000;
-+              if (data & 0x2000) {
-+                      return 0;
-+              }
-+              if (++timeout > TIMEOUT) {
-+                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+                      return 0;
-+              }
-+      } while (!data);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      return 1;
-+}
-+
-+static int mmc_test_burst2(struct ast_private *ast, u32 datagen)
-+{
-+      u32 data, timeout;
-+
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000041 | (datagen << 3));
-+      timeout = 0;
-+      do {
-+              data = ast_mindwm(ast, 0x1e6e0070) & 0x1000;
-+              if (++timeout > TIMEOUT) {
-+                      ast_moutdwm(ast, 0x1e6e0070, 0x0);
-+                      return -1;
-+              }
-+      } while (!data);
-+      data = ast_mindwm(ast, 0x1e6e0078);
-+      data = (data | (data >> 16)) & 0xffff;
-+      ast_moutdwm(ast, 0x1e6e0070, 0x0);
-+      return data;
-+}
-+
-+static int mmc_test_single(struct ast_private *ast, u32 datagen)
-+{
-+      u32 data, timeout;
-+
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x000000c5 | (datagen << 3));
-+      timeout = 0;
-+      do {
-+              data = ast_mindwm(ast, 0x1e6e0070) & 0x3000;
-+              if (data & 0x2000)
-+                      return 0;
-+              if (++timeout > TIMEOUT) {
-+                      ast_moutdwm(ast, 0x1e6e0070, 0x0);
-+                      return 0;
-+              }
-+      } while (!data);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x0);
-+      return 1;
-+}
-+
-+static int mmc_test_single2(struct ast_private *ast, u32 datagen)
-+{
-+      u32 data, timeout;
-+
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
-+      timeout = 0;
-+      do {
-+              data = ast_mindwm(ast, 0x1e6e0070) & 0x1000;
-+              if (++timeout > TIMEOUT) {
-+                      ast_moutdwm(ast, 0x1e6e0070, 0x0);
-+                      return -1;
-+              }
-+      } while (!data);
-+      data = ast_mindwm(ast, 0x1e6e0078);
-+      data = (data | (data >> 16)) & 0xffff;
-+      ast_moutdwm(ast, 0x1e6e0070, 0x0);
-+      return data;
-+}
-+
-+static int cbr_test(struct ast_private *ast)
-+{
-+      u32 data;
-+      int i;
-+      data = mmc_test_single2(ast, 0);
-+      if ((data & 0xff) && (data & 0xff00))
-+              return 0;
-+      for (i = 0; i < 8; i++) {
-+              data = mmc_test_burst2(ast, i);
-+              if ((data & 0xff) && (data & 0xff00))
-+                      return 0;
-+      }
-+      if (!data)
-+              return 3;
-+      else if (data & 0xff)
-+              return 2;
-+      return 1;
-+}
-+
-+static int cbr_scan(struct ast_private *ast)
-+{
-+      u32 data, data2, patcnt, loop;
-+
-+      data2 = 3;
-+      for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
-+              ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
-+              for (loop = 0; loop < CBR_PASSNUM2; loop++) {
-+                      if ((data = cbr_test(ast)) != 0) {
-+                              data2 &= data;
-+                              if (!data2)
-+                                      return 0;
-+                              break;
-+                      }
-+              }
-+              if (loop == CBR_PASSNUM2)
-+                      return 0;
-+      }
-+      return data2;
-+}
-+
-+static u32 cbr_test2(struct ast_private *ast)
-+{
-+      u32 data;
-+
-+      data = mmc_test_burst2(ast, 0);
-+      if (data == 0xffff)
-+              return 0;
-+      data |= mmc_test_single2(ast, 0);
-+      if (data == 0xffff)
-+              return 0;
-+
-+      return ~data & 0xffff;
-+}
-+
-+static u32 cbr_scan2(struct ast_private *ast)
-+{
-+      u32 data, data2, patcnt, loop;
-+
-+      data2 = 0xffff;
-+      for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
-+              ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
-+              for (loop = 0; loop < CBR_PASSNUM2; loop++) {
-+                      if ((data = cbr_test2(ast)) != 0) {
-+                              data2 &= data;
-+                              if (!data2)
-+                                      return 0;
-+                              break;
-+                      }
-+              }
-+              if (loop == CBR_PASSNUM2)
-+                      return 0;
-+      }
-+      return data2;
-+}
-+
-+static u32 cbr_test3(struct ast_private *ast)
-+{
-+      if (!mmc_test_burst(ast, 0))
-+              return 0;
-+      if (!mmc_test_single(ast, 0))
-+              return 0;
-+      return 1;
-+}
-+
-+static u32 cbr_scan3(struct ast_private *ast)
-+{
-+      u32 patcnt, loop;
-+
-+      for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
-+              ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
-+              for (loop = 0; loop < 2; loop++) {
-+                      if (cbr_test3(ast))
-+                              break;
-+              }
-+              if (loop == 2)
-+                      return 0;
-+      }
-+      return 1;
-+}
-+
-+static bool finetuneDQI_L(struct ast_private *ast, struct ast2300_dram_param 
*param)
-+{
-+      u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, 
passcnt, retry = 0;
-+      bool status = false;
-+FINETUNE_START:
-+      for (cnt = 0; cnt < 16; cnt++) {
-+              dllmin[cnt] = 0xff;
-+              dllmax[cnt] = 0x0;
-+      }
-+      passcnt = 0;
-+      for (dlli = 0; dlli < 76; dlli++) {
-+              ast_moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli 
<< 24));
-+              ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE1);
-+              data = cbr_scan2(ast);
-+              if (data != 0) {
-+                      mask = 0x00010001;
-+                      for (cnt = 0; cnt < 16; cnt++) {
-+                              if (data & mask) {
-+                                      if (dllmin[cnt] > dlli) {
-+                                              dllmin[cnt] = dlli;
-+                                      }
-+                                      if (dllmax[cnt] < dlli) {
-+                                              dllmax[cnt] = dlli;
-+                                      }
-+                              }
-+                              mask <<= 1;
-+                      }
-+                      passcnt++;
-+              } else if (passcnt >= CBR_THRESHOLD2) {
-+                      break;
-+              }
-+      }
-+      gold_sadj[0] = 0x0;
-+      passcnt = 0;
-+      for (cnt = 0; cnt < 16; cnt++) {
-+              if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) 
>= CBR_THRESHOLD2)) {
-+                      gold_sadj[0] += dllmin[cnt];
-+                      passcnt++;
-+              }
-+      }
-+      if (retry++ > 10)
-+              goto FINETUNE_DONE;
-+      if (passcnt != 16) {
-+              goto FINETUNE_START;
-+      }
-+      status = true;
-+FINETUNE_DONE:
-+      gold_sadj[0] = gold_sadj[0] >> 4;
-+      gold_sadj[1] = gold_sadj[0];
-+
-+      data = 0;
-+      for (cnt = 0; cnt < 8; cnt++) {
-+              data >>= 3;
-+              if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) 
>= CBR_THRESHOLD2)) {
-+                      dlli = dllmin[cnt];
-+                      if (gold_sadj[0] >= dlli) {
-+                              dlli = ((gold_sadj[0] - dlli) * 19) >> 5;
-+                              if (dlli > 3) {
-+                                      dlli = 3;
-+                              }
-+                      } else {
-+                              dlli = ((dlli - gold_sadj[0]) * 19) >> 5;
-+                              if (dlli > 4) {
-+                                      dlli = 4;
-+                              }
-+                              dlli = (8 - dlli) & 0x7;
-+                      }
-+                      data |= dlli << 21;
-+              }
-+      }
-+      ast_moutdwm(ast, 0x1E6E0080, data);
-+
-+      data = 0;
-+      for (cnt = 8; cnt < 16; cnt++) {
-+              data >>= 3;
-+              if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) 
>= CBR_THRESHOLD2)) {
-+                      dlli = dllmin[cnt];
-+                      if (gold_sadj[1] >= dlli) {
-+                              dlli = ((gold_sadj[1] - dlli) * 19) >> 5;
-+                              if (dlli > 3) {
-+                                      dlli = 3;
-+                              } else {
-+                                      dlli = (dlli - 1) & 0x7;
-+                              }
-+                      } else {
-+                              dlli = ((dlli - gold_sadj[1]) * 19) >> 5;
-+                              dlli += 1;
-+                              if (dlli > 4) {
-+                                      dlli = 4;
-+                              }
-+                              dlli = (8 - dlli) & 0x7;
-+                      }
-+                      data |= dlli << 21;
-+              }
-+      }
-+      ast_moutdwm(ast, 0x1E6E0084, data);
-+      return status;
-+} /* finetuneDQI_L */
-+
-+static void finetuneDQSI(struct ast_private *ast)
-+{
-+      u32 dlli, dqsip, dqidly;
-+      u32 reg_mcr18, reg_mcr0c, passcnt[2], diff;
-+      u32 g_dqidly, g_dqsip, g_margin, g_side;
-+      u16 pass[32][2][2];
-+      char tag[2][76];
-+
-+      /* Disable DQI CBR */
-+      reg_mcr0c  = ast_mindwm(ast, 0x1E6E000C);
-+      reg_mcr18  = ast_mindwm(ast, 0x1E6E0018);
-+      reg_mcr18 &= 0x0000ffff;
-+      ast_moutdwm(ast, 0x1E6E0018, reg_mcr18);
-+
-+      for (dlli = 0; dlli < 76; dlli++) {
-+              tag[0][dlli] = 0x0;
-+              tag[1][dlli] = 0x0;
-+      }
-+      for (dqidly = 0; dqidly < 32; dqidly++) {
-+              pass[dqidly][0][0] = 0xff;
-+              pass[dqidly][0][1] = 0x0;
-+              pass[dqidly][1][0] = 0xff;
-+              pass[dqidly][1][1] = 0x0;
-+      }
-+      for (dqidly = 0; dqidly < 32; dqidly++) {
-+              passcnt[0] = passcnt[1] = 0;
-+              for (dqsip = 0; dqsip < 2; dqsip++) {
-+                      ast_moutdwm(ast, 0x1E6E000C, 0);
-+                      ast_moutdwm(ast, 0x1E6E0018, reg_mcr18 | (dqidly << 16) 
| (dqsip << 23));
-+                      ast_moutdwm(ast, 0x1E6E000C, reg_mcr0c);
-+                      for (dlli = 0; dlli < 76; dlli++) {
-+                              ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli 
<< 16) | (dlli << 24));
-+                              ast_moutdwm(ast, 0x1E6E0070, 0);
-+                              ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE0);
-+                              if (cbr_scan3(ast)) {
-+                                      if (dlli == 0)
-+                                              break;
-+                                      passcnt[dqsip]++;
-+                                      tag[dqsip][dlli] = 'P';
-+                                      if (dlli < pass[dqidly][dqsip][0])
-+                                              pass[dqidly][dqsip][0] = (u16) 
dlli;
-+                                      if (dlli > pass[dqidly][dqsip][1])
-+                                              pass[dqidly][dqsip][1] = (u16) 
dlli;
-+                              } else if (passcnt[dqsip] >= 5)
-+                                      break;
-+                              else {
-+                                      pass[dqidly][dqsip][0] = 0xff;
-+                                      pass[dqidly][dqsip][1] = 0x0;
-+                              }
-+                      }
-+              }
-+              if (passcnt[0] == 0 && passcnt[1] == 0)
-+                      dqidly++;
-+      }
-+      /* Search margin */
-+      g_dqidly = g_dqsip = g_margin = g_side = 0;
-+
-+      for (dqidly = 0; dqidly < 32; dqidly++) {
-+              for (dqsip = 0; dqsip < 2; dqsip++) {
-+                      if (pass[dqidly][dqsip][0] > pass[dqidly][dqsip][1])
-+                              continue;
-+                      diff = pass[dqidly][dqsip][1] - pass[dqidly][dqsip][0];
-+                      if ((diff+2) < g_margin)
-+                              continue;
-+                      passcnt[0] = passcnt[1] = 0;
-+                      for (dlli = pass[dqidly][dqsip][0]; dlli > 0  && 
tag[dqsip][dlli] != 0; dlli--, passcnt[0]++);
-+                      for (dlli = pass[dqidly][dqsip][1]; dlli < 76 && 
tag[dqsip][dlli] != 0; dlli++, passcnt[1]++);
-+                      if (passcnt[0] > passcnt[1])
-+                              passcnt[0] = passcnt[1];
-+                      passcnt[1] = 0;
-+                      if (passcnt[0] > g_side)
-+                              passcnt[1] = passcnt[0] - g_side;
-+                      if (diff > (g_margin+1) && (passcnt[1] > 0 || 
passcnt[0] > 8)) {
-+                              g_margin = diff;
-+                              g_dqidly = dqidly;
-+                              g_dqsip  = dqsip;
-+                              g_side   = passcnt[0];
-+                      } else if (passcnt[1] > 1 && g_side < 8) {
-+                              if (diff > g_margin)
-+                                      g_margin = diff;
-+                              g_dqidly = dqidly;
-+                              g_dqsip  = dqsip;
-+                              g_side   = passcnt[0];
-+                      }
-+              }
-+      }
-+      reg_mcr18 = reg_mcr18 | (g_dqidly << 16) | (g_dqsip << 23);
-+      ast_moutdwm(ast, 0x1E6E0018, reg_mcr18);
-+
-+}
-+static bool cbr_dll2(struct ast_private *ast, struct ast2300_dram_param 
*param)
-+{
-+      u32 dllmin[2], dllmax[2], dlli, data, passcnt, retry = 0;
-+      bool status = false;
-+
-+      finetuneDQSI(ast);
-+      if (finetuneDQI_L(ast, param) == false)
-+              return status;
-+
-+CBR_START2:
-+      dllmin[0] = dllmin[1] = 0xff;
-+      dllmax[0] = dllmax[1] = 0x0;
-+      passcnt = 0;
-+      for (dlli = 0; dlli < 76; dlli++) {
-+              ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli 
<< 24));
-+              ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE2);
-+              data = cbr_scan(ast);
-+              if (data != 0) {
-+                      if (data & 0x1) {
-+                              if (dllmin[0] > dlli) {
-+                                      dllmin[0] = dlli;
-+                              }
-+                              if (dllmax[0] < dlli) {
-+                                      dllmax[0] = dlli;
-+                              }
-+                      }
-+                      if (data & 0x2) {
-+                              if (dllmin[1] > dlli) {
-+                                      dllmin[1] = dlli;
-+                              }
-+                              if (dllmax[1] < dlli) {
-+                                      dllmax[1] = dlli;
-+                              }
-+                      }
-+                      passcnt++;
-+              } else if (passcnt >= CBR_THRESHOLD) {
-+                      break;
-+              }
-+      }
-+      if (retry++ > 10)
-+              goto CBR_DONE2;
-+      if (dllmax[0] == 0 || (dllmax[0]-dllmin[0]) < CBR_THRESHOLD) {
-+              goto CBR_START2;
-+      }
-+      if (dllmax[1] == 0 || (dllmax[1]-dllmin[1]) < CBR_THRESHOLD) {
-+              goto CBR_START2;
-+      }
-+      status = true;
-+CBR_DONE2:
-+      dlli  = (dllmin[1] + dllmax[1]) >> 1;
-+      dlli <<= 8;
-+      dlli += (dllmin[0] + dllmax[0]) >> 1;
-+      ast_moutdwm(ast, 0x1E6E0068, ast_mindwm(ast, 0x1E720058) | (dlli << 
16));
-+      return status;
-+} /* CBRDLL2 */
-+
-+static void get_ddr3_info(struct ast_private *ast, struct ast2300_dram_param 
*param)
-+{
-+      u32 trap, trap_AC2, trap_MRS;
-+
-+      ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
-+
-+      /* Ger trap info */
-+      trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
-+      trap_AC2  = 0x00020000 + (trap << 16);
-+      trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19);
-+      trap_MRS  = 0x00000010 + (trap << 4);
-+      trap_MRS |= ((trap & 0x2) << 18);
-+
-+      param->reg_MADJ       = 0x00034C4C;
-+      param->reg_SADJ       = 0x00001800;
-+      param->reg_DRV        = 0x000000F0;
-+      param->reg_PERIOD     = param->dram_freq;
-+      param->rodt           = 0;
-+
-+      switch (param->dram_freq) {
-+      case 336:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0190);
-+              param->wodt          = 0;
-+              param->reg_AC1       = 0x22202725;
-+              param->reg_AC2       = 0xAA007613 | trap_AC2;
-+              param->reg_DQSIC     = 0x000000BA;
-+              param->reg_MRS       = 0x04001400 | trap_MRS;
-+              param->reg_EMRS      = 0x00000000;
-+              param->reg_IOZ       = 0x00000023;
-+              param->reg_DQIDLY    = 0x00000074;
-+              param->reg_FREQ      = 0x00004DC0;
-+              param->madj_max      = 96;
-+              param->dll2_finetune_step = 3;
-+              switch (param->dram_chipid) {
-+              default:
-+              case AST_DRAM_512Mx16:
-+              case AST_DRAM_1Gx16:
-+                      param->reg_AC2   = 0xAA007613 | trap_AC2;
-+                      break;
-+              case AST_DRAM_2Gx16:
-+                      param->reg_AC2   = 0xAA00761C | trap_AC2;
-+                      break;
-+              case AST_DRAM_4Gx16:
-+                      param->reg_AC2   = 0xAA007636 | trap_AC2;
-+                      break;
-+              }
-+              break;
-+      default:
-+      case 396:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x03F1);
-+              param->wodt          = 1;
-+              param->reg_AC1       = 0x33302825;
-+              param->reg_AC2       = 0xCC009617 | trap_AC2;
-+              param->reg_DQSIC     = 0x000000E2;
-+              param->reg_MRS       = 0x04001600 | trap_MRS;
-+              param->reg_EMRS      = 0x00000000;
-+              param->reg_IOZ       = 0x00000034;
-+              param->reg_DRV       = 0x000000FA;
-+              param->reg_DQIDLY    = 0x00000089;
-+              param->reg_FREQ      = 0x00005040;
-+              param->madj_max      = 96;
-+              param->dll2_finetune_step = 4;
-+
-+              switch (param->dram_chipid) {
-+              default:
-+              case AST_DRAM_512Mx16:
-+              case AST_DRAM_1Gx16:
-+                      param->reg_AC2   = 0xCC009617 | trap_AC2;
-+                      break;
-+              case AST_DRAM_2Gx16:
-+                      param->reg_AC2   = 0xCC009622 | trap_AC2;
-+                      break;
-+              case AST_DRAM_4Gx16:
-+                      param->reg_AC2   = 0xCC00963F | trap_AC2;
-+                      break;
-+              }
-+              break;
-+
-+      case 408:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x01F0);
-+              param->wodt          = 1;
-+              param->reg_AC1       = 0x33302825;
-+              param->reg_AC2       = 0xCC009617 | trap_AC2;
-+              param->reg_DQSIC     = 0x000000E2;
-+              param->reg_MRS       = 0x04001600 | trap_MRS;
-+              param->reg_EMRS      = 0x00000000;
-+              param->reg_IOZ       = 0x00000023;
-+              param->reg_DRV       = 0x000000FA;
-+              param->reg_DQIDLY    = 0x00000089;
-+              param->reg_FREQ      = 0x000050C0;
-+              param->madj_max      = 96;
-+              param->dll2_finetune_step = 4;
-+
-+              switch (param->dram_chipid) {
-+              default:
-+              case AST_DRAM_512Mx16:
-+              case AST_DRAM_1Gx16:
-+                      param->reg_AC2   = 0xCC009617 | trap_AC2;
-+                      break;
-+              case AST_DRAM_2Gx16:
-+                      param->reg_AC2   = 0xCC009622 | trap_AC2;
-+                      break;
-+              case AST_DRAM_4Gx16:
-+                      param->reg_AC2   = 0xCC00963F | trap_AC2;
-+                      break;
-+              }
-+
-+              break;
-+      case 456:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0230);
-+              param->wodt          = 0;
-+              param->reg_AC1       = 0x33302926;
-+              param->reg_AC2       = 0xCD44961A;
-+              param->reg_DQSIC     = 0x000000FC;
-+              param->reg_MRS       = 0x00081830;
-+              param->reg_EMRS      = 0x00000000;
-+              param->reg_IOZ       = 0x00000045;
-+              param->reg_DQIDLY    = 0x00000097;
-+              param->reg_FREQ      = 0x000052C0;
-+              param->madj_max      = 88;
-+              param->dll2_finetune_step = 4;
-+              break;
-+      case 504:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0270);
-+              param->wodt          = 1;
-+              param->reg_AC1       = 0x33302926;
-+              param->reg_AC2       = 0xDE44A61D;
-+              param->reg_DQSIC     = 0x00000117;
-+              param->reg_MRS       = 0x00081A30;
-+              param->reg_EMRS      = 0x00000000;
-+              param->reg_IOZ       = 0x070000BB;
-+              param->reg_DQIDLY    = 0x000000A0;
-+              param->reg_FREQ      = 0x000054C0;
-+              param->madj_max      = 79;
-+              param->dll2_finetune_step = 4;
-+              break;
-+      case 528:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0290);
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x33302926;
-+              param->reg_AC2       = 0xEF44B61E;
-+              param->reg_DQSIC     = 0x00000125;
-+              param->reg_MRS       = 0x00081A30;
-+              param->reg_EMRS      = 0x00000040;
-+              param->reg_DRV       = 0x000000F5;
-+              param->reg_IOZ       = 0x00000023;
-+              param->reg_DQIDLY    = 0x00000088;
-+              param->reg_FREQ      = 0x000055C0;
-+              param->madj_max      = 76;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 576:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0140);
-+              param->reg_MADJ      = 0x00136868;
-+              param->reg_SADJ      = 0x00004534;
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x33302A37;
-+              param->reg_AC2       = 0xEF56B61E;
-+              param->reg_DQSIC     = 0x0000013F;
-+              param->reg_MRS       = 0x00101A50;
-+              param->reg_EMRS      = 0x00000040;
-+              param->reg_DRV       = 0x000000FA;
-+              param->reg_IOZ       = 0x00000023;
-+              param->reg_DQIDLY    = 0x00000078;
-+              param->reg_FREQ      = 0x000057C0;
-+              param->madj_max      = 136;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 600:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x02E1);
-+              param->reg_MADJ      = 0x00136868;
-+              param->reg_SADJ      = 0x00004534;
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x32302A37;
-+              param->reg_AC2       = 0xDF56B61F;
-+              param->reg_DQSIC     = 0x0000014D;
-+              param->reg_MRS       = 0x00101A50;
-+              param->reg_EMRS      = 0x00000004;
-+              param->reg_DRV       = 0x000000F5;
-+              param->reg_IOZ       = 0x00000023;
-+              param->reg_DQIDLY    = 0x00000078;
-+              param->reg_FREQ      = 0x000058C0;
-+              param->madj_max      = 132;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 624:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0160);
-+              param->reg_MADJ      = 0x00136868;
-+              param->reg_SADJ      = 0x00004534;
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x32302A37;
-+              param->reg_AC2       = 0xEF56B621;
-+              param->reg_DQSIC     = 0x0000015A;
-+              param->reg_MRS       = 0x02101A50;
-+              param->reg_EMRS      = 0x00000004;
-+              param->reg_DRV       = 0x000000F5;
-+              param->reg_IOZ       = 0x00000034;
-+              param->reg_DQIDLY    = 0x00000078;
-+              param->reg_FREQ      = 0x000059C0;
-+              param->madj_max      = 128;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      } /* switch freq */
-+
-+      switch (param->dram_chipid) {
-+      case AST_DRAM_512Mx16:
-+              param->dram_config = 0x130;
-+              break;
-+      default:
-+      case AST_DRAM_1Gx16:
-+              param->dram_config = 0x131;
-+              break;
-+      case AST_DRAM_2Gx16:
-+              param->dram_config = 0x132;
-+              break;
-+      case AST_DRAM_4Gx16:
-+              param->dram_config = 0x133;
-+              break;
-+      } /* switch size */
-+
-+      switch (param->vram_size) {
-+      default:
-+      case AST_VIDMEM_SIZE_8M:
-+              param->dram_config |= 0x00;
-+              break;
-+      case AST_VIDMEM_SIZE_16M:
-+              param->dram_config |= 0x04;
-+              break;
-+      case AST_VIDMEM_SIZE_32M:
-+              param->dram_config |= 0x08;
-+              break;
-+      case AST_VIDMEM_SIZE_64M:
-+              param->dram_config |= 0x0c;
-+              break;
-+      }
-+
-+}
-+
-+static void ddr3_init(struct ast_private *ast, struct ast2300_dram_param 
*param)
-+{
-+      u32 data, data2, retry = 0;
-+
-+ddr3_init_start:
-+      ast_moutdwm(ast, 0x1E6E0000, 0xFC600309);
-+      ast_moutdwm(ast, 0x1E6E0018, 0x00000100);
-+      ast_moutdwm(ast, 0x1E6E0024, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0034, 0x00000000);
-+      udelay(10);
-+      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
-+      ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
-+      udelay(10);
-+      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
-+      udelay(10);
-+
-+      ast_moutdwm(ast, 0x1E6E0004, param->dram_config);
-+      ast_moutdwm(ast, 0x1E6E0008, 0x90040f);
-+      ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1);
-+      ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2);
-+      ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
-+      ast_moutdwm(ast, 0x1E6E0080, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0084, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
-+      ast_moutdwm(ast, 0x1E6E0018, 0x4000A170);
-+      ast_moutdwm(ast, 0x1E6E0018, 0x00002370);
-+      ast_moutdwm(ast, 0x1E6E0038, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0040, 0xFF444444);
-+      ast_moutdwm(ast, 0x1E6E0044, 0x22222222);
-+      ast_moutdwm(ast, 0x1E6E0048, 0x22222222);
-+      ast_moutdwm(ast, 0x1E6E004C, 0x00000002);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0054, 0);
-+      ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV);
-+      ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
-+      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0074, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0078, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
-+      /* Wait MCLK2X lock to MCLK */
-+      do {
-+              data = ast_mindwm(ast, 0x1E6E001C);
-+      } while (!(data & 0x08000000));
-+      data = ast_mindwm(ast, 0x1E6E001C);
-+      data = (data >> 8) & 0xff;
-+      while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
-+              data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
-+              if ((data2 & 0xff) > param->madj_max) {
-+                      break;
-+              }
-+              ast_moutdwm(ast, 0x1E6E0064, data2);
-+              if (data2 & 0x00100000) {
-+                      data2 = ((data2 & 0xff) >> 3) + 3;
-+              } else {
-+                      data2 = ((data2 & 0xff) >> 2) + 5;
-+              }
-+              data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff;
-+              data2 += data & 0xff;
-+              data = data | (data2 << 8);
-+              ast_moutdwm(ast, 0x1E6E0068, data);
-+              udelay(10);
-+              ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 
0xC0000);
-+              udelay(10);
-+              data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
-+              ast_moutdwm(ast, 0x1E6E0018, data);
-+              data = data | 0x200;
-+              ast_moutdwm(ast, 0x1E6E0018, data);
-+              do {
-+                      data = ast_mindwm(ast, 0x1E6E001C);
-+              } while (!(data & 0x08000000));
-+
-+              data = ast_mindwm(ast, 0x1E6E001C);
-+              data = (data >> 8) & 0xff;
-+      }
-+      ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0068) & 0xffff);
-+      data = ast_mindwm(ast, 0x1E6E0018) | 0xC00;
-+      ast_moutdwm(ast, 0x1E6E0018, data);
-+
-+      ast_moutdwm(ast, 0x1E6E0034, 0x00000001);
-+      ast_moutdwm(ast, 0x1E6E000C, 0x00000040);
-+      udelay(50);
-+      /* Mode Register Setting */
-+      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
-+      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000005);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000007);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
-+      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS);
-+      ast_moutdwm(ast, 0x1E6E000C, 0x00005C08);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
-+
-+      ast_moutdwm(ast, 0x1E6E000C, 0x00005C01);
-+      data = 0;
-+      if (param->wodt) {
-+              data = 0x300;
-+      }
-+      if (param->rodt) {
-+              data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
-+      }
-+      ast_moutdwm(ast, 0x1E6E0034, data | 0x3);
-+
-+      /* Calibrate the DQSI delay */
-+      if ((cbr_dll2(ast, param) == false) && (retry++ < 10))
-+              goto ddr3_init_start;
-+
-+      ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
-+      /* ECC Memory Initialization */
-+#ifdef ECC
-+      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0070, 0x221);
-+      do {
-+              data = ast_mindwm(ast, 0x1E6E0070);
-+      } while (!(data & 0x00001000));
-+      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
-+#endif
-+
-+
-+}
-+
-+static void get_ddr2_info(struct ast_private *ast, struct ast2300_dram_param 
*param)
-+{
-+      u32 trap, trap_AC2, trap_MRS;
-+
-+      ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
-+
-+      /* Ger trap info */
-+      trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
-+      trap_AC2  = (trap << 20) | (trap << 16);
-+      trap_AC2 += 0x00110000;
-+      trap_MRS  = 0x00000040 | (trap << 4);
-+
-+
-+      param->reg_MADJ       = 0x00034C4C;
-+      param->reg_SADJ       = 0x00001800;
-+      param->reg_DRV        = 0x000000F0;
-+      param->reg_PERIOD     = param->dram_freq;
-+      param->rodt           = 0;
-+
-+      switch (param->dram_freq) {
-+      case 264:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0130);
-+              param->wodt          = 0;
-+              param->reg_AC1       = 0x11101513;
-+              param->reg_AC2       = 0x78117011;
-+              param->reg_DQSIC     = 0x00000092;
-+              param->reg_MRS       = 0x00000842;
-+              param->reg_EMRS      = 0x00000000;
-+              param->reg_DRV       = 0x000000F0;
-+              param->reg_IOZ       = 0x00000034;
-+              param->reg_DQIDLY    = 0x0000005A;
-+              param->reg_FREQ      = 0x00004AC0;
-+              param->madj_max      = 138;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 336:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0190);
-+              param->wodt          = 1;
-+              param->reg_AC1       = 0x22202613;
-+              param->reg_AC2       = 0xAA009016 | trap_AC2;
-+              param->reg_DQSIC     = 0x000000BA;
-+              param->reg_MRS       = 0x00000A02 | trap_MRS;
-+              param->reg_EMRS      = 0x00000040;
-+              param->reg_DRV       = 0x000000FA;
-+              param->reg_IOZ       = 0x00000034;
-+              param->reg_DQIDLY    = 0x00000074;
-+              param->reg_FREQ      = 0x00004DC0;
-+              param->madj_max      = 96;
-+              param->dll2_finetune_step = 3;
-+              switch (param->dram_chipid) {
-+              default:
-+              case AST_DRAM_512Mx16:
-+                      param->reg_AC2   = 0xAA009012 | trap_AC2;
-+                      break;
-+              case AST_DRAM_1Gx16:
-+                      param->reg_AC2   = 0xAA009016 | trap_AC2;
-+                      break;
-+              case AST_DRAM_2Gx16:
-+                      param->reg_AC2   = 0xAA009023 | trap_AC2;
-+                      break;
-+              case AST_DRAM_4Gx16:
-+                      param->reg_AC2   = 0xAA00903B | trap_AC2;
-+                      break;
-+              }
-+              break;
-+      default:
-+      case 396:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x03F1);
-+              param->wodt          = 1;
-+              param->rodt          = 0;
-+              param->reg_AC1       = 0x33302714;
-+              param->reg_AC2       = 0xCC00B01B | trap_AC2;
-+              param->reg_DQSIC     = 0x000000E2;
-+              param->reg_MRS       = 0x00000C02 | trap_MRS;
-+              param->reg_EMRS      = 0x00000040;
-+              param->reg_DRV       = 0x000000FA;
-+              param->reg_IOZ       = 0x00000034;
-+              param->reg_DQIDLY    = 0x00000089;
-+              param->reg_FREQ      = 0x00005040;
-+              param->madj_max      = 96;
-+              param->dll2_finetune_step = 4;
-+
-+              switch (param->dram_chipid) {
-+              case AST_DRAM_512Mx16:
-+                      param->reg_AC2   = 0xCC00B016 | trap_AC2;
-+                      break;
-+              default:
-+              case AST_DRAM_1Gx16:
-+                      param->reg_AC2   = 0xCC00B01B | trap_AC2;
-+                      break;
-+              case AST_DRAM_2Gx16:
-+                      param->reg_AC2   = 0xCC00B02B | trap_AC2;
-+                      break;
-+              case AST_DRAM_4Gx16:
-+                      param->reg_AC2   = 0xCC00B03F | trap_AC2;
-+                      break;
-+              }
-+
-+              break;
-+
-+      case 408:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x01F0);
-+              param->wodt          = 1;
-+              param->rodt          = 0;
-+              param->reg_AC1       = 0x33302714;
-+              param->reg_AC2       = 0xCC00B01B | trap_AC2;
-+              param->reg_DQSIC     = 0x000000E2;
-+              param->reg_MRS       = 0x00000C02 | trap_MRS;
-+              param->reg_EMRS      = 0x00000040;
-+              param->reg_DRV       = 0x000000FA;
-+              param->reg_IOZ       = 0x00000034;
-+              param->reg_DQIDLY    = 0x00000089;
-+              param->reg_FREQ      = 0x000050C0;
-+              param->madj_max      = 96;
-+              param->dll2_finetune_step = 4;
-+
-+              switch (param->dram_chipid) {
-+              case AST_DRAM_512Mx16:
-+                      param->reg_AC2   = 0xCC00B016 | trap_AC2;
-+                      break;
-+              default:
-+              case AST_DRAM_1Gx16:
-+                      param->reg_AC2   = 0xCC00B01B | trap_AC2;
-+                      break;
-+              case AST_DRAM_2Gx16:
-+                      param->reg_AC2   = 0xCC00B02B | trap_AC2;
-+                      break;
-+              case AST_DRAM_4Gx16:
-+                      param->reg_AC2   = 0xCC00B03F | trap_AC2;
-+                      break;
-+              }
-+
-+              break;
-+      case 456:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0230);
-+              param->wodt          = 0;
-+              param->reg_AC1       = 0x33302815;
-+              param->reg_AC2       = 0xCD44B01E;
-+              param->reg_DQSIC     = 0x000000FC;
-+              param->reg_MRS       = 0x00000E72;
-+              param->reg_EMRS      = 0x00000000;
-+              param->reg_DRV       = 0x00000000;
-+              param->reg_IOZ       = 0x00000034;
-+              param->reg_DQIDLY    = 0x00000097;
-+              param->reg_FREQ      = 0x000052C0;
-+              param->madj_max      = 88;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 504:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0261);
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x33302815;
-+              param->reg_AC2       = 0xDE44C022;
-+              param->reg_DQSIC     = 0x00000117;
-+              param->reg_MRS       = 0x00000E72;
-+              param->reg_EMRS      = 0x00000040;
-+              param->reg_DRV       = 0x0000000A;
-+              param->reg_IOZ       = 0x00000045;
-+              param->reg_DQIDLY    = 0x000000A0;
-+              param->reg_FREQ      = 0x000054C0;
-+              param->madj_max      = 79;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 528:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0120);
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x33302815;
-+              param->reg_AC2       = 0xEF44D024;
-+              param->reg_DQSIC     = 0x00000125;
-+              param->reg_MRS       = 0x00000E72;
-+              param->reg_EMRS      = 0x00000004;
-+              param->reg_DRV       = 0x000000F9;
-+              param->reg_IOZ       = 0x00000045;
-+              param->reg_DQIDLY    = 0x000000A7;
-+              param->reg_FREQ      = 0x000055C0;
-+              param->madj_max      = 76;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 552:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x02A1);
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x43402915;
-+              param->reg_AC2       = 0xFF44E025;
-+              param->reg_DQSIC     = 0x00000132;
-+              param->reg_MRS       = 0x00000E72;
-+              param->reg_EMRS      = 0x00000040;
-+              param->reg_DRV       = 0x0000000A;
-+              param->reg_IOZ       = 0x00000045;
-+              param->reg_DQIDLY    = 0x000000AD;
-+              param->reg_FREQ      = 0x000056C0;
-+              param->madj_max      = 76;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      case 576:
-+              ast_moutdwm(ast, 0x1E6E2020, 0x0140);
-+              param->wodt          = 1;
-+              param->rodt          = 1;
-+              param->reg_AC1       = 0x43402915;
-+              param->reg_AC2       = 0xFF44E027;
-+              param->reg_DQSIC     = 0x0000013F;
-+              param->reg_MRS       = 0x00000E72;
-+              param->reg_EMRS      = 0x00000004;
-+              param->reg_DRV       = 0x000000F5;
-+              param->reg_IOZ       = 0x00000045;
-+              param->reg_DQIDLY    = 0x000000B3;
-+              param->reg_FREQ      = 0x000057C0;
-+              param->madj_max      = 76;
-+              param->dll2_finetune_step = 3;
-+              break;
-+      }
-+
-+      switch (param->dram_chipid) {
-+      case AST_DRAM_512Mx16:
-+              param->dram_config = 0x100;
-+              break;
-+      default:
-+      case AST_DRAM_1Gx16:
-+              param->dram_config = 0x121;
-+              break;
-+      case AST_DRAM_2Gx16:
-+              param->dram_config = 0x122;
-+              break;
-+      case AST_DRAM_4Gx16:
-+              param->dram_config = 0x123;
-+              break;
-+      } /* switch size */
-+
-+      switch (param->vram_size) {
-+      default:
-+      case AST_VIDMEM_SIZE_8M:
-+              param->dram_config |= 0x00;
-+              break;
-+      case AST_VIDMEM_SIZE_16M:
-+              param->dram_config |= 0x04;
-+              break;
-+      case AST_VIDMEM_SIZE_32M:
-+              param->dram_config |= 0x08;
-+              break;
-+      case AST_VIDMEM_SIZE_64M:
-+              param->dram_config |= 0x0c;
-+              break;
-+      }
-+}
-+
-+static void ddr2_init(struct ast_private *ast, struct ast2300_dram_param 
*param)
-+{
-+      u32 data, data2, retry = 0;
-+
-+ddr2_init_start:
-+      ast_moutdwm(ast, 0x1E6E0000, 0xFC600309);
-+      ast_moutdwm(ast, 0x1E6E0018, 0x00000100);
-+      ast_moutdwm(ast, 0x1E6E0024, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
-+      ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
-+      udelay(10);
-+      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
-+      udelay(10);
-+
-+      ast_moutdwm(ast, 0x1E6E0004, param->dram_config);
-+      ast_moutdwm(ast, 0x1E6E0008, 0x90040f);
-+      ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1);
-+      ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2);
-+      ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
-+      ast_moutdwm(ast, 0x1E6E0080, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0084, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
-+      ast_moutdwm(ast, 0x1E6E0018, 0x4000A130);
-+      ast_moutdwm(ast, 0x1E6E0018, 0x00002330);
-+      ast_moutdwm(ast, 0x1E6E0038, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0040, 0xFF808000);
-+      ast_moutdwm(ast, 0x1E6E0044, 0x88848466);
-+      ast_moutdwm(ast, 0x1E6E0048, 0x44440008);
-+      ast_moutdwm(ast, 0x1E6E004C, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0054, 0);
-+      ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV);
-+      ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
-+      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0074, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0078, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
-+
-+      /* Wait MCLK2X lock to MCLK */
-+      do {
-+              data = ast_mindwm(ast, 0x1E6E001C);
-+      } while (!(data & 0x08000000));
-+      data = ast_mindwm(ast, 0x1E6E001C);
-+      data = (data >> 8) & 0xff;
-+      while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
-+              data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
-+              if ((data2 & 0xff) > param->madj_max) {
-+                      break;
-+              }
-+              ast_moutdwm(ast, 0x1E6E0064, data2);
-+              if (data2 & 0x00100000) {
-+                      data2 = ((data2 & 0xff) >> 3) + 3;
-+              } else {
-+                      data2 = ((data2 & 0xff) >> 2) + 5;
-+              }
-+              data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff;
-+              data2 += data & 0xff;
-+              data = data | (data2 << 8);
-+              ast_moutdwm(ast, 0x1E6E0068, data);
-+              udelay(10);
-+              ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 
0xC0000);
-+              udelay(10);
-+              data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
-+              ast_moutdwm(ast, 0x1E6E0018, data);
-+              data = data | 0x200;
-+              ast_moutdwm(ast, 0x1E6E0018, data);
-+              do {
-+                      data = ast_mindwm(ast, 0x1E6E001C);
-+              } while (!(data & 0x08000000));
-+
-+              data = ast_mindwm(ast, 0x1E6E001C);
-+              data = (data >> 8) & 0xff;
-+      }
-+      ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0008) & 0xffff);
-+      data = ast_mindwm(ast, 0x1E6E0018) | 0xC00;
-+      ast_moutdwm(ast, 0x1E6E0018, data);
-+
-+      ast_moutdwm(ast, 0x1E6E0034, 0x00000001);
-+      ast_moutdwm(ast, 0x1E6E000C, 0x00000000);
-+      udelay(50);
-+      /* Mode Register Setting */
-+      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
-+      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000005);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000007);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
-+
-+      ast_moutdwm(ast, 0x1E6E000C, 0x00005C08);
-+      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
-+      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
-+      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
-+      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
-+
-+      ast_moutdwm(ast, 0x1E6E000C, 0x7FFF5C01);
-+      data = 0;
-+      if (param->wodt) {
-+              data = 0x500;
-+      }
-+      if (param->rodt) {
-+              data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
-+      }
-+      ast_moutdwm(ast, 0x1E6E0034, data | 0x3);
-+      ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
-+
-+      /* Calibrate the DQSI delay */
-+      if ((cbr_dll2(ast, param) == false) && (retry++ < 10))
-+              goto ddr2_init_start;
-+
-+      /* ECC Memory Initialization */
-+#ifdef ECC
-+      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0070, 0x221);
-+      do {
-+              data = ast_mindwm(ast, 0x1E6E0070);
-+      } while (!(data & 0x00001000));
-+      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
-+      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
-+#endif
-+
-+}
-+
-+static void ast_init_dram_2300(struct drm_device *dev)
-+{
-+      struct ast_private *ast = dev->dev_private;
-+      struct ast2300_dram_param param;
-+      u32 temp;
-+      u8 reg;
-+
-+      reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
-+      if ((reg & 0x80) == 0) {/* vga only */
-+              ast_write32(ast, 0xf004, 0x1e6e0000);
-+              ast_write32(ast, 0xf000, 0x1);
-+              ast_write32(ast, 0x12000, 0x1688a8a8);
-+              do {
-+                      ;
-+              } while (ast_read32(ast, 0x12000) != 0x1);
-+
-+              ast_write32(ast, 0x10000, 0xfc600309);
-+              do {
-+                      ;
-+              } while (ast_read32(ast, 0x10000) != 0x1);
-+
-+              /* Slow down CPU/AHB CLK in VGA only mode */
-+              temp = ast_read32(ast, 0x12008);
-+              temp |= 0x73;
-+              ast_write32(ast, 0x12008, temp);
-+
-+              param.dram_type = AST_DDR3;
-+              if (temp & 0x01000000)
-+                      param.dram_type = AST_DDR2;
-+              param.dram_chipid = ast->dram_type;
-+              param.dram_freq = ast->mclk;
-+              param.vram_size = ast->vram_size;
-+
-+              if (param.dram_type == AST_DDR3) {
-+                      get_ddr3_info(ast, &param);
-+                      ddr3_init(ast, &param);
-+              } else {
-+                      get_ddr2_info(ast, &param);
-+                      ddr2_init(ast, &param);
-+              }
-+
-+              temp = ast_mindwm(ast, 0x1e6e2040);
-+              ast_moutdwm(ast, 0x1e6e2040, temp | 0x40);
-+      }
-+
-+      /* wait ready */
-+      do {
-+              reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
-+      } while ((reg & 0x40) == 0);
-+}
-+
-diff --git a/src/drivers/aspeed/common/ast_tables.h 
b/src/drivers/aspeed/common/ast_tables.h
-new file mode 100644
-index 0000000..3608d5a
---- /dev/null
-+++ b/src/drivers/aspeed/common/ast_tables.h
-@@ -0,0 +1,305 @@
-+/*
-+ * Copyright (c) 2005 ASPEED Technology Inc.
-+ *
-+ * Permission to use, copy, modify, distribute, and sell this software and its
-+ * documentation for any purpose is hereby granted without fee, provided that
-+ * the above copyright notice appear in all copies and that both that
-+ * copyright notice and this permission notice appear in supporting
-+ * documentation, and that the name of the authors not be used in
-+ * advertising or publicity pertaining to distribution of the software without
-+ * specific, written prior permission.  The authors makes no representations
-+ * about the suitability of this software for any purpose.  It is provided
-+ * "as is" without express or implied warranty.
-+ *
-+ * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
-+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
-+ * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
-+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
-+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-+ * PERFORMANCE OF THIS SOFTWARE.
-+ */
-+/* Ported from xf86-video-ast driver */
-+
-+#ifndef AST_TABLES_H
-+#define AST_TABLES_H
-+
-+/* Std. Table Index Definition */
-+#define TextModeIndex         0
-+#define EGAModeIndex          1
-+#define VGAModeIndex          2
-+#define HiCModeIndex          3
-+#define TrueCModeIndex                4
-+
-+#define Charx8Dot               0x00000001
-+#define HalfDCLK                0x00000002
-+#define DoubleScanMode          0x00000004
-+#define LineCompareOff          0x00000008
-+#define HBorder                 0x00000020
-+#define VBorder                 0x00000010
-+#define WideScreenMode                0x00000100
-+#define NewModeInfo           0x00000200
-+#define NHSync                        0x00000400
-+#define PHSync                        0x00000800
-+#define NVSync                        0x00001000
-+#define PVSync                        0x00002000
-+#define SyncPP                        (PVSync | PHSync)
-+#define SyncPN                        (PVSync | NHSync)
-+#define SyncNP                        (NVSync | PHSync)
-+#define SyncNN                        (NVSync | NHSync)
-+
-+/* DCLK Index */
-+#define VCLK25_175                    0x00
-+#define VCLK28_322                    0x01
-+#define VCLK31_5                      0x02
-+#define VCLK36                        0x03
-+#define VCLK40                        0x04
-+#define VCLK49_5                      0x05
-+#define VCLK50                        0x06
-+#define VCLK56_25                     0x07
-+#define VCLK65                        0x08
-+#define VCLK75                        0x09
-+#define VCLK78_75                     0x0A
-+#define VCLK94_5                      0x0B
-+#define VCLK108                       0x0C
-+#define VCLK135                       0x0D
-+#define VCLK157_5                     0x0E
-+#define VCLK162                       0x0F
-+/* #define VCLK193_25                 0x10 */
-+#define VCLK154               0x10
-+#define VCLK83_5              0x11
-+#define VCLK106_5             0x12
-+#define VCLK146_25            0x13
-+#define VCLK148_5             0x14
-+#define VCLK71                0x15
-+#define VCLK88_75             0x16
-+#define VCLK119               0x17
-+#define VCLK85_5              0x18
-+#define VCLK97_75                     0x19
-+#define VCLK118_25                    0x1A
-+
-+static struct ast_vbios_dclk_info dclk_table[] = {
-+      {0x2C, 0xE7, 0x03},                                     /* 00: 
VCLK25_175       */
-+      {0x95, 0x62, 0x03},                                     /* 01: 
VCLK28_322       */
-+      {0x67, 0x63, 0x01},                                     /* 02: VCLK31_5 
        */
-+      {0x76, 0x63, 0x01},                                     /* 03: VCLK36   
        */
-+      {0xEE, 0x67, 0x01},                                     /* 04: VCLK40   
        */
-+      {0x82, 0x62, 0x01},                             /* 05: VCLK49_5         
*/
-+      {0xC6, 0x64, 0x01},                                     /* 06: VCLK50   
        */
-+      {0x94, 0x62, 0x01},                                     /* 07: 
VCLK56_25        */
-+      {0x80, 0x64, 0x00},                                     /* 08: VCLK65   
        */
-+      {0x7B, 0x63, 0x00},                                     /* 09: VCLK75   
        */
-+      {0x67, 0x62, 0x00},                                     /* 0A: 
VCLK78_75        */
-+      {0x7C, 0x62, 0x00},                                     /* 0B: VCLK94_5 
        */
-+      {0x8E, 0x62, 0x00},                                     /* 0C: VCLK108  
        */
-+      {0x85, 0x24, 0x00},                                     /* 0D: VCLK135  
        */
-+      {0x67, 0x22, 0x00},                                     /* 0E: 
VCLK157_5        */
-+      {0x6A, 0x22, 0x00},                                     /* 0F: VCLK162  
        */
-+      {0x4d, 0x4c, 0x80},                                     /* 10: VCLK154  
        */
-+      {0xa7, 0x78, 0x80},                                     /* 11: VCLK83.5 
        */
-+      {0x28, 0x49, 0x80},                                     /* 12: 
VCLK106.5        */
-+      {0x37, 0x49, 0x80},                                     /* 13: 
VCLK146.25       */
-+      {0x1f, 0x45, 0x80},                                     /* 14: 
VCLK148.5        */
-+      {0x47, 0x6c, 0x80},                                     /* 15: VCLK71   
    */
-+      {0x25, 0x65, 0x80},                                     /* 16: 
VCLK88.75    */
-+      {0x77, 0x58, 0x80},                                     /* 17: VCLK119  
    */
-+      {0x32, 0x67, 0x80},                                 /* 18: VCLK85_5     
*/
-+      {0x6a, 0x6d, 0x80},                                     /* 19: 
VCLK97_75        */
-+      {0x3b, 0x2c, 0x81},                                     /* 1A: 
VCLK118_25       */
-+};
-+
-+static struct ast_vbios_stdtable vbios_stdtable[] = {
-+      /* MD_2_3_400 */
-+      {
-+              0x67,
-+              {0x00,0x03,0x00,0x02},
-+              {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-+               0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-+               0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-+               0xff},
-+              {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-+               0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-+               0x0c,0x00,0x0f,0x08},
-+              {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
-+               0xff}
-+      },
-+      /* Mode12/ExtEGATable */
-+      {
-+              0xe3,
-+              {0x01,0x0f,0x00,0x06},
-+              {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
-+               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-+               0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
-+               0xff},
-+              {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-+               0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-+               0x01,0x00,0x0f,0x00},
-+              {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-+               0xff}
-+      },
-+      /* ExtVGATable */
-+      {
-+              0x2f,
-+              {0x01,0x0f,0x00,0x0e},
-+              {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-+               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-+               0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-+               0xff},
-+              {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-+               0x01,0x00,0x00,0x00},
-+              {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
-+               0xff}
-+      },
-+      /* ExtHiCTable */
-+      {
-+              0x2f,
-+              {0x01,0x0f,0x00,0x0e},
-+              {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-+               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-+               0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-+               0xff},
-+              {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-+               0x01,0x00,0x00,0x00},
-+              {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-+               0xff}
-+      },
-+      /* ExtTrueCTable */
-+      {
-+              0x2f,
-+              {0x01,0x0f,0x00,0x0e},
-+              {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-+               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-+               0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-+               0xff},
-+              {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-+               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-+               0x01,0x00,0x00,0x00},
-+              {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
-+               0xff}
-+      },
-+};
-+
-+static struct ast_vbios_enhtable res_640x480[] = {
-+      { 800, 640, 8, 96, 525, 480, 2, 2, VCLK25_175,  /* 60Hz */
-+        (SyncNN | HBorder | VBorder | Charx8Dot), 60, 1, 0x2E },
-+      { 832, 640, 16, 40, 520, 480, 1, 3, VCLK31_5,   /* 72Hz */
-+        (SyncNN | HBorder | VBorder | Charx8Dot), 72, 2, 0x2E  },
-+      { 840, 640, 16, 64, 500, 480, 1, 3, VCLK31_5,   /* 75Hz */
-+        (SyncNN | Charx8Dot) , 75, 3, 0x2E },
-+      { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36,             /* 85Hz */
-+        (SyncNN | Charx8Dot) , 85, 4, 0x2E },
-+      { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36,             /* end */
-+        (SyncNN | Charx8Dot) , 0xFF, 4, 0x2E },
-+};
-+
-+static struct ast_vbios_enhtable res_800x600[] = {
-+      {1024, 800, 24, 72, 625, 600, 1, 2, VCLK36,             /* 56Hz */
-+       (SyncPP | Charx8Dot), 56, 1, 0x30 },
-+      {1056, 800, 40, 128, 628, 600, 1, 4, VCLK40,    /* 60Hz */
-+       (SyncPP | Charx8Dot), 60, 2, 0x30 },
-+      {1040, 800, 56, 120, 666, 600, 37, 6, VCLK50,   /* 72Hz */
-+       (SyncPP | Charx8Dot), 72, 3, 0x30 },
-+      {1056, 800, 16, 80, 625, 600, 1, 3, VCLK49_5,   /* 75Hz */
-+       (SyncPP | Charx8Dot), 75, 4, 0x30 },
-+      {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25,  /* 85Hz */
-+       (SyncPP | Charx8Dot), 84, 5, 0x30 },
-+      {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25,  /* end */
-+       (SyncPP | Charx8Dot), 0xFF, 5, 0x30 },
-+};
-+
-+
-+static struct ast_vbios_enhtable res_1024x768[] = {
-+      {1344, 1024, 24, 136, 806, 768, 3, 6, VCLK65,   /* 60Hz */
-+       (SyncNN | Charx8Dot), 60, 1, 0x31 },
-+      {1328, 1024, 24, 136, 806, 768, 3, 6, VCLK75,   /* 70Hz */
-+       (SyncNN | Charx8Dot), 70, 2, 0x31 },
-+      {1312, 1024, 16, 96, 800, 768, 1, 3, VCLK78_75, /* 75Hz */
-+       (SyncPP | Charx8Dot), 75, 3, 0x31 },
-+      {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5,  /* 85Hz */
-+       (SyncPP | Charx8Dot), 84, 4, 0x31 },
-+      {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5,  /* end */
-+       (SyncPP | Charx8Dot), 0xFF, 4, 0x31 },
-+};
-+
-+static struct ast_vbios_enhtable res_1280x1024[] = {
-+      {1688, 1280, 48, 112, 1066, 1024, 1, 3, VCLK108,        /* 60Hz */
-+       (SyncPP | Charx8Dot), 60, 1, 0x32 },
-+      {1688, 1280, 16, 144, 1066, 1024, 1, 3, VCLK135,        /* 75Hz */
-+       (SyncPP | Charx8Dot), 75, 2, 0x32 },
-+      {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5,      /* 85Hz */
-+       (SyncPP | Charx8Dot), 85, 3, 0x32 },
-+      {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5,      /* end */
-+       (SyncPP | Charx8Dot), 0xFF, 3, 0x32 },
-+};
-+
-+static struct ast_vbios_enhtable res_1600x1200[] = {
-+      {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162,        /* 60Hz */
-+       (SyncPP | Charx8Dot), 60, 1, 0x33 },
-+      {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162,        /* end */
-+       (SyncPP | Charx8Dot), 0xFF, 1, 0x33 },
-+};
-+
-+/* 16:9 */
-+static struct ast_vbios_enhtable res_1360x768[] = {
-+      {1792, 1360, 64,112, 795,  768, 3, 6, VCLK85_5,          /* 60Hz */
-+       (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x39 },
-+      {1792, 1360, 64,112, 795,  768, 3, 6, VCLK85_5,          /* end */
-+       (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 1, 0x39 },
-+};
-+
-+static struct ast_vbios_enhtable res_1600x900[] = {
-+      {1760, 1600, 48, 32, 926,  900, 3, 5, VCLK97_75,        /* 60Hz CVT RB 
*/
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x3A },
-+      {2112, 1600, 88,168, 934,  900, 3, 5, VCLK118_25,       /* 60Hz CVT */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x3A },
-+      {2112, 1600, 88,168, 934,  900, 3, 5, VCLK118_25,       /* 60Hz CVT */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x3A },
-+};
-+
-+static struct ast_vbios_enhtable res_1920x1080[] = {
-+      {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x38 },
-+      {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 1, 0x38 },
-+};
-+
-+
-+/* 16:10 */
-+static struct ast_vbios_enhtable res_1280x800[] = {
-+      {1440, 1280, 48, 32,  823,  800, 3, 6, VCLK71,  /* 60Hz RB */
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x35 },
-+      {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x35 },
-+      {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x35 },
-+
-+};
-+
-+static struct ast_vbios_enhtable res_1440x900[] = {
-+      {1600, 1440, 48, 32,  926,  900, 3, 6, VCLK88_75,       /* 60Hz RB */
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x36 },
-+      {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x36 },
-+      {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x36 },
-+};
-+
-+static struct ast_vbios_enhtable res_1680x1050[] = {
-+      {1840, 1680, 48, 32, 1080, 1050, 3, 6, VCLK119, /* 60Hz RB */
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x37 },
-+      {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x37 },
-+      {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
-+       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x37 },
-+};
-+
-+static struct ast_vbios_enhtable res_1920x1200[] = {
-+      {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB*/
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x34 },
-+      {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB */
-+       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 1, 0x34 },
-+};
-+
-+#endif
-diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
-index dcb8a42..fcaf4aa 100644
---- a/src/include/device/pci_ids.h
-+++ b/src/include/device/pci_ids.h
-@@ -1991,6 +1991,9 @@
- #define PCI_DEVICE_ID_XGI_20          0x0020
- #define PCI_DEVICE_ID_XGI_40          0x0040
- 
-+#define PCI_VENDOR_ID_ASPEED          0x1a03
-+#define PCI_DEVICE_ID_ASPEED_AST2050_VGA      0x2000
-+
- #define PCI_VENDOR_ID_SYMPHONY                0x1c1c
- #define PCI_DEVICE_ID_SYMPHONY_101    0x0001
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0004-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
 
b/resources/libreboot/patch/kgpe-d16/0004-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
new file mode 100644
index 0000000..ccb52ae
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0004-drivers-i2c-w83795-Add-option-to-use-auxiliary-SMBUS.patch
@@ -0,0 +1,68 @@
+From 8996dda2293b74ec84251cc2eefb7722acd6bd6b Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 17 Oct 2015 04:37:10 -0500
+Subject: [PATCH 004/143] drivers/i2c/w83795: Add option to use auxiliary
+ SMBUS controller
+
+Change-Id: I5a9b5eba992853b84b0cb6c3a1764edf42ac49b2
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/drivers/i2c/w83795/chip.h   |    7 +++++++
+ src/drivers/i2c/w83795/w83795.c |   17 +++++++++++++++++
+ 2 files changed, 24 insertions(+)
+
+diff --git a/src/drivers/i2c/w83795/chip.h b/src/drivers/i2c/w83795/chip.h
+index c8a42ea..9a3f847 100644
+--- a/src/drivers/i2c/w83795/chip.h
++++ b/src/drivers/i2c/w83795/chip.h
+@@ -139,4 +139,11 @@ struct drivers_i2c_w83795_config {
+       uint8_t fan6_duty;                      /* % of full speed (0-100) */
+       uint8_t fan7_duty;                      /* % of full speed (0-100) */
+       uint8_t fan8_duty;                      /* % of full speed (0-100) */
++
++      uint8_t smbus_aux;                      /* 0   == device located on 
primary SMBUS,
++                                               * 1   == device located on 
first auxiliary
++                                               *        SMBUS channel,
++                                               * <n> == device located on <n> 
auxiliary
++                                               *        SMBUS channel
++                                               */
+ };
+diff --git a/src/drivers/i2c/w83795/w83795.c b/src/drivers/i2c/w83795/w83795.c
+index 0af272f..0f82e1c 100644
+--- a/src/drivers/i2c/w83795/w83795.c
++++ b/src/drivers/i2c/w83795/w83795.c
+@@ -141,7 +141,18 @@ static void w83795_init(struct device *dev, 
w83795_fan_mode_t mode, u8 dts_src)
+       uint8_t val;
+       uint16_t limit_value;
+ 
++#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX_CHANNELS)
++      uint8_t smbus_aux_channel_prev = smbus_current_aux_channel();
++      smbus_switch_to_aux_channel(config->smbus_aux);
++      printk(BIOS_DEBUG, "Set SMBUS controller to channel %d\n", 
config->smbus_aux);
++#endif
++
+       if (smbus_read_byte(dev, 0x00) < 0) {
++#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX_CHANNELS)
++              /* Restore SMBUS channel setting */
++              smbus_switch_to_aux_channel(smbus_aux_channel_prev);
++              printk(BIOS_DEBUG, "Set SMBUS controller to channel %d\n", 
smbus_aux_channel_prev);
++#endif
+               printk(BIOS_ERR, "W83795G/ADG Nuvoton H/W Monitor not found\n");
+               return;
+       }
+@@ -332,6 +343,12 @@ static void w83795_init(struct device *dev, 
w83795_fan_mode_t mode, u8 dts_src)
+       val = w83795_read(dev, W83795_REG_CONFIG);
+       val |= W83795_REG_CONFIG_START;
+       w83795_write(dev, W83795_REG_CONFIG, val);
++
++#if IS_ENABLED(CONFIG_SMBUS_HAS_AUX_CHANNELS)
++      /* Restore SMBUS channel setting */
++      smbus_switch_to_aux_channel(smbus_aux_channel_prev);
++      printk(BIOS_DEBUG, "Set SMBUS controller to channel %d\n", 
smbus_aux_channel_prev);
++#endif
+ }
+ 
+ static void w83795_hwm_init(struct device *dev)
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0005-mainboard-Update-mainboards-using-the-w83795-sensor-.patch
 
b/resources/libreboot/patch/kgpe-d16/0005-mainboard-Update-mainboards-using-the-w83795-sensor-.patch
new file mode 100644
index 0000000..e848f49
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0005-mainboard-Update-mainboards-using-the-w83795-sensor-.patch
@@ -0,0 +1,323 @@
+From 2b9d5ca0b29cbe6e1600879b5cc731c2c4cb106d Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 22 Oct 2015 02:53:39 -0500
+Subject: [PATCH 005/143] mainboard: Update mainboards using the w83795 sensor
+ device
+
+Update mainboards using the w83795 sensor device with sane default
+values.  Note that in some cases the defaults may vary from the
+defaults provided by the old driver, for example the default fan
+speeds and control modes have changed as I do not have any information
+on the correct sensor to fan mappings for these boards.
+
+Change-Id: Id2ad6222d7a0f29483b022fa097d7d098c6b4122
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/supermicro/h8qgi/devicetree.cb |   89 ++++++++++++++++++++++++++
+ src/mainboard/supermicro/h8scm/devicetree.cb |   89 ++++++++++++++++++++++++++
+ src/mainboard/tyan/s8226/devicetree.cb       |   89 ++++++++++++++++++++++++++
+ 3 files changed, 267 insertions(+)
+
+diff --git a/src/mainboard/supermicro/h8qgi/devicetree.cb 
b/src/mainboard/supermicro/h8qgi/devicetree.cb
+index 59740c9..6c3ee90 100644
+--- a/src/mainboard/supermicro/h8qgi/devicetree.cb
++++ b/src/mainboard/supermicro/h8qgi/devicetree.cb
+@@ -107,6 +107,95 @@ chip northbridge/amd/agesa/family15/root_complex
+                                                       end
+                                               end #superio/winbond/w83627dhg
+                                               chip drivers/i2c/w83795
++                                                      register "fanin_ctl1" = 
"0xff"                  # Enable monitoring of FANIN1 - FANIN8
++                                                      register "fanin_ctl2" = 
"0x00"                  # Connect FANIN11 - FANIN14 to alternate functions
++                                                      register "temp_ctl1" = 
"0x2a"                   # Enable monitoring of DTS, VSEN12, and VSEN13
++                                                      register "temp_ctl2" = 
"0x01"                   # Enable monitoring of TD1/TR1
++                                                      register "temp_dtse" = 
"0x03"                   # Enable DTS1 and DTS2
++                                                      register "volt_ctl1" = 
"0xff"                   # Enable monitoring of VSEN1 - VSEN8
++                                                      register "volt_ctl2" = 
"0xf7"                   # Enable monitoring of VSEN9 - VSEN11, 3VDD, 3VSB, and 
VBAT
++                                                      register 
"temp1_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp1)
++                                                      register 
"temp2_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp2)
++                                                      register 
"temp3_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp3)
++                                                      register 
"temp4_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp4)
++                                                      register 
"temp5_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp5)
++                                                      register 
"temp6_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp6)
++                                                      register 
"temp1_source_select" = "0x00"         # Use TD1/TR1 as data source for Temp1
++                                                      register 
"temp2_source_select" = "0x00"         # Use TD2/TR2 as data source for Temp2
++                                                      register 
"temp3_source_select" = "0x00"         # Use TD3/TR3 as data source for Temp3
++                                                      register 
"temp4_source_select" = "0x00"         # Use TD4/TR4 as data source for Temp4
++                                                      register 
"temp5_source_select" = "0x00"         # Use TR5 as data source for Temp5
++                                                      register 
"temp6_source_select" = "0x00"         # Use TR6 as data source for Temp6
++                                                      register 
"tr1_critical_temperature" = "85"      # Set TD1/TR1 critical temperature to 
85°C
++                                                      register 
"tr1_critical_hysteresis" = "80"       # Set TD1/TR1 critical hysteresis 
temperature to 80°C
++                                                      register 
"tr1_warning_temperature" = "70"       # Set TD1/TR1 warning temperature to 70°C
++                                                      register 
"tr1_warning_hysteresis" = "65"        # Set TD1/TR1 warning hysteresis 
temperature to 65°C
++                                                      register 
"dts_critical_temperature" = "85"      # Set DTS (CPU) critical temperature to 
85°C
++                                                      register 
"dts_critical_hysteresis" = "80"       # Set DTS (CPU) critical hysteresis 
temperature to 80°C
++                                                      register 
"dts_warning_temperature" = "70"       # Set DTS (CPU) warning temperature to 
70°C
++                                                      register 
"dts_warning_hysteresis" = "65"        # Set DTS (CPU) warning hysteresis 
temperature to 65°C
++                                                      register 
"temp1_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp2_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp3_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp4_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp5_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp6_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp1_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp2_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp3_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp4_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp5_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp6_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register "fan1_nonstop" 
= "7"                   # Set Fan 1 minimum speed
++                                                      register "fan2_nonstop" 
= "7"                   # Set Fan 2 minimum speed
++                                                      register "fan3_nonstop" 
= "7"                   # Set Fan 3 minimum speed
++                                                      register "fan4_nonstop" 
= "7"                   # Set Fan 4 minimum speed
++                                                      register "fan5_nonstop" 
= "7"                   # Set Fan 5 minimum speed
++                                                      register "fan6_nonstop" 
= "7"                   # Set Fan 6 minimum speed
++                                                      register "fan7_nonstop" 
= "7"                   # Set Fan 7 minimum speed
++                                                      register "fan8_nonstop" 
= "7"                   # Set Fan 8 minimum speed
++                                                      register 
"default_speed" = "100"                # All fans to full speed on power up
++                                                      register "fan1_duty" = 
"100"                    # Fan 1 to full speed
++                                                      register "fan2_duty" = 
"100"                    # Fan 2 to full speed
++                                                      register "fan3_duty" = 
"100"                    # Fan 3 to full speed
++                                                      register "fan4_duty" = 
"100"                    # Fan 4 to full speed
++                                                      register "fan5_duty" = 
"100"                    # Fan 5 to full speed
++                                                      register "fan6_duty" = 
"100"                    # Fan 6 to full speed
++                                                      register "fan7_duty" = 
"100"                    # Fan 7 to full speed
++                                                      register "fan8_duty" = 
"100"                    # Fan 8 to full speed
++                                                      register 
"vcore1_high_limit_mv" = "1500"        # VCORE1 (Node 0) high limit to 1.5V
++                                                      register 
"vcore1_low_limit_mv" = "900"          # VCORE1 (Node 0) low limit to 0.9V
++                                                      register 
"vcore2_high_limit_mv" = "1500"        # VCORE2 (Node 1) high limit to 1.5V
++                                                      register 
"vcore2_low_limit_mv" = "900"          # VCORE2 (Node 1) low limit to 0.9V
++                                                      register 
"vsen3_high_limit_mv" = "1600"         # VSEN1 (Node 0 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen3_low_limit_mv" = "1100"          # VSEN1 (Node 0 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen4_high_limit_mv" = "1600"         # VSEN2 (Node 1 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen4_low_limit_mv" = "1100"          # VSEN2 (Node 1 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen5_high_limit_mv" = "1250"         # VSEN5 (Node 0 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen5_low_limit_mv" = "1150"          # VSEN5 (Node 0 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen6_high_limit_mv" = "1250"         # VSEN6 (Node 1 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen6_low_limit_mv" = "1150"          # VSEN6 (Node 1 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen7_high_limit_mv" = "1150"         # VSEN7 (Northbridge core voltage) high 
limit to 1.15V
++                                                      register 
"vsen7_low_limit_mv" = "1050"          # VSEN7 (Northbridge core voltage) low 
limit to 1.05V
++                                                      register 
"vsen8_high_limit_mv" = "1900"         # VSEN8 (+1.8V) high limit to 1.9V
++                                                      register 
"vsen8_low_limit_mv" = "1700"          # VSEN8 (+1.8V) low limit to 1.7V
++                                                      register 
"vsen9_high_limit_mv" = "1250"         # VSEN9 (+1.2V) high limit to 1.25V
++                                                      register 
"vsen9_low_limit_mv" = "1150"          # VSEN9 (+1.2V) low limit to 1.15V
++                                                      register 
"vsen10_high_limit_mv" = "1150"        # VSEN10 (+1.1V) high limit to 1.15V
++                                                      register 
"vsen10_low_limit_mv" = "1050"         # VSEN10 (+1.1V) low limit to 1.05V
++                                                      register 
"vsen11_high_limit_mv" = "1625"        # VSEN11 (5VSB, scaling factor ~3.2) 
high limit to 5.2V
++                                                      register 
"vsen11_low_limit_mv" = "1500"         # VSEN11 (5VSB, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vsen12_high_limit_mv" = "1083"        # VSEN12 (+12V, scaling factor ~12) high 
limit to 13V
++                                                      register 
"vsen12_low_limit_mv" = "917"          # VSEN12 (+12V, scaling factor ~12) low 
limit to 11V
++                                                      register 
"vsen13_high_limit_mv" = "1625"        # VSEN13 (+5V, scaling factor ~3.2) high 
limit to 5.2V
++                                                      register 
"vsen13_low_limit_mv" = "1500"         # VSEN13 (+5V, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vdd_high_limit_mv" = "3500"           # 3VDD high limit to 3.5V
++                                                      register 
"vdd_low_limit_mv" = "3100"            # 3VDD low limit to 3.1V
++                                                      register 
"vsb_high_limit_mv" = "3500"           # 3VSB high limit to 3.5V
++                                                      register 
"vsb_low_limit_mv" = "3100"            # 3VSB low limit to 3.1V
++                                                      register 
"vbat_high_limit_mv" = "3500"          # VBAT (+3V) high limit to 3.5V
++                                                      register 
"vbat_low_limit_mv" = "2500"           # VBAT (+3V) low limit to 2.5V
++                                                      register "smbus_aux" = 
"0"                      # Device located on primary SMBUS
+                                                       device pnp 5e on #hwm
+                                                       end
+                                               end #drivers/i2c/w83795
+diff --git a/src/mainboard/supermicro/h8scm/devicetree.cb 
b/src/mainboard/supermicro/h8scm/devicetree.cb
+index b8fb823..a280e62 100644
+--- a/src/mainboard/supermicro/h8scm/devicetree.cb
++++ b/src/mainboard/supermicro/h8scm/devicetree.cb
+@@ -106,6 +106,95 @@ chip northbridge/amd/agesa/family15/root_complex
+                                                       end
+                                               end #superio/winbond/w83627dhg
+                                               chip drivers/i2c/w83795
++                                                      register "fanin_ctl1" = 
"0xff"                  # Enable monitoring of FANIN1 - FANIN8
++                                                      register "fanin_ctl2" = 
"0x00"                  # Connect FANIN11 - FANIN14 to alternate functions
++                                                      register "temp_ctl1" = 
"0x2a"                   # Enable monitoring of DTS, VSEN12, and VSEN13
++                                                      register "temp_ctl2" = 
"0x01"                   # Enable monitoring of TD1/TR1
++                                                      register "temp_dtse" = 
"0x03"                   # Enable DTS1 and DTS2
++                                                      register "volt_ctl1" = 
"0xff"                   # Enable monitoring of VSEN1 - VSEN8
++                                                      register "volt_ctl2" = 
"0xf7"                   # Enable monitoring of VSEN9 - VSEN11, 3VDD, 3VSB, and 
VBAT
++                                                      register 
"temp1_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp1)
++                                                      register 
"temp2_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp2)
++                                                      register 
"temp3_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp3)
++                                                      register 
"temp4_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp4)
++                                                      register 
"temp5_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp5)
++                                                      register 
"temp6_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp6)
++                                                      register 
"temp1_source_select" = "0x00"         # Use TD1/TR1 as data source for Temp1
++                                                      register 
"temp2_source_select" = "0x00"         # Use TD2/TR2 as data source for Temp2
++                                                      register 
"temp3_source_select" = "0x00"         # Use TD3/TR3 as data source for Temp3
++                                                      register 
"temp4_source_select" = "0x00"         # Use TD4/TR4 as data source for Temp4
++                                                      register 
"temp5_source_select" = "0x00"         # Use TR5 as data source for Temp5
++                                                      register 
"temp6_source_select" = "0x00"         # Use TR6 as data source for Temp6
++                                                      register 
"tr1_critical_temperature" = "85"      # Set TD1/TR1 critical temperature to 
85°C
++                                                      register 
"tr1_critical_hysteresis" = "80"       # Set TD1/TR1 critical hysteresis 
temperature to 80°C
++                                                      register 
"tr1_warning_temperature" = "70"       # Set TD1/TR1 warning temperature to 70°C
++                                                      register 
"tr1_warning_hysteresis" = "65"        # Set TD1/TR1 warning hysteresis 
temperature to 65°C
++                                                      register 
"dts_critical_temperature" = "85"      # Set DTS (CPU) critical temperature to 
85°C
++                                                      register 
"dts_critical_hysteresis" = "80"       # Set DTS (CPU) critical hysteresis 
temperature to 80°C
++                                                      register 
"dts_warning_temperature" = "70"       # Set DTS (CPU) warning temperature to 
70°C
++                                                      register 
"dts_warning_hysteresis" = "65"        # Set DTS (CPU) warning hysteresis 
temperature to 65°C
++                                                      register 
"temp1_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp2_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp3_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp4_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp5_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp6_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp1_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp2_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp3_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp4_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp5_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp6_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register "fan1_nonstop" 
= "7"                   # Set Fan 1 minimum speed
++                                                      register "fan2_nonstop" 
= "7"                   # Set Fan 2 minimum speed
++                                                      register "fan3_nonstop" 
= "7"                   # Set Fan 3 minimum speed
++                                                      register "fan4_nonstop" 
= "7"                   # Set Fan 4 minimum speed
++                                                      register "fan5_nonstop" 
= "7"                   # Set Fan 5 minimum speed
++                                                      register "fan6_nonstop" 
= "7"                   # Set Fan 6 minimum speed
++                                                      register "fan7_nonstop" 
= "7"                   # Set Fan 7 minimum speed
++                                                      register "fan8_nonstop" 
= "7"                   # Set Fan 8 minimum speed
++                                                      register 
"default_speed" = "100"                # All fans to full speed on power up
++                                                      register "fan1_duty" = 
"100"                    # Fan 1 to full speed
++                                                      register "fan2_duty" = 
"100"                    # Fan 2 to full speed
++                                                      register "fan3_duty" = 
"100"                    # Fan 3 to full speed
++                                                      register "fan4_duty" = 
"100"                    # Fan 4 to full speed
++                                                      register "fan5_duty" = 
"100"                    # Fan 5 to full speed
++                                                      register "fan6_duty" = 
"100"                    # Fan 6 to full speed
++                                                      register "fan7_duty" = 
"100"                    # Fan 7 to full speed
++                                                      register "fan8_duty" = 
"100"                    # Fan 8 to full speed
++                                                      register 
"vcore1_high_limit_mv" = "1500"        # VCORE1 (Node 0) high limit to 1.5V
++                                                      register 
"vcore1_low_limit_mv" = "900"          # VCORE1 (Node 0) low limit to 0.9V
++                                                      register 
"vcore2_high_limit_mv" = "1500"        # VCORE2 (Node 1) high limit to 1.5V
++                                                      register 
"vcore2_low_limit_mv" = "900"          # VCORE2 (Node 1) low limit to 0.9V
++                                                      register 
"vsen3_high_limit_mv" = "1600"         # VSEN1 (Node 0 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen3_low_limit_mv" = "1100"          # VSEN1 (Node 0 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen4_high_limit_mv" = "1600"         # VSEN2 (Node 1 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen4_low_limit_mv" = "1100"          # VSEN2 (Node 1 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen5_high_limit_mv" = "1250"         # VSEN5 (Node 0 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen5_low_limit_mv" = "1150"          # VSEN5 (Node 0 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen6_high_limit_mv" = "1250"         # VSEN6 (Node 1 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen6_low_limit_mv" = "1150"          # VSEN6 (Node 1 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen7_high_limit_mv" = "1150"         # VSEN7 (Northbridge core voltage) high 
limit to 1.15V
++                                                      register 
"vsen7_low_limit_mv" = "1050"          # VSEN7 (Northbridge core voltage) low 
limit to 1.05V
++                                                      register 
"vsen8_high_limit_mv" = "1900"         # VSEN8 (+1.8V) high limit to 1.9V
++                                                      register 
"vsen8_low_limit_mv" = "1700"          # VSEN8 (+1.8V) low limit to 1.7V
++                                                      register 
"vsen9_high_limit_mv" = "1250"         # VSEN9 (+1.2V) high limit to 1.25V
++                                                      register 
"vsen9_low_limit_mv" = "1150"          # VSEN9 (+1.2V) low limit to 1.15V
++                                                      register 
"vsen10_high_limit_mv" = "1150"        # VSEN10 (+1.1V) high limit to 1.15V
++                                                      register 
"vsen10_low_limit_mv" = "1050"         # VSEN10 (+1.1V) low limit to 1.05V
++                                                      register 
"vsen11_high_limit_mv" = "1625"        # VSEN11 (5VSB, scaling factor ~3.2) 
high limit to 5.2V
++                                                      register 
"vsen11_low_limit_mv" = "1500"         # VSEN11 (5VSB, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vsen12_high_limit_mv" = "1083"        # VSEN12 (+12V, scaling factor ~12) high 
limit to 13V
++                                                      register 
"vsen12_low_limit_mv" = "917"          # VSEN12 (+12V, scaling factor ~12) low 
limit to 11V
++                                                      register 
"vsen13_high_limit_mv" = "1625"        # VSEN13 (+5V, scaling factor ~3.2) high 
limit to 5.2V
++                                                      register 
"vsen13_low_limit_mv" = "1500"         # VSEN13 (+5V, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vdd_high_limit_mv" = "3500"           # 3VDD high limit to 3.5V
++                                                      register 
"vdd_low_limit_mv" = "3100"            # 3VDD low limit to 3.1V
++                                                      register 
"vsb_high_limit_mv" = "3500"           # 3VSB high limit to 3.5V
++                                                      register 
"vsb_low_limit_mv" = "3100"            # 3VSB low limit to 3.1V
++                                                      register 
"vbat_high_limit_mv" = "3500"          # VBAT (+3V) high limit to 3.5V
++                                                      register 
"vbat_low_limit_mv" = "2500"           # VBAT (+3V) low limit to 2.5V
++                                                      register "smbus_aux" = 
"0"                      # Device located on primary SMBUS
+                                                       device pnp 5e on #hwm
+                                                       end
+                                               end #drivers/i2c/w83795
+diff --git a/src/mainboard/tyan/s8226/devicetree.cb 
b/src/mainboard/tyan/s8226/devicetree.cb
+index 64701a5..9f5e584 100644
+--- a/src/mainboard/tyan/s8226/devicetree.cb
++++ b/src/mainboard/tyan/s8226/devicetree.cb
+@@ -106,6 +106,95 @@ chip northbridge/amd/agesa/family15/root_complex
+                                                       end
+                                               end #superio/winbond/w83627dhg
+                                               chip drivers/i2c/w83795
++                                                      register "fanin_ctl1" = 
"0xff"                  # Enable monitoring of FANIN1 - FANIN8
++                                                      register "fanin_ctl2" = 
"0x00"                  # Connect FANIN11 - FANIN14 to alternate functions
++                                                      register "temp_ctl1" = 
"0x2a"                   # Enable monitoring of DTS, VSEN12, and VSEN13
++                                                      register "temp_ctl2" = 
"0x01"                   # Enable monitoring of TD1/TR1
++                                                      register "temp_dtse" = 
"0x03"                   # Enable DTS1 and DTS2
++                                                      register "volt_ctl1" = 
"0xff"                   # Enable monitoring of VSEN1 - VSEN8
++                                                      register "volt_ctl2" = 
"0xf7"                   # Enable monitoring of VSEN9 - VSEN11, 3VDD, 3VSB, and 
VBAT
++                                                      register 
"temp1_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp1)
++                                                      register 
"temp2_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp2)
++                                                      register 
"temp3_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp3)
++                                                      register 
"temp4_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp4)
++                                                      register 
"temp5_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp5)
++                                                      register 
"temp6_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp6)
++                                                      register 
"temp1_source_select" = "0x00"         # Use TD1/TR1 as data source for Temp1
++                                                      register 
"temp2_source_select" = "0x00"         # Use TD2/TR2 as data source for Temp2
++                                                      register 
"temp3_source_select" = "0x00"         # Use TD3/TR3 as data source for Temp3
++                                                      register 
"temp4_source_select" = "0x00"         # Use TD4/TR4 as data source for Temp4
++                                                      register 
"temp5_source_select" = "0x00"         # Use TR5 as data source for Temp5
++                                                      register 
"temp6_source_select" = "0x00"         # Use TR6 as data source for Temp6
++                                                      register 
"tr1_critical_temperature" = "85"      # Set TD1/TR1 critical temperature to 
85°C
++                                                      register 
"tr1_critical_hysteresis" = "80"       # Set TD1/TR1 critical hysteresis 
temperature to 80°C
++                                                      register 
"tr1_warning_temperature" = "70"       # Set TD1/TR1 warning temperature to 70°C
++                                                      register 
"tr1_warning_hysteresis" = "65"        # Set TD1/TR1 warning hysteresis 
temperature to 65°C
++                                                      register 
"dts_critical_temperature" = "85"      # Set DTS (CPU) critical temperature to 
85°C
++                                                      register 
"dts_critical_hysteresis" = "80"       # Set DTS (CPU) critical hysteresis 
temperature to 80°C
++                                                      register 
"dts_warning_temperature" = "70"       # Set DTS (CPU) warning temperature to 
70°C
++                                                      register 
"dts_warning_hysteresis" = "65"        # Set DTS (CPU) warning hysteresis 
temperature to 65°C
++                                                      register 
"temp1_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp2_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp3_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp4_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp5_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp6_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp1_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp2_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp3_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp4_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp5_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp6_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register "fan1_nonstop" 
= "7"                   # Set Fan 1 minimum speed
++                                                      register "fan2_nonstop" 
= "7"                   # Set Fan 2 minimum speed
++                                                      register "fan3_nonstop" 
= "7"                   # Set Fan 3 minimum speed
++                                                      register "fan4_nonstop" 
= "7"                   # Set Fan 4 minimum speed
++                                                      register "fan5_nonstop" 
= "7"                   # Set Fan 5 minimum speed
++                                                      register "fan6_nonstop" 
= "7"                   # Set Fan 6 minimum speed
++                                                      register "fan7_nonstop" 
= "7"                   # Set Fan 7 minimum speed
++                                                      register "fan8_nonstop" 
= "7"                   # Set Fan 8 minimum speed
++                                                      register 
"default_speed" = "100"                # All fans to full speed on power up
++                                                      register "fan1_duty" = 
"100"                    # Fan 1 to full speed
++                                                      register "fan2_duty" = 
"100"                    # Fan 2 to full speed
++                                                      register "fan3_duty" = 
"100"                    # Fan 3 to full speed
++                                                      register "fan4_duty" = 
"100"                    # Fan 4 to full speed
++                                                      register "fan5_duty" = 
"100"                    # Fan 5 to full speed
++                                                      register "fan6_duty" = 
"100"                    # Fan 6 to full speed
++                                                      register "fan7_duty" = 
"100"                    # Fan 7 to full speed
++                                                      register "fan8_duty" = 
"100"                    # Fan 8 to full speed
++                                                      register 
"vcore1_high_limit_mv" = "1500"        # VCORE1 (Node 0) high limit to 1.5V
++                                                      register 
"vcore1_low_limit_mv" = "900"          # VCORE1 (Node 0) low limit to 0.9V
++                                                      register 
"vcore2_high_limit_mv" = "1500"        # VCORE2 (Node 1) high limit to 1.5V
++                                                      register 
"vcore2_low_limit_mv" = "900"          # VCORE2 (Node 1) low limit to 0.9V
++                                                      register 
"vsen3_high_limit_mv" = "1600"         # VSEN1 (Node 0 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen3_low_limit_mv" = "1100"          # VSEN1 (Node 0 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen4_high_limit_mv" = "1600"         # VSEN2 (Node 1 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen4_low_limit_mv" = "1100"          # VSEN2 (Node 1 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen5_high_limit_mv" = "1250"         # VSEN5 (Node 0 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen5_low_limit_mv" = "1150"          # VSEN5 (Node 0 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen6_high_limit_mv" = "1250"         # VSEN6 (Node 1 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen6_low_limit_mv" = "1150"          # VSEN6 (Node 1 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen7_high_limit_mv" = "1150"         # VSEN7 (Northbridge core voltage) high 
limit to 1.15V
++                                                      register 
"vsen7_low_limit_mv" = "1050"          # VSEN7 (Northbridge core voltage) low 
limit to 1.05V
++                                                      register 
"vsen8_high_limit_mv" = "1900"         # VSEN8 (+1.8V) high limit to 1.9V
++                                                      register 
"vsen8_low_limit_mv" = "1700"          # VSEN8 (+1.8V) low limit to 1.7V
++                                                      register 
"vsen9_high_limit_mv" = "1250"         # VSEN9 (+1.2V) high limit to 1.25V
++                                                      register 
"vsen9_low_limit_mv" = "1150"          # VSEN9 (+1.2V) low limit to 1.15V
++                                                      register 
"vsen10_high_limit_mv" = "1150"        # VSEN10 (+1.1V) high limit to 1.15V
++                                                      register 
"vsen10_low_limit_mv" = "1050"         # VSEN10 (+1.1V) low limit to 1.05V
++                                                      register 
"vsen11_high_limit_mv" = "1625"        # VSEN11 (5VSB, scaling factor ~3.2) 
high limit to 5.2V
++                                                      register 
"vsen11_low_limit_mv" = "1500"         # VSEN11 (5VSB, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vsen12_high_limit_mv" = "1083"        # VSEN12 (+12V, scaling factor ~12) high 
limit to 13V
++                                                      register 
"vsen12_low_limit_mv" = "917"          # VSEN12 (+12V, scaling factor ~12) low 
limit to 11V
++                                                      register 
"vsen13_high_limit_mv" = "1625"        # VSEN13 (+5V, scaling factor ~3.2) high 
limit to 5.2V
++                                                      register 
"vsen13_low_limit_mv" = "1500"         # VSEN13 (+5V, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vdd_high_limit_mv" = "3500"           # 3VDD high limit to 3.5V
++                                                      register 
"vdd_low_limit_mv" = "3100"            # 3VDD low limit to 3.1V
++                                                      register 
"vsb_high_limit_mv" = "3500"           # 3VSB high limit to 3.5V
++                                                      register 
"vsb_low_limit_mv" = "3100"            # 3VSB low limit to 3.1V
++                                                      register 
"vbat_high_limit_mv" = "3500"          # VBAT (+3V) high limit to 3.5V
++                                                      register 
"vbat_low_limit_mv" = "2500"           # VBAT (+3V) low limit to 2.5V
++                                                      register "smbus_aux" = 
"0"                      # Device located on primary SMBUS
+                                                       device pnp 5e on #hwm
+                                                       end
+                                               end #drivers/i2c/w83795
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0005-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
 
b/resources/libreboot/patch/kgpe-d16/0005-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
deleted file mode 100644
index a895479..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0005-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
+++ /dev/null
@@ -1,642 +0,0 @@
-From e897086a84f3b7c1af321e2a8a303cc49367b390 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 17:46:15 -0500
-Subject: [PATCH 005/139] southbridge/amd/sb700: Fix boot hang on ASUS KGPE-D16
-
-Change-Id: I1d7d6715663a13ab94fd6d71808e35f0f7384d00
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/Kconfig       |   4 +
- src/southbridge/amd/sb700/acpi/ide.asl  | 234 ++++++++++++++++++++++++++++++++
- src/southbridge/amd/sb700/acpi/sata.asl | 133 ++++++++++++++++++
- src/southbridge/amd/sb700/bootblock.c   |  46 ++++++-
- src/southbridge/amd/sb700/early_setup.c |  18 +++
- src/southbridge/amd/sb700/lpc.c         |   3 +
- src/southbridge/amd/sb700/sm.c          |  21 +--
- src/southbridge/amd/sb700/smbus.h       |   5 +-
- 8 files changed, 447 insertions(+), 17 deletions(-)
- create mode 100644 src/southbridge/amd/sb700/acpi/ide.asl
- create mode 100644 src/southbridge/amd/sb700/acpi/sata.asl
-
-diff --git a/src/southbridge/amd/sb700/Kconfig 
b/src/southbridge/amd/sb700/Kconfig
-index a5dfe07..f56f84a 100644
---- a/src/southbridge/amd/sb700/Kconfig
-+++ b/src/southbridge/amd/sb700/Kconfig
-@@ -42,6 +42,10 @@ config SOUTHBRIDGE_AMD_SB700_SKIP_ISA_DMA_INIT
-       bool
-       default n
- 
-+config SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
-+      bool
-+      default n
-+
- config EHCI_BAR
-       hex
-       default 0xfef00000
-diff --git a/src/southbridge/amd/sb700/acpi/ide.asl 
b/src/southbridge/amd/sb700/acpi/ide.asl
-new file mode 100644
-index 0000000..9b5e3ea
---- /dev/null
-+++ b/src/southbridge/amd/sb700/acpi/ide.asl
-@@ -0,0 +1,234 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+/* Some timing tables */
-+Name(UDTT, Package(){ /* Udma timing table */
-+      120, 90, 60, 45, 30, 20, 15, 0  /* UDMA modes 0 -> 6 */
-+})
-+
-+Name(MDTT, Package(){ /* MWDma timing table */
-+      480, 150, 120, 0        /* Legacy DMA modes 0 -> 2 */
-+})
-+
-+Name(POTT, Package(){ /* Pio timing table */
-+      600, 390, 270, 180, 120, 0      /* PIO modes 0 -> 4 */
-+})
-+
-+/* Some timing register value tables */
-+Name(MDRT, Package(){ /* MWDma timing register table */
-+      0x77, 0x21, 0x20, 0xFF  /* Legacy DMA modes 0 -> 2 */
-+})
-+
-+Name(PORT, Package(){
-+      0x99, 0x47, 0x34, 0x22, 0x20, 0x99      /* PIO modes 0 -> 4 */
-+})
-+
-+OperationRegion(ICRG, PCI_Config, 0x40, 0x20) /* ide control registers */
-+      Field(ICRG, AnyAcc, NoLock, Preserve)
-+{
-+      PPTS, 8,        /* Primary PIO Slave Timing */
-+      PPTM, 8,        /* Primary PIO Master Timing */
-+      OFFSET(0x04), PMTS, 8,  /* Primary MWDMA Slave Timing */
-+      PMTM, 8,        /* Primary MWDMA Master Timing */
-+      OFFSET(0x08), PPCR, 8,  /* Primary PIO Control */
-+      OFFSET(0x0A), PPMM, 4,  /* Primary PIO master Mode */
-+      PPSM, 4,        /* Primary PIO slave Mode */
-+      OFFSET(0x14), PDCR, 2,  /* Primary UDMA Control */
-+      OFFSET(0x16), PDMM, 4,  /* Primary UltraDMA Mode */
-+      PDSM, 4,        /* Primary UltraDMA Mode */
-+}
-+
-+Method(GTTM, 1) /* get total time*/
-+{
-+      Store(And(Arg0, 0x0F), Local0)  /* Recovery Width */
-+      Increment(Local0)
-+      Store(ShiftRight(Arg0, 4), Local1)      /* Command Width */
-+      Increment(Local1)
-+      Return(Multiply(30, Add(Local0, Local1)))
-+}
-+
-+Device(PRID)
-+{
-+      Name (_ADR, Zero)
-+      Method(_GTM, 0, Serialized)
-+      {
-+              NAME(OTBF, Buffer(20) { /* out buffer */
-+                      0xFF, 0xFF, 0xFF, 0xFF,
-+                      0xFF, 0xFF, 0xFF, 0xFF,
-+                      0xFF, 0xFF, 0xFF, 0xFF,
-+                      0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00
-+              })
-+
-+              CreateDwordField(OTBF, 0, PSD0)   /* PIO spd0 */
-+              CreateDwordField(OTBF, 4, DSD0)   /* DMA spd0 */
-+              CreateDwordField(OTBF, 8, PSD1)   /* PIO spd1 */
-+              CreateDwordField(OTBF, 12, DSD1) /* DMA spd1 */
-+              CreateDwordField(OTBF, 16, BFFG) /* buffer flags */
-+
-+              /* Just return if the channel is disabled */
-+              If(And(PPCR, 0x01)) { /* primary PIO control */
-+                      Return(OTBF)
-+              }
-+
-+              /* Always tell them independent timing available and 
IOChannelReady used on both drives */
-+              Or(BFFG, 0x1A, BFFG)
-+
-+              Store(GTTM(PPTM), PSD0) /* save total time of primary PIO 
master timming  to PIO spd0 */
-+              Store(GTTM(PPTS), PSD1) /* save total time of primary PIO slave 
Timing  to PIO spd1 */
-+
-+              If(And(PDCR, 0x01)) {   /* It's under UDMA mode */
-+                      Or(BFFG, 0x01, BFFG)
-+                      Store(DerefOf(Index(UDTT, PDMM)), DSD0)
-+              }
-+              Else {
-+                      Store(GTTM(PMTM), DSD0) /* Primary MWDMA Master Timing, 
 DmaSpd0 */
-+              }
-+
-+              If(And(PDCR, 0x02)) {   /* It's under UDMA mode */
-+                      Or(BFFG, 0x04, BFFG)
-+                      Store(DerefOf(Index(UDTT, PDSM)), DSD1)
-+              }
-+              Else {
-+                      Store(GTTM(PMTS), DSD1) /* Primary MWDMA Slave Timing,  
DmaSpd0 */
-+              }
-+
-+              Return(OTBF) /* out buffer */
-+      }                               /* End Method(_GTM) */
-+
-+      Method(_STM, 3, Serialized)
-+      {
-+              NAME(INBF, Buffer(20) { /* in buffer */
-+                      0xFF, 0xFF, 0xFF, 0xFF,
-+                      0xFF, 0xFF, 0xFF, 0xFF,
-+                      0xFF, 0xFF, 0xFF, 0xFF,
-+                      0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00
-+              })
-+
-+              CreateDwordField(INBF, 0, PSD0)    /* PIO spd0 */
-+              CreateDwordField(INBF, 4, DSD0)   /* PIO spd0 */
-+              CreateDwordField(INBF, 8, PSD1)   /* PIO spd1 */
-+              CreateDwordField(INBF, 12, DSD1) /* DMA spd1 */
-+              CreateDwordField(INBF, 16, BFFG) /*buffer flag */
-+
-+              Store(Match(POTT, MLE, PSD0, MTR, 0, 0), Local0)
-+              Divide(Local0, 5, PPMM,) /* Primary PIO master Mode */
-+              Store(Match(POTT, MLE, PSD1, MTR, 0, 0), Local1)
-+              Divide(Local1, 5, PPSM,) /* Primary PIO slave Mode */
-+
-+              Store(DerefOf(Index(PORT, Local0)), PPTM) /* Primary PIO Master 
Timing */
-+              Store(DerefOf(Index(PORT, Local1)), PPTS) /* Primary PIO Slave 
Timing */
-+
-+              If(And(BFFG, 0x01)) {   /* Drive 0 is under UDMA mode */
-+                      Store(Match(UDTT, MLE, DSD0, MTR, 0, 0), Local0)
-+                      Divide(Local0, 7, PDMM,)
-+                      Or(PDCR, 0x01, PDCR)
-+              }
-+              Else {
-+                      If(LNotEqual(DSD0, 0xFFFFFFFF)) {
-+                              Store(Match(MDTT, MLE, DSD0, MTR, 0, 0), Local0)
-+                              Store(DerefOf(Index(MDRT, Local0)), PMTM)
-+                      }
-+              }
-+
-+              If(And(BFFG, 0x04)) {   /* Drive 1 is under UDMA mode */
-+                      Store(Match(UDTT, MLE, DSD1, MTR, 0, 0), Local0)
-+                      Divide(Local0, 7, PDSM,)
-+                      Or(PDCR, 0x02, PDCR)
-+              }
-+              Else {
-+                      If(LNotEqual(DSD1, 0xFFFFFFFF)) {
-+                              Store(Match(MDTT, MLE, DSD1, MTR, 0, 0), Local0)
-+                              Store(DerefOf(Index(MDRT, Local0)), PMTS)
-+                      }
-+              }
-+              /* Return(INBF) */
-+      }               /*End Method(_STM) */
-+      Device(MST)
-+      {
-+              Name(_ADR, 0)
-+              Method(_GTF, 0, Serialized) {
-+                      Name(CMBF, Buffer(21) {
-+                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
-+                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
-+                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5
-+                      })
-+                      CreateByteField(CMBF, 1, POMD)
-+                      CreateByteField(CMBF, 8, DMMD)
-+                      CreateByteField(CMBF, 5, CMDA)
-+                      CreateByteField(CMBF, 12, CMDB)
-+                      CreateByteField(CMBF, 19, CMDC)
-+
-+                      Store(0xA0, CMDA)
-+                      Store(0xA0, CMDB)
-+                      Store(0xA0, CMDC)
-+
-+                      Or(PPMM, 0x08, POMD)
-+
-+                      If(And(PDCR, 0x01)) {
-+                              Or(PDMM, 0x40, DMMD)
-+                      }
-+                      Else {
-+                              Store(Match
-+                                    (MDTT, MLE, GTTM(PMTM),
-+                                     MTR, 0, 0), Local0)
-+                              If(LLess(Local0, 3)) {
-+                                      Or(0x20, Local0, DMMD)
-+                              }
-+                      }
-+                      Return(CMBF)
-+              }
-+      }               /* End Device(MST) */
-+
-+      Device(SLAV)
-+      {
-+              Name(_ADR, 1)
-+              Method(_GTF, 0, Serialized) {
-+                      Name(CMBF, Buffer(21) {
-+                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
-+                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
-+                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5
-+                      })
-+                      CreateByteField(CMBF, 1, POMD)
-+                      CreateByteField(CMBF, 8, DMMD)
-+                      CreateByteField(CMBF, 5, CMDA)
-+                      CreateByteField(CMBF, 12, CMDB)
-+                      CreateByteField(CMBF, 19, CMDC)
-+
-+                      Store(0xB0, CMDA)
-+                      Store(0xB0, CMDB)
-+                      Store(0xB0, CMDC)
-+
-+                      Or(PPSM, 0x08, POMD)
-+
-+                      If(And(PDCR, 0x02)) {
-+                              Or(PDSM, 0x40, DMMD)
-+                      }
-+                      Else {
-+                              Store(Match
-+                                    (MDTT, MLE, GTTM(PMTS),
-+                                     MTR, 0, 0), Local0)
-+                              If(LLess(Local0, 3)) {
-+                                      Or(0x20, Local0, DMMD)
-+                              }
-+                      }
-+                      Return(CMBF)
-+              }
-+      }                       /* End Device(SLAV) */
-+}
-diff --git a/src/southbridge/amd/sb700/acpi/sata.asl 
b/src/southbridge/amd/sb700/acpi/sata.asl
-new file mode 100644
-index 0000000..46a82b7
---- /dev/null
-+++ b/src/southbridge/amd/sb700/acpi/sata.asl
-@@ -0,0 +1,133 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+Name(STTM, Buffer(20) {
-+      0x78, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
-+      0x78, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
-+      0x1f, 0x00, 0x00, 0x00
-+})
-+
-+/* Start by clearing the PhyRdyChg bits */
-+Method(_INI) {
-+      \_GPE._L1F()
-+}
-+
-+Device(PMRY)
-+{
-+      Name(_ADR, 0)
-+      Method(_GTM, 0x0, NotSerialized) {
-+              Return(STTM)
-+      }
-+      Method(_STM, 0x3, NotSerialized) {}
-+
-+      Device(PMST) {
-+              Name(_ADR, 0)
-+              Method(_STA,0) {
-+                      if (LGreater(P0IS,0)) {
-+                              return (0x0F) /* sata is visible */
-+                      } else {
-+                              return  (0x00) /* sata is missing */
-+                      }
-+              }
-+      }/* end of PMST */
-+
-+      Device(PSLA)
-+      {
-+              Name(_ADR, 1)
-+              Method(_STA,0) {
-+                      if (LGreater(P1IS,0)) {
-+                              return (0x0F) /* sata is visible */
-+                      } else {
-+                              return (0x00) /* sata is missing */
-+                      }
-+              }
-+      }       /* end of PSLA */
-+}   /* end of PMRY */
-+
-+
-+Device(SEDY)
-+{
-+      Name(_ADR, 1)           /* IDE Scondary Channel */
-+      Method(_GTM, 0x0, NotSerialized) {
-+              Return(STTM)
-+      }
-+      Method(_STM, 0x3, NotSerialized) {}
-+
-+      Device(SMST)
-+      {
-+              Name(_ADR, 0)
-+              Method(_STA,0) {
-+                      if (LGreater(P2IS,0)) {
-+                              return (0x0F) /* sata is visible */
-+                      } else {
-+                              return (0x00) /* sata is missing */
-+                      }
-+              }
-+      } /* end of SMST */
-+
-+      Device(SSLA)
-+      {
-+              Name(_ADR, 1)
-+              Method(_STA,0) {
-+                      if (LGreater(P3IS,0)) {
-+                              return (0x0F) /* sata is visible */
-+                      } else {
-+                              return (0x00) /* sata is missing */
-+                      }
-+              }
-+      } /* end of SSLA */
-+}   /* end of SEDY */
-+
-+/* SATA Hot Plug Support */
-+Scope(\_GPE) {
-+      Method(_L1F,0x0,NotSerialized) {
-+              if (\_SB.P0PR) {
-+                      if (LGreater(\_SB.P0IS,0)) {
-+                              sleep(32)
-+                      }
-+                      Notify(\_SB.PCI0.SAT0.PMRY.PMST, 0x01) /* 
NOTIFY_DEVICE_CHECK */
-+                      store(one, \_SB.P0PR)
-+              }
-+
-+              if (\_SB.P1PR) {
-+                      if (LGreater(\_SB.P1IS,0)) {
-+                              sleep(32)
-+                      }
-+                      Notify(\_SB.PCI0.SAT0.PMRY.PSLA, 0x01) /* 
NOTIFY_DEVICE_CHECK */
-+                      store(one, \_SB.P1PR)
-+              }
-+
-+              if (\_SB.P2PR) {
-+                      if (LGreater(\_SB.P2IS,0)) {
-+                              sleep(32)
-+                      }
-+                      Notify(\_SB.PCI0.SAT0.SEDY.SMST, 0x01) /* 
NOTIFY_DEVICE_CHECK */
-+                      store(one, \_SB.P2PR)
-+              }
-+
-+              if (\_SB.P3PR) {
-+                      if (LGreater(\_SB.P3IS,0)) {
-+                              sleep(32)
-+                      }
-+                      Notify(\_SB.PCI0.SAT0.SEDY.SSLA, 0x01) /* 
NOTIFY_DEVICE_CHECK */
-+                      store(one, \_SB.P3PR)
-+              }
-+      }
-+}
-diff --git a/src/southbridge/amd/sb700/bootblock.c 
b/src/southbridge/amd/sb700/bootblock.c
-index 67e6434..8f722a8 100644
---- a/src/southbridge/amd/sb700/bootblock.c
-+++ b/src/southbridge/amd/sb700/bootblock.c
-@@ -1,6 +1,7 @@
- /*
-  * This file is part of the coreboot project.
-  *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-  *
-  * This program is free software; you can redistribute it and/or modify
-@@ -35,10 +36,17 @@
- static void sb700_enable_rom(void)
- {
-       u8 reg8;
-+      u32 dword;
-       pci_devfn_t dev;
- 
-       dev = PCI_DEV(0, 0x14, 3);
- 
-+      /* The LPC settings below work for SPI flash as well;
-+       * the hardware does not distinguish between LPC and SPI flash ROM
-+       * aside from offering additional side-channel access to SPI flash
-+       * via a separate register-based interface.
-+       */
-+
-       /* Decode variable LPC ROM address ranges 1 and 2. */
-       reg8 = pci_io_read_config8(dev, 0x48);
-       reg8 |= (1 << 3) | (1 << 4);
-@@ -52,15 +60,41 @@ static void sb700_enable_rom(void)
- 
-       /* LPC ROM address range 2: */
-       /*
--       * Enable LPC ROM range start at:
--       * 0xfff8(0000): 512KB
--       * 0xfff0(0000): 1MB
--       * 0xffe0(0000): 2MB
--       * 0xffc0(0000): 4MB
--       */
-+      * Enable LPC ROM range start at:
-+      * 0xfff8(0000): 512KB
-+      * 0xfff0(0000): 1MB
-+      * 0xffe0(0000): 2MB
-+      * 0xffc0(0000): 4MB
-+      * 0xff80(0000): 8MB
-+      */
-       pci_io_write_config16(dev, 0x6c, 0x10000 - (CONFIG_COREBOOT_ROMSIZE_KB 
>> 6));
-       /* Enable LPC ROM range end at 0xffff(ffff). */
-       pci_io_write_config16(dev, 0x6e, 0xffff);
-+
-+      /* SB700 LPC Bridge 0x48h.
-+       * Turn on all LPC IO Port decode enables
-+       */
-+      dword = pci_io_read_config32(dev, 0x44);
-+      dword = 0xffffffff;
-+      pci_io_write_config32(dev, 0x44, dword);
-+
-+      /* SB700 LPC Bridge 0x48h.
-+       * BIT0: Port Enable for SuperIO 0x2E-0x2F
-+       * BIT1: Port Enable for SuperIO 0x4E-0x4F
-+       * BIT4: Port Enable for LPC ROM Address Arrage2 (0x68-0x6C)
-+       * BIT6: Port Enable for RTC IO 0x70-0x73
-+       * BIT21: Port Enable for Port 0x80
-+       */
-+      reg8 = pci_io_read_config8(dev, 0x48);
-+      reg8 |= (1<<0) | (1<<1) | (1<<4) | (1<<6);
-+      pci_io_write_config8(dev, 0x48, reg8);
-+
-+      /* SB700 LPC Bridge 0x4ah.
-+       * BIT4: Port Enable for Port 0x80
-+       */
-+      reg8 = pci_io_read_config8(dev, 0x4a);
-+      reg8 |= (1<<4);
-+      pci_io_write_config8(dev, 0x4a, reg8);
- }
- 
- static void bootblock_southbridge_init(void)
-diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
-index d25599e..de3fa97 100644
---- a/src/southbridge/amd/sb700/early_setup.c
-+++ b/src/southbridge/amd/sb700/early_setup.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -395,6 +396,15 @@ static void sb700_devices_por_init(void)
-       byte |= (1 << 0);
-       pci_write_config8(dev, 0xd2, byte);
- 
-+      /* set auxiliary smbus iobase and enable controller */
-+      pci_write_config32(dev, 0x58, SMBUS_AUX_IO_BASE | 1);
-+
-+      if (inw(SMBUS_IO_BASE) == 0xFF)
-+              printk(BIOS_INFO, "sb700_devices_por_init(): Primary SMBUS 
controller I/O not found\n");
-+
-+      if (inw(SMBUS_AUX_IO_BASE) == 0xFF)
-+              printk(BIOS_INFO, "sb700_devices_por_init(): Secondary SMBUS 
controller I/O not found\n");
-+
-       /* KB2RstEnable */
-       pci_write_config8(dev, 0x40, 0x44);
- 
-@@ -439,6 +449,14 @@ static void sb700_devices_por_init(void)
-       /*pci_write_config8(dev, 0x79, 0x4F); */
-       pci_write_config8(dev, 0x78, 0xFF);
- 
-+      if (IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
-+              printk(BIOS_DEBUG, "sb700_devices_por_init(): Disabling ISA DMA 
support\n");
-+              /* Disable LPC ISA DMA Capability */
-+              byte = pci_read_config8(dev, 0x78);
-+              byte &= ~(1 << 0);
-+              pci_write_config8(dev, 0x78, byte);
-+      }
-+
-       /* Set smbus iospace enable, I don't know why write 0x04 into reg5 that 
is reserved */
-       pci_write_config16(dev, 0x4, 0x0407);
- 
-diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c
-index a39ec18..0cc1e8b 100644
---- a/src/southbridge/amd/sb700/lpc.c
-+++ b/src/southbridge/amd/sb700/lpc.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -45,6 +46,8 @@ static void lpc_init(device_t dev)
-       u32 dword;
-       device_t sm_dev;
- 
-+      printk(BIOS_SPEW, "%s\n", __func__);
-+
-       /* Enable the LPC Controller */
-       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
-       dword = pci_read_config32(sm_dev, 0x64);
-diff --git a/src/southbridge/amd/sb700/sm.c b/src/southbridge/amd/sb700/sm.c
-index c216e1f..a4b78d0 100644
---- a/src/southbridge/amd/sb700/sm.c
-+++ b/src/southbridge/amd/sb700/sm.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -59,11 +60,8 @@ static void sm_init(device_t dev)
-       printk(BIOS_INFO, "sm_init().\n");
- 
-       rev = get_sb700_revision(dev);
--      ioapic_base = (void *)(pci_read_config32(dev, 0x74) & (0xffffffe0));    
/* some like mem resource, but does not have  enable bit */
--      /* Don't rename APIC ID */
--      /* TODO: We should call setup_ioapic() here. But kernel hangs if cpu is 
K8.
--       * We need to check out why and change back. */
--      clear_ioapic(ioapic_base);
-+      ioapic_base = (void *)(pci_read_config32(dev, 0x74) & (0xffffffe0));    
/* some like mem resource, but does not have enable bit */
-+      setup_ioapic(ioapic_base, 0); /* Don't rename IOAPIC ID. */
- 
-       /* 2.10 Interrupt Routing/Filtering */
-       dword = pci_read_config8(dev, 0x62);
-@@ -129,9 +127,10 @@ static void sm_init(device_t dev)
-       get_option(&on, "power_on_after_fail");
-       byte = pm_ioread(0x74);
-       byte &= ~0x03;
--      if (on) {
--              byte |= 2;
--      }
-+      if (on == 1)
-+              byte |= 0x1;    /* Force power on */
-+      else if (on == 2)
-+              byte |= 0x2;    /* Use last power state */
-       byte |= 1 << 2;
-       pm_iowrite(0x74, byte);
-       printk(BIOS_INFO, "set power %s after power fail\n", on ? "on" : "off");
-@@ -295,6 +294,10 @@ static void sm_init(device_t dev)
-       byte &= ~(1 << 1);
-       pm_iowrite(0x59, byte);
- 
-+      /* Enable SCI as irq9. */
-+      outb(0x4, 0xC00);
-+      outb(0x9, 0xC01);
-+
-       printk(BIOS_INFO, "sm_init() end\n");
- 
-       /* Enable NbSb virtual channel */
-@@ -385,7 +388,7 @@ static void sb700_sm_read_resources(device_t dev)
-       struct resource *res;
- 
-       /* Get the normal pci resources of this device */
--      /* pci_dev_read_resources(dev); */
-+      pci_dev_read_resources(dev);
- 
-       /* apic */
-       res = new_resource(dev, 0x74);
-diff --git a/src/southbridge/amd/sb700/smbus.h 
b/src/southbridge/amd/sb700/smbus.h
-index d223fe7..34b4098 100644
---- a/src/southbridge/amd/sb700/smbus.h
-+++ b/src/southbridge/amd/sb700/smbus.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -24,8 +25,8 @@
- #include "stddef.h"
- #include <arch/io.h>
- 
--#define SMBUS_IO_BASE 0x6000  /* Is it a temporary SMBus I/O base address? */
--                              /*SIZE 0x40 */
-+#define SMBUS_IO_BASE 0xb00
-+#define SMBUS_AUX_IO_BASE 0xb20
- 
- #define SMBHSTSTAT 0x0
- #define SMBSLVSTAT 0x1
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0006-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
 
b/resources/libreboot/patch/kgpe-d16/0006-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
new file mode 100644
index 0000000..b243026
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0006-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch
@@ -0,0 +1,3675 @@
+From 913f5fe9e0107c27e0029fe76f62b37f88ccb221 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 17:38:09 -0500
+Subject: [PATCH 006/143] drivers/aspeed: Add native text mode VGA support for
+ the AST2050
+
+Change-Id: I37763a59d2546cd0c0e57b31fdb7aa77c2c50bee
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/drivers/aspeed/Kconfig                  |    2 +
+ src/drivers/aspeed/Makefile.inc             |    1 +
+ src/drivers/aspeed/ast2050/Kconfig          |   14 +
+ src/drivers/aspeed/ast2050/Makefile.inc     |    1 +
+ src/drivers/aspeed/ast2050/ast2050.c        |   83 ++
+ src/drivers/aspeed/common/Kconfig           |   10 +
+ src/drivers/aspeed/common/Makefile.inc      |    1 +
+ src/drivers/aspeed/common/aspeed_coreboot.h |  210 ++++
+ src/drivers/aspeed/common/ast_dp501.c       |  443 +++++++
+ src/drivers/aspeed/common/ast_dram_tables.h |  165 +++
+ src/drivers/aspeed/common/ast_drv.h         |  223 ++++
+ src/drivers/aspeed/common/ast_main.c        |  393 +++++++
+ src/drivers/aspeed/common/ast_post.c        | 1679 +++++++++++++++++++++++++++
+ src/drivers/aspeed/common/ast_tables.h      |  305 +++++
+ src/include/device/pci_ids.h                |    3 +
+ 15 files changed, 3533 insertions(+)
+ create mode 100644 src/drivers/aspeed/Kconfig
+ create mode 100644 src/drivers/aspeed/Makefile.inc
+ create mode 100644 src/drivers/aspeed/ast2050/Kconfig
+ create mode 100644 src/drivers/aspeed/ast2050/Makefile.inc
+ create mode 100644 src/drivers/aspeed/ast2050/ast2050.c
+ create mode 100644 src/drivers/aspeed/common/Kconfig
+ create mode 100644 src/drivers/aspeed/common/Makefile.inc
+ create mode 100644 src/drivers/aspeed/common/aspeed_coreboot.h
+ create mode 100644 src/drivers/aspeed/common/ast_dp501.c
+ create mode 100644 src/drivers/aspeed/common/ast_dram_tables.h
+ create mode 100644 src/drivers/aspeed/common/ast_drv.h
+ create mode 100644 src/drivers/aspeed/common/ast_main.c
+ create mode 100644 src/drivers/aspeed/common/ast_post.c
+ create mode 100644 src/drivers/aspeed/common/ast_tables.h
+
+diff --git a/src/drivers/aspeed/Kconfig b/src/drivers/aspeed/Kconfig
+new file mode 100644
+index 0000000..27469b5
+--- /dev/null
++++ b/src/drivers/aspeed/Kconfig
+@@ -0,0 +1,2 @@
++source src/drivers/aspeed/common/Kconfig
++source src/drivers/aspeed/ast2050/Kconfig
+\ No newline at end of file
+diff --git a/src/drivers/aspeed/Makefile.inc b/src/drivers/aspeed/Makefile.inc
+new file mode 100644
+index 0000000..955a213
+--- /dev/null
++++ b/src/drivers/aspeed/Makefile.inc
+@@ -0,0 +1 @@
++subdirs-y += common ast2050
+\ No newline at end of file
+diff --git a/src/drivers/aspeed/ast2050/Kconfig 
b/src/drivers/aspeed/ast2050/Kconfig
+new file mode 100644
+index 0000000..f110d58
+--- /dev/null
++++ b/src/drivers/aspeed/ast2050/Kconfig
+@@ -0,0 +1,14 @@
++config DRIVERS_ASPEED_AST2050
++      bool
++
++if DRIVERS_ASPEED_AST2050
++
++config DEVICE_SPECIFIC_OPTIONS # dummy
++      def_bool y
++      select DRIVERS_ASPEED_AST_COMMON
++
++config NATIVE_VGA_INIT_USE_EDID
++      bool
++      default n
++
++endif # DRIVERS_ASPEED_AST2050
+diff --git a/src/drivers/aspeed/ast2050/Makefile.inc 
b/src/drivers/aspeed/ast2050/Makefile.inc
+new file mode 100644
+index 0000000..3ba9dde
+--- /dev/null
++++ b/src/drivers/aspeed/ast2050/Makefile.inc
+@@ -0,0 +1 @@
++ramstage-$(CONFIG_DRIVERS_ASPEED_AST2050) += ast2050.c
+\ No newline at end of file
+diff --git a/src/drivers/aspeed/ast2050/ast2050.c 
b/src/drivers/aspeed/ast2050/ast2050.c
+new file mode 100644
+index 0000000..809e9de
+--- /dev/null
++++ b/src/drivers/aspeed/ast2050/ast2050.c
+@@ -0,0 +1,83 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++#include <delay.h>
++#include <stdlib.h>
++#include <string.h>
++#include <arch/io.h>
++#include <edid.h>
++
++#include <console/console.h>
++#include <device/device.h>
++#include <device/pci.h>
++#include <device/pci_ids.h>
++#include <device/pci_ops.h>
++
++#include <pc80/vga.h>
++
++#include "../common/aspeed_coreboot.h"
++#include "../common/ast_drv.h"
++
++static void aspeed_ast2050_set_resources(device_t dev)
++{
++      /* Reserve VGA regions */
++      mmio_resource(dev, 3, 0xa0000 >> 10, 0x1ffff >> 10);
++
++      /* Run standard resource set routine */
++      pci_dev_set_resources(dev);
++}
++
++static void aspeed_ast2050_init(struct device *dev)
++{
++      u8 ret;
++      struct drm_device drm_dev;
++
++      drm_dev.pdev = dev;
++
++      printk(BIOS_INFO, "ASpeed AST2050: initializing video device\n");
++      ret = ast_driver_load(&drm_dev, 0);
++
++      /* Unlock extended configuration registers */
++      outb(0x80, 0x3d4); outb(0xa8, 0x3d5);
++
++      /* Set CRT Request Threshold */
++      outb(0xa6, 0x3d4); outb(0x2f, 0x3d5);
++      outb(0xa7, 0x3d4); outb(0x3f, 0x3d5);
++
++      /* Initialize standard VGA text mode */
++      vga_io_init();
++      vga_textmode_init();
++      printk(BIOS_INFO, "ASpeed VGA text mode initialized\n");
++
++      /* if we don't have console, at least print something... */
++      vga_line_write(0, "ASpeed VGA text mode initialized");
++}
++
++static struct device_operations aspeed_ast2050_ops  = {
++      .read_resources   = pci_dev_read_resources,
++      .set_resources    = aspeed_ast2050_set_resources,
++      .enable_resources = pci_dev_enable_resources,
++      .init             = aspeed_ast2050_init,
++      .scan_bus         = 0,
++};
++
++static const struct pci_driver aspeed_ast2050_driver __pci_driver = {
++        .ops    = &aspeed_ast2050_ops,
++        .vendor = PCI_VENDOR_ID_ASPEED,
++        .device = PCI_DEVICE_ID_ASPEED_AST2050_VGA,
++};
+diff --git a/src/drivers/aspeed/common/Kconfig 
b/src/drivers/aspeed/common/Kconfig
+new file mode 100644
+index 0000000..0f7056b
+--- /dev/null
++++ b/src/drivers/aspeed/common/Kconfig
+@@ -0,0 +1,10 @@
++config DRIVERS_ASPEED_AST_COMMON
++      bool
++
++if !MAINBOARD_DO_NATIVE_VGA_INIT
++
++config DEVICE_SPECIFIC_OPTIONS # dummy
++      def_bool y
++      select VGA
++
++endif # MAINBOARD_DO_NATIVE_VGA_INIT
+diff --git a/src/drivers/aspeed/common/Makefile.inc 
b/src/drivers/aspeed/common/Makefile.inc
+new file mode 100644
+index 0000000..75f8b48
+--- /dev/null
++++ b/src/drivers/aspeed/common/Makefile.inc
+@@ -0,0 +1 @@
++ramstage-$(CONFIG_DRIVERS_ASPEED_AST_COMMON) += ast_dp501.c ast_main.c 
ast_post.c
+diff --git a/src/drivers/aspeed/common/aspeed_coreboot.h 
b/src/drivers/aspeed/common/aspeed_coreboot.h
+new file mode 100644
+index 0000000..237c23f
+--- /dev/null
++++ b/src/drivers/aspeed/common/aspeed_coreboot.h
+@@ -0,0 +1,210 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef _ASPEED_COREBOOT_
++#define _ASPEED_COREBOOT_
++
++#include <delay.h>
++#include <stdlib.h>
++#include <stdint.h>
++#include <string.h>
++#include <arch/io.h>
++
++#include <console/console.h>
++#include <device/device.h>
++#include <device/pci.h>
++#include <device/pci_ids.h>
++#include <device/pci_ops.h>
++
++/* coreboot <--> kernel code interface */
++#define __iomem
++typedef u64 phys_addr_t;
++#define pci_dev device
++
++#define SZ_16M 0x01000000
++
++#define min_t(type, x, y) ({                  \
++      type __min1 = (x);                      \
++      type __min2 = (y);                      \
++      __min1 < __min2 ? __min1 : __min2; })
++
++#define dev_info(dev, format, arg...) printk(BIOS_INFO, "ASpeed VGA: " 
format, ##arg)
++#define dev_dbg(dev, format, arg...) printk(BIOS_DEBUG, "ASpeed VGA: " 
format, ##arg)
++#define dev_err(dev, format, arg...) printk(BIOS_ERR, "ASpeed VGA: " format, 
##arg)
++
++#define pr_info(format, arg...) printk(BIOS_INFO, "ASpeed VGA: " format, 
##arg)
++#define pr_debug(format, arg...) printk(BIOS_INFO, "ASpeed VGA: " format, 
##arg)
++#define pr_err(format, arg...) printk(BIOS_ERR, "ASpeed VGA: " format, ##arg)
++
++#define DRM_INFO pr_info
++
++#define GFP_KERNEL 0
++#define GFP_ATOMIC 1
++#define kfree(address) free(address)
++
++#define EIO 5
++#define ENOMEM 12
++
++struct firmware {
++      size_t size;
++      const u8 *data;
++      struct page **pages;
++
++      /* firmware loader private fields */
++      void *priv;
++};
++
++struct drm_device {
++      struct pci_dev *pdev;
++      void *dev_private;
++};
++
++static inline void *kzalloc(size_t size, int flags) {
++      void* ptr = malloc(size);
++      memset(ptr, 0, size);
++      return ptr;
++}
++
++static inline void writel(u32 val, volatile void *addr) {
++      *(u32*)addr = val;
++}
++
++static inline u32 readl(const volatile void *addr) {
++      return *(u32*)addr;
++}
++
++static inline void writew(u16 val, volatile void *addr) {
++      *(u16*)addr = val;
++}
++
++static inline u16 readw(const volatile void *addr) {
++      return *(u16*)addr;
++}
++
++static inline void writeb(u8 val, volatile void *addr) {
++      *(u8*)addr = val;
++}
++
++static inline u8 readb(const volatile void *addr) {
++      return *(u8*)addr;
++}
++
++static inline int pci_read_config_dword(struct pci_dev *dev, int where,
++      u32 *val)
++{
++      *val = pci_read_config32(dev, where);
++      return 0;
++}
++
++static inline int pci_write_config_dword(struct pci_dev *dev, int where,
++      u32 val)
++{
++      pci_write_config32(dev, where, val);
++      return 0;
++}
++
++static inline int pci_read_config_byte(struct pci_dev *dev, int where,
++      u8 *val)
++{
++      *val = pci_read_config8(dev, where);
++      return 0;
++}
++
++static inline struct resource* resource_at_bar(struct pci_dev *dev, u8 bar) {
++      struct resource *res = dev->resource_list;
++      int i;
++      for (i = 0; i < bar; i++) {
++              res = res->next;
++              if (res == NULL)
++                      return NULL;
++      }
++
++      return res;
++}
++
++static inline resource_t pci_resource_len(struct pci_dev *dev, u8 bar) {
++      struct resource *res = resource_at_bar(dev, bar);
++      if (res)
++              return res->size;
++      else
++              return 0;
++}
++
++static inline resource_t pci_resource_start(struct pci_dev *dev, u8 bar) {
++      struct resource *res = resource_at_bar(dev, bar);
++      if (res)
++              return res->base;
++      else
++              return 0;
++}
++
++static inline unsigned int ioread32(void __iomem *p) {
++      return readl(p);
++}
++
++static inline void iowrite32(u32 val, void __iomem *p) {
++      writel(val, p);
++}
++
++static inline unsigned int ioread16(void __iomem *p) {
++      return readw(p);
++}
++
++static inline void iowrite16(u16 val, void __iomem *p) {
++      writew(val, p);
++}
++
++static inline unsigned int ioread8(void __iomem *p) {
++      return readb(p);
++}
++
++static inline void iowrite8(u8 val, void __iomem *p) {
++      writeb(val, p);
++}
++
++static inline unsigned int ioread_cbio32(void __iomem *p) {
++      return inl((uint16_t)((intptr_t)p));
++}
++
++static inline void iowrite_cbio32(u32 val, void __iomem *p) {
++      outl(val, (uint16_t)((intptr_t)p));
++}
++
++static inline unsigned int ioread_cbio16(void __iomem *p) {
++      return inw((uint16_t)((intptr_t)p));
++}
++
++static inline void iowrite_cbio16(u16 val, void __iomem *p) {
++      outw(val, (uint16_t)((intptr_t)p));
++}
++
++static inline unsigned int ioread_cbio8(void __iomem *p) {
++      return inb((uint16_t)((intptr_t)p));
++}
++
++static inline void iowrite_cbio8(u8 val, void __iomem *p) {
++      outb(val, (uint16_t)((intptr_t)p));
++}
++
++static inline void msleep(unsigned int msecs) {
++      udelay(msecs * 1000);
++}
++
++#endif
+\ No newline at end of file
+diff --git a/src/drivers/aspeed/common/ast_dp501.c 
b/src/drivers/aspeed/common/ast_dp501.c
+new file mode 100644
+index 0000000..5be8ec3
+--- /dev/null
++++ b/src/drivers/aspeed/common/ast_dp501.c
+@@ -0,0 +1,443 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * File taken from the Linux ast driver (v3.18.5)
++ * Coreboot-specific includes added at top and/or contents modified
++ * as needed to function within the coreboot environment.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc.
++ */
++
++#include "ast_drv.h"
++
++static void send_ack(struct ast_private *ast)
++{
++      u8 sendack;
++      sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
++      sendack |= 0x80;
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
++}
++
++static void send_nack(struct ast_private *ast)
++{
++      u8 sendack;
++      sendack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0xff);
++      sendack &= ~0x80;
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, 0x00, sendack);
++}
++
++static bool wait_ack(struct ast_private *ast)
++{
++      u8 waitack;
++      u32 retry = 0;
++      do {
++              waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 
0xff);
++              waitack &= 0x80;
++              udelay(100);
++      } while ((!waitack) && (retry++ < 1000));
++
++      if (retry < 1000)
++              return true;
++      else
++              return false;
++}
++
++static bool wait_nack(struct ast_private *ast)
++{
++      u8 waitack;
++      u32 retry = 0;
++      do {
++              waitack = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 
0xff);
++              waitack &= 0x80;
++              udelay(100);
++      } while ((waitack) && (retry++ < 1000));
++
++      if (retry < 1000)
++              return true;
++      else
++              return false;
++}
++
++static void set_cmd_trigger(struct ast_private *ast)
++{
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x40);
++}
++
++static void clear_cmd_trigger(struct ast_private *ast)
++{
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9b, ~0x40, 0x00);
++}
++
++#if 0
++static bool wait_fw_ready(struct ast_private *ast)
++{
++      u8 waitready;
++      u32 retry = 0;
++      do {
++              waitready = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd2, 
0xff);
++              waitready &= 0x40;
++              udelay(100);
++      } while ((!waitready) && (retry++ < 1000));
++
++      if (retry < 1000)
++              return true;
++      else
++              return false;
++}
++#endif
++
++static bool ast_write_cmd(struct drm_device *dev, u8 data)
++{
++      struct ast_private *ast = dev->dev_private;
++      int retry = 0;
++      if (wait_nack(ast)) {
++              send_nack(ast);
++              ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
++              send_ack(ast);
++              set_cmd_trigger(ast);
++              do {
++                      if (wait_ack(ast)) {
++                              clear_cmd_trigger(ast);
++                              send_nack(ast);
++                              return true;
++                      }
++              } while (retry++ < 100);
++      }
++      clear_cmd_trigger(ast);
++      send_nack(ast);
++      return false;
++}
++
++static bool ast_write_data(struct drm_device *dev, u8 data)
++{
++      struct ast_private *ast = dev->dev_private;
++
++      if (wait_nack(ast)) {
++              send_nack(ast);
++              ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, data);
++              send_ack(ast);
++              if (wait_ack(ast)) {
++                      send_nack(ast);
++                      return true;
++              }
++      }
++      send_nack(ast);
++      return false;
++}
++
++#if 0
++static bool ast_read_data(struct drm_device *dev, u8 *data)
++{
++      struct ast_private *ast = dev->dev_private;
++      u8 tmp;
++
++      *data = 0;
++
++      if (wait_ack(ast) == false)
++              return false;
++      tmp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd3, 0xff);
++      *data = tmp;
++      if (wait_nack(ast) == false) {
++              send_nack(ast);
++              return false;
++      }
++      send_nack(ast);
++      return true;
++}
++
++static void clear_cmd(struct ast_private *ast)
++{
++      send_nack(ast);
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x9a, 0x00, 0x00);
++}
++#endif
++
++void ast_set_dp501_video_output(struct drm_device *dev, u8 mode)
++{
++      ast_write_cmd(dev, 0x40);
++      ast_write_data(dev, mode);
++
++      msleep(10);
++}
++
++static u32 get_fw_base(struct ast_private *ast)
++{
++      return ast_mindwm(ast, 0x1e6e2104) & 0x7fffffff;
++}
++
++bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size)
++{
++      struct ast_private *ast = dev->dev_private;
++      u32 i, data;
++      u32 boot_address;
++
++      data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
++      if (data) {
++              boot_address = get_fw_base(ast);
++              for (i = 0; i < size; i += 4)
++                      *(u32 *)(addr + i) = ast_mindwm(ast, boot_address + i);
++              return true;
++      }
++      return false;
++}
++
++bool ast_launch_m68k(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u32 i, data, len = 0;
++      u32 boot_address;
++      u8 *fw_addr = NULL;
++      u8 jreg;
++
++      data = ast_mindwm(ast, 0x1e6e2100) & 0x01;
++      if (!data) {
++
++              if (ast->dp501_fw_addr) {
++                      fw_addr = ast->dp501_fw_addr;
++                      len = 32*1024;
++              } else if (ast->dp501_fw) {
++                      fw_addr = (u8 *)ast->dp501_fw->data;
++                      len = ast->dp501_fw->size;
++              }
++              /* Get BootAddress */
++              ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
++              data = ast_mindwm(ast, 0x1e6e0004);
++              switch (data & 0x03) {
++              case 0:
++                      boot_address = 0x44000000;
++                      break;
++              default:
++              case 1:
++                      boot_address = 0x48000000;
++                      break;
++              case 2:
++                      boot_address = 0x50000000;
++                      break;
++              case 3:
++                      boot_address = 0x60000000;
++                      break;
++              }
++              boot_address -= 0x200000; /* -2MB */
++
++              /* copy image to buffer */
++              for (i = 0; i < len; i += 4) {
++                      data = *(u32 *)(fw_addr + i);
++                      ast_moutdwm(ast, boot_address + i, data);
++              }
++
++              /* Init SCU */
++              ast_moutdwm(ast, 0x1e6e2000, 0x1688a8a8);
++
++              /* Launch FW */
++              ast_moutdwm(ast, 0x1e6e2104, 0x80000000 + boot_address);
++              ast_moutdwm(ast, 0x1e6e2100, 1);
++
++              /* Update Scratch */
++              data = ast_mindwm(ast, 0x1e6e2040) & 0xfffff1ff;                
/* D[11:9] = 100b: UEFI handling */
++              data |= 0x800;
++              ast_moutdwm(ast, 0x1e6e2040, data);
++
++              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x99, 
0xfc); /* D[1:0]: Reserved Video Buffer */
++              jreg |= 0x02;
++              ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x99, jreg);
++      }
++      return true;
++}
++
++u8 ast_get_dp501_max_clk(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u32 boot_address, offset, data;
++      u8 linkcap[4], linkrate, linklanes, maxclk = 0xff;
++
++      boot_address = get_fw_base(ast);
++
++      /* validate FW version */
++      offset = 0xf000;
++      data = ast_mindwm(ast, boot_address + offset);
++      if ((data & 0xf0) != 0x10) /* version: 1x */
++              return maxclk;
++
++      /* Read Link Capability */
++      offset  = 0xf014;
++      data = ast_mindwm(ast, boot_address + offset);
++      linkcap[0] = (data & 0xff000000) >> 24;
++      linkcap[1] = (data & 0x00ff0000) >> 16;
++      linkcap[2] = (data & 0x0000ff00) >> 8;
++      linkcap[3] = (data & 0x000000ff);
++      if (linkcap[2] == 0) {
++              linkrate = linkcap[0];
++              linklanes = linkcap[1];
++              data = (linkrate == 0x0a) ? (90 * linklanes) : (54 * linklanes);
++              if (data > 0xff)
++                      data = 0xff;
++              maxclk = (u8)data;
++      }
++      return maxclk;
++}
++
++bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata)
++{
++      struct ast_private *ast = dev->dev_private;
++      u32 i, boot_address, offset, data;
++
++      boot_address = get_fw_base(ast);
++
++      /* validate FW version */
++      offset = 0xf000;
++      data = ast_mindwm(ast, boot_address + offset);
++      if ((data & 0xf0) != 0x10)
++              return false;
++
++      /* validate PnP Monitor */
++      offset = 0xf010;
++      data = ast_mindwm(ast, boot_address + offset);
++      if (!(data & 0x01))
++              return false;
++
++      /* Read EDID */
++      offset = 0xf020;
++      for (i = 0; i < 128; i += 4) {
++              data = ast_mindwm(ast, boot_address + offset + i);
++              *(u32 *)(ediddata + i) = data;
++      }
++
++      return true;
++}
++
++static bool ast_init_dvo(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u8 jreg;
++      u32 data;
++      ast_write32(ast, 0xf004, 0x1e6e0000);
++      ast_write32(ast, 0xf000, 0x1);
++      ast_write32(ast, 0x12000, 0x1688a8a8);
++
++      jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
++      if (!(jreg & 0x80)) {
++              /* Init SCU DVO Settings */
++              data = ast_read32(ast, 0x12008);
++              /* delay phase */
++              data &= 0xfffff8ff;
++              data |= 0x00000500;
++              ast_write32(ast, 0x12008, data);
++
++              if (ast->chip == AST2300) {
++                      data = ast_read32(ast, 0x12084);
++                      /* multi-pins for DVO single-edge */
++                      data |= 0xfffe0000;
++                      ast_write32(ast, 0x12084, data);
++
++                      data = ast_read32(ast, 0x12088);
++                      /* multi-pins for DVO single-edge */
++                      data |= 0x000fffff;
++                      ast_write32(ast, 0x12088, data);
++
++                      data = ast_read32(ast, 0x12090);
++                      /* multi-pins for DVO single-edge */
++                      data &= 0xffffffcf;
++                      data |= 0x00000020;
++                      ast_write32(ast, 0x12090, data);
++              } else { /* AST2400 */
++                      data = ast_read32(ast, 0x12088);
++                      /* multi-pins for DVO single-edge */
++                      data |= 0x30000000;
++                      ast_write32(ast, 0x12088, data);
++
++                      data = ast_read32(ast, 0x1208c);
++                      /* multi-pins for DVO single-edge */
++                      data |= 0x000000cf;
++                      ast_write32(ast, 0x1208c, data);
++
++                      data = ast_read32(ast, 0x120a4);
++                      /* multi-pins for DVO single-edge */
++                      data |= 0xffff0000;
++                      ast_write32(ast, 0x120a4, data);
++
++                      data = ast_read32(ast, 0x120a8);
++                      /* multi-pins for DVO single-edge */
++                      data |= 0x0000000f;
++                      ast_write32(ast, 0x120a8, data);
++
++                      data = ast_read32(ast, 0x12094);
++                      /* multi-pins for DVO single-edge */
++                      data |= 0x00000002;
++                      ast_write32(ast, 0x12094, data);
++              }
++      }
++
++      /* Force to DVO */
++      data = ast_read32(ast, 0x1202c);
++      data &= 0xfffbffff;
++      ast_write32(ast, 0x1202c, data);
++
++      /* Init VGA DVO Settings */
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80);
++      return true;
++}
++
++
++static void ast_init_analog(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u32 data;
++
++      /*
++       * Set DAC source to VGA mode in SCU2C via the P2A
++       * bridge. First configure the P2U to target the SCU
++       * in case it isn't at this stage.
++       */
++      ast_write32(ast, 0xf004, 0x1e6e0000);
++      ast_write32(ast, 0xf000, 0x1);
++
++      /* Then unlock the SCU with the magic password */
++      ast_write32(ast, 0x12000, 0x1688a8a8);
++      ast_write32(ast, 0x12000, 0x1688a8a8);
++      ast_write32(ast, 0x12000, 0x1688a8a8);
++
++      /* Finally, clear bits [17:16] of SCU2c */
++      data = ast_read32(ast, 0x1202c);
++      data &= 0xfffcffff;
++      ast_write32(ast, 0, data);
++
++      /* Disable DVO */
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x00);
++}
++
++void ast_init_3rdtx(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u8 jreg;
++
++      if (ast->chip == AST2300 || ast->chip == AST2400) {
++              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 
0xff);
++              switch (jreg & 0x0e) {
++              case 0x04:
++                      ast_init_dvo(dev);
++                      break;
++              case 0x08:
++                      ast_launch_m68k(dev);
++                      break;
++              case 0x0c:
++                      ast_init_dvo(dev);
++                      break;
++              default:
++                      if (ast->tx_chip_type == AST_TX_SIL164)
++                              ast_init_dvo(dev);
++                      else
++                              ast_init_analog(dev);
++              }
++      }
++}
+diff --git a/src/drivers/aspeed/common/ast_dram_tables.h 
b/src/drivers/aspeed/common/ast_dram_tables.h
+new file mode 100644
+index 0000000..4884cba
+--- /dev/null
++++ b/src/drivers/aspeed/common/ast_dram_tables.h
+@@ -0,0 +1,165 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * File taken from the Linux ast driver (v3.18.5)
++ * Coreboot-specific includes added at top and/or contents modified
++ * as needed to function within the coreboot environment.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc.
++ */
++
++#ifndef AST_DRAM_TABLES_H
++#define AST_DRAM_TABLES_H
++
++/* DRAM timing tables */
++struct ast_dramstruct {
++      u16 index;
++      u32 data;
++};
++
++static const struct ast_dramstruct ast2000_dram_table_data[] = {
++      { 0x0108, 0x00000000 },
++      { 0x0120, 0x00004a21 },
++      { 0xFF00, 0x00000043 },
++      { 0x0000, 0xFFFFFFFF },
++      { 0x0004, 0x00000089 },
++      { 0x0008, 0x22331353 },
++      { 0x000C, 0x0d07000b },
++      { 0x0010, 0x11113333 },
++      { 0x0020, 0x00110350 },
++      { 0x0028, 0x1e0828f0 },
++      { 0x0024, 0x00000001 },
++      { 0x001C, 0x00000000 },
++      { 0x0014, 0x00000003 },
++      { 0xFF00, 0x00000043 },
++      { 0x0018, 0x00000131 },
++      { 0x0014, 0x00000001 },
++      { 0xFF00, 0x00000043 },
++      { 0x0018, 0x00000031 },
++      { 0x0014, 0x00000001 },
++      { 0xFF00, 0x00000043 },
++      { 0x0028, 0x1e0828f1 },
++      { 0x0024, 0x00000003 },
++      { 0x002C, 0x1f0f28fb },
++      { 0x0030, 0xFFFFFE01 },
++      { 0xFFFF, 0xFFFFFFFF }
++};
++
++static const struct ast_dramstruct ast1100_dram_table_data[] = {
++      { 0x2000, 0x1688a8a8 },
++      { 0x2020, 0x000041f0 },
++      { 0xFF00, 0x00000043 },
++      { 0x0000, 0xfc600309 },
++      { 0x006C, 0x00909090 },
++      { 0x0064, 0x00050000 },
++      { 0x0004, 0x00000585 },
++      { 0x0008, 0x0011030f },
++      { 0x0010, 0x22201724 },
++      { 0x0018, 0x1e29011a },
++      { 0x0020, 0x00c82222 },
++      { 0x0014, 0x01001523 },
++      { 0x001C, 0x1024010d },
++      { 0x0024, 0x00cb2522 },
++      { 0x0038, 0xffffff82 },
++      { 0x003C, 0x00000000 },
++      { 0x0040, 0x00000000 },
++      { 0x0044, 0x00000000 },
++      { 0x0048, 0x00000000 },
++      { 0x004C, 0x00000000 },
++      { 0x0050, 0x00000000 },
++      { 0x0054, 0x00000000 },
++      { 0x0058, 0x00000000 },
++      { 0x005C, 0x00000000 },
++      { 0x0060, 0x032aa02a },
++      { 0x0064, 0x002d3000 },
++      { 0x0068, 0x00000000 },
++      { 0x0070, 0x00000000 },
++      { 0x0074, 0x00000000 },
++      { 0x0078, 0x00000000 },
++      { 0x007C, 0x00000000 },
++      { 0x0034, 0x00000001 },
++      { 0xFF00, 0x00000043 },
++      { 0x002C, 0x00000732 },
++      { 0x0030, 0x00000040 },
++      { 0x0028, 0x00000005 },
++      { 0x0028, 0x00000007 },
++      { 0x0028, 0x00000003 },
++      { 0x0028, 0x00000001 },
++      { 0x000C, 0x00005a08 },
++      { 0x002C, 0x00000632 },
++      { 0x0028, 0x00000001 },
++      { 0x0030, 0x000003c0 },
++      { 0x0028, 0x00000003 },
++      { 0x0030, 0x00000040 },
++      { 0x0028, 0x00000003 },
++      { 0x000C, 0x00005a21 },
++      { 0x0034, 0x00007c03 },
++      { 0x0120, 0x00004c41 },
++      { 0xffff, 0xffffffff },
++};
++
++static const struct ast_dramstruct ast2100_dram_table_data[] = {
++      { 0x2000, 0x1688a8a8 },
++      { 0x2020, 0x00004120 },
++      { 0xFF00, 0x00000043 },
++      { 0x0000, 0xfc600309 },
++      { 0x006C, 0x00909090 },
++      { 0x0064, 0x00070000 },
++      { 0x0004, 0x00000489 },
++      { 0x0008, 0x0011030f },
++      { 0x0010, 0x32302926 },
++      { 0x0018, 0x274c0122 },
++      { 0x0020, 0x00ce2222 },
++      { 0x0014, 0x01001523 },
++      { 0x001C, 0x1024010d },
++      { 0x0024, 0x00cb2522 },
++      { 0x0038, 0xffffff82 },
++      { 0x003C, 0x00000000 },
++      { 0x0040, 0x00000000 },
++      { 0x0044, 0x00000000 },
++      { 0x0048, 0x00000000 },
++      { 0x004C, 0x00000000 },
++      { 0x0050, 0x00000000 },
++      { 0x0054, 0x00000000 },
++      { 0x0058, 0x00000000 },
++      { 0x005C, 0x00000000 },
++      { 0x0060, 0x0f2aa02a },
++      { 0x0064, 0x003f3005 },
++      { 0x0068, 0x02020202 },
++      { 0x0070, 0x00000000 },
++      { 0x0074, 0x00000000 },
++      { 0x0078, 0x00000000 },
++      { 0x007C, 0x00000000 },
++      { 0x0034, 0x00000001 },
++      { 0xFF00, 0x00000043 },
++      { 0x002C, 0x00000942 },
++      { 0x0030, 0x00000040 },
++      { 0x0028, 0x00000005 },
++      { 0x0028, 0x00000007 },
++      { 0x0028, 0x00000003 },
++      { 0x0028, 0x00000001 },
++      { 0x000C, 0x00005a08 },
++      { 0x002C, 0x00000842 },
++      { 0x0028, 0x00000001 },
++      { 0x0030, 0x000003c0 },
++      { 0x0028, 0x00000003 },
++      { 0x0030, 0x00000040 },
++      { 0x0028, 0x00000003 },
++      { 0x000C, 0x00005a21 },
++      { 0x0034, 0x00007c03 },
++      { 0x0120, 0x00005061 },
++      { 0xffff, 0xffffffff },
++};
++
++#endif
+diff --git a/src/drivers/aspeed/common/ast_drv.h 
b/src/drivers/aspeed/common/ast_drv.h
+new file mode 100644
+index 0000000..53640f1
+--- /dev/null
++++ b/src/drivers/aspeed/common/ast_drv.h
+@@ -0,0 +1,223 @@
++/*
++ * Copyright 2012 Red Hat Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the
++ * "Software"), to deal in the Software without restriction, including
++ * without limitation the rights to use, copy, modify, merge, publish,
++ * distribute, sub license, and/or sell copies of the Software, and to
++ * permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY 
CLAIM,
++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
++ * USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * The above copyright notice and this permission notice (including the
++ * next paragraph) shall be included in all copies or substantial portions
++ * of the Software.
++ *
++ */
++/*
++ * Authors: Dave Airlie <address@hidden>
++ */
++#ifndef __AST_DRV_H__
++#define __AST_DRV_H__
++
++#include "aspeed_coreboot.h"
++
++#define PCI_CHIP_AST2000 0x2000
++#define PCI_CHIP_AST2100 0x2010
++#define PCI_CHIP_AST1180 0x1180
++
++
++enum ast_chip {
++      AST2000,
++      AST2100,
++      AST1100,
++      AST2200,
++      AST2150,
++      AST2300,
++      AST2400,
++      AST1180,
++};
++
++enum ast_tx_chip {
++      AST_TX_NONE,
++      AST_TX_SIL164,
++      AST_TX_ITE66121,
++      AST_TX_DP501,
++};
++
++#define AST_DRAM_512Mx16 0
++#define AST_DRAM_1Gx16   1
++#define AST_DRAM_512Mx32 2
++#define AST_DRAM_1Gx32   3
++#define AST_DRAM_2Gx16   6
++#define AST_DRAM_4Gx16   7
++
++struct ast_fbdev;
++
++struct ast_private {
++      struct drm_device *dev;
++
++      void __iomem *regs;
++      void __iomem *ioregs;
++      bool io_space_uses_mmap;
++
++      enum ast_chip chip;
++      bool vga2_clone;
++      uint32_t dram_bus_width;
++      uint32_t dram_type;
++      uint32_t mclk;
++      uint32_t vram_size;
++
++      struct ast_fbdev *fbdev;
++
++      int fb_mtrr;
++
++      struct drm_gem_object *cursor_cache;
++      uint64_t cursor_cache_gpu_addr;
++
++      int next_cursor;
++      bool support_wide_screen;
++
++      enum ast_tx_chip tx_chip_type;
++      u8 dp501_maxclk;
++      u8 *dp501_fw_addr;
++      const struct firmware *dp501_fw;        /* dp501 fw */
++};
++
++int ast_driver_load(struct drm_device *dev, unsigned long flags);
++int ast_driver_unload(struct drm_device *dev);
++
++#define AST_IO_AR_PORT_WRITE          (0x40)
++#define AST_IO_MISC_PORT_WRITE                (0x42)
++#define AST_IO_VGA_ENABLE_PORT                (0x43)
++#define AST_IO_SEQ_PORT                       (0x44)
++#define AST_IO_DAC_INDEX_READ         (0x47)
++#define AST_IO_DAC_INDEX_WRITE                (0x48)
++#define AST_IO_DAC_DATA                       (0x49)
++#define AST_IO_GR_PORT                        (0x4E)
++#define AST_IO_CRTC_PORT              (0x54)
++#define AST_IO_INPUT_STATUS1_READ     (0x5A)
++#define AST_IO_MISC_PORT_READ         (0x4C)
++
++#define AST_IO_MM_OFFSET              (0x380)
++
++#define __ast_read(x) \
++static inline u##x ast_read##x(struct ast_private *ast, u32 reg) { \
++u##x val = 0;\
++val = ioread##x(ast->regs + reg); \
++return val;\
++}
++
++__ast_read(8);
++__ast_read(16);
++__ast_read(32)
++
++#define __ast_io_read(x) \
++static inline u##x ast_io_read##x(struct ast_private *ast, u32 reg) { \
++u##x val = 0;\
++if (ast->io_space_uses_mmap) \
++val = ioread##x(ast->regs + reg); \
++else \
++val = ioread_cbio##x(ast->ioregs + reg); \
++return val;\
++}
++
++__ast_io_read(8);
++__ast_io_read(16);
++__ast_io_read(32);
++
++#define __ast_write(x) \
++static inline void ast_write##x(struct ast_private *ast, u32 reg, u##x val) {\
++      iowrite##x(val, ast->regs + reg);\
++      }
++
++__ast_write(8);
++__ast_write(16);
++__ast_write(32);
++
++#define __ast_io_write(x) \
++static inline void ast_io_write##x(struct ast_private *ast, u32 reg, u##x 
val) {\
++      if (ast->io_space_uses_mmap) \
++      iowrite##x(val, ast->regs + reg);\
++      else \
++      iowrite_cbio##x(val, ast->ioregs + reg);\
++      }
++
++__ast_io_write(8);
++__ast_io_write(16);
++#undef __ast_io_write
++
++static inline void ast_set_index_reg(struct ast_private *ast,
++                                   uint32_t base, uint8_t index,
++                                   uint8_t val)
++{
++      ast_io_write16(ast, base, ((u16)val << 8) | index);
++}
++
++void ast_set_index_reg_mask(struct ast_private *ast,
++                          uint32_t base, uint8_t index,
++                          uint8_t mask, uint8_t val);
++uint8_t ast_get_index_reg(struct ast_private *ast,
++                        uint32_t base, uint8_t index);
++uint8_t ast_get_index_reg_mask(struct ast_private *ast,
++                             uint32_t base, uint8_t index, uint8_t mask);
++
++static inline void ast_open_key(struct ast_private *ast)
++{
++      ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x80, 0xA8);
++}
++
++#define AST_VIDMEM_SIZE_8M    0x00800000
++#define AST_VIDMEM_SIZE_16M   0x01000000
++#define AST_VIDMEM_SIZE_32M   0x02000000
++#define AST_VIDMEM_SIZE_64M   0x04000000
++#define AST_VIDMEM_SIZE_128M  0x08000000
++
++#define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M
++
++#define AST_MAX_HWC_WIDTH 64
++#define AST_MAX_HWC_HEIGHT 64
++
++#define AST_HWC_SIZE                (AST_MAX_HWC_WIDTH*AST_MAX_HWC_HEIGHT*2)
++#define AST_HWC_SIGNATURE_SIZE      32
++
++#define AST_DEFAULT_HWC_NUM 2
++/* define for signature structure */
++#define AST_HWC_SIGNATURE_CHECKSUM  0x00
++#define AST_HWC_SIGNATURE_SizeX     0x04
++#define AST_HWC_SIGNATURE_SizeY     0x08
++#define AST_HWC_SIGNATURE_X         0x0C
++#define AST_HWC_SIGNATURE_Y         0x10
++#define AST_HWC_SIGNATURE_HOTSPOTX  0x14
++#define AST_HWC_SIGNATURE_HOTSPOTY  0x18
++
++#define AST_MM_ALIGN_SHIFT 4
++#define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1)
++
++#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
++
++/* ast post */
++void ast_enable_vga(struct drm_device *dev);
++void ast_enable_mmio(struct drm_device *dev);
++bool ast_is_vga_enabled(struct drm_device *dev);
++void ast_post_gpu(struct drm_device *dev);
++u32 ast_mindwm(struct ast_private *ast, u32 r);
++void ast_moutdwm(struct ast_private *ast, u32 r, u32 v);
++/* ast dp501 */
++int ast_load_dp501_microcode(struct drm_device *dev);
++void ast_set_dp501_video_output(struct drm_device *dev, u8 mode);
++bool ast_launch_m68k(struct drm_device *dev);
++bool ast_backup_fw(struct drm_device *dev, u8 *addr, u32 size);
++bool ast_dp501_read_edid(struct drm_device *dev, u8 *ediddata);
++u8 ast_get_dp501_max_clk(struct drm_device *dev);
++void ast_init_3rdtx(struct drm_device *dev);
++#endif
+diff --git a/src/drivers/aspeed/common/ast_main.c 
b/src/drivers/aspeed/common/ast_main.c
+new file mode 100644
+index 0000000..2939442
+--- /dev/null
++++ b/src/drivers/aspeed/common/ast_main.c
+@@ -0,0 +1,393 @@
++/*
++ * Copyright 2012 Red Hat Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the
++ * "Software"), to deal in the Software without restriction, including
++ * without limitation the rights to use, copy, modify, merge, publish,
++ * distribute, sub license, and/or sell copies of the Software, and to
++ * permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY 
CLAIM,
++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
++ * USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * The above copyright notice and this permission notice (including the
++ * next paragraph) shall be included in all copies or substantial portions
++ * of the Software.
++ *
++ */
++/*
++ * Authors: Dave Airlie <address@hidden>
++ */
++#include "ast_drv.h"
++
++#include "ast_dram_tables.h"
++
++void ast_set_index_reg_mask(struct ast_private *ast,
++                          uint32_t base, uint8_t index,
++                          uint8_t mask, uint8_t val)
++{
++      u8 tmp;
++      ast_io_write8(ast, base, index);
++      tmp = (ast_io_read8(ast, base + 1) & mask) | val;
++      ast_set_index_reg(ast, base, index, tmp);
++}
++
++uint8_t ast_get_index_reg(struct ast_private *ast,
++                        uint32_t base, uint8_t index)
++{
++      uint8_t ret;
++      ast_io_write8(ast, base, index);
++      ret = ast_io_read8(ast, base + 1);
++      return ret;
++}
++
++uint8_t ast_get_index_reg_mask(struct ast_private *ast,
++                             uint32_t base, uint8_t index, uint8_t mask)
++{
++      uint8_t ret;
++      ast_io_write8(ast, base, index);
++      ret = ast_io_read8(ast, base + 1) & mask;
++      return ret;
++}
++
++
++static int ast_detect_chip(struct drm_device *dev, bool *need_post)
++{
++      struct ast_private *ast = dev->dev_private;
++      uint32_t data, jreg;
++      ast_open_key(ast);
++
++      if (dev->pdev->device == PCI_CHIP_AST1180) {
++              ast->chip = AST1100;
++              DRM_INFO("AST 1180 detected\n");
++      } else {
++              pci_read_config_dword(ast->dev->pdev, 0x08, &data);
++              uint8_t revision = data & 0xff;
++
++              if (revision >= 0x30) {
++                      ast->chip = AST2400;
++                      DRM_INFO("AST 2400 detected\n");
++              } else if (revision >= 0x20) {
++                      ast->chip = AST2300;
++                      DRM_INFO("AST 2300 detected\n");
++              } else if (revision >= 0x10) {
++                      ast_write32(ast, 0xf004, 0x1e6e0000);
++                      ast_write32(ast, 0xf000, 0x1);
++
++                      data = ast_read32(ast, 0x1207c);
++                      switch (data & 0x0300) {
++                      case 0x0200:
++                              ast->chip = AST1100;
++                              DRM_INFO("AST 1100 detected\n");
++                              break;
++                      case 0x0100:
++                              ast->chip = AST2200;
++                              DRM_INFO("AST 2200 detected\n");
++                              break;
++                      case 0x0000:
++                              ast->chip = AST2150;
++                              DRM_INFO("AST 2150 detected\n");
++                              break;
++                      default:
++                              ast->chip = AST2100;
++                              DRM_INFO("AST 2100 detected\n");
++                              break;
++                      }
++                      ast->vga2_clone = false;
++              } else {
++                      ast->chip = AST2000;
++                      DRM_INFO("AST 2000 detected\n");
++              }
++      }
++
++      /*
++       * If VGA isn't enabled, we need to enable now or subsequent
++       * access to the scratch registers will fail. We also inform
++       * our caller that it needs to POST the chip
++       * (Assumption: VGA not enabled -> need to POST)
++       */
++      if (!ast_is_vga_enabled(dev)) {
++              ast_enable_vga(dev);
++              ast_enable_mmio(dev);
++              DRM_INFO("VGA not enabled on entry, requesting chip POST\n");
++              *need_post = true;
++      } else
++              *need_post = false;
++
++      /* Check if we support wide screen */
++      switch (ast->chip) {
++      case AST1180:
++              ast->support_wide_screen = true;
++              break;
++      case AST2000:
++              ast->support_wide_screen = false;
++              break;
++      default:
++              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 
0xff);
++              if (!(jreg & 0x80))
++                      ast->support_wide_screen = true;
++              else if (jreg & 0x01)
++                      ast->support_wide_screen = true;
++              else {
++                      ast->support_wide_screen = false;
++                      /* Read SCU7c (silicon revision register) */
++                      ast_write32(ast, 0xf004, 0x1e6e0000);
++                      ast_write32(ast, 0xf000, 0x1);
++                      data = ast_read32(ast, 0x1207c);
++                      data &= 0x300;
++                      if (ast->chip == AST2300 && data == 0x0) /* ast1300 */
++                              ast->support_wide_screen = true;
++                      if (ast->chip == AST2400 && data == 0x100) /* ast1400 */
++                              ast->support_wide_screen = true;
++              }
++              break;
++      }
++
++      /* Check 3rd Tx option (digital output afaik) */
++      ast->tx_chip_type = AST_TX_NONE;
++
++      /*
++       * VGACRA3 Enhanced Color Mode Register, check if DVO is already
++       * enabled, in that case, assume we have a SIL164 TMDS transmitter
++       *
++       * Don't make that assumption if we the chip wasn't enabled and
++       * is at power-on reset, otherwise we'll incorrectly "detect" a
++       * SIL164 when there is none.
++       */
++      if (!*need_post) {
++              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 
0xff);
++              if (jreg & 0x80)
++                      ast->tx_chip_type = AST_TX_SIL164;
++      }
++
++      if ((ast->chip == AST2300) || (ast->chip == AST2400)) {
++              /*
++               * On AST2300 and 2400, look the configuration set by the SoC in
++               * the SOC scratch register #1 bits 11:8 (interestingly marked
++               * as "reserved" in the spec)
++               */
++              jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd1, 
0xff);
++              switch (jreg) {
++              case 0x04:
++                      ast->tx_chip_type = AST_TX_SIL164;
++                      break;
++              case 0x08:
++                      ast->dp501_fw_addr = kzalloc(32*1024, GFP_KERNEL);
++                      if (ast->dp501_fw_addr) {
++                              /* backup firmware */
++                              if (ast_backup_fw(dev, ast->dp501_fw_addr, 
32*1024)) {
++                                      kfree(ast->dp501_fw_addr);
++                                      ast->dp501_fw_addr = NULL;
++                              }
++                      }
++                      /* fallthrough */
++              case 0x0c:
++                      ast->tx_chip_type = AST_TX_DP501;
++              }
++      }
++
++      /* Print stuff for diagnostic purposes */
++      switch(ast->tx_chip_type) {
++      case AST_TX_SIL164:
++              DRM_INFO("Using Sil164 TMDS transmitter\n");
++              break;
++      case AST_TX_DP501:
++              DRM_INFO("Using DP501 DisplayPort transmitter\n");
++              break;
++      default:
++              DRM_INFO("Analog VGA only\n");
++      }
++      return 0;
++}
++
++static int ast_get_dram_info(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      uint8_t i;
++      uint32_t data, data2;
++      uint32_t denum, num, div, ref_pll;
++
++      ast_write32(ast, 0xf004, 0x1e6e0000);
++      ast_write32(ast, 0xf000, 0x1);
++
++
++      ast_write32(ast, 0x10000, 0xfc600309);
++
++      /* Wait up to 2.5 seconds for device initialization / register unlock */
++      for (i = 0; i < 250; i++) {
++              if (ast_read32(ast, 0x10000) == 0x01)
++                      break;
++              mdelay(10);
++      }
++      if (ast_read32(ast, 0x10000) != 0x01)
++              dev_err(dev->pdev, "Unable to unlock SDRAM control 
registers\n");
++
++      data = ast_read32(ast, 0x10004);
++
++      if (data & 0x400)
++              ast->dram_bus_width = 16;
++      else
++              ast->dram_bus_width = 32;
++
++      if (ast->chip == AST2300 || ast->chip == AST2400) {
++              switch (data & 0x03) {
++              case 0:
++                      ast->dram_type = AST_DRAM_512Mx16;
++                      break;
++              default:
++              case 1:
++                      ast->dram_type = AST_DRAM_1Gx16;
++                      break;
++              case 2:
++                      ast->dram_type = AST_DRAM_2Gx16;
++                      break;
++              case 3:
++                      ast->dram_type = AST_DRAM_4Gx16;
++                      break;
++              }
++      } else {
++              switch (data & 0x0c) {
++              case 0:
++              case 4:
++                      ast->dram_type = AST_DRAM_512Mx16;
++                      break;
++              case 8:
++                      if (data & 0x40)
++                              ast->dram_type = AST_DRAM_1Gx16;
++                      else
++                              ast->dram_type = AST_DRAM_512Mx32;
++                      break;
++              case 0xc:
++                      ast->dram_type = AST_DRAM_1Gx32;
++                      break;
++              }
++      }
++
++      data = ast_read32(ast, 0x10120);
++      data2 = ast_read32(ast, 0x10170);
++      if (data2 & 0x2000)
++              ref_pll = 14318;
++      else
++              ref_pll = 12000;
++
++      denum = data & 0x1f;
++      num = (data & 0x3fe0) >> 5;
++      data = (data & 0xc000) >> 14;
++      switch (data) {
++      case 3:
++              div = 0x4;
++              break;
++      case 2:
++      case 1:
++              div = 0x2;
++              break;
++      default:
++              div = 0x1;
++              break;
++      }
++      ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
++      return 0;
++}
++
++static u32 ast_get_vram_info(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u8 jreg;
++      u32 vram_size;
++      ast_open_key(ast);
++
++      vram_size = AST_VIDMEM_DEFAULT_SIZE;
++      jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
++      switch (jreg & 3) {
++      case 0: vram_size = AST_VIDMEM_SIZE_8M; break;
++      case 1: vram_size = AST_VIDMEM_SIZE_16M; break;
++      case 2: vram_size = AST_VIDMEM_SIZE_32M; break;
++      case 3: vram_size = AST_VIDMEM_SIZE_64M; break;
++      }
++
++      return vram_size;
++}
++
++int ast_driver_load(struct drm_device *dev, unsigned long flags)
++{
++      struct ast_private *ast;
++      bool need_post;
++      int ret = 0;
++      struct resource *res;
++
++      ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
++      if (!ast)
++              return -ENOMEM;
++
++      dev->dev_private = ast;
++      ast->dev = dev;
++
++      /* PCI BAR 1 */
++        res = find_resource(dev->pdev, 0x14);
++      if (!res) {
++              dev_err(dev->pdev, "BAR1 resource not found.\n");
++              ret = -EIO;
++              goto out_free;
++      }
++      ast->regs = res2mmio(res, 0, 0);
++      if (!ast->regs) {
++              ret = -EIO;
++              goto out_free;
++      }
++
++      /* PCI BAR 2 */
++      ast->io_space_uses_mmap = false;
++      res = find_resource(dev->pdev, 0x18);
++      if (!res) {
++              dev_err(dev->pdev, "BAR2 resource not found.\n");
++              ret = -EIO;
++              goto out_free;
++      }
++
++      /*
++       * If we don't have IO space at all, use MMIO now and
++       * assume the chip has MMIO enabled by default (rev 0x20
++       * and higher).
++       */
++      if (!(res->flags & IORESOURCE_IO)) {
++              DRM_INFO("platform has no IO space, trying MMIO\n");
++              ast->ioregs = ast->regs + AST_IO_MM_OFFSET;
++              ast->io_space_uses_mmap = true;
++      }
++
++      /* "map" IO regs if the above hasn't done so already */
++      if (!ast->ioregs) {
++              ast->ioregs = res2mmio(res, 0, 0);
++              if (!ast->ioregs) {
++                      ret = -EIO;
++                      goto out_free;
++              }
++              /* Adjust the I/O space location to match expectations (the 
code expects offset 0x0 to be I/O location 0x380) */
++              ast->ioregs = (void *)AST_IO_MM_OFFSET;
++      }
++
++      ast_detect_chip(dev, &need_post);
++
++      if (ast->chip != AST1180) {
++              ast_get_dram_info(dev);
++              ast->vram_size = ast_get_vram_info(dev);
++              DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, 
ast->dram_bus_width, ast->vram_size);
++      }
++
++      if (need_post)
++              ast_post_gpu(dev);
++
++      return 0;
++out_free:
++      kfree(ast);
++      dev->dev_private = NULL;
++      return ret;
++}
+diff --git a/src/drivers/aspeed/common/ast_post.c 
b/src/drivers/aspeed/common/ast_post.c
+new file mode 100644
+index 0000000..7d31845
+--- /dev/null
++++ b/src/drivers/aspeed/common/ast_post.c
+@@ -0,0 +1,1679 @@
++/*
++ * Copyright 2012 Red Hat Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the
++ * "Software"), to deal in the Software without restriction, including
++ * without limitation the rights to use, copy, modify, merge, publish,
++ * distribute, sub license, and/or sell copies of the Software, and to
++ * permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY 
CLAIM,
++ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
++ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
++ * USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * The above copyright notice and this permission notice (including the
++ * next paragraph) shall be included in all copies or substantial portions
++ * of the Software.
++ *
++ */
++/*
++ * Authors: Dave Airlie <address@hidden>
++ */
++
++#include "ast_drv.h"
++
++#include "ast_dram_tables.h"
++
++static void ast_init_dram_2300(struct drm_device *dev);
++
++void ast_enable_vga(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++
++      ast_io_write8(ast, AST_IO_VGA_ENABLE_PORT, 0x01);
++      ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, 0x01);
++}
++
++void ast_enable_mmio(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04);
++}
++
++
++bool ast_is_vga_enabled(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u8 ch;
++
++      if (ast->chip == AST1180) {
++              /* TODO 1180 */
++      } else {
++              ch = ast_io_read8(ast, AST_IO_VGA_ENABLE_PORT);
++              if (ch) {
++                      ast_open_key(ast);
++                      ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 
0xb6, 0xff);
++                      return ch & 0x04;
++              }
++      }
++      return 0;
++}
++
++static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
++static const u8 extreginfo_ast2300a0[] = { 0x0f, 0x04, 0x1c, 0xff };
++static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff };
++
++static void
++ast_set_def_ext_reg(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u8 i, index, reg;
++      uint32_t data;
++      const u8 *ext_reg_info;
++
++      pci_read_config_dword(ast->dev->pdev, 0x08, &data);
++      uint8_t revision = data & 0xff;
++
++      /* reset scratch */
++      for (i = 0x81; i <= 0x8f; i++)
++              ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, 0x00);
++
++      if (ast->chip == AST2300 || ast->chip == AST2400) {
++              if (revision >= 0x20)
++                      ext_reg_info = extreginfo_ast2300;
++              else
++                      ext_reg_info = extreginfo_ast2300a0;
++      } else
++              ext_reg_info = extreginfo;
++
++      index = 0xa0;
++      while (*ext_reg_info != 0xff) {
++              ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, index, 0x00, 
*ext_reg_info);
++              index++;
++              ext_reg_info++;
++      }
++
++      /* disable standard IO/MEM decode if secondary */
++      /* ast_set_index_reg-mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x3); */
++
++      /* Set Ext. Default */
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x8c, 0x00, 0x01);
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x00, 0x00);
++
++      /* Enable RAMDAC for A1 */
++      reg = 0x04;
++      if (ast->chip == AST2300 || ast->chip == AST2400)
++              reg |= 0x20;
++      ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff, reg);
++}
++
++u32 ast_mindwm(struct ast_private *ast, u32 r)
++{
++      uint32_t data;
++
++      ast_write32(ast, 0xf004, r & 0xffff0000);
++      ast_write32(ast, 0xf000, 0x1);
++
++      do {
++              data = ast_read32(ast, 0xf004) & 0xffff0000;
++      } while (data != (r & 0xffff0000));
++      return ast_read32(ast, 0x10000 + (r & 0x0000ffff));
++}
++
++void ast_moutdwm(struct ast_private *ast, u32 r, u32 v)
++{
++      uint32_t data;
++      ast_write32(ast, 0xf004, r & 0xffff0000);
++      ast_write32(ast, 0xf000, 0x1);
++      do {
++              data = ast_read32(ast, 0xf004) & 0xffff0000;
++      } while (data != (r & 0xffff0000));
++      ast_write32(ast, 0x10000 + (r & 0x0000ffff), v);
++}
++
++/*
++ * AST2100/2150 DLL CBR Setting
++ */
++#define CBR_SIZE_AST2150           ((16 << 10) - 1)
++#define CBR_PASSNUM_AST2150          5
++#define CBR_THRESHOLD_AST2150        10
++#define CBR_THRESHOLD2_AST2150       10
++#define TIMEOUT_AST2150              5000000
++
++#define CBR_PATNUM_AST2150           8
++
++static const u32 pattern_AST2150[14] = {
++      0xFF00FF00,
++      0xCC33CC33,
++      0xAA55AA55,
++      0xFFFE0001,
++      0x683501FE,
++      0x0F1929B0,
++      0x2D0B4346,
++      0x60767F02,
++      0x6FBE36A6,
++      0x3A253035,
++      0x3019686D,
++      0x41C6167E,
++      0x620152BF,
++      0x20F050E0
++};
++
++static u32 mmctestburst2_ast2150(struct ast_private *ast, u32 datagen)
++{
++      u32 data, timeout;
++
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3));
++      timeout = 0;
++      do {
++              data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
++              if (++timeout > TIMEOUT_AST2150) {
++                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++                      return 0xffffffff;
++              }
++      } while (!data);
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3));
++      timeout = 0;
++      do {
++              data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
++              if (++timeout > TIMEOUT_AST2150) {
++                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++                      return 0xffffffff;
++              }
++      } while (!data);
++      data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      return data;
++}
++
++#if 0 /* unused in DDX driver - here for completeness */
++static u32 mmctestsingle2_ast2150(struct ast_private *ast, u32 datagen)
++{
++      u32 data, timeout;
++
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
++      timeout = 0;
++      do {
++              data = ast_mindwm(ast, 0x1e6e0070) & 0x40;
++              if (++timeout > TIMEOUT_AST2150) {
++                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++                      return 0xffffffff;
++              }
++      } while (!data);
++      data = (ast_mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      return data;
++}
++#endif
++
++static int cbrtest_ast2150(struct ast_private *ast)
++{
++      int i;
++
++      for (i = 0; i < 8; i++)
++              if (mmctestburst2_ast2150(ast, i))
++                      return 0;
++      return 1;
++}
++
++static int cbrscan_ast2150(struct ast_private *ast, int busw)
++{
++      u32 patcnt, loop;
++
++      for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) {
++              ast_moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]);
++              for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) {
++                      if (cbrtest_ast2150(ast))
++                              break;
++              }
++              if (loop == CBR_PASSNUM_AST2150)
++                      return 0;
++      }
++      return 1;
++}
++
++
++static void cbrdlli_ast2150(struct ast_private *ast, int busw)
++{
++      u32 dll_min[4], dll_max[4], dlli, data, passcnt;
++
++cbr_start:
++      dll_min[0] = dll_min[1] = dll_min[2] = dll_min[3] = 0xff;
++      dll_max[0] = dll_max[1] = dll_max[2] = dll_max[3] = 0x0;
++      passcnt = 0;
++
++      for (dlli = 0; dlli < 100; dlli++) {
++              ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) 
| (dlli << 24));
++              data = cbrscan_ast2150(ast, busw);
++              if (data != 0) {
++                      if (data & 0x1) {
++                              if (dll_min[0] > dlli)
++                                      dll_min[0] = dlli;
++                              if (dll_max[0] < dlli)
++                                      dll_max[0] = dlli;
++                      }
++                      passcnt++;
++              } else if (passcnt >= CBR_THRESHOLD_AST2150)
++                      goto cbr_start;
++      }
++      if (dll_max[0] == 0 || (dll_max[0]-dll_min[0]) < CBR_THRESHOLD_AST2150)
++              goto cbr_start;
++
++      dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4);
++      ast_moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli 
<< 24));
++}
++
++
++
++static void ast_init_dram_reg(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      u8 j;
++      u32 data, temp, i;
++      const struct ast_dramstruct *dram_reg_info;
++
++      j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
++
++      if ((j & 0x80) == 0) { /* VGA only */
++              if (ast->chip == AST2000) {
++                      dram_reg_info = ast2000_dram_table_data;
++                      ast_write32(ast, 0xf004, 0x1e6e0000);
++                      ast_write32(ast, 0xf000, 0x1);
++                      ast_write32(ast, 0x10100, 0xa8);
++
++                      do {
++                              ;
++                      } while (ast_read32(ast, 0x10100) != 0xa8);
++              } else {/* AST2100/1100 */
++                      if (ast->chip == AST2100 || ast->chip == 2200)
++                              dram_reg_info = ast2100_dram_table_data;
++                      else
++                              dram_reg_info = ast1100_dram_table_data;
++
++                      ast_write32(ast, 0xf004, 0x1e6e0000);
++                      ast_write32(ast, 0xf000, 0x1);
++                      ast_write32(ast, 0x12000, 0x1688A8A8);
++
++                      /* Wait up to 2.5 seconds for device initialization / 
register unlock */
++                      for (i = 0; i < 250; i++) {
++                              if (ast_read32(ast, 0x12000) == 0x01)
++                                      break;
++                              mdelay(10);
++                      }
++                      if (ast_read32(ast, 0x12000) != 0x01)
++                              dev_err(dev->pdev, "Unable to unlock SCU 
registers\n");
++
++                      ast_write32(ast, 0x10000, 0xfc600309);
++
++                      /* Wait up to 2.5 seconds for device initialization / 
register unlock */
++                      for (i = 0; i < 250; i++) {
++                              if (ast_read32(ast, 0x10000) == 0x01)
++                                      break;
++                              mdelay(10);
++                      }
++                      if (ast_read32(ast, 0x10000) != 0x01)
++                              dev_err(dev->pdev, "Unable to unlock SDRAM 
control registers\n");
++              }
++
++              while (dram_reg_info->index != 0xffff) {
++                      if (dram_reg_info->index == 0xff00) {/* delay fn */
++                              for (i = 0; i < 15; i++)
++                                      udelay(dram_reg_info->data);
++                      } else if (dram_reg_info->index == 0x4 && ast->chip != 
AST2000) {
++                              data = dram_reg_info->data;
++                              if (ast->dram_type == AST_DRAM_1Gx16)
++                                      data = 0x00000d89;
++                              else if (ast->dram_type == AST_DRAM_1Gx32)
++                                      data = 0x00000c8d;
++
++                              temp = ast_read32(ast, 0x12070);
++                              temp &= 0xc;
++                              temp <<= 2;
++                              ast_write32(ast, 0x10000 + 
dram_reg_info->index, data | temp);
++                      } else
++                              ast_write32(ast, 0x10000 + 
dram_reg_info->index, dram_reg_info->data);
++                      dram_reg_info++;
++              }
++
++              /* AST 2100/2150 DRAM calibration */
++              data = ast_read32(ast, 0x10120);
++              if (data == 0x5061) { /* 266Mhz */
++                      data = ast_read32(ast, 0x10004);
++                      if (data & 0x40)
++                              cbrdlli_ast2150(ast, 16); /* 16 bits */
++                      else
++                              cbrdlli_ast2150(ast, 32); /* 32 bits */
++              }
++
++              switch (ast->chip) {
++              case AST2000:
++                      temp = ast_read32(ast, 0x10140);
++                      ast_write32(ast, 0x10140, temp | 0x40);
++                      break;
++              case AST1100:
++              case AST2100:
++              case AST2200:
++              case AST2150:
++                      temp = ast_read32(ast, 0x1200c);
++                      ast_write32(ast, 0x1200c, temp & 0xfffffffd);
++                      temp = ast_read32(ast, 0x12040);
++                      ast_write32(ast, 0x12040, temp | 0x40);
++                      break;
++              default:
++                      break;
++              }
++      }
++
++      /* wait ready */
++      /* Wait up to 2.5 seconds for device to become ready */
++      for (i = 0; i < 250; i++) {
++              j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
++              mdelay(10);
++              if ((j & 0x40) != 0)
++                      break;
++      }
++      if ((j & 0x40) == 0)
++              dev_err(dev->pdev, "Timeout while waiting for device to signal 
ready\n");
++}
++
++void ast_post_gpu(struct drm_device *dev)
++{
++      u32 reg;
++      struct ast_private *ast = dev->dev_private;
++
++      pci_read_config_dword(ast->dev->pdev, 0x04, &reg);
++      reg |= 0x3;
++      pci_write_config_dword(ast->dev->pdev, 0x04, reg);
++
++      ast_enable_vga(dev);
++      ast_enable_mmio(dev);
++      ast_open_key(ast);
++      ast_set_def_ext_reg(dev);
++
++      if (ast->chip == AST2300 || ast->chip == AST2400)
++              ast_init_dram_2300(dev);
++      else
++              ast_init_dram_reg(dev);
++
++      ast_init_3rdtx(dev);
++}
++
++/* AST 2300 DRAM settings */
++#define AST_DDR3 0
++#define AST_DDR2 1
++
++struct ast2300_dram_param {
++      u32 dram_type;
++      u32 dram_chipid;
++      u32 dram_freq;
++      u32 vram_size;
++      u32 odt;
++      u32 wodt;
++      u32 rodt;
++      u32 dram_config;
++      u32 reg_PERIOD;
++      u32 reg_MADJ;
++      u32 reg_SADJ;
++      u32 reg_MRS;
++      u32 reg_EMRS;
++      u32 reg_AC1;
++      u32 reg_AC2;
++      u32 reg_DQSIC;
++      u32 reg_DRV;
++      u32 reg_IOZ;
++      u32 reg_DQIDLY;
++      u32 reg_FREQ;
++      u32 madj_max;
++      u32 dll2_finetune_step;
++};
++
++/*
++ * DQSI DLL CBR Setting
++ */
++#define CBR_SIZE0            ((1  << 10) - 1)
++#define CBR_SIZE1            ((4  << 10) - 1)
++#define CBR_SIZE2            ((64 << 10) - 1)
++#define CBR_PASSNUM          5
++#define CBR_PASSNUM2         5
++#define CBR_THRESHOLD        10
++#define CBR_THRESHOLD2       10
++#define TIMEOUT              5000000
++#define CBR_PATNUM           8
++
++static const u32 pattern[8] = {
++      0xFF00FF00,
++      0xCC33CC33,
++      0xAA55AA55,
++      0x88778877,
++      0x92CC4D6E,
++      0x543D3CDE,
++      0xF1E843C7,
++      0x7C61D253
++};
++
++static int mmc_test_burst(struct ast_private *ast, u32 datagen)
++{
++      u32 data, timeout;
++
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      ast_moutdwm(ast, 0x1e6e0070, 0x000000c1 | (datagen << 3));
++      timeout = 0;
++      do {
++              data = ast_mindwm(ast, 0x1e6e0070) & 0x3000;
++              if (data & 0x2000) {
++                      return 0;
++              }
++              if (++timeout > TIMEOUT) {
++                      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++                      return 0;
++              }
++      } while (!data);
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      return 1;
++}
++
++static int mmc_test_burst2(struct ast_private *ast, u32 datagen)
++{
++      u32 data, timeout;
++
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000041 | (datagen << 3));
++      timeout = 0;
++      do {
++              data = ast_mindwm(ast, 0x1e6e0070) & 0x1000;
++              if (++timeout > TIMEOUT) {
++                      ast_moutdwm(ast, 0x1e6e0070, 0x0);
++                      return -1;
++              }
++      } while (!data);
++      data = ast_mindwm(ast, 0x1e6e0078);
++      data = (data | (data >> 16)) & 0xffff;
++      ast_moutdwm(ast, 0x1e6e0070, 0x0);
++      return data;
++}
++
++static int mmc_test_single(struct ast_private *ast, u32 datagen)
++{
++      u32 data, timeout;
++
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      ast_moutdwm(ast, 0x1e6e0070, 0x000000c5 | (datagen << 3));
++      timeout = 0;
++      do {
++              data = ast_mindwm(ast, 0x1e6e0070) & 0x3000;
++              if (data & 0x2000)
++                      return 0;
++              if (++timeout > TIMEOUT) {
++                      ast_moutdwm(ast, 0x1e6e0070, 0x0);
++                      return 0;
++              }
++      } while (!data);
++      ast_moutdwm(ast, 0x1e6e0070, 0x0);
++      return 1;
++}
++
++static int mmc_test_single2(struct ast_private *ast, u32 datagen)
++{
++      u32 data, timeout;
++
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000000);
++      ast_moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
++      timeout = 0;
++      do {
++              data = ast_mindwm(ast, 0x1e6e0070) & 0x1000;
++              if (++timeout > TIMEOUT) {
++                      ast_moutdwm(ast, 0x1e6e0070, 0x0);
++                      return -1;
++              }
++      } while (!data);
++      data = ast_mindwm(ast, 0x1e6e0078);
++      data = (data | (data >> 16)) & 0xffff;
++      ast_moutdwm(ast, 0x1e6e0070, 0x0);
++      return data;
++}
++
++static int cbr_test(struct ast_private *ast)
++{
++      u32 data;
++      int i;
++      data = mmc_test_single2(ast, 0);
++      if ((data & 0xff) && (data & 0xff00))
++              return 0;
++      for (i = 0; i < 8; i++) {
++              data = mmc_test_burst2(ast, i);
++              if ((data & 0xff) && (data & 0xff00))
++                      return 0;
++      }
++      if (!data)
++              return 3;
++      else if (data & 0xff)
++              return 2;
++      return 1;
++}
++
++static int cbr_scan(struct ast_private *ast)
++{
++      u32 data, data2, patcnt, loop;
++
++      data2 = 3;
++      for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
++              ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
++              for (loop = 0; loop < CBR_PASSNUM2; loop++) {
++                      if ((data = cbr_test(ast)) != 0) {
++                              data2 &= data;
++                              if (!data2)
++                                      return 0;
++                              break;
++                      }
++              }
++              if (loop == CBR_PASSNUM2)
++                      return 0;
++      }
++      return data2;
++}
++
++static u32 cbr_test2(struct ast_private *ast)
++{
++      u32 data;
++
++      data = mmc_test_burst2(ast, 0);
++      if (data == 0xffff)
++              return 0;
++      data |= mmc_test_single2(ast, 0);
++      if (data == 0xffff)
++              return 0;
++
++      return ~data & 0xffff;
++}
++
++static u32 cbr_scan2(struct ast_private *ast)
++{
++      u32 data, data2, patcnt, loop;
++
++      data2 = 0xffff;
++      for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
++              ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
++              for (loop = 0; loop < CBR_PASSNUM2; loop++) {
++                      if ((data = cbr_test2(ast)) != 0) {
++                              data2 &= data;
++                              if (!data2)
++                                      return 0;
++                              break;
++                      }
++              }
++              if (loop == CBR_PASSNUM2)
++                      return 0;
++      }
++      return data2;
++}
++
++static u32 cbr_test3(struct ast_private *ast)
++{
++      if (!mmc_test_burst(ast, 0))
++              return 0;
++      if (!mmc_test_single(ast, 0))
++              return 0;
++      return 1;
++}
++
++static u32 cbr_scan3(struct ast_private *ast)
++{
++      u32 patcnt, loop;
++
++      for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
++              ast_moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
++              for (loop = 0; loop < 2; loop++) {
++                      if (cbr_test3(ast))
++                              break;
++              }
++              if (loop == 2)
++                      return 0;
++      }
++      return 1;
++}
++
++static bool finetuneDQI_L(struct ast_private *ast, struct ast2300_dram_param 
*param)
++{
++      u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, 
passcnt, retry = 0;
++      bool status = false;
++FINETUNE_START:
++      for (cnt = 0; cnt < 16; cnt++) {
++              dllmin[cnt] = 0xff;
++              dllmax[cnt] = 0x0;
++      }
++      passcnt = 0;
++      for (dlli = 0; dlli < 76; dlli++) {
++              ast_moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli 
<< 24));
++              ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE1);
++              data = cbr_scan2(ast);
++              if (data != 0) {
++                      mask = 0x00010001;
++                      for (cnt = 0; cnt < 16; cnt++) {
++                              if (data & mask) {
++                                      if (dllmin[cnt] > dlli) {
++                                              dllmin[cnt] = dlli;
++                                      }
++                                      if (dllmax[cnt] < dlli) {
++                                              dllmax[cnt] = dlli;
++                                      }
++                              }
++                              mask <<= 1;
++                      }
++                      passcnt++;
++              } else if (passcnt >= CBR_THRESHOLD2) {
++                      break;
++              }
++      }
++      gold_sadj[0] = 0x0;
++      passcnt = 0;
++      for (cnt = 0; cnt < 16; cnt++) {
++              if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) 
>= CBR_THRESHOLD2)) {
++                      gold_sadj[0] += dllmin[cnt];
++                      passcnt++;
++              }
++      }
++      if (retry++ > 10)
++              goto FINETUNE_DONE;
++      if (passcnt != 16) {
++              goto FINETUNE_START;
++      }
++      status = true;
++FINETUNE_DONE:
++      gold_sadj[0] = gold_sadj[0] >> 4;
++      gold_sadj[1] = gold_sadj[0];
++
++      data = 0;
++      for (cnt = 0; cnt < 8; cnt++) {
++              data >>= 3;
++              if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) 
>= CBR_THRESHOLD2)) {
++                      dlli = dllmin[cnt];
++                      if (gold_sadj[0] >= dlli) {
++                              dlli = ((gold_sadj[0] - dlli) * 19) >> 5;
++                              if (dlli > 3) {
++                                      dlli = 3;
++                              }
++                      } else {
++                              dlli = ((dlli - gold_sadj[0]) * 19) >> 5;
++                              if (dlli > 4) {
++                                      dlli = 4;
++                              }
++                              dlli = (8 - dlli) & 0x7;
++                      }
++                      data |= dlli << 21;
++              }
++      }
++      ast_moutdwm(ast, 0x1E6E0080, data);
++
++      data = 0;
++      for (cnt = 8; cnt < 16; cnt++) {
++              data >>= 3;
++              if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) 
>= CBR_THRESHOLD2)) {
++                      dlli = dllmin[cnt];
++                      if (gold_sadj[1] >= dlli) {
++                              dlli = ((gold_sadj[1] - dlli) * 19) >> 5;
++                              if (dlli > 3) {
++                                      dlli = 3;
++                              } else {
++                                      dlli = (dlli - 1) & 0x7;
++                              }
++                      } else {
++                              dlli = ((dlli - gold_sadj[1]) * 19) >> 5;
++                              dlli += 1;
++                              if (dlli > 4) {
++                                      dlli = 4;
++                              }
++                              dlli = (8 - dlli) & 0x7;
++                      }
++                      data |= dlli << 21;
++              }
++      }
++      ast_moutdwm(ast, 0x1E6E0084, data);
++      return status;
++} /* finetuneDQI_L */
++
++static void finetuneDQSI(struct ast_private *ast)
++{
++      u32 dlli, dqsip, dqidly;
++      u32 reg_mcr18, reg_mcr0c, passcnt[2], diff;
++      u32 g_dqidly, g_dqsip, g_margin, g_side;
++      u16 pass[32][2][2];
++      char tag[2][76];
++
++      /* Disable DQI CBR */
++      reg_mcr0c  = ast_mindwm(ast, 0x1E6E000C);
++      reg_mcr18  = ast_mindwm(ast, 0x1E6E0018);
++      reg_mcr18 &= 0x0000ffff;
++      ast_moutdwm(ast, 0x1E6E0018, reg_mcr18);
++
++      for (dlli = 0; dlli < 76; dlli++) {
++              tag[0][dlli] = 0x0;
++              tag[1][dlli] = 0x0;
++      }
++      for (dqidly = 0; dqidly < 32; dqidly++) {
++              pass[dqidly][0][0] = 0xff;
++              pass[dqidly][0][1] = 0x0;
++              pass[dqidly][1][0] = 0xff;
++              pass[dqidly][1][1] = 0x0;
++      }
++      for (dqidly = 0; dqidly < 32; dqidly++) {
++              passcnt[0] = passcnt[1] = 0;
++              for (dqsip = 0; dqsip < 2; dqsip++) {
++                      ast_moutdwm(ast, 0x1E6E000C, 0);
++                      ast_moutdwm(ast, 0x1E6E0018, reg_mcr18 | (dqidly << 16) 
| (dqsip << 23));
++                      ast_moutdwm(ast, 0x1E6E000C, reg_mcr0c);
++                      for (dlli = 0; dlli < 76; dlli++) {
++                              ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli 
<< 16) | (dlli << 24));
++                              ast_moutdwm(ast, 0x1E6E0070, 0);
++                              ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE0);
++                              if (cbr_scan3(ast)) {
++                                      if (dlli == 0)
++                                              break;
++                                      passcnt[dqsip]++;
++                                      tag[dqsip][dlli] = 'P';
++                                      if (dlli < pass[dqidly][dqsip][0])
++                                              pass[dqidly][dqsip][0] = (u16) 
dlli;
++                                      if (dlli > pass[dqidly][dqsip][1])
++                                              pass[dqidly][dqsip][1] = (u16) 
dlli;
++                              } else if (passcnt[dqsip] >= 5)
++                                      break;
++                              else {
++                                      pass[dqidly][dqsip][0] = 0xff;
++                                      pass[dqidly][dqsip][1] = 0x0;
++                              }
++                      }
++              }
++              if (passcnt[0] == 0 && passcnt[1] == 0)
++                      dqidly++;
++      }
++      /* Search margin */
++      g_dqidly = g_dqsip = g_margin = g_side = 0;
++
++      for (dqidly = 0; dqidly < 32; dqidly++) {
++              for (dqsip = 0; dqsip < 2; dqsip++) {
++                      if (pass[dqidly][dqsip][0] > pass[dqidly][dqsip][1])
++                              continue;
++                      diff = pass[dqidly][dqsip][1] - pass[dqidly][dqsip][0];
++                      if ((diff+2) < g_margin)
++                              continue;
++                      passcnt[0] = passcnt[1] = 0;
++                      for (dlli = pass[dqidly][dqsip][0]; dlli > 0  && 
tag[dqsip][dlli] != 0; dlli--, passcnt[0]++);
++                      for (dlli = pass[dqidly][dqsip][1]; dlli < 76 && 
tag[dqsip][dlli] != 0; dlli++, passcnt[1]++);
++                      if (passcnt[0] > passcnt[1])
++                              passcnt[0] = passcnt[1];
++                      passcnt[1] = 0;
++                      if (passcnt[0] > g_side)
++                              passcnt[1] = passcnt[0] - g_side;
++                      if (diff > (g_margin+1) && (passcnt[1] > 0 || 
passcnt[0] > 8)) {
++                              g_margin = diff;
++                              g_dqidly = dqidly;
++                              g_dqsip  = dqsip;
++                              g_side   = passcnt[0];
++                      } else if (passcnt[1] > 1 && g_side < 8) {
++                              if (diff > g_margin)
++                                      g_margin = diff;
++                              g_dqidly = dqidly;
++                              g_dqsip  = dqsip;
++                              g_side   = passcnt[0];
++                      }
++              }
++      }
++      reg_mcr18 = reg_mcr18 | (g_dqidly << 16) | (g_dqsip << 23);
++      ast_moutdwm(ast, 0x1E6E0018, reg_mcr18);
++
++}
++static bool cbr_dll2(struct ast_private *ast, struct ast2300_dram_param 
*param)
++{
++      u32 dllmin[2], dllmax[2], dlli, data, passcnt, retry = 0;
++      bool status = false;
++
++      finetuneDQSI(ast);
++      if (finetuneDQI_L(ast, param) == false)
++              return status;
++
++CBR_START2:
++      dllmin[0] = dllmin[1] = 0xff;
++      dllmax[0] = dllmax[1] = 0x0;
++      passcnt = 0;
++      for (dlli = 0; dlli < 76; dlli++) {
++              ast_moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli 
<< 24));
++              ast_moutdwm(ast, 0x1E6E0074, CBR_SIZE2);
++              data = cbr_scan(ast);
++              if (data != 0) {
++                      if (data & 0x1) {
++                              if (dllmin[0] > dlli) {
++                                      dllmin[0] = dlli;
++                              }
++                              if (dllmax[0] < dlli) {
++                                      dllmax[0] = dlli;
++                              }
++                      }
++                      if (data & 0x2) {
++                              if (dllmin[1] > dlli) {
++                                      dllmin[1] = dlli;
++                              }
++                              if (dllmax[1] < dlli) {
++                                      dllmax[1] = dlli;
++                              }
++                      }
++                      passcnt++;
++              } else if (passcnt >= CBR_THRESHOLD) {
++                      break;
++              }
++      }
++      if (retry++ > 10)
++              goto CBR_DONE2;
++      if (dllmax[0] == 0 || (dllmax[0]-dllmin[0]) < CBR_THRESHOLD) {
++              goto CBR_START2;
++      }
++      if (dllmax[1] == 0 || (dllmax[1]-dllmin[1]) < CBR_THRESHOLD) {
++              goto CBR_START2;
++      }
++      status = true;
++CBR_DONE2:
++      dlli  = (dllmin[1] + dllmax[1]) >> 1;
++      dlli <<= 8;
++      dlli += (dllmin[0] + dllmax[0]) >> 1;
++      ast_moutdwm(ast, 0x1E6E0068, ast_mindwm(ast, 0x1E720058) | (dlli << 
16));
++      return status;
++} /* CBRDLL2 */
++
++static void get_ddr3_info(struct ast_private *ast, struct ast2300_dram_param 
*param)
++{
++      u32 trap, trap_AC2, trap_MRS;
++
++      ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
++
++      /* Ger trap info */
++      trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
++      trap_AC2  = 0x00020000 + (trap << 16);
++      trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19);
++      trap_MRS  = 0x00000010 + (trap << 4);
++      trap_MRS |= ((trap & 0x2) << 18);
++
++      param->reg_MADJ       = 0x00034C4C;
++      param->reg_SADJ       = 0x00001800;
++      param->reg_DRV        = 0x000000F0;
++      param->reg_PERIOD     = param->dram_freq;
++      param->rodt           = 0;
++
++      switch (param->dram_freq) {
++      case 336:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0190);
++              param->wodt          = 0;
++              param->reg_AC1       = 0x22202725;
++              param->reg_AC2       = 0xAA007613 | trap_AC2;
++              param->reg_DQSIC     = 0x000000BA;
++              param->reg_MRS       = 0x04001400 | trap_MRS;
++              param->reg_EMRS      = 0x00000000;
++              param->reg_IOZ       = 0x00000023;
++              param->reg_DQIDLY    = 0x00000074;
++              param->reg_FREQ      = 0x00004DC0;
++              param->madj_max      = 96;
++              param->dll2_finetune_step = 3;
++              switch (param->dram_chipid) {
++              default:
++              case AST_DRAM_512Mx16:
++              case AST_DRAM_1Gx16:
++                      param->reg_AC2   = 0xAA007613 | trap_AC2;
++                      break;
++              case AST_DRAM_2Gx16:
++                      param->reg_AC2   = 0xAA00761C | trap_AC2;
++                      break;
++              case AST_DRAM_4Gx16:
++                      param->reg_AC2   = 0xAA007636 | trap_AC2;
++                      break;
++              }
++              break;
++      default:
++      case 396:
++              ast_moutdwm(ast, 0x1E6E2020, 0x03F1);
++              param->wodt          = 1;
++              param->reg_AC1       = 0x33302825;
++              param->reg_AC2       = 0xCC009617 | trap_AC2;
++              param->reg_DQSIC     = 0x000000E2;
++              param->reg_MRS       = 0x04001600 | trap_MRS;
++              param->reg_EMRS      = 0x00000000;
++              param->reg_IOZ       = 0x00000034;
++              param->reg_DRV       = 0x000000FA;
++              param->reg_DQIDLY    = 0x00000089;
++              param->reg_FREQ      = 0x00005040;
++              param->madj_max      = 96;
++              param->dll2_finetune_step = 4;
++
++              switch (param->dram_chipid) {
++              default:
++              case AST_DRAM_512Mx16:
++              case AST_DRAM_1Gx16:
++                      param->reg_AC2   = 0xCC009617 | trap_AC2;
++                      break;
++              case AST_DRAM_2Gx16:
++                      param->reg_AC2   = 0xCC009622 | trap_AC2;
++                      break;
++              case AST_DRAM_4Gx16:
++                      param->reg_AC2   = 0xCC00963F | trap_AC2;
++                      break;
++              }
++              break;
++
++      case 408:
++              ast_moutdwm(ast, 0x1E6E2020, 0x01F0);
++              param->wodt          = 1;
++              param->reg_AC1       = 0x33302825;
++              param->reg_AC2       = 0xCC009617 | trap_AC2;
++              param->reg_DQSIC     = 0x000000E2;
++              param->reg_MRS       = 0x04001600 | trap_MRS;
++              param->reg_EMRS      = 0x00000000;
++              param->reg_IOZ       = 0x00000023;
++              param->reg_DRV       = 0x000000FA;
++              param->reg_DQIDLY    = 0x00000089;
++              param->reg_FREQ      = 0x000050C0;
++              param->madj_max      = 96;
++              param->dll2_finetune_step = 4;
++
++              switch (param->dram_chipid) {
++              default:
++              case AST_DRAM_512Mx16:
++              case AST_DRAM_1Gx16:
++                      param->reg_AC2   = 0xCC009617 | trap_AC2;
++                      break;
++              case AST_DRAM_2Gx16:
++                      param->reg_AC2   = 0xCC009622 | trap_AC2;
++                      break;
++              case AST_DRAM_4Gx16:
++                      param->reg_AC2   = 0xCC00963F | trap_AC2;
++                      break;
++              }
++
++              break;
++      case 456:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0230);
++              param->wodt          = 0;
++              param->reg_AC1       = 0x33302926;
++              param->reg_AC2       = 0xCD44961A;
++              param->reg_DQSIC     = 0x000000FC;
++              param->reg_MRS       = 0x00081830;
++              param->reg_EMRS      = 0x00000000;
++              param->reg_IOZ       = 0x00000045;
++              param->reg_DQIDLY    = 0x00000097;
++              param->reg_FREQ      = 0x000052C0;
++              param->madj_max      = 88;
++              param->dll2_finetune_step = 4;
++              break;
++      case 504:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0270);
++              param->wodt          = 1;
++              param->reg_AC1       = 0x33302926;
++              param->reg_AC2       = 0xDE44A61D;
++              param->reg_DQSIC     = 0x00000117;
++              param->reg_MRS       = 0x00081A30;
++              param->reg_EMRS      = 0x00000000;
++              param->reg_IOZ       = 0x070000BB;
++              param->reg_DQIDLY    = 0x000000A0;
++              param->reg_FREQ      = 0x000054C0;
++              param->madj_max      = 79;
++              param->dll2_finetune_step = 4;
++              break;
++      case 528:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0290);
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x33302926;
++              param->reg_AC2       = 0xEF44B61E;
++              param->reg_DQSIC     = 0x00000125;
++              param->reg_MRS       = 0x00081A30;
++              param->reg_EMRS      = 0x00000040;
++              param->reg_DRV       = 0x000000F5;
++              param->reg_IOZ       = 0x00000023;
++              param->reg_DQIDLY    = 0x00000088;
++              param->reg_FREQ      = 0x000055C0;
++              param->madj_max      = 76;
++              param->dll2_finetune_step = 3;
++              break;
++      case 576:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0140);
++              param->reg_MADJ      = 0x00136868;
++              param->reg_SADJ      = 0x00004534;
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x33302A37;
++              param->reg_AC2       = 0xEF56B61E;
++              param->reg_DQSIC     = 0x0000013F;
++              param->reg_MRS       = 0x00101A50;
++              param->reg_EMRS      = 0x00000040;
++              param->reg_DRV       = 0x000000FA;
++              param->reg_IOZ       = 0x00000023;
++              param->reg_DQIDLY    = 0x00000078;
++              param->reg_FREQ      = 0x000057C0;
++              param->madj_max      = 136;
++              param->dll2_finetune_step = 3;
++              break;
++      case 600:
++              ast_moutdwm(ast, 0x1E6E2020, 0x02E1);
++              param->reg_MADJ      = 0x00136868;
++              param->reg_SADJ      = 0x00004534;
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x32302A37;
++              param->reg_AC2       = 0xDF56B61F;
++              param->reg_DQSIC     = 0x0000014D;
++              param->reg_MRS       = 0x00101A50;
++              param->reg_EMRS      = 0x00000004;
++              param->reg_DRV       = 0x000000F5;
++              param->reg_IOZ       = 0x00000023;
++              param->reg_DQIDLY    = 0x00000078;
++              param->reg_FREQ      = 0x000058C0;
++              param->madj_max      = 132;
++              param->dll2_finetune_step = 3;
++              break;
++      case 624:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0160);
++              param->reg_MADJ      = 0x00136868;
++              param->reg_SADJ      = 0x00004534;
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x32302A37;
++              param->reg_AC2       = 0xEF56B621;
++              param->reg_DQSIC     = 0x0000015A;
++              param->reg_MRS       = 0x02101A50;
++              param->reg_EMRS      = 0x00000004;
++              param->reg_DRV       = 0x000000F5;
++              param->reg_IOZ       = 0x00000034;
++              param->reg_DQIDLY    = 0x00000078;
++              param->reg_FREQ      = 0x000059C0;
++              param->madj_max      = 128;
++              param->dll2_finetune_step = 3;
++              break;
++      } /* switch freq */
++
++      switch (param->dram_chipid) {
++      case AST_DRAM_512Mx16:
++              param->dram_config = 0x130;
++              break;
++      default:
++      case AST_DRAM_1Gx16:
++              param->dram_config = 0x131;
++              break;
++      case AST_DRAM_2Gx16:
++              param->dram_config = 0x132;
++              break;
++      case AST_DRAM_4Gx16:
++              param->dram_config = 0x133;
++              break;
++      } /* switch size */
++
++      switch (param->vram_size) {
++      default:
++      case AST_VIDMEM_SIZE_8M:
++              param->dram_config |= 0x00;
++              break;
++      case AST_VIDMEM_SIZE_16M:
++              param->dram_config |= 0x04;
++              break;
++      case AST_VIDMEM_SIZE_32M:
++              param->dram_config |= 0x08;
++              break;
++      case AST_VIDMEM_SIZE_64M:
++              param->dram_config |= 0x0c;
++              break;
++      }
++
++}
++
++static void ddr3_init(struct ast_private *ast, struct ast2300_dram_param 
*param)
++{
++      u32 data, data2, retry = 0;
++
++ddr3_init_start:
++      ast_moutdwm(ast, 0x1E6E0000, 0xFC600309);
++      ast_moutdwm(ast, 0x1E6E0018, 0x00000100);
++      ast_moutdwm(ast, 0x1E6E0024, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0034, 0x00000000);
++      udelay(10);
++      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
++      ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
++      udelay(10);
++      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
++      udelay(10);
++
++      ast_moutdwm(ast, 0x1E6E0004, param->dram_config);
++      ast_moutdwm(ast, 0x1E6E0008, 0x90040f);
++      ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1);
++      ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2);
++      ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
++      ast_moutdwm(ast, 0x1E6E0080, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0084, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
++      ast_moutdwm(ast, 0x1E6E0018, 0x4000A170);
++      ast_moutdwm(ast, 0x1E6E0018, 0x00002370);
++      ast_moutdwm(ast, 0x1E6E0038, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0040, 0xFF444444);
++      ast_moutdwm(ast, 0x1E6E0044, 0x22222222);
++      ast_moutdwm(ast, 0x1E6E0048, 0x22222222);
++      ast_moutdwm(ast, 0x1E6E004C, 0x00000002);
++      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
++      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0054, 0);
++      ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV);
++      ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
++      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0074, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0078, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
++      /* Wait MCLK2X lock to MCLK */
++      do {
++              data = ast_mindwm(ast, 0x1E6E001C);
++      } while (!(data & 0x08000000));
++      data = ast_mindwm(ast, 0x1E6E001C);
++      data = (data >> 8) & 0xff;
++      while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
++              data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
++              if ((data2 & 0xff) > param->madj_max) {
++                      break;
++              }
++              ast_moutdwm(ast, 0x1E6E0064, data2);
++              if (data2 & 0x00100000) {
++                      data2 = ((data2 & 0xff) >> 3) + 3;
++              } else {
++                      data2 = ((data2 & 0xff) >> 2) + 5;
++              }
++              data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff;
++              data2 += data & 0xff;
++              data = data | (data2 << 8);
++              ast_moutdwm(ast, 0x1E6E0068, data);
++              udelay(10);
++              ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 
0xC0000);
++              udelay(10);
++              data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
++              ast_moutdwm(ast, 0x1E6E0018, data);
++              data = data | 0x200;
++              ast_moutdwm(ast, 0x1E6E0018, data);
++              do {
++                      data = ast_mindwm(ast, 0x1E6E001C);
++              } while (!(data & 0x08000000));
++
++              data = ast_mindwm(ast, 0x1E6E001C);
++              data = (data >> 8) & 0xff;
++      }
++      ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0068) & 0xffff);
++      data = ast_mindwm(ast, 0x1E6E0018) | 0xC00;
++      ast_moutdwm(ast, 0x1E6E0018, data);
++
++      ast_moutdwm(ast, 0x1E6E0034, 0x00000001);
++      ast_moutdwm(ast, 0x1E6E000C, 0x00000040);
++      udelay(50);
++      /* Mode Register Setting */
++      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
++      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000005);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000007);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
++      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS);
++      ast_moutdwm(ast, 0x1E6E000C, 0x00005C08);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
++
++      ast_moutdwm(ast, 0x1E6E000C, 0x00005C01);
++      data = 0;
++      if (param->wodt) {
++              data = 0x300;
++      }
++      if (param->rodt) {
++              data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
++      }
++      ast_moutdwm(ast, 0x1E6E0034, data | 0x3);
++
++      /* Calibrate the DQSI delay */
++      if ((cbr_dll2(ast, param) == false) && (retry++ < 10))
++              goto ddr3_init_start;
++
++      ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
++      /* ECC Memory Initialization */
++#ifdef ECC
++      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0070, 0x221);
++      do {
++              data = ast_mindwm(ast, 0x1E6E0070);
++      } while (!(data & 0x00001000));
++      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
++      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
++#endif
++
++
++}
++
++static void get_ddr2_info(struct ast_private *ast, struct ast2300_dram_param 
*param)
++{
++      u32 trap, trap_AC2, trap_MRS;
++
++      ast_moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
++
++      /* Ger trap info */
++      trap = (ast_mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
++      trap_AC2  = (trap << 20) | (trap << 16);
++      trap_AC2 += 0x00110000;
++      trap_MRS  = 0x00000040 | (trap << 4);
++
++
++      param->reg_MADJ       = 0x00034C4C;
++      param->reg_SADJ       = 0x00001800;
++      param->reg_DRV        = 0x000000F0;
++      param->reg_PERIOD     = param->dram_freq;
++      param->rodt           = 0;
++
++      switch (param->dram_freq) {
++      case 264:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0130);
++              param->wodt          = 0;
++              param->reg_AC1       = 0x11101513;
++              param->reg_AC2       = 0x78117011;
++              param->reg_DQSIC     = 0x00000092;
++              param->reg_MRS       = 0x00000842;
++              param->reg_EMRS      = 0x00000000;
++              param->reg_DRV       = 0x000000F0;
++              param->reg_IOZ       = 0x00000034;
++              param->reg_DQIDLY    = 0x0000005A;
++              param->reg_FREQ      = 0x00004AC0;
++              param->madj_max      = 138;
++              param->dll2_finetune_step = 3;
++              break;
++      case 336:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0190);
++              param->wodt          = 1;
++              param->reg_AC1       = 0x22202613;
++              param->reg_AC2       = 0xAA009016 | trap_AC2;
++              param->reg_DQSIC     = 0x000000BA;
++              param->reg_MRS       = 0x00000A02 | trap_MRS;
++              param->reg_EMRS      = 0x00000040;
++              param->reg_DRV       = 0x000000FA;
++              param->reg_IOZ       = 0x00000034;
++              param->reg_DQIDLY    = 0x00000074;
++              param->reg_FREQ      = 0x00004DC0;
++              param->madj_max      = 96;
++              param->dll2_finetune_step = 3;
++              switch (param->dram_chipid) {
++              default:
++              case AST_DRAM_512Mx16:
++                      param->reg_AC2   = 0xAA009012 | trap_AC2;
++                      break;
++              case AST_DRAM_1Gx16:
++                      param->reg_AC2   = 0xAA009016 | trap_AC2;
++                      break;
++              case AST_DRAM_2Gx16:
++                      param->reg_AC2   = 0xAA009023 | trap_AC2;
++                      break;
++              case AST_DRAM_4Gx16:
++                      param->reg_AC2   = 0xAA00903B | trap_AC2;
++                      break;
++              }
++              break;
++      default:
++      case 396:
++              ast_moutdwm(ast, 0x1E6E2020, 0x03F1);
++              param->wodt          = 1;
++              param->rodt          = 0;
++              param->reg_AC1       = 0x33302714;
++              param->reg_AC2       = 0xCC00B01B | trap_AC2;
++              param->reg_DQSIC     = 0x000000E2;
++              param->reg_MRS       = 0x00000C02 | trap_MRS;
++              param->reg_EMRS      = 0x00000040;
++              param->reg_DRV       = 0x000000FA;
++              param->reg_IOZ       = 0x00000034;
++              param->reg_DQIDLY    = 0x00000089;
++              param->reg_FREQ      = 0x00005040;
++              param->madj_max      = 96;
++              param->dll2_finetune_step = 4;
++
++              switch (param->dram_chipid) {
++              case AST_DRAM_512Mx16:
++                      param->reg_AC2   = 0xCC00B016 | trap_AC2;
++                      break;
++              default:
++              case AST_DRAM_1Gx16:
++                      param->reg_AC2   = 0xCC00B01B | trap_AC2;
++                      break;
++              case AST_DRAM_2Gx16:
++                      param->reg_AC2   = 0xCC00B02B | trap_AC2;
++                      break;
++              case AST_DRAM_4Gx16:
++                      param->reg_AC2   = 0xCC00B03F | trap_AC2;
++                      break;
++              }
++
++              break;
++
++      case 408:
++              ast_moutdwm(ast, 0x1E6E2020, 0x01F0);
++              param->wodt          = 1;
++              param->rodt          = 0;
++              param->reg_AC1       = 0x33302714;
++              param->reg_AC2       = 0xCC00B01B | trap_AC2;
++              param->reg_DQSIC     = 0x000000E2;
++              param->reg_MRS       = 0x00000C02 | trap_MRS;
++              param->reg_EMRS      = 0x00000040;
++              param->reg_DRV       = 0x000000FA;
++              param->reg_IOZ       = 0x00000034;
++              param->reg_DQIDLY    = 0x00000089;
++              param->reg_FREQ      = 0x000050C0;
++              param->madj_max      = 96;
++              param->dll2_finetune_step = 4;
++
++              switch (param->dram_chipid) {
++              case AST_DRAM_512Mx16:
++                      param->reg_AC2   = 0xCC00B016 | trap_AC2;
++                      break;
++              default:
++              case AST_DRAM_1Gx16:
++                      param->reg_AC2   = 0xCC00B01B | trap_AC2;
++                      break;
++              case AST_DRAM_2Gx16:
++                      param->reg_AC2   = 0xCC00B02B | trap_AC2;
++                      break;
++              case AST_DRAM_4Gx16:
++                      param->reg_AC2   = 0xCC00B03F | trap_AC2;
++                      break;
++              }
++
++              break;
++      case 456:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0230);
++              param->wodt          = 0;
++              param->reg_AC1       = 0x33302815;
++              param->reg_AC2       = 0xCD44B01E;
++              param->reg_DQSIC     = 0x000000FC;
++              param->reg_MRS       = 0x00000E72;
++              param->reg_EMRS      = 0x00000000;
++              param->reg_DRV       = 0x00000000;
++              param->reg_IOZ       = 0x00000034;
++              param->reg_DQIDLY    = 0x00000097;
++              param->reg_FREQ      = 0x000052C0;
++              param->madj_max      = 88;
++              param->dll2_finetune_step = 3;
++              break;
++      case 504:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0261);
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x33302815;
++              param->reg_AC2       = 0xDE44C022;
++              param->reg_DQSIC     = 0x00000117;
++              param->reg_MRS       = 0x00000E72;
++              param->reg_EMRS      = 0x00000040;
++              param->reg_DRV       = 0x0000000A;
++              param->reg_IOZ       = 0x00000045;
++              param->reg_DQIDLY    = 0x000000A0;
++              param->reg_FREQ      = 0x000054C0;
++              param->madj_max      = 79;
++              param->dll2_finetune_step = 3;
++              break;
++      case 528:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0120);
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x33302815;
++              param->reg_AC2       = 0xEF44D024;
++              param->reg_DQSIC     = 0x00000125;
++              param->reg_MRS       = 0x00000E72;
++              param->reg_EMRS      = 0x00000004;
++              param->reg_DRV       = 0x000000F9;
++              param->reg_IOZ       = 0x00000045;
++              param->reg_DQIDLY    = 0x000000A7;
++              param->reg_FREQ      = 0x000055C0;
++              param->madj_max      = 76;
++              param->dll2_finetune_step = 3;
++              break;
++      case 552:
++              ast_moutdwm(ast, 0x1E6E2020, 0x02A1);
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x43402915;
++              param->reg_AC2       = 0xFF44E025;
++              param->reg_DQSIC     = 0x00000132;
++              param->reg_MRS       = 0x00000E72;
++              param->reg_EMRS      = 0x00000040;
++              param->reg_DRV       = 0x0000000A;
++              param->reg_IOZ       = 0x00000045;
++              param->reg_DQIDLY    = 0x000000AD;
++              param->reg_FREQ      = 0x000056C0;
++              param->madj_max      = 76;
++              param->dll2_finetune_step = 3;
++              break;
++      case 576:
++              ast_moutdwm(ast, 0x1E6E2020, 0x0140);
++              param->wodt          = 1;
++              param->rodt          = 1;
++              param->reg_AC1       = 0x43402915;
++              param->reg_AC2       = 0xFF44E027;
++              param->reg_DQSIC     = 0x0000013F;
++              param->reg_MRS       = 0x00000E72;
++              param->reg_EMRS      = 0x00000004;
++              param->reg_DRV       = 0x000000F5;
++              param->reg_IOZ       = 0x00000045;
++              param->reg_DQIDLY    = 0x000000B3;
++              param->reg_FREQ      = 0x000057C0;
++              param->madj_max      = 76;
++              param->dll2_finetune_step = 3;
++              break;
++      }
++
++      switch (param->dram_chipid) {
++      case AST_DRAM_512Mx16:
++              param->dram_config = 0x100;
++              break;
++      default:
++      case AST_DRAM_1Gx16:
++              param->dram_config = 0x121;
++              break;
++      case AST_DRAM_2Gx16:
++              param->dram_config = 0x122;
++              break;
++      case AST_DRAM_4Gx16:
++              param->dram_config = 0x123;
++              break;
++      } /* switch size */
++
++      switch (param->vram_size) {
++      default:
++      case AST_VIDMEM_SIZE_8M:
++              param->dram_config |= 0x00;
++              break;
++      case AST_VIDMEM_SIZE_16M:
++              param->dram_config |= 0x04;
++              break;
++      case AST_VIDMEM_SIZE_32M:
++              param->dram_config |= 0x08;
++              break;
++      case AST_VIDMEM_SIZE_64M:
++              param->dram_config |= 0x0c;
++              break;
++      }
++}
++
++static void ddr2_init(struct ast_private *ast, struct ast2300_dram_param 
*param)
++{
++      u32 data, data2, retry = 0;
++
++ddr2_init_start:
++      ast_moutdwm(ast, 0x1E6E0000, 0xFC600309);
++      ast_moutdwm(ast, 0x1E6E0018, 0x00000100);
++      ast_moutdwm(ast, 0x1E6E0024, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
++      ast_moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
++      udelay(10);
++      ast_moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
++      udelay(10);
++
++      ast_moutdwm(ast, 0x1E6E0004, param->dram_config);
++      ast_moutdwm(ast, 0x1E6E0008, 0x90040f);
++      ast_moutdwm(ast, 0x1E6E0010, param->reg_AC1);
++      ast_moutdwm(ast, 0x1E6E0014, param->reg_AC2);
++      ast_moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
++      ast_moutdwm(ast, 0x1E6E0080, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0084, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
++      ast_moutdwm(ast, 0x1E6E0018, 0x4000A130);
++      ast_moutdwm(ast, 0x1E6E0018, 0x00002330);
++      ast_moutdwm(ast, 0x1E6E0038, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0040, 0xFF808000);
++      ast_moutdwm(ast, 0x1E6E0044, 0x88848466);
++      ast_moutdwm(ast, 0x1E6E0048, 0x44440008);
++      ast_moutdwm(ast, 0x1E6E004C, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
++      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0054, 0);
++      ast_moutdwm(ast, 0x1E6E0060, param->reg_DRV);
++      ast_moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
++      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0074, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0078, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
++
++      /* Wait MCLK2X lock to MCLK */
++      do {
++              data = ast_mindwm(ast, 0x1E6E001C);
++      } while (!(data & 0x08000000));
++      data = ast_mindwm(ast, 0x1E6E001C);
++      data = (data >> 8) & 0xff;
++      while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
++              data2 = (ast_mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
++              if ((data2 & 0xff) > param->madj_max) {
++                      break;
++              }
++              ast_moutdwm(ast, 0x1E6E0064, data2);
++              if (data2 & 0x00100000) {
++                      data2 = ((data2 & 0xff) >> 3) + 3;
++              } else {
++                      data2 = ((data2 & 0xff) >> 2) + 5;
++              }
++              data = ast_mindwm(ast, 0x1E6E0068) & 0xffff00ff;
++              data2 += data & 0xff;
++              data = data | (data2 << 8);
++              ast_moutdwm(ast, 0x1E6E0068, data);
++              udelay(10);
++              ast_moutdwm(ast, 0x1E6E0064, ast_mindwm(ast, 0x1E6E0064) | 
0xC0000);
++              udelay(10);
++              data = ast_mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
++              ast_moutdwm(ast, 0x1E6E0018, data);
++              data = data | 0x200;
++              ast_moutdwm(ast, 0x1E6E0018, data);
++              do {
++                      data = ast_mindwm(ast, 0x1E6E001C);
++              } while (!(data & 0x08000000));
++
++              data = ast_mindwm(ast, 0x1E6E001C);
++              data = (data >> 8) & 0xff;
++      }
++      ast_moutdwm(ast, 0x1E720058, ast_mindwm(ast, 0x1E6E0008) & 0xffff);
++      data = ast_mindwm(ast, 0x1E6E0018) | 0xC00;
++      ast_moutdwm(ast, 0x1E6E0018, data);
++
++      ast_moutdwm(ast, 0x1E6E0034, 0x00000001);
++      ast_moutdwm(ast, 0x1E6E000C, 0x00000000);
++      udelay(50);
++      /* Mode Register Setting */
++      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
++      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000005);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000007);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
++
++      ast_moutdwm(ast, 0x1E6E000C, 0x00005C08);
++      ast_moutdwm(ast, 0x1E6E002C, param->reg_MRS);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000001);
++      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
++      ast_moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
++      ast_moutdwm(ast, 0x1E6E0028, 0x00000003);
++
++      ast_moutdwm(ast, 0x1E6E000C, 0x7FFF5C01);
++      data = 0;
++      if (param->wodt) {
++              data = 0x500;
++      }
++      if (param->rodt) {
++              data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
++      }
++      ast_moutdwm(ast, 0x1E6E0034, data | 0x3);
++      ast_moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
++
++      /* Calibrate the DQSI delay */
++      if ((cbr_dll2(ast, param) == false) && (retry++ < 10))
++              goto ddr2_init_start;
++
++      /* ECC Memory Initialization */
++#ifdef ECC
++      ast_moutdwm(ast, 0x1E6E007C, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0070, 0x221);
++      do {
++              data = ast_mindwm(ast, 0x1E6E0070);
++      } while (!(data & 0x00001000));
++      ast_moutdwm(ast, 0x1E6E0070, 0x00000000);
++      ast_moutdwm(ast, 0x1E6E0050, 0x80000000);
++      ast_moutdwm(ast, 0x1E6E0050, 0x00000000);
++#endif
++
++}
++
++static void ast_init_dram_2300(struct drm_device *dev)
++{
++      struct ast_private *ast = dev->dev_private;
++      struct ast2300_dram_param param;
++      u32 temp;
++      u8 reg;
++
++      reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
++      if ((reg & 0x80) == 0) {/* vga only */
++              ast_write32(ast, 0xf004, 0x1e6e0000);
++              ast_write32(ast, 0xf000, 0x1);
++              ast_write32(ast, 0x12000, 0x1688a8a8);
++              do {
++                      ;
++              } while (ast_read32(ast, 0x12000) != 0x1);
++
++              ast_write32(ast, 0x10000, 0xfc600309);
++              do {
++                      ;
++              } while (ast_read32(ast, 0x10000) != 0x1);
++
++              /* Slow down CPU/AHB CLK in VGA only mode */
++              temp = ast_read32(ast, 0x12008);
++              temp |= 0x73;
++              ast_write32(ast, 0x12008, temp);
++
++              param.dram_type = AST_DDR3;
++              if (temp & 0x01000000)
++                      param.dram_type = AST_DDR2;
++              param.dram_chipid = ast->dram_type;
++              param.dram_freq = ast->mclk;
++              param.vram_size = ast->vram_size;
++
++              if (param.dram_type == AST_DDR3) {
++                      get_ddr3_info(ast, &param);
++                      ddr3_init(ast, &param);
++              } else {
++                      get_ddr2_info(ast, &param);
++                      ddr2_init(ast, &param);
++              }
++
++              temp = ast_mindwm(ast, 0x1e6e2040);
++              ast_moutdwm(ast, 0x1e6e2040, temp | 0x40);
++      }
++
++      /* wait ready */
++      do {
++              reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
++      } while ((reg & 0x40) == 0);
++}
++
+diff --git a/src/drivers/aspeed/common/ast_tables.h 
b/src/drivers/aspeed/common/ast_tables.h
+new file mode 100644
+index 0000000..3608d5a
+--- /dev/null
++++ b/src/drivers/aspeed/common/ast_tables.h
+@@ -0,0 +1,305 @@
++/*
++ * Copyright (c) 2005 ASPEED Technology Inc.
++ *
++ * Permission to use, copy, modify, distribute, and sell this software and its
++ * documentation for any purpose is hereby granted without fee, provided that
++ * the above copyright notice appear in all copies and that both that
++ * copyright notice and this permission notice appear in supporting
++ * documentation, and that the name of the authors not be used in
++ * advertising or publicity pertaining to distribution of the software without
++ * specific, written prior permission.  The authors makes no representations
++ * about the suitability of this software for any purpose.  It is provided
++ * "as is" without express or implied warranty.
++ *
++ * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++ * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
++ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
++ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++ * PERFORMANCE OF THIS SOFTWARE.
++ */
++/* Ported from xf86-video-ast driver */
++
++#ifndef AST_TABLES_H
++#define AST_TABLES_H
++
++/* Std. Table Index Definition */
++#define TextModeIndex         0
++#define EGAModeIndex          1
++#define VGAModeIndex          2
++#define HiCModeIndex          3
++#define TrueCModeIndex                4
++
++#define Charx8Dot               0x00000001
++#define HalfDCLK                0x00000002
++#define DoubleScanMode          0x00000004
++#define LineCompareOff          0x00000008
++#define HBorder                 0x00000020
++#define VBorder                 0x00000010
++#define WideScreenMode                0x00000100
++#define NewModeInfo           0x00000200
++#define NHSync                        0x00000400
++#define PHSync                        0x00000800
++#define NVSync                        0x00001000
++#define PVSync                        0x00002000
++#define SyncPP                        (PVSync | PHSync)
++#define SyncPN                        (PVSync | NHSync)
++#define SyncNP                        (NVSync | PHSync)
++#define SyncNN                        (NVSync | NHSync)
++
++/* DCLK Index */
++#define VCLK25_175                    0x00
++#define VCLK28_322                    0x01
++#define VCLK31_5                      0x02
++#define VCLK36                        0x03
++#define VCLK40                        0x04
++#define VCLK49_5                      0x05
++#define VCLK50                        0x06
++#define VCLK56_25                     0x07
++#define VCLK65                        0x08
++#define VCLK75                        0x09
++#define VCLK78_75                     0x0A
++#define VCLK94_5                      0x0B
++#define VCLK108                       0x0C
++#define VCLK135                       0x0D
++#define VCLK157_5                     0x0E
++#define VCLK162                       0x0F
++/* #define VCLK193_25                 0x10 */
++#define VCLK154               0x10
++#define VCLK83_5              0x11
++#define VCLK106_5             0x12
++#define VCLK146_25            0x13
++#define VCLK148_5             0x14
++#define VCLK71                0x15
++#define VCLK88_75             0x16
++#define VCLK119               0x17
++#define VCLK85_5              0x18
++#define VCLK97_75                     0x19
++#define VCLK118_25                    0x1A
++
++static struct ast_vbios_dclk_info dclk_table[] = {
++      {0x2C, 0xE7, 0x03},                                     /* 00: 
VCLK25_175       */
++      {0x95, 0x62, 0x03},                                     /* 01: 
VCLK28_322       */
++      {0x67, 0x63, 0x01},                                     /* 02: VCLK31_5 
        */
++      {0x76, 0x63, 0x01},                                     /* 03: VCLK36   
        */
++      {0xEE, 0x67, 0x01},                                     /* 04: VCLK40   
        */
++      {0x82, 0x62, 0x01},                             /* 05: VCLK49_5         
*/
++      {0xC6, 0x64, 0x01},                                     /* 06: VCLK50   
        */
++      {0x94, 0x62, 0x01},                                     /* 07: 
VCLK56_25        */
++      {0x80, 0x64, 0x00},                                     /* 08: VCLK65   
        */
++      {0x7B, 0x63, 0x00},                                     /* 09: VCLK75   
        */
++      {0x67, 0x62, 0x00},                                     /* 0A: 
VCLK78_75        */
++      {0x7C, 0x62, 0x00},                                     /* 0B: VCLK94_5 
        */
++      {0x8E, 0x62, 0x00},                                     /* 0C: VCLK108  
        */
++      {0x85, 0x24, 0x00},                                     /* 0D: VCLK135  
        */
++      {0x67, 0x22, 0x00},                                     /* 0E: 
VCLK157_5        */
++      {0x6A, 0x22, 0x00},                                     /* 0F: VCLK162  
        */
++      {0x4d, 0x4c, 0x80},                                     /* 10: VCLK154  
        */
++      {0xa7, 0x78, 0x80},                                     /* 11: VCLK83.5 
        */
++      {0x28, 0x49, 0x80},                                     /* 12: 
VCLK106.5        */
++      {0x37, 0x49, 0x80},                                     /* 13: 
VCLK146.25       */
++      {0x1f, 0x45, 0x80},                                     /* 14: 
VCLK148.5        */
++      {0x47, 0x6c, 0x80},                                     /* 15: VCLK71   
    */
++      {0x25, 0x65, 0x80},                                     /* 16: 
VCLK88.75    */
++      {0x77, 0x58, 0x80},                                     /* 17: VCLK119  
    */
++      {0x32, 0x67, 0x80},                                 /* 18: VCLK85_5     
*/
++      {0x6a, 0x6d, 0x80},                                     /* 19: 
VCLK97_75        */
++      {0x3b, 0x2c, 0x81},                                     /* 1A: 
VCLK118_25       */
++};
++
++static struct ast_vbios_stdtable vbios_stdtable[] = {
++      /* MD_2_3_400 */
++      {
++              0x67,
++              {0x00,0x03,0x00,0x02},
++              {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
++               0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
++               0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
++               0xff},
++              {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++               0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++               0x0c,0x00,0x0f,0x08},
++              {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
++               0xff}
++      },
++      /* Mode12/ExtEGATable */
++      {
++              0xe3,
++              {0x01,0x0f,0x00,0x06},
++              {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
++               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++               0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
++               0xff},
++              {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
++               0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
++               0x01,0x00,0x0f,0x00},
++              {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
++               0xff}
++      },
++      /* ExtVGATable */
++      {
++              0x2f,
++              {0x01,0x0f,0x00,0x0e},
++              {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
++               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++               0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
++               0xff},
++              {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
++               0x01,0x00,0x00,0x00},
++              {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
++               0xff}
++      },
++      /* ExtHiCTable */
++      {
++              0x2f,
++              {0x01,0x0f,0x00,0x0e},
++              {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
++               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++               0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
++               0xff},
++              {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
++               0x01,0x00,0x00,0x00},
++              {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
++               0xff}
++      },
++      /* ExtTrueCTable */
++      {
++              0x2f,
++              {0x01,0x0f,0x00,0x0e},
++              {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
++               0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
++               0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
++               0xff},
++              {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
++               0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
++               0x01,0x00,0x00,0x00},
++              {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
++               0xff}
++      },
++};
++
++static struct ast_vbios_enhtable res_640x480[] = {
++      { 800, 640, 8, 96, 525, 480, 2, 2, VCLK25_175,  /* 60Hz */
++        (SyncNN | HBorder | VBorder | Charx8Dot), 60, 1, 0x2E },
++      { 832, 640, 16, 40, 520, 480, 1, 3, VCLK31_5,   /* 72Hz */
++        (SyncNN | HBorder | VBorder | Charx8Dot), 72, 2, 0x2E  },
++      { 840, 640, 16, 64, 500, 480, 1, 3, VCLK31_5,   /* 75Hz */
++        (SyncNN | Charx8Dot) , 75, 3, 0x2E },
++      { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36,             /* 85Hz */
++        (SyncNN | Charx8Dot) , 85, 4, 0x2E },
++      { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36,             /* end */
++        (SyncNN | Charx8Dot) , 0xFF, 4, 0x2E },
++};
++
++static struct ast_vbios_enhtable res_800x600[] = {
++      {1024, 800, 24, 72, 625, 600, 1, 2, VCLK36,             /* 56Hz */
++       (SyncPP | Charx8Dot), 56, 1, 0x30 },
++      {1056, 800, 40, 128, 628, 600, 1, 4, VCLK40,    /* 60Hz */
++       (SyncPP | Charx8Dot), 60, 2, 0x30 },
++      {1040, 800, 56, 120, 666, 600, 37, 6, VCLK50,   /* 72Hz */
++       (SyncPP | Charx8Dot), 72, 3, 0x30 },
++      {1056, 800, 16, 80, 625, 600, 1, 3, VCLK49_5,   /* 75Hz */
++       (SyncPP | Charx8Dot), 75, 4, 0x30 },
++      {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25,  /* 85Hz */
++       (SyncPP | Charx8Dot), 84, 5, 0x30 },
++      {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25,  /* end */
++       (SyncPP | Charx8Dot), 0xFF, 5, 0x30 },
++};
++
++
++static struct ast_vbios_enhtable res_1024x768[] = {
++      {1344, 1024, 24, 136, 806, 768, 3, 6, VCLK65,   /* 60Hz */
++       (SyncNN | Charx8Dot), 60, 1, 0x31 },
++      {1328, 1024, 24, 136, 806, 768, 3, 6, VCLK75,   /* 70Hz */
++       (SyncNN | Charx8Dot), 70, 2, 0x31 },
++      {1312, 1024, 16, 96, 800, 768, 1, 3, VCLK78_75, /* 75Hz */
++       (SyncPP | Charx8Dot), 75, 3, 0x31 },
++      {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5,  /* 85Hz */
++       (SyncPP | Charx8Dot), 84, 4, 0x31 },
++      {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5,  /* end */
++       (SyncPP | Charx8Dot), 0xFF, 4, 0x31 },
++};
++
++static struct ast_vbios_enhtable res_1280x1024[] = {
++      {1688, 1280, 48, 112, 1066, 1024, 1, 3, VCLK108,        /* 60Hz */
++       (SyncPP | Charx8Dot), 60, 1, 0x32 },
++      {1688, 1280, 16, 144, 1066, 1024, 1, 3, VCLK135,        /* 75Hz */
++       (SyncPP | Charx8Dot), 75, 2, 0x32 },
++      {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5,      /* 85Hz */
++       (SyncPP | Charx8Dot), 85, 3, 0x32 },
++      {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5,      /* end */
++       (SyncPP | Charx8Dot), 0xFF, 3, 0x32 },
++};
++
++static struct ast_vbios_enhtable res_1600x1200[] = {
++      {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162,        /* 60Hz */
++       (SyncPP | Charx8Dot), 60, 1, 0x33 },
++      {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162,        /* end */
++       (SyncPP | Charx8Dot), 0xFF, 1, 0x33 },
++};
++
++/* 16:9 */
++static struct ast_vbios_enhtable res_1360x768[] = {
++      {1792, 1360, 64,112, 795,  768, 3, 6, VCLK85_5,          /* 60Hz */
++       (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x39 },
++      {1792, 1360, 64,112, 795,  768, 3, 6, VCLK85_5,          /* end */
++       (SyncPP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 1, 0x39 },
++};
++
++static struct ast_vbios_enhtable res_1600x900[] = {
++      {1760, 1600, 48, 32, 926,  900, 3, 5, VCLK97_75,        /* 60Hz CVT RB 
*/
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x3A },
++      {2112, 1600, 88,168, 934,  900, 3, 5, VCLK118_25,       /* 60Hz CVT */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x3A },
++      {2112, 1600, 88,168, 934,  900, 3, 5, VCLK118_25,       /* 60Hz CVT */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x3A },
++};
++
++static struct ast_vbios_enhtable res_1920x1080[] = {
++      {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x38 },
++      {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 1, 0x38 },
++};
++
++
++/* 16:10 */
++static struct ast_vbios_enhtable res_1280x800[] = {
++      {1440, 1280, 48, 32,  823,  800, 3, 6, VCLK71,  /* 60Hz RB */
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x35 },
++      {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x35 },
++      {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x35 },
++
++};
++
++static struct ast_vbios_enhtable res_1440x900[] = {
++      {1600, 1440, 48, 32,  926,  900, 3, 6, VCLK88_75,       /* 60Hz RB */
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x36 },
++      {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x36 },
++      {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x36 },
++};
++
++static struct ast_vbios_enhtable res_1680x1050[] = {
++      {1840, 1680, 48, 32, 1080, 1050, 3, 6, VCLK119, /* 60Hz RB */
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x37 },
++      {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 2, 0x37 },
++      {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
++       (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 2, 0x37 },
++};
++
++static struct ast_vbios_enhtable res_1920x1200[] = {
++      {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB*/
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
60, 1, 0x34 },
++      {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz RB */
++       (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode | NewModeInfo), 
0xFF, 1, 0x34 },
++};
++
++#endif
+diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
+index dcb8a42..fcaf4aa 100644
+--- a/src/include/device/pci_ids.h
++++ b/src/include/device/pci_ids.h
+@@ -1991,6 +1991,9 @@
+ #define PCI_DEVICE_ID_XGI_20          0x0020
+ #define PCI_DEVICE_ID_XGI_40          0x0040
+ 
++#define PCI_VENDOR_ID_ASPEED          0x1a03
++#define PCI_DEVICE_ID_ASPEED_AST2050_VGA      0x2000
++
+ #define PCI_VENDOR_ID_SYMPHONY                0x1c1c
+ #define PCI_DEVICE_ID_SYMPHONY_101    0x0001
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0006-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
 
b/resources/libreboot/patch/kgpe-d16/0006-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
deleted file mode 100644
index a0273e2..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0006-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
+++ /dev/null
@@ -1,621 +0,0 @@
-From 03ff36542c8f8260b2ff7db5f41a16e9299a1bd0 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 17:46:38 -0500
-Subject: [PATCH 006/139] southbridge/amd/sr5650: Fix boot failure on ASUS
- KGPE-D16
-
-Change-Id: Ia13ba58118a826e830a4dc6e2378b76110fcabad
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sr5650/acpi/sr5650.asl | 388 +++++++++++++++++++++++++++++
- src/southbridge/amd/sr5650/early_setup.c   |   7 +-
- src/southbridge/amd/sr5650/ht.c            |   3 +-
- src/southbridge/amd/sr5650/pcie.c          |  37 ++-
- src/southbridge/amd/sr5650/sr5650.c        |  51 ++--
- 5 files changed, 456 insertions(+), 30 deletions(-)
- create mode 100644 src/southbridge/amd/sr5650/acpi/sr5650.asl
-
-diff --git a/src/southbridge/amd/sr5650/acpi/sr5650.asl 
b/src/southbridge/amd/sr5650/acpi/sr5650.asl
-new file mode 100644
-index 0000000..a6ab114
---- /dev/null
-+++ b/src/southbridge/amd/sr5650/acpi/sr5650.asl
-@@ -0,0 +1,388 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2009 Advanced Micro Devices, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+Scope(\) {
-+      Name(PCBA, 0xE0000000)  /* Base address of PCIe config space */
-+      Name(HPBA, 0xFED00000)  /* Base address of HPET table */
-+
-+      /* PIC IRQ mapping registers, C00h-C01h */
-+      OperationRegion(PRQM, SystemIO, 0x00000C00, 0x00000002)
-+              Field(PRQM, ByteAcc, NoLock, Preserve) {
-+              PRQI, 0x00000008,
-+              PRQD, 0x00000008,  /* Offset: 1h */
-+      }
-+      IndexField(PRQI, PRQD, ByteAcc, NoLock, Preserve) {
-+              PINA, 0x00000008,       /* Index 0 */
-+              PINB, 0x00000008,       /* Index 1 */
-+              PINC, 0x00000008,       /* Index 2 */
-+              PIND, 0x00000008,       /* Index 3 */
-+              AINT, 0x00000008,       /* Index 4 */
-+              SINT, 0x00000008,       /* Index 5 */
-+                  , 0x00000008,       /* Index 6 */
-+              AAUD, 0x00000008,       /* Index 7 */
-+              AMOD, 0x00000008,       /* Index 8 */
-+              PINE, 0x00000008,       /* Index 9 */
-+              PINF, 0x00000008,       /* Index A */
-+              PING, 0x00000008,       /* Index B */
-+              PINH, 0x00000008,       /* Index C */
-+      }
-+
-+      /* PCI Error control register */
-+      OperationRegion(PERC, SystemIO, 0x00000C14, 0x00000001)
-+              Field(PERC, ByteAcc, NoLock, Preserve) {
-+              SENS, 0x00000001,
-+              PENS, 0x00000001,
-+              SENE, 0x00000001,
-+              PENE, 0x00000001,
-+      }
-+
-+      Scope(\_SB) {
-+              /* PCIe Configuration Space for 16 busses */
-+              OperationRegion(PCFG, SystemMemory, PCBA, 0x01000000) /* Each 
bus consumes 1MB */
-+                      Field(PCFG, ByteAcc, NoLock, Preserve) {
-+                      /* Byte offsets are computed using the following 
technique:
-+                       * ((bus number + 1) * ((device number * 8) * 4096)) + 
register offset
-+                       * The 8 comes from 8 functions per device, and 4096 
bytes per function config space
-+                      */
-+                      Offset(0x00088024),     /* Byte offset to SATA register 
24h - Bus 0, Device 17, Function 0 */
-+                      STB5, 32,
-+                      Offset(0x00098042),     /* Byte offset to OHCI0 
register 42h - Bus 0, Device 19, Function 0 */
-+                      PT0D, 1,
-+                      PT1D, 1,
-+                      PT2D, 1,
-+                      PT3D, 1,
-+                      PT4D, 1,
-+                      PT5D, 1,
-+                      PT6D, 1,
-+                      PT7D, 1,
-+                      PT8D, 1,
-+                      PT9D, 1,
-+                      Offset(0x000A0004),     /* Byte offset to SMBUS 
register 4h - Bus 0, Device 20, Function 0 */
-+                      SBIE, 1,
-+                      SBME, 1,
-+                      Offset(0x000A0008),     /* Byte offset to SMBUS 
register 8h - Bus 0, Device 20, Function 0 */
-+                      SBRI, 8,
-+                      Offset(0x000A0014),     /* Byte offset to SMBUS 
register 14h - Bus 0, Device 20, Function 0 */
-+                      SBB1, 32,
-+                      Offset(0x000A0078),     /* Byte offset to SMBUS 
register 78h - Bus 0, Device 20, Function 0 */
-+                      ,14,
-+                      P92E, 1,                /* Port92 decode enable */
-+              }
-+
-+              OperationRegion(SB5, SystemMemory, STB5, 0x1000)
-+                      Field(SB5, AnyAcc, NoLock, Preserve){
-+                      /* Port 0 */
-+                      Offset(0x120),          /* Port 0 Task file status */
-+                      P0ER, 1,
-+                      , 2,
-+                      P0DQ, 1,
-+                      , 3,
-+                      P0BY, 1,
-+                      Offset(0x128),          /* Port 0 Serial ATA status */
-+                      P0DD, 4,
-+                      , 4,
-+                      P0IS, 4,
-+                      Offset(0x12C),          /* Port 0 Serial ATA control */
-+                      P0DI, 4,
-+                      Offset(0x130),          /* Port 0 Serial ATA error */
-+                      , 16,
-+                      P0PR, 1,
-+
-+                      /* Port 1 */
-+                      offset(0x1A0),          /* Port 1 Task file status */
-+                      P1ER, 1,
-+                      , 2,
-+                      P1DQ, 1,
-+                      , 3,
-+                      P1BY, 1,
-+                      Offset(0x1A8),          /* Port 1 Serial ATA status */
-+                      P1DD, 4,
-+                      , 4,
-+                      P1IS, 4,
-+                      Offset(0x1AC),          /* Port 1 Serial ATA control */
-+                      P1DI, 4,
-+                      Offset(0x1B0),          /* Port 1 Serial ATA error */
-+                      , 16,
-+                      P1PR, 1,
-+
-+                      /* Port 2 */
-+                      Offset(0x220),          /* Port 2 Task file status */
-+                      P2ER, 1,
-+                      , 2,
-+                      P2DQ, 1,
-+                      , 3,
-+                      P2BY, 1,
-+                      Offset(0x228),          /* Port 2 Serial ATA status */
-+                      P2DD, 4,
-+                      , 4,
-+                      P2IS, 4,
-+                      Offset(0x22C),          /* Port 2 Serial ATA control */
-+                      P2DI, 4,
-+                      Offset(0x230),          /* Port 2 Serial ATA error */
-+                      , 16,
-+                      P2PR, 1,
-+
-+                      /* Port 3 */
-+                      Offset(0x2A0),          /* Port 3 Task file status */
-+                      P3ER, 1,
-+                      , 2,
-+                      P3DQ, 1,
-+                      , 3,
-+                      P3BY, 1,
-+                      Offset(0x2A8),          /* Port 3 Serial ATA status */
-+                      P3DD, 4,
-+                      , 4,
-+                      P3IS, 4,
-+                      Offset(0x2AC),          /* Port 3 Serial ATA control */
-+                      P3DI, 4,
-+                      Offset(0x2B0),          /* Port 3 Serial ATA error */
-+                      , 16,
-+                      P3PR, 1,
-+              }
-+
-+              Method(CIRQ, 0x00, NotSerialized){
-+                      Store(0, PINA)
-+                      Store(0, PINB)
-+                      Store(0, PINC)
-+                      Store(0, PIND)
-+                      Store(0, PINE)
-+                      Store(0, PINF)
-+                      Store(0, PING)
-+                      Store(0, PINH)
-+              }
-+
-+              /* set "A", 8259 interrupts */
-+              Name (PRSA, ResourceTemplate () {
-+                      IRQ(Level, ActiveLow, Exclusive) {4, 7, 10, 11, 12, 14, 
15}
-+              })
-+
-+              Method (CRSA, 1, Serialized) {
-+                      Name (LRTL, ResourceTemplate() {
-+                              IRQ(Level, ActiveLow, Shared) {15}
-+                      })
-+                      CreateWordField(LRTL, 1, LIRQ)
-+                      ShiftLeft(1, Arg0, LIRQ)
-+                      Return (LRTL)
-+              }
-+
-+              Method (SRSA, 1, Serialized) {
-+                      CreateWordField(Arg0, 1, LIRQ)
-+                      FindSetRightBit(LIRQ, Local0)
-+                      if (Local0) {
-+                              Decrement(Local0)
-+                      }
-+                      Return (Local0)
-+              }
-+
-+              Device(LNKA) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 1)
-+                      Method(_STA, 0) {
-+                              if (PINA) {
-+                                      Return(0x0B) /* LNKA is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKA is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PINA)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PINA))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PINA)
-+                      }
-+              }
-+
-+              Device(LNKB) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 2)
-+                      Method(_STA, 0) {
-+                              if (PINB) {
-+                                      Return(0x0B) /* LNKB is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKB is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PINB)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PINB))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PINB)
-+                      }
-+              }
-+
-+              Device(LNKC) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 3)
-+                      Method(_STA, 0) {
-+                              if (PINC) {
-+                                      Return(0x0B) /* LNKC is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKC is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PINC)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PINC))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PINC)
-+                      }
-+              }
-+
-+              Device(LNKD) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 4)
-+                      Method(_STA, 0) {
-+                              if (PIND) {
-+                                      Return(0x0B) /* LNKD is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKD is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PIND)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PIND))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PIND)
-+                      }
-+              }
-+
-+              Device(LNKE) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 5)
-+                      Method(_STA, 0) {
-+                              if (PINE) {
-+                                      Return(0x0B) /* LNKE is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKE is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PINE)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PINE))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PINE)
-+                      }
-+              }
-+
-+              Device(LNKF) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 6)
-+                      Method(_STA, 0) {
-+                              if (PINF) {
-+                                      Return(0x0B) /* LNKF is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKF is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PINF)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PINF))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PINF)
-+                      }
-+              }
-+
-+              Device(LNKG) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 7)
-+                      Method(_STA, 0) {
-+                              if (PING) {
-+                                      Return(0x0B) /* LNKG is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKG is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PING)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PING))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PING)
-+                      }
-+              }
-+
-+              Device(LNKH) {
-+                      Name(_HID, EISAID("PNP0C0F"))
-+                      Name(_UID, 8)
-+                      Method(_STA, 0) {
-+                              if (PINH) {
-+                                      Return(0x0B) /* LNKH is invisible */
-+                              } else {
-+                                      Return(0x09) /* LNKH is disabled */
-+                              }
-+                      }
-+                      Method(_DIS, 0) {
-+                              Store(0, PINH)
-+                      }
-+                      Method(_PRS, 0) {
-+                              Return (PRSA)
-+                      }
-+                      Method (_CRS, 0, Serialized) {
-+                              Return (CRSA(PINH))
-+                      }
-+                      Method (_SRS, 1, Serialized) {
-+                              Store (SRSA(Arg0), PINH)
-+                      }
-+              }
-+
-+      }   /* End Scope(_SB)  */
-+
-+}  /* End Scope(/)  */
-diff --git a/src/southbridge/amd/sr5650/early_setup.c 
b/src/southbridge/amd/sr5650/early_setup.c
-index ec555f8..664f60a 100644
---- a/src/southbridge/amd/sr5650/early_setup.c
-+++ b/src/southbridge/amd/sr5650/early_setup.c
-@@ -3,6 +3,7 @@
-  *
-  * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -504,7 +505,8 @@ void sr5650_early_setup(void)
-       /*ATINB_PrepareInit */
-       get_cpu_rev();
- 
--      switch (get_nb_rev(nb_dev)) {   /* PCIEMiscInit */
-+      uint8_t revno = get_nb_rev(nb_dev);
-+      switch (revno) {        /* PCIEMiscInit */
-       case REV_SR5650_A11:
-               printk(BIOS_INFO, "NB Revision is A11.\n");
-               break;
-@@ -514,6 +516,9 @@ void sr5650_early_setup(void)
-       case REV_SR5650_A21:
-               printk(BIOS_INFO, "NB Revision is A21.\n");
-               break;
-+      default:
-+              printk(BIOS_INFO, "NB Revision is %02x (Unrecognized).\n", 
revno);
-+              break;
-       }
- 
-       fam10_optimization();
-diff --git a/src/southbridge/amd/sr5650/ht.c b/src/southbridge/amd/sr5650/ht.c
-index c497107..02f4f7f 100644
---- a/src/southbridge/amd/sr5650/ht.c
-+++ b/src/southbridge/amd/sr5650/ht.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -55,7 +56,7 @@ static const apic_device_info default_apic_device_info_t [] 
= {
-       [13] = {4,     ABCD,       30}    /* Dev13 Grp4 [Int - 16..19] */
- };
- 
--/* Their name are quite regular. So I undefine them. */
-+/* These define names are common, so undefine them to avoid potential issues 
in other code */
- #undef ABCD
- #undef BCDA
- #undef CDAB
-diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
-index 3720a61..d306b5a 100644
---- a/src/southbridge/amd/sr5650/pcie.c
-+++ b/src/southbridge/amd/sr5650/pcie.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -61,8 +62,10 @@ static void ValidatePortEn(device_t nb_dev)
- *****************************************************************/
- static void PciePowerOffGppPorts(device_t nb_dev, device_t dev, u32 port)
- {
-+      printk(BIOS_DEBUG, "PciePowerOffGppPorts() port %d\n", port);
-       u32 reg;
-       u16 state_save;
-+      uint8_t i;
-       struct southbridge_amd_sr5650_config *cfg =
-               (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
-       u16 state = cfg->port_enable;
-@@ -72,6 +75,28 @@ static void PciePowerOffGppPorts(device_t nb_dev, device_t 
dev, u32 port)
-       state = ~state;
-       state &= (1 << 4) + (1 << 5) + (1 << 6) + (1 << 7);
-       state_save = state << 17;
-+      /* Disable ports any that failed training */
-+      for (i = 9; i <= 13; i++) {
-+              if (!(AtiPcieCfg.PortDetect & 1 << i)) {
-+                      if ((port >= 9) && (port <= 13)) {
-+                              state |= (1 << (port + 7));
-+                      }
-+                      if (port == 9)
-+                              state_save |= 1 << 25;
-+                      if (port == 10)
-+                              state_save |= 1 << 26;
-+                      if (port == 11)
-+                              state_save |= 1 << 6;
-+                      if (port == 12)
-+                              state_save |= 1 << 7;
-+
-+                      if (port == 13) {
-+                              reg = nbmisc_read_index(nb_dev, 0x2a);
-+                              reg |= 1 << 4;
-+                              nbmisc_write_index(nb_dev, 0x2a, reg);
-+                      }
-+              }
-+      }
-       state &= !(AtiPcieCfg.PortHp);
-       reg = nbmisc_read_index(nb_dev, 0x0c);
-       reg |= state;
-@@ -483,6 +508,8 @@ static void EnableLclkGating(device_t dev)
- *****************************************/
- void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, u32 port)
- {
-+      uint8_t training_ok = 1;
-+
-       u32 gpp_sb_sel = 0;
-       struct southbridge_amd_sr5650_config *cfg =
-           (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
-@@ -701,6 +728,12 @@ void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, 
u32 port)
-                               printk(BIOS_DEBUG, "PcieTrainPort port=0x%x 
result=%d\n", port, res);
-                               if (res) {
-                                       AtiPcieCfg.PortDetect |= 1 << port;
-+                              } else {
-+                                      /* If the training failed the disable 
the bridge to prevent subsequent
-+                                       * lockup on bridge configuration 
register read during the PCI bus scan
-+                                       */
-+                                      training_ok = 0;
-+                                      dev->enabled = 0;
-                               }
-                       }
-               }
-@@ -747,8 +780,8 @@ void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, u32 
port)
-        * wait dev 0x6B bit3 clear
-        */
- 
--      if (port == 8){
--              PciePowerOffGppPorts(nb_dev, dev, port); /* , This should be 
run for all ports that are not hotplug and don't detect devices */
-+      if ((port == 8) || (!training_ok)) {
-+              PciePowerOffGppPorts(nb_dev, dev, port);        /* This is run 
for all ports that are not hotplug and don't detect devices */
-       }
- }
- 
-diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
-index 441be66..75383de 100644
---- a/src/southbridge/amd/sr5650/sr5650.c
-+++ b/src/southbridge/amd/sr5650/sr5650.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -95,32 +96,30 @@ void nbpcie_ind_write_index(device_t nb_dev, u32 index, 
u32 data)
- void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add)
- {
-       /* K8 Function1 is address map */
--      device_t k8_f1;
--      device_t np = dev_find_slot(0, PCI_DEVFN(0x19, 1));
--      u16 node;
--
--      for (node = 0; node < CONFIG_MAX_PHYSICAL_CPUS; node++) {
--              k8_f1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
--              if (!k8_f1) {
--                      break;
--              }
--
--              if (in_out) {
--                      /* Fill MMIO limit/base pair. */
--                      pci_write_config32(k8_f1, 0xbc,
--                                         (((pcie_base_add + 0x10000000 -
--                                            1) >> 8) & 0xffffff00) | 0x8 | 
(np ? 2 << 4 : 0 << 4));
--                      pci_write_config32(k8_f1, 0xb8, (pcie_base_add >> 8) | 
0x3);
--                      pci_write_config32(k8_f1, 0xb4,
--                                         ((mmio_base_add + 0x10000000 -
--                                           1) >> 8) | (np ? 2 << 4 : 0 << 4));
--                      pci_write_config32(k8_f1, 0xb0, (mmio_base_add >> 8) | 
0x3);
--              } else {
--                      pci_write_config32(k8_f1, 0xb8, 0);
--                      pci_write_config32(k8_f1, 0xbc, 0);
--                      pci_write_config32(k8_f1, 0xb0, 0);
--                      pci_write_config32(k8_f1, 0xb4, 0);
--              }
-+      device_t k8_f1 = dev_find_slot(0, PCI_DEVFN(0x18, 1));
-+      device_t k8_f0 = dev_find_slot(0, PCI_DEVFN(0x18, 0));
-+
-+      if (in_out) {
-+              u32 dword, sblk;
-+
-+              /* Get SBLink value (HyperTransport I/O Hub Link ID). */
-+              dword = pci_read_config32(k8_f0, 0x64);
-+              sblk = (dword >> 8) & 0x3;
-+
-+              /* Fill MMIO limit/base pair. */
-+              pci_write_config32(k8_f1, 0xbc,
-+                                 (((pcie_base_add + 0x10000000 -
-+                                   1) >> 8) & 0xffffff00) | 0x80 | (sblk << 
4));
-+              pci_write_config32(k8_f1, 0xb8, (pcie_base_add >> 8) | 0x3);
-+              pci_write_config32(k8_f1, 0xb4,
-+                                 (((mmio_base_add + 0x10000000 -
-+                                   1) >> 8) & 0xffffff00) | (sblk << 4));
-+              pci_write_config32(k8_f1, 0xb0, (mmio_base_add >> 8) | 0x3);
-+      } else {
-+              pci_write_config32(k8_f1, 0xb8, 0);
-+              pci_write_config32(k8_f1, 0xbc, 0);
-+              pci_write_config32(k8_f1, 0xb0, 0);
-+              pci_write_config32(k8_f1, 0xb4, 0);
-       }
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0007-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
 
b/resources/libreboot/patch/kgpe-d16/0007-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
deleted file mode 100644
index 017295e..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0007-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
+++ /dev/null
@@ -1,832 +0,0 @@
-From 1c4603c0b0003dc41519ed8e03782ff6e1f9222f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 17:50:29 -0500
-Subject: [PATCH 007/139] cpu/amd: Add initial support for AMD Socket G34
- processors
-
-Change-Id: Iccd034f32c26513edd52ca3a11a30f61c362682d
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/Kconfig                        |   1 +
- src/cpu/amd/Makefile.inc                   |   1 +
- src/cpu/amd/car/post_cache_as_ram.c        |  19 ++++-
- src/cpu/amd/model_10xxx/init_cpus.c        |  34 ++++++++-
- src/cpu/amd/model_10xxx/model_10xxx_init.c |   2 +
- src/cpu/amd/model_10xxx/processor_name.c   |  23 +++++++
- src/cpu/amd/model_10xxx/ram_calc.c         |   2 +
- src/cpu/amd/quadcore/quadcore_id.c         |  77 ++++++++++++++++-----
- src/cpu/amd/socket_G34/Kconfig             |  29 ++++++++
- src/cpu/amd/socket_G34/Makefile.inc        |  14 ++++
- src/cpu/amd/socket_G34/socket_G34.c        |  25 +++++++
- src/northbridge/amd/amdfam10/northbridge.c | 102 ++++++++++++++++++++++-----
- src/northbridge/amd/amdht/ht_wrapper.c     | 107 ++++++++++++++++++++++++++++-
- src/northbridge/amd/amdht/ht_wrapper.h     |  25 +++++++
- 14 files changed, 417 insertions(+), 44 deletions(-)
- create mode 100644 src/cpu/amd/socket_G34/Kconfig
- create mode 100644 src/cpu/amd/socket_G34/Makefile.inc
- create mode 100644 src/cpu/amd/socket_G34/socket_G34.c
- create mode 100644 src/northbridge/amd/amdht/ht_wrapper.h
-
-diff --git a/src/cpu/amd/Kconfig b/src/cpu/amd/Kconfig
-index 8286b2a..3a02043 100644
---- a/src/cpu/amd/Kconfig
-+++ b/src/cpu/amd/Kconfig
-@@ -5,6 +5,7 @@ source src/cpu/amd/socket_AM2/Kconfig
- source src/cpu/amd/socket_AM2r2/Kconfig
- source src/cpu/amd/socket_AM3/Kconfig
- source src/cpu/amd/socket_C32/Kconfig
-+source src/cpu/amd/socket_G34/Kconfig
- source src/cpu/amd/socket_ASB2/Kconfig
- source src/cpu/amd/socket_F/Kconfig
- source src/cpu/amd/socket_F_1207/Kconfig
-diff --git a/src/cpu/amd/Makefile.inc b/src/cpu/amd/Makefile.inc
-index a73e25f..e532aba 100644
---- a/src/cpu/amd/Makefile.inc
-+++ b/src/cpu/amd/Makefile.inc
-@@ -8,6 +8,7 @@ subdirs-$(CONFIG_CPU_AMD_SOCKET_AM2R2) += socket_AM2r2
- subdirs-$(CONFIG_CPU_AMD_SOCKET_AM3) += socket_AM3
- subdirs-$(CONFIG_CPU_AMD_SOCKET_ASB2) += socket_ASB2
- subdirs-$(CONFIG_CPU_AMD_SOCKET_C32_NON_AGESA) += socket_C32
-+subdirs-$(CONFIG_CPU_AMD_SOCKET_G34_NON_AGESA) += socket_G34
- subdirs-$(CONFIG_CPU_AMD_GEODE_GX2) += geode_gx2
- subdirs-$(CONFIG_CPU_AMD_GEODE_LX) += geode_lx
- subdirs-$(CONFIG_CPU_AMD_SOCKET_S1G1) += socket_S1G1
-diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
-index 96df3e7..230d1aa 100644
---- a/src/cpu/amd/car/post_cache_as_ram.c
-+++ b/src/cpu/amd/car/post_cache_as_ram.c
-@@ -1,4 +1,5 @@
--/* 2005.6 by yhlu
-+/* Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * 2005.6 by yhlu
-  * 2006.3 yhlu add copy data from CAR to ram
-  */
- #include <string.h>
-@@ -46,6 +47,15 @@ static void memset_(void *d, int val, size_t len)
-       memset(d, val, len);
- }
- 
-+static int memcmp_(void *d, const void *s, size_t len)
-+{
-+#if PRINTK_IN_CAR
-+      printk(BIOS_SPEW, " Compare [%08x-%08x] with [%08x - %08x] ... ",
-+              (u32) s, (u32) (s + len - 1), (u32) d, (u32) (d + len - 1));
-+#endif
-+      return memcmp(d, s, len);
-+}
-+
- static void prepare_romstage_ramstack(void *resume_backup_memory)
- {
-       size_t backup_top = backup_size();
-@@ -110,6 +120,12 @@ void post_cache_as_ram(void)
-       memcpy_(migrated_car, &_car_data_start[0], car_size);
-       print_car_debug("Done\n");
- 
-+      print_car_debug("Verifying data integrity in RAM... ");
-+      if (memcmp_(migrated_car, &_car_data_start[0], car_size) == 0)
-+              print_car_debug("Done\n");
-+      else
-+              print_car_debug("FAILED\n");
-+
-       /* New stack grows right below migrated_car. */
-       print_car_debug("Switching to use RAM as stack... ");
-       cache_as_ram_switch_stack(migrated_car);
-@@ -128,6 +144,7 @@ void cache_as_ram_new_stack (void)
-       disable_cache_as_ram_bsp();
- 
-       disable_cache();
-+      /* Enable cached access to RAM in the range 1M to CONFIG_RAMTOP */
-       set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
-       enable_cache();
- 
-diff --git a/src/cpu/amd/model_10xxx/init_cpus.c 
b/src/cpu/amd/model_10xxx/init_cpus.c
-index 4c72848..8de6d25 100644
---- a/src/cpu/amd/model_10xxx/init_cpus.c
-+++ b/src/cpu/amd/model_10xxx/init_cpus.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -67,6 +68,9 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
-       u32 nb_cfg_54;
-       int i, j;
-       u32 ApicIdCoreIdSize;
-+      uint8_t rev_gte_d = 0;
-+      uint8_t dual_node = 0;
-+      uint32_t f3xe8;
- 
-       /* get_nodes define in ht_wrapper.c */
-       nodes = get_nodes();
-@@ -81,6 +85,16 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
-       /* Assume that all node are same stepping, otherwise we can use use
-          nb_cfg_54 from bsp for all nodes */
-       nb_cfg_54 = read_nb_cfg_54();
-+      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
-+
-+      if (cpuid_eax(0x80000001) >= 0x8)
-+              /* Revision D or later */
-+              rev_gte_d = 1;
-+
-+      if (rev_gte_d)
-+               /* Check for dual node capability */
-+              if (f3xe8 & 0x20000000)
-+                      dual_node = 1;
- 
-       ApicIdCoreIdSize = (cpuid_ecx(0x80000008) >> 12 & 0xf);
-       if (ApicIdCoreIdSize) {
-@@ -91,6 +105,8 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
- 
-       for (i = 0; i < nodes; i++) {
-               cores_found = get_core_num_in_bsp(i);
-+              if (siblings > cores_found)
-+                      siblings = cores_found;
- 
-               u32 jstart, jend;
- 
-@@ -107,9 +123,21 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
-               }
- 
-               for (j = jstart; j <= jend; j++) {
--                      ap_apicid =
--                          i * (nb_cfg_54 ? (siblings + 1) : 1) +
--                          j * (nb_cfg_54 ? 1 : 64);
-+                      if (dual_node) {
-+                              ap_apicid = 0;
-+                              if (nb_cfg_54) {
-+                                      ap_apicid |= ((i >> 1) & 0x3) << 4;     
                /* Node ID */
-+                                      ap_apicid |= ((i & 0x1) * (siblings + 
1)) + j;          /* Core ID */
-+                              } else {
-+                                      ap_apicid |= i & 0x3;                   
                /* Node ID */
-+                                      ap_apicid |= (((i & 0x1) * (siblings + 
1)) + j) << 4;   /* Core ID */
-+                              }
-+                      } else {
-+                              ap_apicid =
-+                              i * (nb_cfg_54 ? (siblings + 1) : 1) +
-+                              j * (nb_cfg_54 ? 1 : 64);
-+                      }
-+
- 
- #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET > 0)
- #if !CONFIG_LIFT_BSP_APIC_ID
-diff --git a/src/cpu/amd/model_10xxx/model_10xxx_init.c 
b/src/cpu/amd/model_10xxx/model_10xxx_init.c
-index 590b89d..b942c1a 100644
---- a/src/cpu/amd/model_10xxx/model_10xxx_init.c
-+++ b/src/cpu/amd/model_10xxx/model_10xxx_init.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -153,6 +154,7 @@ static struct cpu_device_id cpu_table[] = {
-       { X86_VENDOR_AMD, 0x100F63 },           /* DA-C3 */
-       { X86_VENDOR_AMD, 0x100F80 },           /* HY-D0 */
-       { X86_VENDOR_AMD, 0x100F81 },           /* HY-D1 */
-+      { X86_VENDOR_AMD, 0x100F91 },           /* HY-D1 */
-       { X86_VENDOR_AMD, 0x100FA0 },           /* PH-E0 */
-       { 0, 0 },
- };
-diff --git a/src/cpu/amd/model_10xxx/processor_name.c 
b/src/cpu/amd/model_10xxx/processor_name.c
-index a25e3a9..12c45c9 100644
---- a/src/cpu/amd/model_10xxx/processor_name.c
-+++ b/src/cpu/amd/model_10xxx/processor_name.c
-@@ -157,6 +157,24 @@ static const struct str_s String2_socket_AM2[] = {
-       {0, 0, 0, NULL}
- };
- 
-+static const struct str_s String1_socket_G34[] = {
-+      {0x00, 0x07, 0x00, "AMD Opteron(tm) Processor 61"},
-+      {0x00, 0x0B, 0x00, "AMD Opteron(tm) Processor 61"},
-+      {0x01, 0x07, 0x01, "Embedded AMD Opteron(tm) Processor "},
-+      {0, 0, 0, NULL}
-+};
-+
-+static const struct str_s String2_socket_G34[] = {
-+      {0x00, 0x07, 0x00, " HE"},
-+      {0x00, 0x07, 0x01, " SE"},
-+      {0x00, 0x0B, 0x00, " HE"},
-+      {0x00, 0x0B, 0x01, " SE"},
-+      {0x00, 0x0B, 0x0F, ""},
-+      {0x01, 0x07, 0x01, " QS"},
-+      {0x01, 0x07, 0x02, " KS"},
-+      {0, 0, 0, NULL}
-+};
-+
- static const struct str_s String1_socket_C32[] = {
-       {0x00, 0x03, 0x00, "AMD Opteron(tm) Processor 41"},
-       {0x00, 0x05, 0x00, "AMD Opteron(tm) Processor 41"},
-@@ -240,6 +258,11 @@ int init_processor_name(void)
-               str = String1_socket_AM2;
-               str2 = String2_socket_AM2;
-               break;
-+      case 3:         /* G34 */
-+              str = String1_socket_G34;
-+              str2 = String2_socket_G34;
-+              str2_checkNC = 0;
-+              break;
-       case 5:         /* C32 */
-               str = String1_socket_C32;
-               str2 = String2_socket_C32;
-diff --git a/src/cpu/amd/model_10xxx/ram_calc.c 
b/src/cpu/amd/model_10xxx/ram_calc.c
-index c8637c9..46ccdbd 100644
---- a/src/cpu/amd/model_10xxx/ram_calc.c
-+++ b/src/cpu/amd/model_10xxx/ram_calc.c
-@@ -26,6 +26,7 @@
- 
- #include "ram_calc.h"
- 
-+#if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
- uint64_t get_uma_memory_size(uint64_t topmem)
- {
-       uint64_t uma_size = 0;
-@@ -50,3 +51,4 @@ void *cbmem_top(void)
- 
-       return (void *) topmem - get_uma_memory_size(topmem);
- }
-+#endif
-diff --git a/src/cpu/amd/quadcore/quadcore_id.c 
b/src/cpu/amd/quadcore/quadcore_id.c
-index cf45196..c5921de 100644
---- a/src/cpu/amd/quadcore/quadcore_id.c
-+++ b/src/cpu/amd/quadcore/quadcore_id.c
-@@ -1,6 +1,7 @@
- /*
-  * This file is part of the coreboot project.
-  *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-  *
-  * This program is free software; you can redistribute it and/or modify
-@@ -37,33 +38,71 @@ u32 get_initial_apicid(void)
-       return ((cpuid_ebx(1) >> 24) & 0xff);
- }
- 
--//called by amd_siblings too
--#define CORE_ID_BIT 2
--#define NODE_ID_BIT 6
-+/* Called by amd_siblings (ramstage) as well */
- struct node_core_id get_node_core_id(u32 nb_cfg_54)
- {
-       struct node_core_id id;
--      u32 core_id_bits;
-+      uint8_t apicid;
-+      uint8_t rev_gte_d = 0;
-+      uint8_t dual_node = 0;
-+      uint32_t f3xe8;
- 
--      u32 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
--      if(ApicIdCoreIdSize) {
--              core_id_bits = ApicIdCoreIdSize;
--      } else {
--              core_id_bits = CORE_ID_BIT; //quad core
--      }
-+#ifdef __PRE_RAM__
-+      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
-+#else
-+      f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
-+#endif
-+
-+      if (cpuid_eax(0x80000001) >= 0x8)
-+              /* Revision D or later */
-+              rev_gte_d = 1;
- 
--      // get the apicid via cpuid(1) ebx[31:24]
-+      if (rev_gte_d)
-+               /* Check for dual node capability */
-+              if (f3xe8 & 0x20000000)
-+                      dual_node = 1;
-+
-+      /* Get the apicid via cpuid(1) ebx[31:24]
-+       * The apicid format varies based on processor revision
-+       */
-+      apicid = (cpuid_ebx(1) >> 24) & 0xff;
-       if( nb_cfg_54) {
--              // when NB_CFG[54] is set, nodeid = ebx[31:26], coreid = 
ebx[25:24]
--              id.coreid = (cpuid_ebx(1) >> 24) & 0xff;
--              id.nodeid = (id.coreid>>core_id_bits);
--              id.coreid &= ((1<<core_id_bits)-1);
-+              if (rev_gte_d && dual_node) {
-+                      id.coreid = apicid & 0xf;
-+                      id.nodeid = (apicid & 0x30) >> 4;
-+              } else if (rev_gte_d && !dual_node) {
-+                      id.coreid = apicid & 0x7;
-+                      id.nodeid = (apicid & 0x38) >> 3;
-+              } else {
-+                      id.coreid = apicid & 0x3;
-+                      id.nodeid = (apicid & 0x1c) >> 2;
-+              }
-       } else {
--              // when NB_CFG[54] is clear, nodeid = ebx[29:24], coreid = 
ebx[31:30]
--              id.nodeid = (cpuid_ebx(1) >> 24) & 0xff;
--              id.coreid = (id.nodeid>>NODE_ID_BIT);
--              id.nodeid &= ((1<<NODE_ID_BIT)-1);
-+              if (rev_gte_d && dual_node) {
-+                      id.coreid = (apicid & 0xf0) >> 4;
-+                      id.nodeid = apicid & 0x3;
-+              } else if (rev_gte_d && !dual_node) {
-+                      id.coreid = (apicid & 0xe0) >> 5;
-+                      id.nodeid = apicid & 0x7;
-+              } else {
-+                      id.coreid = (apicid & 0x60) >> 5;
-+                      id.nodeid = apicid & 0x7;
-+              }
-       }
-+
-+      if (rev_gte_d && dual_node) {
-+              /* Coreboot expects each separate processor die to be on a 
different nodeid.
-+               * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
-+               */
-+              uint8_t core_count = (((f3xe8 & 0x00008000) >> 13) | ((f3xe8 & 
0x00003000) >> 12)) + 1;
-+
-+              id.nodeid = id.nodeid * 2;
-+              if (id.coreid >= core_count) {
-+                      id.nodeid += 1;
-+                      id.coreid = id.coreid - core_count;
-+              }
-+      }
-+
-       return id;
- }
- 
-diff --git a/src/cpu/amd/socket_G34/Kconfig b/src/cpu/amd/socket_G34/Kconfig
-new file mode 100644
-index 0000000..abc9726
---- /dev/null
-+++ b/src/cpu/amd/socket_G34/Kconfig
-@@ -0,0 +1,29 @@
-+config CPU_AMD_SOCKET_G34_NON_AGESA
-+      bool
-+      select CPU_AMD_MODEL_10XXX
-+      select PCI_IO_CFG_EXT
-+      select X86_AMD_FIXED_MTRRS
-+
-+if CPU_AMD_SOCKET_G34_NON_AGESA
-+
-+config CPU_SOCKET_TYPE
-+      hex
-+      default 0x15
-+
-+config EXT_RT_TBL_SUPPORT
-+      bool
-+      default n
-+
-+config CBB
-+      hex
-+      default 0x0
-+
-+config CDB
-+      hex
-+      default 0x18
-+
-+config XIP_ROM_SIZE
-+      hex
-+      default 0x80000
-+
-+endif
-diff --git a/src/cpu/amd/socket_G34/Makefile.inc 
b/src/cpu/amd/socket_G34/Makefile.inc
-new file mode 100644
-index 0000000..a8e1333
---- /dev/null
-+++ b/src/cpu/amd/socket_G34/Makefile.inc
-@@ -0,0 +1,14 @@
-+ramstage-y += socket_G34.c
-+subdirs-y += ../model_10xxx
-+subdirs-y += ../quadcore
-+subdirs-y += ../mtrr
-+subdirs-y += ../microcode
-+subdirs-y += ../../x86/tsc
-+subdirs-y += ../../x86/lapic
-+subdirs-y += ../../x86/cache
-+subdirs-y += ../../x86/pae
-+subdirs-y += ../../x86/mtrr
-+subdirs-y += ../../x86/smm
-+subdirs-y += ../smm
-+
-+cpu_incs-y += $(src)/cpu/amd/car/cache_as_ram.inc
-diff --git a/src/cpu/amd/socket_G34/socket_G34.c 
b/src/cpu/amd/socket_G34/socket_G34.c
-new file mode 100644
-index 0000000..90f7b8c
---- /dev/null
-+++ b/src/cpu/amd/socket_G34/socket_G34.c
-@@ -0,0 +1,25 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <device/device.h>
-+
-+struct chip_operations cpu_amd_socket_G34_ops = {
-+      CHIP_NAME("socket G34")
-+};
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 6d91cbd..74cecc8 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -187,6 +187,43 @@ static void ht_route_link(struct bus *link, scan_state 
mode)
-       }
- }
- 
-+static void amd_g34_fixup(struct bus *link, device_t dev)
-+{
-+      uint32_t nodeid = amdfam10_nodeid(dev);
-+      uint8_t rev_gte_d = 0;
-+      uint8_t dual_node = 0;
-+      uint32_t f3xe8;
-+
-+      if (cpuid_eax(0x80000001) >= 0x8)
-+              /* Revision D or later */
-+              rev_gte_d = 1;
-+
-+      if (rev_gte_d) {
-+              f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
-+
-+              /* Check for dual node capability */
-+              if (f3xe8 & 0x20000000)
-+                      dual_node = 1;
-+
-+              if (dual_node) {
-+                      /* Each G34 processor contains a defective HT link.
-+                      * See the BKDG Rev 3.62 section 2.7.1.5 for details.
-+                      */
-+                      f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 
0xe8);
-+                      uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 
30);
-+                      if (internal_node_number == 0) {
-+                              /* Node 0 */
-+                              if (link->link_num == 6)        /* Link 2 
Sublink 1 */
-+                                      printk(BIOS_DEBUG, 
"amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT 
link\n", nodeid, internal_node_number);
-+                      } else {
-+                              /* Node 1 */
-+                              if (link->link_num == 5)        /* Link 1 
Sublink 1 */
-+                                      printk(BIOS_DEBUG, 
"amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT 
link\n", nodeid, internal_node_number);
-+                      }
-+              }
-+      }
-+}
-+
- static void amdfam10_scan_chain(struct bus *link)
- {
-               unsigned int next_unitid;
-@@ -277,8 +314,11 @@ static void amdfam10_scan_chains(device_t dev)
-       trim_ht_chain(dev);
- 
-       for (link = dev->link_list; link; link = link->next) {
--              if (link->ht_link_up)
-+              if (link->ht_link_up) {
-+                      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
-+                              amd_g34_fixup(link, dev);
-                       amdfam10_scan_chain(link);
-+              }
-       }
- }
- 
-@@ -323,8 +363,7 @@ static struct resource *amdfam10_find_iopair(device_t dev, 
unsigned nodeid, unsi
-               if (result == 1) {
-                       /* I have been allocated this one */
-                       break;
--              }
--              else if (result > 1) {
-+              } else if (result > 1) {
-                       /* I have a free register pair */
-                       free_reg = reg;
-               }
-@@ -357,8 +396,7 @@ static struct resource *amdfam10_find_mempair(device_t 
dev, u32 nodeid, u32 link
-               if (result == 1) {
-                       /* I have been allocated this one */
-                       break;
--              }
--              else if (result > 1) {
-+              } else if (result > 1) {
-                       /* I have a free register pair */
-                       free_reg = reg;
-               }
-@@ -473,8 +511,7 @@ static void amdfam10_set_resource(device_t dev, struct 
resource *resource,
- 
-               set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8);
-               store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 
24), rbase>>8, rend>>8);
--      }
--      else if (resource->flags & IORESOURCE_MEM) {
-+      } else if (resource->flags & IORESOURCE_MEM) {
-               set_mmio_addr_reg(nodeid, link_num, reg, (resource->index 
>>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
-               store_conf_mmio_addr(nodeid, link_num, reg, (resource->index 
>>24), rbase>>8, rend>>8);
-       }
-@@ -799,8 +836,7 @@ static void amdfam10_domain_set_resources(device_t dev)
-                       }
-                       if ((basek + sizek) <= 4*1024*1024) {
-                               sizek = 0;
--                      }
--                      else {
-+                      } else {
-                               basek = 4*1024*1024;
-                               sizek -= (4*1024*1024 - mmio_basek);
-                       }
-@@ -977,8 +1013,7 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
-                               if (dimm_size_bytes > 0x800000000) {
-                                       t->size = 0x7FFF;
-                                       t->extended_size = dimm_size_bytes;
--                              }
--                              else {
-+                              } else {
-                                       t->size = dimm_size_bytes / (1024*1024);
-                                       t->size &= (~0x8000);   /* size 
specified in megabytes */
-                               }
-@@ -1005,8 +1040,7 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
-                               t->part_number = smbios_add_string(t->eos, 
mem_info->dct_stat[node].DimmPartNumber[slot]);
-                               if 
(mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) {
-                                       t->serial_number = 
smbios_add_string(t->eos, "None");
--                              }
--                              else {
-+                              } else {
-                                       snprintf(string_buffer, sizeof 
(string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
-                                       t->serial_number = 
smbios_add_string(t->eos, string_buffer);
-                               }
-@@ -1108,8 +1142,7 @@ static void add_more_links(device_t dev, unsigned 
total_links)
-                       memset(link, 0, links*sizeof(*link));
-                       last->next = link;
-               }
--      }
--      else {
-+      } else {
-               link = malloc(total_links*sizeof(*link));
-               memset(link, 0, total_links*sizeof(*link));
-               dev->link_list = link;
-@@ -1244,6 +1277,10 @@ static void cpu_bus_scan(device_t dev)
-               unsigned busn, devn;
-               struct bus *pbus;
- 
-+              uint8_t rev_gte_d = 0;
-+              uint8_t dual_node = 0;
-+              uint32_t f3xe8;
-+
-               busn = CONFIG_CBB;
-               devn = CONFIG_CDB+i;
-               pbus = dev_mc->bus;
-@@ -1268,6 +1305,7 @@ static void cpu_bus_scan(device_t dev)
-                       }
-               }
- 
-+
-               /* Ok, We need to set the links for that device.
-                * otherwise the device under it will not be scanned
-                */
-@@ -1279,6 +1317,17 @@ static void cpu_bus_scan(device_t dev)
-               if (cdb_dev)
-                       add_more_links(cdb_dev, 4);
- 
-+              f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
-+
-+              if (cpuid_eax(0x80000001) >= 0x8)
-+                      /* Revision D or later */
-+                      rev_gte_d = 1;
-+
-+              if (rev_gte_d)
-+                      /* Check for dual node capability */
-+                      if (f3xe8 & 0x20000000)
-+                              dual_node = 1;
-+
-               cores_found = 0; // one core
-               cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
-               int enable_node = cdb_dev && cdb_dev->enabled;
-@@ -1290,6 +1339,9 @@ static void cpu_bus_scan(device_t dev)
-                       printk(BIOS_DEBUG, "  %s siblings=%d\n", 
dev_path(cdb_dev), cores_found);
-               }
- 
-+              if (siblings > cores_found)
-+                      siblings = cores_found;
-+
-               u32 jj;
-               if(disable_siblings) {
-                       jj = 0;
-@@ -1299,7 +1351,20 @@ static void cpu_bus_scan(device_t dev)
-               }
- 
-               for (j = 0; j <=jj; j++ ) {
--                      u32 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * 
(nb_cfg_54?1:64); // ?
-+                      u32 apic_id;
-+
-+                      if (dual_node) {
-+                              apic_id = 0;
-+                              if (nb_cfg_54) {
-+                                      apic_id |= ((i >> 1) & 0x3) << 4;       
                /* Node ID */
-+                                      apic_id |= ((i & 0x1) * (siblings + 1)) 
+ j;            /* Core ID */
-+                              } else {
-+                                      apic_id |= i & 0x3;                     
                /* Node ID */
-+                                      apic_id |= (((i & 0x1) * (siblings + 
1)) + j) << 4;     /* Core ID */
-+                              }
-+                      } else {
-+                              apic_id = i * (nb_cfg_54?(siblings+1):1) + j * 
(nb_cfg_54?1:64); // ?
-+                      }
- 
- #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
-                       if(sysconf.enabled_apic_ext_id) {
-@@ -1311,7 +1376,7 @@ static void cpu_bus_scan(device_t dev)
-                       device_t cpu = add_cpu_device(cpu_bus, apic_id, 
enable_node);
-                       if (cpu)
-                               amd_cpu_topology(cpu, i, j);
--              } //j
-+              }
-       }
- }
- 
-@@ -1356,8 +1421,7 @@ static void root_complex_enable_dev(struct device *dev)
-       /* Set the operations if it is a special bus type */
-       if (dev->path.type == DEVICE_PATH_DOMAIN) {
-               dev->ops = &pci_domain_ops;
--      }
--      else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
-+      } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
-               dev->ops = &cpu_bus_ops;
-       }
- }
-diff --git a/src/northbridge/amd/amdht/ht_wrapper.c 
b/src/northbridge/amd/amdht/ht_wrapper.c
-index 36fe60b..389b1b1 100644
---- a/src/northbridge/amd/amdht/ht_wrapper.c
-+++ b/src/northbridge/amd/amdht/ht_wrapper.c
-@@ -22,6 +22,8 @@
- #include <console/console.h>
- #include <northbridge/amd/amdfam10/amdfam10.h>
- 
-+#include "ht_wrapper.h"
-+
- /*----------------------------------------------------------------------------
-  *                    TYPEDEFS, DEFINITIONS AND MACROS
-  *
-@@ -113,6 +115,20 @@ void getAmdTopolist(u8 ***p)
-       *p = (u8 **)amd_topo_list;
- }
- 
-+/**
-+ * BOOL AMD_CB_IgnoreLink(u8 Node, u8 Link)
-+ * Description:
-+ *    This routine is used to ignore connected yet faulty HT links,
-+ *    such as those present in a G34 processor package.
-+ *
-+ * Parameters:
-+ *    @param[in]  node   = The node on which this chain is located
-+ *    @param[in]  link   = The link on the host for this chain
-+ */
-+static BOOL AMD_CB_IgnoreLink (u8 node, u8 link)
-+{
-+      return 0;
-+}
- 
- /**
-  * void amd_ht_init(struct sys_info *sysinfo)
-@@ -128,7 +144,7 @@ static void amd_ht_init(struct sys_info *sysinfo)
-               0,      // u8 AutoBusStart;
-               32,     // u8 AutoBusMax;
-               6,      // u8 AutoBusIncrement;
--              NULL,   // BOOL (*AMD_CB_IgnoreLink)();
-+              AMD_CB_IgnoreLink,              // BOOL (*AMD_CB_IgnoreLink)();
-               NULL,   // BOOL (*AMD_CB_OverrideBusNumbers)();
-               AMD_CB_ManualBUIDSwapList,      // BOOL 
(*AMD_CB_ManualBUIDSwapList)();
-               NULL,   // void (*AMD_CB_DeviceCapOverride)();
-@@ -146,6 +162,93 @@ static void amd_ht_init(struct sys_info *sysinfo)
-       printk(BIOS_DEBUG, "Enter amd_ht_init()\n");
-       amdHtInitialize(&ht_wrapper);
-       printk(BIOS_DEBUG, "Exit amd_ht_init()\n");
-+}
- 
--
-+/**
-+ * void amd_ht_fixup(struct sys_info *sysinfo)
-+ *
-+ *  AMD HT fixup
-+ *
-+ */
-+void amd_ht_fixup(struct sys_info *sysinfo) {
-+      printk(BIOS_DEBUG, "amd_ht_fixup()\n");
-+      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX)) {
-+              uint8_t rev_gte_d = 0;
-+              uint8_t dual_node = 0;
-+              uint32_t f3xe8;
-+              uint32_t family;
-+              uint32_t model;
-+
-+              family = model = cpuid_eax(0x80000001);
-+              model = ((model & 0xf0000) >> 16) | ((model & 0xf0) >> 4);
-+
-+              if (model >= 0x8)
-+                      /* Revision D or later */
-+                      rev_gte_d = 1;
-+
-+              if (rev_gte_d) {
-+                      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
-+
-+                      /* Check for dual node capability */
-+                      if (f3xe8 & 0x20000000)
-+                              dual_node = 1;
-+
-+                      if (dual_node) {
-+                              /* Each G34 processor contains a defective HT 
link.
-+                              * See the BKDG Rev 3.62 section 2.7.1.5 for 
details.
-+                              */
-+                              uint8_t node;
-+                              uint8_t node_count = get_nodes();
-+                              uint32_t dword;
-+                              for (node = 0; node < node_count; node++) {
-+                                      f3xe8 = 
pci_read_config32(NODE_PCI(node, 3), 0xe8);
-+                                      uint8_t internal_node_number = ((f3xe8 
& 0xc0000000) >> 30);
-+                                      printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link\n", node, 
internal_node_number);
-+                                      if (internal_node_number == 0) {
-+                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xd8) & 0x1;
-+                                              if (package_link_3_connected) {
-+                                                      /* Set WidthIn and 
WidthOut to 0 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xc4);
-+                                                      dword &= ~0x77000000;
-+                                                      
pci_write_config32(NODE_PCI(node, 0), 0xc4, dword);
-+                                                      /* Set Ganged to 1 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x178);
-+                                                      dword |= 0x00000001;
-+                                                      
pci_write_config32(NODE_PCI(node, 0), 0x178, dword);
-+                                              } else {
-+                                                      /* Set ConnDly to 1 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
-+                                                      dword |= 0x00000100;
-+                                                      
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
-+                                                      /* Set TransOff and 
EndOfChain to 1 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xc4);
-+                                                      dword |= 0x000000c0;
-+                                                      
pci_write_config32(NODE_PCI(node, 4), 0xc4, dword);
-+                                              }
-+                                      } else if (internal_node_number == 1) {
-+                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xb8) & 0x1;
-+                                              if (package_link_3_connected) {
-+                                                      /* Set WidthIn and 
WidthOut to 0 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xa4);
-+                                                      dword &= ~0x77000000;
-+                                                      
pci_write_config32(NODE_PCI(node, 0), 0xa4, dword);
-+                                                      /* Set Ganged to 1 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x174);
-+                                                      dword |= 0x00000001;
-+                                                      
pci_write_config32(NODE_PCI(node, 0), 0x174, dword);
-+                                              } else {
-+                                                      /* Set ConnDly to 1 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
-+                                                      dword |= 0x00000100;
-+                                                      
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
-+                                                      /* Set TransOff and 
EndOfChain to 1 */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xa4);
-+                                                      dword |= 0x000000c0;
-+                                                      
pci_write_config32(NODE_PCI(node, 4), 0xa4, dword);
-+                                              }
-+                                      }
-+                              }
-+                      }
-+              }
-+      }
- }
-diff --git a/src/northbridge/amd/amdht/ht_wrapper.h 
b/src/northbridge/amd/amdht/ht_wrapper.h
-new file mode 100644
-index 0000000..3e9d957
---- /dev/null
-+++ b/src/northbridge/amd/amdht/ht_wrapper.h
-@@ -0,0 +1,25 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc.
-+ */
-+
-+#ifndef AMD_HT_WRAPPER_H
-+#define AMD_HT_WRAPPER_H
-+
-+void amd_ht_fixup(struct sys_info *sysinfo);
-+
-+#endif
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0007-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
 
b/resources/libreboot/patch/kgpe-d16/0007-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
new file mode 100644
index 0000000..0cac522
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0007-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch
@@ -0,0 +1,619 @@
+From c95c41fbedceda4de85a076f8fc600c82106727c Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 17:46:15 -0500
+Subject: [PATCH 007/143] southbridge/amd/sb700: Fix boot hang on ASUS
+ KGPE-D16
+
+Change-Id: I1d7d6715663a13ab94fd6d71808e35f0f7384d00
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/Kconfig       |    4 +
+ src/southbridge/amd/sb700/acpi/ide.asl  |  234 +++++++++++++++++++++++++++++++
+ src/southbridge/amd/sb700/acpi/sata.asl |  133 ++++++++++++++++++
+ src/southbridge/amd/sb700/bootblock.c   |   46 +++++-
+ src/southbridge/amd/sb700/early_setup.c |   18 +++
+ src/southbridge/amd/sb700/lpc.c         |    3 +
+ src/southbridge/amd/sb700/sm.c          |   21 +--
+ 7 files changed, 444 insertions(+), 15 deletions(-)
+ create mode 100644 src/southbridge/amd/sb700/acpi/ide.asl
+ create mode 100644 src/southbridge/amd/sb700/acpi/sata.asl
+
+diff --git a/src/southbridge/amd/sb700/Kconfig 
b/src/southbridge/amd/sb700/Kconfig
+index 0761934..bca74fb 100644
+--- a/src/southbridge/amd/sb700/Kconfig
++++ b/src/southbridge/amd/sb700/Kconfig
+@@ -42,6 +42,10 @@ config SOUTHBRIDGE_AMD_SB700_SKIP_ISA_DMA_INIT
+       bool
+       default n
+ 
++config SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
++      bool
++      default n
++
+ config EHCI_BAR
+       hex
+       default 0xfef00000
+diff --git a/src/southbridge/amd/sb700/acpi/ide.asl 
b/src/southbridge/amd/sb700/acpi/ide.asl
+new file mode 100644
+index 0000000..9b5e3ea
+--- /dev/null
++++ b/src/southbridge/amd/sb700/acpi/ide.asl
+@@ -0,0 +1,234 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/* Some timing tables */
++Name(UDTT, Package(){ /* Udma timing table */
++      120, 90, 60, 45, 30, 20, 15, 0  /* UDMA modes 0 -> 6 */
++})
++
++Name(MDTT, Package(){ /* MWDma timing table */
++      480, 150, 120, 0        /* Legacy DMA modes 0 -> 2 */
++})
++
++Name(POTT, Package(){ /* Pio timing table */
++      600, 390, 270, 180, 120, 0      /* PIO modes 0 -> 4 */
++})
++
++/* Some timing register value tables */
++Name(MDRT, Package(){ /* MWDma timing register table */
++      0x77, 0x21, 0x20, 0xFF  /* Legacy DMA modes 0 -> 2 */
++})
++
++Name(PORT, Package(){
++      0x99, 0x47, 0x34, 0x22, 0x20, 0x99      /* PIO modes 0 -> 4 */
++})
++
++OperationRegion(ICRG, PCI_Config, 0x40, 0x20) /* ide control registers */
++      Field(ICRG, AnyAcc, NoLock, Preserve)
++{
++      PPTS, 8,        /* Primary PIO Slave Timing */
++      PPTM, 8,        /* Primary PIO Master Timing */
++      OFFSET(0x04), PMTS, 8,  /* Primary MWDMA Slave Timing */
++      PMTM, 8,        /* Primary MWDMA Master Timing */
++      OFFSET(0x08), PPCR, 8,  /* Primary PIO Control */
++      OFFSET(0x0A), PPMM, 4,  /* Primary PIO master Mode */
++      PPSM, 4,        /* Primary PIO slave Mode */
++      OFFSET(0x14), PDCR, 2,  /* Primary UDMA Control */
++      OFFSET(0x16), PDMM, 4,  /* Primary UltraDMA Mode */
++      PDSM, 4,        /* Primary UltraDMA Mode */
++}
++
++Method(GTTM, 1) /* get total time*/
++{
++      Store(And(Arg0, 0x0F), Local0)  /* Recovery Width */
++      Increment(Local0)
++      Store(ShiftRight(Arg0, 4), Local1)      /* Command Width */
++      Increment(Local1)
++      Return(Multiply(30, Add(Local0, Local1)))
++}
++
++Device(PRID)
++{
++      Name (_ADR, Zero)
++      Method(_GTM, 0, Serialized)
++      {
++              NAME(OTBF, Buffer(20) { /* out buffer */
++                      0xFF, 0xFF, 0xFF, 0xFF,
++                      0xFF, 0xFF, 0xFF, 0xFF,
++                      0xFF, 0xFF, 0xFF, 0xFF,
++                      0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00
++              })
++
++              CreateDwordField(OTBF, 0, PSD0)   /* PIO spd0 */
++              CreateDwordField(OTBF, 4, DSD0)   /* DMA spd0 */
++              CreateDwordField(OTBF, 8, PSD1)   /* PIO spd1 */
++              CreateDwordField(OTBF, 12, DSD1) /* DMA spd1 */
++              CreateDwordField(OTBF, 16, BFFG) /* buffer flags */
++
++              /* Just return if the channel is disabled */
++              If(And(PPCR, 0x01)) { /* primary PIO control */
++                      Return(OTBF)
++              }
++
++              /* Always tell them independent timing available and 
IOChannelReady used on both drives */
++              Or(BFFG, 0x1A, BFFG)
++
++              Store(GTTM(PPTM), PSD0) /* save total time of primary PIO 
master timming  to PIO spd0 */
++              Store(GTTM(PPTS), PSD1) /* save total time of primary PIO slave 
Timing  to PIO spd1 */
++
++              If(And(PDCR, 0x01)) {   /* It's under UDMA mode */
++                      Or(BFFG, 0x01, BFFG)
++                      Store(DerefOf(Index(UDTT, PDMM)), DSD0)
++              }
++              Else {
++                      Store(GTTM(PMTM), DSD0) /* Primary MWDMA Master Timing, 
 DmaSpd0 */
++              }
++
++              If(And(PDCR, 0x02)) {   /* It's under UDMA mode */
++                      Or(BFFG, 0x04, BFFG)
++                      Store(DerefOf(Index(UDTT, PDSM)), DSD1)
++              }
++              Else {
++                      Store(GTTM(PMTS), DSD1) /* Primary MWDMA Slave Timing,  
DmaSpd0 */
++              }
++
++              Return(OTBF) /* out buffer */
++      }                               /* End Method(_GTM) */
++
++      Method(_STM, 3, Serialized)
++      {
++              NAME(INBF, Buffer(20) { /* in buffer */
++                      0xFF, 0xFF, 0xFF, 0xFF,
++                      0xFF, 0xFF, 0xFF, 0xFF,
++                      0xFF, 0xFF, 0xFF, 0xFF,
++                      0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00
++              })
++
++              CreateDwordField(INBF, 0, PSD0)    /* PIO spd0 */
++              CreateDwordField(INBF, 4, DSD0)   /* PIO spd0 */
++              CreateDwordField(INBF, 8, PSD1)   /* PIO spd1 */
++              CreateDwordField(INBF, 12, DSD1) /* DMA spd1 */
++              CreateDwordField(INBF, 16, BFFG) /*buffer flag */
++
++              Store(Match(POTT, MLE, PSD0, MTR, 0, 0), Local0)
++              Divide(Local0, 5, PPMM,) /* Primary PIO master Mode */
++              Store(Match(POTT, MLE, PSD1, MTR, 0, 0), Local1)
++              Divide(Local1, 5, PPSM,) /* Primary PIO slave Mode */
++
++              Store(DerefOf(Index(PORT, Local0)), PPTM) /* Primary PIO Master 
Timing */
++              Store(DerefOf(Index(PORT, Local1)), PPTS) /* Primary PIO Slave 
Timing */
++
++              If(And(BFFG, 0x01)) {   /* Drive 0 is under UDMA mode */
++                      Store(Match(UDTT, MLE, DSD0, MTR, 0, 0), Local0)
++                      Divide(Local0, 7, PDMM,)
++                      Or(PDCR, 0x01, PDCR)
++              }
++              Else {
++                      If(LNotEqual(DSD0, 0xFFFFFFFF)) {
++                              Store(Match(MDTT, MLE, DSD0, MTR, 0, 0), Local0)
++                              Store(DerefOf(Index(MDRT, Local0)), PMTM)
++                      }
++              }
++
++              If(And(BFFG, 0x04)) {   /* Drive 1 is under UDMA mode */
++                      Store(Match(UDTT, MLE, DSD1, MTR, 0, 0), Local0)
++                      Divide(Local0, 7, PDSM,)
++                      Or(PDCR, 0x02, PDCR)
++              }
++              Else {
++                      If(LNotEqual(DSD1, 0xFFFFFFFF)) {
++                              Store(Match(MDTT, MLE, DSD1, MTR, 0, 0), Local0)
++                              Store(DerefOf(Index(MDRT, Local0)), PMTS)
++                      }
++              }
++              /* Return(INBF) */
++      }               /*End Method(_STM) */
++      Device(MST)
++      {
++              Name(_ADR, 0)
++              Method(_GTF, 0, Serialized) {
++                      Name(CMBF, Buffer(21) {
++                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
++                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
++                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5
++                      })
++                      CreateByteField(CMBF, 1, POMD)
++                      CreateByteField(CMBF, 8, DMMD)
++                      CreateByteField(CMBF, 5, CMDA)
++                      CreateByteField(CMBF, 12, CMDB)
++                      CreateByteField(CMBF, 19, CMDC)
++
++                      Store(0xA0, CMDA)
++                      Store(0xA0, CMDB)
++                      Store(0xA0, CMDC)
++
++                      Or(PPMM, 0x08, POMD)
++
++                      If(And(PDCR, 0x01)) {
++                              Or(PDMM, 0x40, DMMD)
++                      }
++                      Else {
++                              Store(Match
++                                    (MDTT, MLE, GTTM(PMTM),
++                                     MTR, 0, 0), Local0)
++                              If(LLess(Local0, 3)) {
++                                      Or(0x20, Local0, DMMD)
++                              }
++                      }
++                      Return(CMBF)
++              }
++      }               /* End Device(MST) */
++
++      Device(SLAV)
++      {
++              Name(_ADR, 1)
++              Method(_GTF, 0, Serialized) {
++                      Name(CMBF, Buffer(21) {
++                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
++                              0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xEF,
++                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5
++                      })
++                      CreateByteField(CMBF, 1, POMD)
++                      CreateByteField(CMBF, 8, DMMD)
++                      CreateByteField(CMBF, 5, CMDA)
++                      CreateByteField(CMBF, 12, CMDB)
++                      CreateByteField(CMBF, 19, CMDC)
++
++                      Store(0xB0, CMDA)
++                      Store(0xB0, CMDB)
++                      Store(0xB0, CMDC)
++
++                      Or(PPSM, 0x08, POMD)
++
++                      If(And(PDCR, 0x02)) {
++                              Or(PDSM, 0x40, DMMD)
++                      }
++                      Else {
++                              Store(Match
++                                    (MDTT, MLE, GTTM(PMTS),
++                                     MTR, 0, 0), Local0)
++                              If(LLess(Local0, 3)) {
++                                      Or(0x20, Local0, DMMD)
++                              }
++                      }
++                      Return(CMBF)
++              }
++      }                       /* End Device(SLAV) */
++}
+diff --git a/src/southbridge/amd/sb700/acpi/sata.asl 
b/src/southbridge/amd/sb700/acpi/sata.asl
+new file mode 100644
+index 0000000..46a82b7
+--- /dev/null
++++ b/src/southbridge/amd/sb700/acpi/sata.asl
+@@ -0,0 +1,133 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++Name(STTM, Buffer(20) {
++      0x78, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
++      0x78, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
++      0x1f, 0x00, 0x00, 0x00
++})
++
++/* Start by clearing the PhyRdyChg bits */
++Method(_INI) {
++      \_GPE._L1F()
++}
++
++Device(PMRY)
++{
++      Name(_ADR, 0)
++      Method(_GTM, 0x0, NotSerialized) {
++              Return(STTM)
++      }
++      Method(_STM, 0x3, NotSerialized) {}
++
++      Device(PMST) {
++              Name(_ADR, 0)
++              Method(_STA,0) {
++                      if (LGreater(P0IS,0)) {
++                              return (0x0F) /* sata is visible */
++                      } else {
++                              return  (0x00) /* sata is missing */
++                      }
++              }
++      }/* end of PMST */
++
++      Device(PSLA)
++      {
++              Name(_ADR, 1)
++              Method(_STA,0) {
++                      if (LGreater(P1IS,0)) {
++                              return (0x0F) /* sata is visible */
++                      } else {
++                              return (0x00) /* sata is missing */
++                      }
++              }
++      }       /* end of PSLA */
++}   /* end of PMRY */
++
++
++Device(SEDY)
++{
++      Name(_ADR, 1)           /* IDE Scondary Channel */
++      Method(_GTM, 0x0, NotSerialized) {
++              Return(STTM)
++      }
++      Method(_STM, 0x3, NotSerialized) {}
++
++      Device(SMST)
++      {
++              Name(_ADR, 0)
++              Method(_STA,0) {
++                      if (LGreater(P2IS,0)) {
++                              return (0x0F) /* sata is visible */
++                      } else {
++                              return (0x00) /* sata is missing */
++                      }
++              }
++      } /* end of SMST */
++
++      Device(SSLA)
++      {
++              Name(_ADR, 1)
++              Method(_STA,0) {
++                      if (LGreater(P3IS,0)) {
++                              return (0x0F) /* sata is visible */
++                      } else {
++                              return (0x00) /* sata is missing */
++                      }
++              }
++      } /* end of SSLA */
++}   /* end of SEDY */
++
++/* SATA Hot Plug Support */
++Scope(\_GPE) {
++      Method(_L1F,0x0,NotSerialized) {
++              if (\_SB.P0PR) {
++                      if (LGreater(\_SB.P0IS,0)) {
++                              sleep(32)
++                      }
++                      Notify(\_SB.PCI0.SAT0.PMRY.PMST, 0x01) /* 
NOTIFY_DEVICE_CHECK */
++                      store(one, \_SB.P0PR)
++              }
++
++              if (\_SB.P1PR) {
++                      if (LGreater(\_SB.P1IS,0)) {
++                              sleep(32)
++                      }
++                      Notify(\_SB.PCI0.SAT0.PMRY.PSLA, 0x01) /* 
NOTIFY_DEVICE_CHECK */
++                      store(one, \_SB.P1PR)
++              }
++
++              if (\_SB.P2PR) {
++                      if (LGreater(\_SB.P2IS,0)) {
++                              sleep(32)
++                      }
++                      Notify(\_SB.PCI0.SAT0.SEDY.SMST, 0x01) /* 
NOTIFY_DEVICE_CHECK */
++                      store(one, \_SB.P2PR)
++              }
++
++              if (\_SB.P3PR) {
++                      if (LGreater(\_SB.P3IS,0)) {
++                              sleep(32)
++                      }
++                      Notify(\_SB.PCI0.SAT0.SEDY.SSLA, 0x01) /* 
NOTIFY_DEVICE_CHECK */
++                      store(one, \_SB.P3PR)
++              }
++      }
++}
+diff --git a/src/southbridge/amd/sb700/bootblock.c 
b/src/southbridge/amd/sb700/bootblock.c
+index 67e6434..8f722a8 100644
+--- a/src/southbridge/amd/sb700/bootblock.c
++++ b/src/southbridge/amd/sb700/bootblock.c
+@@ -1,6 +1,7 @@
+ /*
+  * This file is part of the coreboot project.
+  *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -35,10 +36,17 @@
+ static void sb700_enable_rom(void)
+ {
+       u8 reg8;
++      u32 dword;
+       pci_devfn_t dev;
+ 
+       dev = PCI_DEV(0, 0x14, 3);
+ 
++      /* The LPC settings below work for SPI flash as well;
++       * the hardware does not distinguish between LPC and SPI flash ROM
++       * aside from offering additional side-channel access to SPI flash
++       * via a separate register-based interface.
++       */
++
+       /* Decode variable LPC ROM address ranges 1 and 2. */
+       reg8 = pci_io_read_config8(dev, 0x48);
+       reg8 |= (1 << 3) | (1 << 4);
+@@ -52,15 +60,41 @@ static void sb700_enable_rom(void)
+ 
+       /* LPC ROM address range 2: */
+       /*
+-       * Enable LPC ROM range start at:
+-       * 0xfff8(0000): 512KB
+-       * 0xfff0(0000): 1MB
+-       * 0xffe0(0000): 2MB
+-       * 0xffc0(0000): 4MB
+-       */
++      * Enable LPC ROM range start at:
++      * 0xfff8(0000): 512KB
++      * 0xfff0(0000): 1MB
++      * 0xffe0(0000): 2MB
++      * 0xffc0(0000): 4MB
++      * 0xff80(0000): 8MB
++      */
+       pci_io_write_config16(dev, 0x6c, 0x10000 - (CONFIG_COREBOOT_ROMSIZE_KB 
>> 6));
+       /* Enable LPC ROM range end at 0xffff(ffff). */
+       pci_io_write_config16(dev, 0x6e, 0xffff);
++
++      /* SB700 LPC Bridge 0x48h.
++       * Turn on all LPC IO Port decode enables
++       */
++      dword = pci_io_read_config32(dev, 0x44);
++      dword = 0xffffffff;
++      pci_io_write_config32(dev, 0x44, dword);
++
++      /* SB700 LPC Bridge 0x48h.
++       * BIT0: Port Enable for SuperIO 0x2E-0x2F
++       * BIT1: Port Enable for SuperIO 0x4E-0x4F
++       * BIT4: Port Enable for LPC ROM Address Arrage2 (0x68-0x6C)
++       * BIT6: Port Enable for RTC IO 0x70-0x73
++       * BIT21: Port Enable for Port 0x80
++       */
++      reg8 = pci_io_read_config8(dev, 0x48);
++      reg8 |= (1<<0) | (1<<1) | (1<<4) | (1<<6);
++      pci_io_write_config8(dev, 0x48, reg8);
++
++      /* SB700 LPC Bridge 0x4ah.
++       * BIT4: Port Enable for Port 0x80
++       */
++      reg8 = pci_io_read_config8(dev, 0x4a);
++      reg8 |= (1<<4);
++      pci_io_write_config8(dev, 0x4a, reg8);
+ }
+ 
+ static void bootblock_southbridge_init(void)
+diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
+index d25599e..de3fa97 100644
+--- a/src/southbridge/amd/sb700/early_setup.c
++++ b/src/southbridge/amd/sb700/early_setup.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -395,6 +396,15 @@ static void sb700_devices_por_init(void)
+       byte |= (1 << 0);
+       pci_write_config8(dev, 0xd2, byte);
+ 
++      /* set auxiliary smbus iobase and enable controller */
++      pci_write_config32(dev, 0x58, SMBUS_AUX_IO_BASE | 1);
++
++      if (inw(SMBUS_IO_BASE) == 0xFF)
++              printk(BIOS_INFO, "sb700_devices_por_init(): Primary SMBUS 
controller I/O not found\n");
++
++      if (inw(SMBUS_AUX_IO_BASE) == 0xFF)
++              printk(BIOS_INFO, "sb700_devices_por_init(): Secondary SMBUS 
controller I/O not found\n");
++
+       /* KB2RstEnable */
+       pci_write_config8(dev, 0x40, 0x44);
+ 
+@@ -439,6 +449,14 @@ static void sb700_devices_por_init(void)
+       /*pci_write_config8(dev, 0x79, 0x4F); */
+       pci_write_config8(dev, 0x78, 0xFF);
+ 
++      if (IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
++              printk(BIOS_DEBUG, "sb700_devices_por_init(): Disabling ISA DMA 
support\n");
++              /* Disable LPC ISA DMA Capability */
++              byte = pci_read_config8(dev, 0x78);
++              byte &= ~(1 << 0);
++              pci_write_config8(dev, 0x78, byte);
++      }
++
+       /* Set smbus iospace enable, I don't know why write 0x04 into reg5 that 
is reserved */
+       pci_write_config16(dev, 0x4, 0x0407);
+ 
+diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c
+index a39ec18..0cc1e8b 100644
+--- a/src/southbridge/amd/sb700/lpc.c
++++ b/src/southbridge/amd/sb700/lpc.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -45,6 +46,8 @@ static void lpc_init(device_t dev)
+       u32 dword;
+       device_t sm_dev;
+ 
++      printk(BIOS_SPEW, "%s\n", __func__);
++
+       /* Enable the LPC Controller */
+       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+       dword = pci_read_config32(sm_dev, 0x64);
+diff --git a/src/southbridge/amd/sb700/sm.c b/src/southbridge/amd/sb700/sm.c
+index 598ebec..71253b5 100644
+--- a/src/southbridge/amd/sb700/sm.c
++++ b/src/southbridge/amd/sb700/sm.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -62,11 +63,8 @@ static void sm_init(device_t dev)
+       printk(BIOS_INFO, "sm_init().\n");
+ 
+       rev = get_sb700_revision(dev);
+-      ioapic_base = (void *)(pci_read_config32(dev, 0x74) & (0xffffffe0));    
/* some like mem resource, but does not have  enable bit */
+-      /* Don't rename APIC ID */
+-      /* TODO: We should call setup_ioapic() here. But kernel hangs if cpu is 
K8.
+-       * We need to check out why and change back. */
+-      clear_ioapic(ioapic_base);
++      ioapic_base = (void *)(pci_read_config32(dev, 0x74) & (0xffffffe0));    
/* some like mem resource, but does not have enable bit */
++      setup_ioapic(ioapic_base, 0); /* Don't rename IOAPIC ID. */
+ 
+       /* 2.10 Interrupt Routing/Filtering */
+       dword = pci_read_config8(dev, 0x62);
+@@ -132,9 +130,10 @@ static void sm_init(device_t dev)
+       get_option(&on, "power_on_after_fail");
+       byte = pm_ioread(0x74);
+       byte &= ~0x03;
+-      if (on) {
+-              byte |= 2;
+-      }
++      if (on == 1)
++              byte |= 0x1;    /* Force power on */
++      else if (on == 2)
++              byte |= 0x2;    /* Use last power state */
+       byte |= 1 << 2;
+       pm_iowrite(0x74, byte);
+       printk(BIOS_INFO, "set power %s after power fail\n", on ? "on" : "off");
+@@ -298,6 +297,10 @@ static void sm_init(device_t dev)
+       byte &= ~(1 << 1);
+       pm_iowrite(0x59, byte);
+ 
++      /* Enable SCI as irq9. */
++      outb(0x4, 0xC00);
++      outb(0x9, 0xC01);
++
+       printk(BIOS_INFO, "sm_init() end\n");
+ 
+       /* Enable NbSb virtual channel */
+@@ -388,7 +391,7 @@ static void sb700_sm_read_resources(device_t dev)
+       struct resource *res;
+ 
+       /* Get the normal pci resources of this device */
+-      /* pci_dev_read_resources(dev); */
++      pci_dev_read_resources(dev);
+ 
+       /* apic */
+       res = new_resource(dev, 0x74);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0008-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
 
b/resources/libreboot/patch/kgpe-d16/0008-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
deleted file mode 100644
index 75367b6..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0008-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
+++ /dev/null
@@ -1,3463 +0,0 @@
-From 2f8bf745a7ffc2e031efa0f60f993b88baf5a714 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 17:55:58 -0500
-Subject: [PATCH 008/139] northbridge/amd/amdmct: Fix broken AMD K10 DDR3
- memory initalization
-
-Change-Id: Iab690db769e820600693ad1170085623b177b94e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/raminit_amdmct.c   |   2 +
- src/northbridge/amd/amdmct/mct/mct_d.c          |   1 -
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c     | 177 +++++-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h     |   8 +-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h |  87 +--
- src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c  |   6 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c  | 806 +++++++++++++-----------
- src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c    |   6 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c  |  14 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c  |   3 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c   |  19 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c    |   5 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c    | 800 ++++++++++++-----------
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c  |  18 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c  |  13 +-
- src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c   |   7 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctwl.c     |  42 +-
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c   | 267 ++++----
- src/northbridge/amd/amdmct/wrappers/mcti_d.c    | 112 +---
- 19 files changed, 1253 insertions(+), 1140 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-index a0d47f4..a585fae 100644
---- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
-+++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-@@ -28,12 +28,14 @@ static  void print_tx(const char *strval, u32 val)
- }
- #endif
- 
-+#if (CONFIG_DIMM_SUPPORT & 0x000F)!=0x0005 /* not needed for AMD_FAM10_DDR3 */
- static  void print_t(const char *strval)
- {
- #if CONFIG_DEBUG_RAM_SETUP
-       printk(BIOS_DEBUG, "%s", strval);
- #endif
- }
-+#endif
- 
- static  void print_tf(const char *func, const char *strval)
- {
-diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c 
b/src/northbridge/amd/amdmct/mct/mct_d.c
-index 3dec934..88910e2 100644
---- a/src/northbridge/amd/amdmct/mct/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct/mct_d.c
-@@ -542,7 +542,6 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
-               pDCTstat = pDCTstatA + Node;
-               devx = pDCTstat->dev_map;
-               DramSelBaseAddr = 0;
--              pDCTstat = pDCTstatA + Node;
-               if (!pDCTstat->GangedMode) {
-                       DramSelBaseAddr = pDCTstat->NodeSysLimit - 
pDCTstat->DCTSysLimit;
-                       /*In unganged mode, we must add DCT0 and DCT1 to 
DCTSysLimit */
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 71a6be8..fa59d71 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -214,6 +214,8 @@ static const u8 Table_DQSRcvEn_Offset[] = 
{0x00,0x01,0x10,0x11,0x2};
- static const u8 Tab_L1CLKDis[]  = {0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 
0x04};
- static const u8 Tab_AM3CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
0x00};
- static const u8 Tab_S1CLKDis[]  = {0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00};
-+static const u8 Tab_C32CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
0x00};   /* Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */
-+static const u8 Tab_G34CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
0x00};   /* Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */
- static const u8 Tab_ManualCLKDis[]= {0x10, 0x04, 0x08, 0x20, 0x00, 0x00, 
0x00, 0x00};
- 
- static const u8 Table_Comp_Rise_Slew_20x[] = {7, 3, 2, 2, 0xFF};
-@@ -277,6 +279,11 @@ restartinit:
-       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-               struct DCTStatStruc *pDCTstat;
-               pDCTstat = pDCTstatA + Node;
-+
-+              /* Zero out data structures to avoid false detection of DIMMs */
-+              memset(pDCTstat, 0, sizeof(struct DCTStatStruc));
-+
-+              /* Initialize data structures */
-               pDCTstat->Node_ID = Node;
-               pDCTstat->dev_host = PA_HOST(Node);
-               pDCTstat->dev_map = PA_MAP(Node);
-@@ -284,17 +291,22 @@ restartinit:
-               pDCTstat->dev_nbmisc = PA_NBMISC(Node);
-               pDCTstat->NodeSysBase = node_sys_base;
- 
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node %d\n", 
Node);
-               mct_init(pMCTstat, pDCTstat);
-               mctNodeIDDebugPort_D();
-               pDCTstat->NodePresent = NodePresent_D(Node);
-               if (pDCTstat->NodePresent) {            /* See if Node is 
there*/
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
-                       clear_legacy_Mode(pMCTstat, pDCTstat);
-                       pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
- 
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
-                       mct_InitialMCT_D(pMCTstat, pDCTstat);
- 
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
-                       mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
- 
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_initDCT\n");
-                       mct_initDCT(pMCTstat, pDCTstat);
-                       if (pDCTstat->ErrCode == SC_FatalErr) {
-                               goto fatalexit;         /* any fatal errors?*/
-@@ -345,6 +357,7 @@ restartinit:
- 
-       mct_FinalMCT_D(pMCTstat, pDCTstatA);
-       printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", 
pMCTstat->GStatus);
-+
-       return;
- 
- fatalexit:
-@@ -560,7 +573,6 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
-               pDCTstat = pDCTstatA + Node;
-               devx = pDCTstat->dev_map;
-               DramSelBaseAddr = 0;
--              pDCTstat = pDCTstatA + Node; /* ??? */
-               if (!pDCTstat->GangedMode) {
-                       DramSelBaseAddr = pDCTstat->NodeSysLimit - 
pDCTstat->DCTSysLimit;
-                       /*In unganged mode, we must add DCT0 and DCT1 to 
DCTSysLimit */
-@@ -645,6 +657,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
-               devx = pDCTstat->dev_map;
- 
-               if (pDCTstat->NodePresent) {
-+                      printk(BIOS_DEBUG, " Copy dram map from Node 0 to Node 
%02x \n", Node);
-                       reg = 0x40;             /*Dram Base 0*/
-                       do {
-                               val = Get_NB32(dev, reg);
-@@ -1162,7 +1175,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
- 
-       /* Program DRAM Timing values */
-       DramTimingLo = 0;       /* Dram Timing Low init */
--      val = pDCTstat->CASL - 2; /* pDCTstat.CASL to reg. definition */
-+      val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
-       DramTimingLo |= val;
- 
-       val = pDCTstat->Trcd - Bias_TrcdT;
-@@ -1406,18 +1419,16 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-       else if (tCKproposed16x <= 24) {
-               pDCTstat->TargetFreq = 6;
-               tCKproposed16x = 24;
--      }
--      else if (tCKproposed16x <= 30) {
-+      } else if (tCKproposed16x <= 30) {
-               pDCTstat->TargetFreq = 5;
-               tCKproposed16x = 30;
--      }
--      else {
-+      } else {
-               pDCTstat->TargetFreq = 4;
-               tCKproposed16x = 40;
-       }
-       /* Running through this loop twice:
-          - First time find tCL at target frequency
--         - Second tim find tCL at 400MHz */
-+         - Second time find tCL at 400MHz */
- 
-       for (;;) {
-               CLT_Fail = 0;
-@@ -1451,7 +1462,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-                       CLT_Fail = 1;
-               /* get CL and T */
-               if (!CLT_Fail) {
--                      bytex = CLactual - 2;
-+                      bytex = CLactual;
-                       if (tCKproposed16x == 20)
-                               byte = 7;
-                       else if (tCKproposed16x == 24)
-@@ -1632,7 +1643,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-               val = 0x0f; /* recommended setting (default) */
-       DramConfigHi |= val << 24;
- 
--      if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Bx))
-+      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx))
-               DramConfigHi |= 1 << DcqArbBypassEn;
- 
-       /* Build MemClkDis Value from Dram Timing Lo and
-@@ -1657,6 +1668,10 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-                               p = Tab_L1CLKDis;
-                       else if (byte == PT_M2 || byte == PT_AS)
-                               p = Tab_AM3CLKDis;
-+                      else if (byte == PT_C3)
-+                              p = Tab_C32CLKDis;
-+                      else if (byte == PT_GR)
-+                              p = Tab_G34CLKDis;
-                       else
-                               p = Tab_S1CLKDis;
- 
-@@ -2102,8 +2117,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                               if (byte == JED_RDIMM || byte == JED_MiniRDIMM) 
{
-                                       RegDIMMPresent |= 1 << i;
-                                       pDCTstat->DimmRegistered[i] = 1;
--                              }
--                              else {
-+                              } else {
-                                       pDCTstat->DimmRegistered[i] = 0;
-                               }
-                               /* Check ECC capable */
-@@ -2977,9 +2991,9 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
-               } else {        /* For Dx CPU */
-                       val = 0x0CE00F00 | 1 << 29/* FlushWrOnStpGnt */;
-                       if (!(pDCTstat->GangedMode))
--                              val |= 0x20; /* MctWrLimit =  8 for Unganed 
mode */
-+                              val |= 0x20; /* MctWrLimit =  8 for Unganged 
mode */
-                       else
--                              val |= 0x40; /* MctWrLimit =  16 for ganed mode 
*/
-+                              val |= 0x40; /* MctWrLimit =  16 for ganged 
mode */
-                       Set_NB32(pDCTstat->dev_dct, 0x11C, val);
- 
-                       val = Get_NB32(pDCTstat->dev_dct, 0x1B0);
-@@ -3414,6 +3428,138 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
-                       Set_NB32(dev,  0x98 + reg_off, 0x0D000030);
-                       Set_NB32(dev,  0x9C + reg_off, dword);
-                       Set_NB32(dev,  0x98 + reg_off, 0x4D040F30);
-+
-+                      /* FIXME
-+                       * Mainboards need to be able to specify the maximum 
number of DIMMs installable per channel
-+                       * For now assume a maximum of 2 DIMMs per channel can 
be installed
-+                       */
-+                      uint8_t MaxDimmsInstallable = 2;
-+
-+                      /* Obtain number of DIMMs on channel */
-+                      uint8_t dimm_count = pDCTstat->MAdimms[i];
-+                      uint8_t rank_count_dimm0;
-+                      uint8_t rank_count_dimm1;
-+                      uint32_t odt_pattern_0;
-+                      uint32_t odt_pattern_1;
-+                      uint32_t odt_pattern_2;
-+                      uint32_t odt_pattern_3;
-+
-+                      /* Select appropriate ODT pattern for installed DIMMs
-+                       * Refer to the BKDG Rev. 3.62, page 120 onwards
-+                       */
-+                      if 
(pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) {
-+                              if (MaxDimmsInstallable == 2) {
-+                                      if (dimm_count == 1) {
-+                                              /* 1 DIMM detected */
-+                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
-+                                              if (rank_count_dimm1 == 1) {
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x00020000;
-+                                              } else if (rank_count_dimm1 == 
2) {
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x02080000;
-+                                              } else if (rank_count_dimm1 == 
4) {
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x020a0000;
-+                                                      odt_pattern_3 = 
0x080a0000;
-+                                              } else {
-+                                                      /* Fallback */
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x00000000;
-+                                              }
-+                                      } else {
-+                                              /* 2 DIMMs detected */
-+                                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[0];
-+                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
-+                                              if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x01010202;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x09030603;
-+                                              } else if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 == 4)) {
-+                                                      odt_pattern_0 = 
0x01010000;
-+                                                      odt_pattern_1 = 
0x01010a0a;
-+                                                      odt_pattern_2 = 
0x01090000;
-+                                                      odt_pattern_3 = 
0x01030e0b;
-+                                              } else if ((rank_count_dimm0 == 
4) && (rank_count_dimm1 < 4)) {
-+                                                      odt_pattern_0 = 
0x00000202;
-+                                                      odt_pattern_1 = 
0x05050202;
-+                                                      odt_pattern_2 = 
0x00000206;
-+                                                      odt_pattern_3 = 
0x0d070203;
-+                                              } else if ((rank_count_dimm0 == 
4) && (rank_count_dimm1 == 4)) {
-+                                                      odt_pattern_0 = 
0x05050a0a;
-+                                                      odt_pattern_1 = 
0x05050a0a;
-+                                                      odt_pattern_2 = 
0x050d0a0e;
-+                                                      odt_pattern_3 = 
0x05070a0b;
-+                                              } else {
-+                                                      /* Fallback */
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x00000000;
-+                                              }
-+                                      }
-+                              } else {
-+                                      /* FIXME
-+                                       * 3 DIMMs per channel UNIMPLEMENTED
-+                                       */
-+                                      odt_pattern_0 = 0x00000000;
-+                                      odt_pattern_1 = 0x00000000;
-+                                      odt_pattern_2 = 0x00000000;
-+                                      odt_pattern_3 = 0x00000000;
-+                              }
-+                      } else {
-+                              if (MaxDimmsInstallable == 2) {
-+                                      if (dimm_count == 1) {
-+                                              /* 1 DIMM detected */
-+                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
-+                                              if (rank_count_dimm1 == 1) {
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x00020000;
-+                                              } else if (rank_count_dimm1 == 
2) {
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x02080000;
-+                                              } else {
-+                                                      /* Fallback */
-+                                                      odt_pattern_0 = 
0x00000000;
-+                                                      odt_pattern_1 = 
0x00000000;
-+                                                      odt_pattern_2 = 
0x00000000;
-+                                                      odt_pattern_3 = 
0x00000000;
-+                                              }
-+                                      } else {
-+                                              /* 2 DIMMs detected */
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x01010202;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x09030603;
-+                                      }
-+                              } else {
-+                                      /* FIXME
-+                                       * 3 DIMMs per channel UNIMPLEMENTED
-+                                       */
-+                                      odt_pattern_0 = 0x00000000;
-+                                      odt_pattern_1 = 0x00000000;
-+                                      odt_pattern_2 = 0x00000000;
-+                                      odt_pattern_3 = 0x00000000;
-+                              }
-+                      }
-+
-+                      /* Program ODT pattern */
-+                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x180, 
odt_pattern_1);
-+                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x181, 
odt_pattern_0);
-+                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x182, 
odt_pattern_3);
-+                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x183, 
odt_pattern_2);
-               }
-       }
- }
-@@ -3657,6 +3803,7 @@ static void mct_BeforeDQSTrain_D(struct MCTStatStruc 
*pMCTstat,
-       }
- }
- 
-+/* Erratum 350 */
- static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-@@ -3692,11 +3839,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc 
*pMCTstat,
-                               mct_Read1LTestPattern_D(pMCTstat, pDCTstat, 
addr);      /* cache fills */
- 
-                               /* Write 0000_8000h to register 
F2x[1,0]9C_xD080F0C */
--                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0x4D080F0C, 0x00008000);
-+                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00008000);
-                               mct_Wait(80); /* wait >= 300ns */
- 
-                               /* Write 0000_0000h to register 
F2x[1,0]9C_xD080F0C */
--                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0x4D080F0C, 0x00000000);
-+                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00000000);
-                               mct_Wait(800); /* wait >= 2us */
-                               break;
-                       }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index e2d7aa8..219aa42 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -499,7 +499,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-               /* CHB DIMM0 Byte 0 - 7  TxDqs */
-               /* CHB DIMM1 Byte 0 - 7  TxDqs */
-               /* CHB DIMM1 Byte 0 - 7  TxDqs */
--      u8 CH_D_B_RCVRDLY[2][4][8];     /* [A/B] [DIMM0-3] [DQS] */
-+      u16 CH_D_B_RCVRDLY[2][4][8];    /* [A/B] [DIMM0-3] [DQS] */
-               /* CHA DIMM 0 Receiver Enable Delay*/
-               /* CHA DIMM 1 Receiver Enable Delay*/
-               /* CHA DIMM 2 Receiver Enable Delay*/
-@@ -509,7 +509,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-               /* CHB DIMM 1 Receiver Enable Delay*/
-               /* CHB DIMM 2 Receiver Enable Delay*/
-               /* CHB DIMM 3 Receiver Enable Delay*/
--      u8 CH_D_BC_RCVRDLY[2][4];
-+      u16 CH_D_BC_RCVRDLY[2][4];
-               /* CHA DIMM 0 - 4 Check Byte Receiver Enable Delay*/
-               /* CHB DIMM 0 - 4 Check Byte Receiver Enable Delay*/
-       u8 DIMMValidDCT[2];     /* DIMM# in DCT0*/
-@@ -769,7 +769,7 @@ u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass);
- u32 SetupDqsPattern_1PassA(u8 Pass);
- u32 SetupDqsPattern_1PassB(u8 Pass);
- u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
--u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 
RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
-+u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, 
u16 RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
- void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- u32 mctGetLogicalCPUID(u32 Node);
-@@ -779,7 +779,7 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTs
- void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,struct DCTStatStruc 
*pDCTstatA);
--void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 
FinalValue, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 
Pass);
-+void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, u8 
FinalValue, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 
Pass);
- void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel);
- void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u32 dct);
- void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-index 60f98bc..c40ea1a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -103,10 +104,10 @@ static void proc_CLFLUSH(u32 addr_hi)
- 
-       __asm__ volatile (
-               /* clflush fs:[eax] */
--              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
--               "clflush %%fs:(%0)\n\t"
-+              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
-+              "clflush %%fs:(%0)\n\t"
-               "mfence\n\t"
--               ::"a" (addr_hi<<8)
-+              ::"a" (addr_hi<<8)
-       );
- }
- 
-@@ -141,6 +142,24 @@ static u32 read32_fs(u32 addr_lo)
-       return value;
- }
- 
-+static uint64_t read64_fs(uint32_t addr_lo)
-+{
-+      uint64_t value = 0;
-+      uint32_t value_lo;
-+      uint32_t value_hi;
-+
-+      __asm__ volatile (
-+              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
-+              "mfence\n\t"
-+              "movl %%fs:(%2), %0\n\t"
-+              "movl %%fs:(%3), %1\n\t"
-+              :"=c"(value_lo), "=d"(value_hi): "a" (addr_lo), "b" (addr_lo + 
4) : "memory"
-+      );
-+      value |= value_lo;
-+      value |= ((uint64_t)value_hi) << 32;
-+      return value;
-+}
-+
- #ifdef UNUSED_CODE
- static u8 read8_fs(u32 addr_lo)
- {
-@@ -210,68 +229,6 @@ static __attribute__((noinline)) void 
FlushDQSTestPattern_L18(u32 addr_lo)
-       );
- }
- 
--static void ReadL18TestPattern(u32 addr_lo)
--{
--      /* set fs and use fs prefix to access the mem */
--      __asm__ volatile (
--              "outb %%al, $0xed\n\t"                  /* _EXECFENCE */
--              "movl %%fs:-128(%%esi), %%eax\n\t"      /* TestAddr cache line 
*/
--              "movl %%fs:-64(%%esi), %%eax\n\t"       /* +1 */
--              "movl %%fs:(%%esi), %%eax\n\t"          /* +2 */
--              "movl %%fs:64(%%esi), %%eax\n\t"        /* +3 */
--
--              "movl %%fs:-128(%%edi), %%eax\n\t"      /* +4 */
--              "movl %%fs:-64(%%edi), %%eax\n\t"       /* +5 */
--              "movl %%fs:(%%edi), %%eax\n\t"          /* +6 */
--              "movl %%fs:64(%%edi), %%eax\n\t"        /* +7 */
--
--              "movl %%fs:-128(%%ebx), %%eax\n\t"      /* +8 */
--              "movl %%fs:-64(%%ebx), %%eax\n\t"       /* +9 */
--              "movl %%fs:(%%ebx), %%eax\n\t"          /* +10 */
--              "movl %%fs:64(%%ebx), %%eax\n\t"        /* +11 */
--
--              "movl %%fs:-128(%%ecx), %%eax\n\t"      /* +12 */
--              "movl %%fs:-64(%%ecx), %%eax\n\t"       /* +13 */
--              "movl %%fs:(%%ecx), %%eax\n\t"          /* +14 */
--              "movl %%fs:64(%%ecx), %%eax\n\t"        /* +15 */
--
--              "movl %%fs:-128(%%edx), %%eax\n\t"      /* +16 */
--              "movl %%fs:-64(%%edx), %%eax\n\t"       /* +17 */
--              "mfence\n\t"
--
--               :: "a"(0), "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
--                  "d" (addr_lo +128+16*64), "S"(addr_lo+128),
--                  "D"(addr_lo+128+4*64)
--      );
--
--}
--
--static void ReadL9TestPattern(u32 addr_lo)
--{
--
--      /* set fs and use fs prefix to access the mem */
--      __asm__ volatile (
--              "outb %%al, $0xed\n\t"                  /* _EXECFENCE */
--
--              "movl %%fs:-128(%%ecx), %%eax\n\t"      /* TestAddr cache line 
*/
--              "movl %%fs:-64(%%ecx), %%eax\n\t"       /* +1 */
--              "movl %%fs:(%%ecx), %%eax\n\t"          /* +2 */
--              "movl %%fs:64(%%ecx), %%eax\n\t"        /* +3 */
--
--              "movl %%fs:-128(%%edx), %%eax\n\t"      /* +4 */
--              "movl %%fs:-64(%%edx), %%eax\n\t"       /* +5 */
--              "movl %%fs:(%%edx), %%eax\n\t"          /* +6 */
--              "movl %%fs:64(%%edx), %%eax\n\t"        /* +7 */
--
--              "movl %%fs:-128(%%ebx), %%eax\n\t"      /* +8 */
--              "mfence\n\t"
--
--               :: "a"(0), "b" (addr_lo+128+8*64), "c"(addr_lo+128),
--                  "d"(addr_lo+128+4*64)
--      );
--
--}
--
- static void ReadMaxRdLat1CLTestPattern_D(u32 addr)
- {
-       SetUpperFSbase(addr);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
-index ae1654c..99a2628 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -17,7 +18,7 @@
-  * Foundation, Inc.
-  */
- 
--/* The socket type F (1207), Fr2, G (1207) are not tested.
-+/* The socket type Fr2, G (1207) are not tested.
-  */
- 
- static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
-@@ -79,8 +80,7 @@ static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 
MAAload,
-                       else
-                               *AddrTmgCTL = 0x00353935;
-               }
--      }
--      else {
-+      } else {
-               if(Speed == 4) {
-                       *AddrTmgCTL = 0x00000000;
-                       if (MAAdimms == 3)
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index 404727b..cc2f43a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -22,13 +23,6 @@ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
-                               u8 scale, u8 ChipSel);
- static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 ChipSel);
--static u8 MiddleDQS_D(u8 min, u8 max);
--static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat,
--                              u8 cs_start);
--static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat,
--                              u8 cs_start);
- static void WriteDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat,
-                                       u32 TestAddr_lo);
-@@ -43,31 +37,19 @@ static void FlushDQSTestPattern_D(struct DCTStatStruc 
*pDCTstat,
-                                       u32 addr_lo);
- static void SetTargetWTIO_D(u32 TestAddr);
- static void ResetTargetWTIO_D(void);
--static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat,
--                                      u32 TestAddr_lo);
--static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
--                                      u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
- void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index);
- u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat);
- static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat,
-                                       u8 ChipSel);
--static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat,
--                                      u8 cs_start);
- u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Channel,
-                               u8 receiver, u8 *valid);
- static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat,
-                               u32 *buffer);
--
--static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
--                                    u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
-+static void proc_IOCLFLUSH_D(u32 addr_hi);
- 
- static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, u8 ChipSel);
- 
-@@ -286,20 +268,99 @@ static void CalcEccDQSPos_D(struct MCTStatStruc 
*pMCTstat,
-       pDCTstat->DQSDelay = (u8)DQSDelay;
- }
- 
-+static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
-+{
-+      uint32_t dword;
-+
-+      /* Lanes 0 - 3 */
-+      dword = Get_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8));
-+      dword &= ~0x7f7f7f7f;
-+      dword |= (delay[3] & 0x7f) << 24;
-+      dword |= (delay[2] & 0x7f) << 16;
-+      dword |= (delay[1] & 0x7f) << 8;
-+      dword |= delay[0] & 0x7f;
-+      Set_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8), dword);
-+
-+      /* Lanes 4 - 7 */
-+      dword = Get_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8));
-+      dword &= ~0x7f7f7f7f;
-+      dword |= (delay[7] & 0x7f) << 24;
-+      dword |= (delay[6] & 0x7f) << 16;
-+      dword |= (delay[5] & 0x7f) << 8;
-+      dword |= delay[4] & 0x7f;
-+      Set_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8), dword);
-+
-+      /* Lane 8 (ECC) */
-+      dword = Get_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8));
-+      dword &= ~0x0000007f;
-+      dword |= delay[8] & 0x7f;
-+      Set_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8), dword);
-+}
-+
-+static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
-+{
-+      uint32_t dword;
-+
-+      /* Lanes 0 - 3 */
-+      dword = Get_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8));
-+      dword &= ~0x3f3f3f3f;
-+      dword |= (delay[3] & 0x3f) << 24;
-+      dword |= (delay[2] & 0x3f) << 16;
-+      dword |= (delay[1] & 0x3f) << 8;
-+      dword |= delay[0] & 0x3f;
-+      Set_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8), dword);
-+
-+      /* Lanes 4 - 7 */
-+      dword = Get_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8));
-+      dword &= ~0x3f3f3f3f;
-+      dword |= (delay[7] & 0x3f) << 24;
-+      dword |= (delay[6] & 0x3f) << 16;
-+      dword |= (delay[5] & 0x3f) << 8;
-+      dword |= delay[4] & 0x3f;
-+      Set_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8), dword);
-+
-+      /* Lane 8 (ECC) */
-+      dword = Get_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8));
-+      dword &= ~0x0000003f;
-+      dword |= delay[8] & 0x3f;
-+      Set_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8), dword);
-+}
-+
-+/* DQS Position Training
-+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.3
-+ */
- static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat,
--                              u8 cs_start)
-+                              struct DCTStatStruc *pDCTstat)
- {
-       u32 Errors;
--      u8 Channel, DQSWrDelay;
-+      u8 Channel;
-+      u8 Receiver;
-       u8 _DisableDramECC = 0;
--      u32 PatternBuffer[292];
-+      u32 PatternBuffer[304]; /* 288 + 16 */
-       u8 _Wrap32Dis = 0, _SSE2 = 0;
--      u8 dqsWrDelay_end;
- 
-+      u32 dev;
-       u32 addr;
-+      u8 valid;
-       u32 cr4;
-       u32 lo, hi;
-+      u32 index_reg;
-+      uint32_t TestAddr;
-+
-+      uint8_t dual_rank;
-+      uint8_t iter;
-+      uint8_t lane;
-+      uint16_t bytelane_test_results;
-+      uint16_t current_write_dqs_delay[MAX_BYTE_LANES];
-+      uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
-+      uint16_t write_dqs_delay_stepping_done[MAX_BYTE_LANES];
-+      uint8_t dqs_read_results_array[2][MAX_BYTE_LANES][64];          /* 
[rank][lane][step] */
-+      uint8_t dqs_write_results_array[2][MAX_BYTE_LANES][128];        /* 
[rank][lane][step] */
-+
-+      uint8_t last_pos = 0;
-+      uint8_t cur_count = 0;
-+      uint8_t best_pos = 0;
-+      uint8_t best_count = 0;
- 
-       print_debug_dqs("\nTrainDQSRdWrPos: Node_ID ", pDCTstat->Node_ID, 0);
-       cr4 = read_cr4();
-@@ -323,50 +384,363 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-       SetupDqsPattern_D(pMCTstat, pDCTstat, PatternBuffer);
- 
-       /* mct_BeforeTrainDQSRdWrPos_D */
--      dqsWrDelay_end = 0x20;
-+
-+      dev = pDCTstat->dev_dct;
-+      pDCTstat->Direction = DQS_READDIR;
-+
-+      /* 2.8.9.9.3 (2)
-+       * Loop over each channel, lane, and rank
-+       */
-+
-+      /* NOTE
-+       * The BKDG originally stated to iterate over lane, then rank, however 
this process is quite slow
-+       * compared to an equivalent loop over rank, then lane as the latter 
allows multiple lanes to be
-+       * tested simultaneously, thus improving performance by around 8x.
-+       */
- 
-       Errors = 0;
-       for (Channel = 0; Channel < 2; Channel++) {
--              print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ",Channel, 1);
-+              print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ", Channel, 1);
-               pDCTstat->Channel = Channel;
- 
-               if (pDCTstat->DIMMValidDCT[Channel] == 0)       /* 
mct_BeforeTrainDQSRdWrPos_D */
-                       continue;
--              pDCTstat->DqsRdWrPos_Saved = 0;
--              for ( DQSWrDelay = 0; DQSWrDelay < dqsWrDelay_end; 
DQSWrDelay++) {
--                      pDCTstat->DQSDelay = DQSWrDelay;
--                      pDCTstat->Direction = DQS_WRITEDIR;
--                      mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
--
--                      print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DQSWrDelay ", 
DQSWrDelay, 2);
--                      TrainReadDQS_D(pMCTstat, pDCTstat, cs_start);
--                      print_debug_dqs("\t\tTrainDQSRdWrPos: 21 
DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 2);
--                      if (pDCTstat->DqsRdWrPos_Saved == 0xFF)
--                              break;
--
--                      print_debug_dqs("\t\tTrainDQSRdWrPos: 22 TrainErrors 
",pDCTstat->TrainErrors, 2);
--                      if (pDCTstat->TrainErrors == 0) {
-+
-+              index_reg = 0x98 + 0x100 * Channel;
-+
-+              dual_rank = 0;
-+              Receiver = mct_InitReceiver_D(pDCTstat, Channel);
-+              /* There are four receiver pairs, loosely associated with 
chipselects.
-+              * This is essentially looping over each rank of each DIMM.
-+              */
-+              for (; Receiver < 8; Receiver++) {
-+                      if ((Receiver & 0x1) == 0) {
-+                              /* Even rank of DIMM */
-+                              if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, 
Channel, Receiver+1))
-+                                      dual_rank = 1;
-+                              else
-+                                      dual_rank = 0;
-+                      }
-+
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
-+                              continue;
-+                      }
-+
-+                      /* Select the base test address for the current rank */
-+                      TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, 
Channel, Receiver, &valid);
-+                      if (!valid) {   /* Address not supported on current CS 
*/
-+                              continue;
-+                      }
-+
-+                      print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 14 TestAddr 
", TestAddr, 4);
-+                      SetUpperFSbase(TestAddr);       /* fs:eax=far ptr to 
target */
-+
-+                      print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 12 Receiver 
", Receiver, 2);
-+
-+                      /* 2.8.9.9.3 (DRAM Write Data Timing Loop)
-+                       * Iterate over all possible DQS delay values (0x0 - 
0x7f)
-+                       */
-+                      uint8_t test_write_dqs_delay = 0;
-+                      uint8_t test_read_dqs_delay = 0;
-+                      uint8_t passing_dqs_delay_found[MAX_BYTE_LANES];
-+
-+                      /* Initialize variables */
-+                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                              current_write_dqs_delay[lane] = 0;
-+                              passing_dqs_delay_found[lane] = 0;
-+                              write_dqs_delay_stepping_done[lane] = 0;
-+                      }
-+
-+                      for (test_write_dqs_delay = 0; test_write_dqs_delay < 
128; test_write_dqs_delay++) {
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 16 
test_write_dqs_delay ", test_write_dqs_delay, 6);
-+
-+                              /* Break out of loop if passing window already 
found, */
-+                              if (write_dqs_delay_stepping_done[0] && 
write_dqs_delay_stepping_done[1]
-+                                      && write_dqs_delay_stepping_done[2] && 
write_dqs_delay_stepping_done[3]
-+                                      && write_dqs_delay_stepping_done[4] && 
write_dqs_delay_stepping_done[5]
-+                                      && write_dqs_delay_stepping_done[6] && 
write_dqs_delay_stepping_done[7])
-                                       break;
-+
-+                              /* Commit the current Write Data Timing 
settings to the hardware registers */
-+                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
-+
-+                              /* Write the DRAM training pattern to the base 
test address */
-+                              WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
-+
-+                              /* 2.8.9.9.3 (DRAM Read DQS Timing Control Loop)
-+                               * Iterate over all possible DQS delay values 
(0x0 - 0x3f)
-+                               */
-+                              for (test_read_dqs_delay = 0; 
test_read_dqs_delay < 64; test_read_dqs_delay++) {
-+                                      
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 test_read_dqs_delay ", 
test_read_dqs_delay, 6);
-+
-+                                      /* Initialize Read DQS Timing Control 
settings for this iteration */
-+                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++)
-+                                              if 
(!write_dqs_delay_stepping_done[lane])
-+                                                      
current_read_dqs_delay[lane] = test_read_dqs_delay;
-+
-+                                      /* Commit the current Read DQS Timing 
Control settings to the hardware registers */
-+                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
-+
-+                                      /* Initialize test result variable */
-+                                      bytelane_test_results = 0xff;
-+
-+                                      /* Read the DRAM training pattern from 
the base test address three times
-+                                       * NOTE
-+                                       * While the BKDG states to read three 
times this is probably excessive!
-+                                       * Decrease training time by only 
reading the test pattern once per iteration
-+                                       */
-+                                      for (iter = 0; iter < 1; iter++) {
-+                                              /* Flush caches */
-+                                              SetTargetWTIO_D(TestAddr);
-+                                              FlushDQSTestPattern_D(pDCTstat, 
TestAddr << 8);
-+                                              ResetTargetWTIO_D();
-+
-+                                              /* Read and compare pattern */
-+                                              bytelane_test_results &= 
(CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8) & 0xff); /* [Lane 7 
:: Lane 0] 0=fail, 1=pass */
-+
-+                                              /* If all lanes have already 
failed testing bypass remaining re-read attempt(s) */
-+                                              if (bytelane_test_results == 
0x0)
-+                                                      break;
-+                                      }
-+
-+                                      /* Store any lanes that passed testing 
for later use */
-+                                      for (lane = 0; lane < 8; lane++)
-+                                              if 
(!write_dqs_delay_stepping_done[lane])
-+                                                      
dqs_read_results_array[Receiver & 0x1][lane][test_read_dqs_delay] = 
(!!(bytelane_test_results & (1 << lane)));
-+
-+                                      
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 162 bytelane_test_results ", 
bytelane_test_results, 6);
-+                              }
-+
-+                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                                      if (write_dqs_delay_stepping_done[lane])
-+                                              continue;
-+
-+                                      /* Determine location and length of 
longest consecutive string of passing values
-+                                       * Output is stored in best_pos and 
best_count
-+                                       */
-+                                      last_pos = 0;
-+                                      cur_count = 0;
-+                                      best_pos = 0;
-+                                      best_count = 0;
-+                                      for (iter = 0; iter < 64; iter++) {
-+                                              if 
((dqs_read_results_array[Receiver & 0x1][lane][iter]) && (iter < 63)) {
-+                                                      /* Pass */
-+                                                      cur_count++;
-+                                              } else {
-+                                                      /* Failure or end of 
loop */
-+                                                      if (cur_count > 
best_count) {
-+                                                              best_count = 
cur_count;
-+                                                              best_pos = 
last_pos;
-+                                                      }
-+                                                      cur_count = 0;
-+                                                      last_pos = iter;
-+                                              }
-+                                      }
-+
-+                                      if (best_count > 2) {
-+                                              /* Exit the DRAM Write Data 
Timing Loop after programming the Read DQS Timing Control
-+                                               * register with the center of 
the passing window
-+                                               */
-+                                              current_read_dqs_delay[lane] = 
(best_pos + (best_count / 2));
-+                                              passing_dqs_delay_found[lane] = 
1;
-+
-+                                              /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
-+                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
-+
-+                                              /* Exit the DRAM Write Data 
Timing Loop */
-+                                              
write_dqs_delay_stepping_done[lane] = 1;
-+
-+                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 largest passing region ", 
best_count, 4);
-+                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 largest passing region start ", 
best_pos, 4);
-+                                      }
-+
-+                                      /* Increment the DQS Write Delay value 
if needed for the next DRAM Write Data Timing Loop iteration */
-+                                      if 
(!write_dqs_delay_stepping_done[lane])
-+                                              current_write_dqs_delay[lane]++;
-+                              }
-                       }
--                      Errors |= pDCTstat->TrainErrors;
--              }
- 
--              pDCTstat->DqsRdWrPos_Saved = 0;
--              if (DQSWrDelay < dqsWrDelay_end) {
--                      Errors = 0;
-+                      /* Flag failure(s) if present */
-+                      for (lane = 0; lane < 8; lane++) {
-+                              if (!passing_dqs_delay_found[lane]) {
-+                                      
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 121 Unable to find passing region for 
lane ", lane, 2);
-+
-+                                      /* Flag absence of passing window */
-+                                      Errors |= 1 << SB_NODQSPOS;
-+                              }
-+                      }
-+
-+                      /* Iterate over all possible Write Data Timing values 
(0x0 - 0x7f)
-+                       * Note that the Read DQS Timing Control was calibrated 
/ centered in the prior nested loop
-+                       */
-+                      for (test_write_dqs_delay = 0; test_write_dqs_delay < 
128; test_write_dqs_delay++) {
-+                              /* Initialize Write Data Timing settings for 
this iteration */
-+                              for (lane = 0; lane < MAX_BYTE_LANES; lane++)
-+                                      current_write_dqs_delay[lane] = 
test_write_dqs_delay;
-+
-+                              /* Commit the current Write Data Timing 
settings to the hardware registers */
-+                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
-+
-+                              /* Write the DRAM training pattern to the base 
test address */
-+                              WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
-+
-+                              /* Flush caches */
-+                              SetTargetWTIO_D(TestAddr);
-+                              FlushDQSTestPattern_D(pDCTstat, TestAddr << 8);
-+                              ResetTargetWTIO_D();
-+
-+                              /* Read and compare pattern from the base test 
address */
-+                              bytelane_test_results = 
(CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8) & 0xff); /* [Lane 7 
:: Lane 0] 0=fail, 1=pass */
-+
-+                              /* Store any lanes that passed testing for 
later use */
-+                              for (lane = 0; lane < 8; lane++)
-+                                      dqs_write_results_array[Receiver & 
0x1][lane][test_write_dqs_delay] = (!!(bytelane_test_results & (1 << lane)));
-+                      }
-+
-+                      for (lane = 0; lane < 8; lane++) {
-+                              if ((!dual_rank) || (dual_rank && (Receiver & 
0x1))) {
-+
-+#ifdef PRINT_PASS_FAIL_BITMAPS
-+                                      for (iter = 0; iter < 64; iter++) {
-+                                              if 
(dqs_read_results_array[0][lane][iter])
-+                                                      printk(BIOS_DEBUG, "+");
-+                                              else
-+                                                      printk(BIOS_DEBUG, ".");
-+                                      }
-+                                      printk(BIOS_DEBUG, "\n");
-+                                      for (iter = 0; iter < 64; iter++) {
-+                                              if 
(dqs_read_results_array[1][lane][iter])
-+                                                      printk(BIOS_DEBUG, "+");
-+                                              else
-+                                                      printk(BIOS_DEBUG, ".");
-+                                      }
-+                                      printk(BIOS_DEBUG, "\n\n");
-+                                      for (iter = 0; iter < 128; iter++) {
-+                                              if 
(dqs_write_results_array[0][lane][iter])
-+                                                      printk(BIOS_DEBUG, "+");
-+                                              else
-+                                                      printk(BIOS_DEBUG, ".");
-+                                      }
-+                                      printk(BIOS_DEBUG, "\n");
-+                                      for (iter = 0; iter < 128; iter++) {
-+                                              if 
(dqs_write_results_array[1][lane][iter])
-+                                                      printk(BIOS_DEBUG, "+");
-+                                              else
-+                                                      printk(BIOS_DEBUG, ".");
-+                                      }
-+                                      printk(BIOS_DEBUG, "\n\n");
-+#endif
-+
-+                                      /* Base rank of single-rank DIMM, or 
odd rank of dual-rank DIMM */
-+                                      if (dual_rank) {
-+                                              /* Intersect the passing 
windows of both ranks */
-+                                              for (iter = 0; iter < 64; 
iter++)
-+                                                      if 
(!dqs_read_results_array[1][lane][iter])
-+                                                              
dqs_read_results_array[0][lane][iter] = 0;
-+                                              for (iter = 0; iter < 128; 
iter++)
-+                                                      if 
(!dqs_write_results_array[1][lane][iter])
-+                                                              
dqs_write_results_array[0][lane][iter] = 0;
-+                                      }
-+
-+                                      /* Determine location and length of 
longest consecutive string of passing values for read DQS timing
-+                                       * Output is stored in best_pos and 
best_count
-+                                       */
-+                                      last_pos = 0;
-+                                      cur_count = 0;
-+                                      best_pos = 0;
-+                                      best_count = 0;
-+                                      for (iter = 0; iter < 64; iter++) {
-+                                              if 
((dqs_read_results_array[0][lane][iter]) && (iter < 63)) {
-+                                                      /* Pass */
-+                                                      cur_count++;
-+                                              } else {
-+                                                      /* Failure or end of 
loop */
-+                                                      if (cur_count > 
best_count) {
-+                                                              best_count = 
cur_count;
-+                                                              best_pos = 
last_pos;
-+                                                      }
-+                                                      cur_count = 0;
-+                                                      last_pos = iter;
-+                                              }
-+                                      }
-+                                      
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 largest read passing region ", 
best_count, 4);
-+                                      if (best_count > 0) {
-+                                              if (best_count < MIN_DQS_WNDW) {
-+                                                      /* Flag excessively 
small passing window */
-+                                                      Errors |= 1 << 
SB_SMALLDQS;
-+                                              }
-+
-+                                              /* Find the center of the 
passing window */
-+                                              current_read_dqs_delay[lane] = 
(best_pos + (best_count / 2));
-+
-+                                              /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
-+                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
-+
-+                                              /* Save the final Read DQS 
Timing Control settings for later use */
-+                                              
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_READDIR][lane] = 
current_read_dqs_delay[lane];
-+                                      } else {
-+                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 122 Unable to find read passing 
region for lane ", lane, 2);
-+
-+                                              /* Flag absence of passing 
window */
-+                                              Errors |= 1 << SB_NODQSPOS;
-+                                      }
-+
-+                                      /* Determine location and length of 
longest consecutive string of passing values for write DQS timing
-+                                       * Output is stored in best_pos and 
best_count
-+                                       */
-+                                      last_pos = 0;
-+                                      cur_count = 0;
-+                                      best_pos = 0;
-+                                      best_count = 0;
-+                                      for (iter = 0; iter < 128; iter++) {
-+                                              if 
((dqs_write_results_array[0][lane][iter]) && (iter < 127)) {
-+                                                      /* Pass */
-+                                                      cur_count++;
-+                                              } else {
-+                                                      /* Failure or end of 
loop */
-+                                                      if (cur_count > 
best_count) {
-+                                                              best_count = 
cur_count;
-+                                                              best_pos = 
last_pos;
-+                                                      }
-+                                                      cur_count = 0;
-+                                                      last_pos = iter;
-+                                              }
-+                                      }
-+                                      
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 largest write passing region ", 
best_count, 4);
-+                                      if (best_count > 0) {
-+                                              if (best_count < MIN_DQS_WNDW) {
-+                                                      /* Flag excessively 
small passing window */
-+                                                      Errors |= 1 << 
SB_SMALLDQS;
-+                                              }
-+
-+                                              /* Find the center of the 
passing window */
-+                                              current_write_dqs_delay[lane] = 
(best_pos + (best_count / 2));
-+
-+                                              /* Commit the current Write 
Data Timing settings to the hardware registers */
-+                                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
-+
-+                                              /* Save the final Write Data 
Timing settings for later use */
-+                                              
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_WRITEDIR][lane] = 
current_write_dqs_delay[lane];
-+                                      } else {
-+                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 123 Unable to find write passing 
region for lane ", lane, 2);
-+
-+                                              /* Flag absence of passing 
window */
-+                                              Errors |= 1 << SB_NODQSPOS;
-+                                      }
-+                              }
-+                      }
- 
--                      print_debug_dqs("\tTrainDQSRdWrPos: 231 DQSWrDelay ", 
DQSWrDelay, 1);
--                      TrainWriteDQS_D(pMCTstat, pDCTstat, cs_start);
-               }
--              print_debug_dqs("\tTrainDQSRdWrPos: 232 Errors ", Errors, 1);
--              pDCTstat->ErrStatus |= Errors;
-       }
- 
-+      pDCTstat->TrainErrors |= Errors;
-+      pDCTstat->ErrStatus |= Errors;
-+
- #if DQS_TRAIN_DEBUG > 0
-       {
-               u8 val;
-               u8 i;
--              u8 Channel, Receiver, Dir;
-+              u8 ChannelDTD, ReceiverDTD, Dir;
-               u8 *p;
- 
-               for (Dir = 0; Dir < 2; Dir++) {
-@@ -375,14 +749,14 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-                       } else {
-                               printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS RD:\n");
-                       }
--                      for (Channel = 0; Channel < 2; Channel++) {
--                              printk(BIOS_DEBUG, "Channel: %02x\n", Channel);
--                              for (Receiver = cs_start; Receiver < (cs_start 
+ 2); Receiver += 2) {
--                                      printk(BIOS_DEBUG, "\t\tReceiver: %02x: 
", Receiver);
--                                      p = 
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][Dir];
-+                      for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
-+                              printk(BIOS_DEBUG, "Channel: %02x\n", 
ChannelDTD);
-+                              for (ReceiverDTD = 0; ReceiverDTD < 
MAX_CS_SUPPORTED; ReceiverDTD += 2) {
-+                                      printk(BIOS_DEBUG, "\t\tReceiver: 
%02x:", ReceiverDTD);
-+                                      p = 
pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
-                                       for (i=0;i<8; i++) {
-                                               val  = p[i];
--                                              printk(BIOS_DEBUG, "%02x ", 
val);
-+                                              printk(BIOS_DEBUG, " %02x", 
val);
-                                       }
-                                       printk(BIOS_DEBUG, "\n");
-                               }
-@@ -437,225 +811,6 @@ static void SetupDqsPattern_D(struct MCTStatStruc 
*pMCTstat,
-       pDCTstat->PtrPatternBufA = (u32)buf;
- }
- 
--static void TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat,
--                              u8 cs_start)
--{
--      u32 Errors;
--      u8 ChipSel, DQSDelay;
--      u8 RnkDlySeqPassMin=0, RnkDlySeqPassMax=0xFF, RnkDlyFilterMin=0, 
RnkDlyFilterMax=0xFF;
--      u8 RnkDlySeqPassMinTot=0, RnkDlySeqPassMaxTot=0xFF, 
RnkDlyFilterMinTot=0, RnkDlyFilterMaxTot=0xFF;
--      u8 LastTest ,LastTestTot;
--      u32 TestAddr;
--      u8 ByteLane;
--      u8 MutualCSPassW[128];
--      u8 BanksPresent;
--      u8 dqsDelay_end;
--      u8 tmp, valid, tmp1;
--      u16 word;
--
--      /* MutualCSPassW: each byte represents a bitmap of pass/fail per
--       * ByteLane.  The indext within MutualCSPassW is the delay value
--       * given the results.
--       */
--      print_debug_dqs("\t\t\tTrainDQSPos begin ", 0, 3);
--
--      Errors = 0;
--      BanksPresent = 0;
--
--      dqsDelay_end = 32;
--      /* Bitmapped status per delay setting, 0xff=All positions
--       * passing (1= PASS). Set the entire array.
--       */
--      for (DQSDelay=0; DQSDelay<128; DQSDelay++) {
--              MutualCSPassW[DQSDelay] = 0xFF;
--      }
--
--      for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) { /* 
logical register chipselects 0..7 */
--              print_debug_dqs("\t\t\t\tTrainDQSPos: 11 ChipSel ", ChipSel, 4);
--
--              if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, 
pDCTstat->Channel, ChipSel)) {
--                      print_debug_dqs("\t\t\t\tmct_RcvrRankEnabled_D CS not 
enabled ", ChipSel, 4);
--                      continue;
--              }
--
--              BanksPresent = 1;       /* flag for at least one bank is 
present */
--              TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, 
pDCTstat->Channel, ChipSel, &valid);
--              if (!valid) {
--                      print_debug_dqs("\t\t\t\tAddress not supported on 
current CS ", TestAddr, 4);
--                      continue;
--              }
--
--              print_debug_dqs("\t\t\t\tTrainDQSPos: 12 TestAddr ", TestAddr, 
4);
--              SetUpperFSbase(TestAddr);       /* fs:eax=far ptr to target */
--
--              if (pDCTstat->Direction == DQS_READDIR) {
--                      print_debug_dqs("\t\t\t\tTrainDQSPos: 13 for read ", 0, 
4);
--                      WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 
8);
--              }
--
--              for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) {
--                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 141 DQSDelay ", 
DQSDelay, 5);
--
--                      tmp = 0xFF;
--                      tmp1 = DQSDelay;
--                      if (pDCTstat->Direction == DQS_READDIR) {
--                              tmp &= MutualCSPassW[DQSDelay];
--                              tmp1 += dqsDelay_end;
--                      }
--                      tmp &= MutualCSPassW[tmp1];
--
--                      if (tmp == 0) {
--                              continue;/* skip current delay value if other 
chipselects have failed all 8 bytelanes */
--                      }
--
--                      pDCTstat->DQSDelay = DQSDelay;
--                      mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
--                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 142 
MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
--
--                      if (pDCTstat->Direction == DQS_WRITEDIR) {
--                              print_debug_dqs("\t\t\t\t\tTrainDQSPos: 143 for 
write", 0, 5);
--                              WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
--                      }
--
--                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 Pattern ", 
pDCTstat->Pattern, 5);
--                      ReadDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8);
--                      /* print_debug_dqs("\t\t\t\t\tTrainDQSPos: 145 
MutualCSPassW ", MutualCSPassW[DQSDelay], 5); */
--                      word = CompareDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8); /* 0=fail, 1=pass */
--                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 1 
", word, 3);
--
--                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 
DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 3);
--                      word &= ~(pDCTstat->DqsRdWrPos_Saved); /* mask out 
bytelanes that already passed */
--                      word &= ~(pDCTstat->DqsRdWrPos_Saved << 8);
--                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 2 
", word, 3);
--
--                      tmp = DQSDelay;
--                      if (pDCTstat->Direction == DQS_READDIR) {
--                              MutualCSPassW[tmp] &= word >> 8;
--                              tmp += dqsDelay_end;
--                      }
--                      MutualCSPassW[tmp] &= word & 0xFF;
--
--                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 
\tMutualCSPassW ", MutualCSPassW[DQSDelay], 5);
--
--                      SetTargetWTIO_D(TestAddr);
--                      FlushDQSTestPattern_D(pDCTstat, TestAddr << 8);
--                      ResetTargetWTIO_D();
--              }
--
--      }
--
--      if (pDCTstat->Direction == DQS_READDIR) {
--              dqsDelay_end <<= 1;
--      }
--
--      if (BanksPresent) {
--              #if 0           /* show the bitmap */
--              for (ByteLane = 0; ByteLane < 8; ByteLane++) { /* just print 
ByteLane 0 */
--                      for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) 
{
--                              if (!(MutualCSPassW[DQSDelay] &(1 << 
ByteLane))) {
--                                      printk(BIOS_DEBUG, ".");
--                              } else {
--                                      printk(BIOS_DEBUG, "*");
--                              }
--                      }
--                      printk(BIOS_DEBUG, "\n");
--              }
--              #endif
--              for (ByteLane = 0; ByteLane < 8; ByteLane++) {
--                      print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane 
",ByteLane, 4);
--                      if (!(pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane))) {
--                              pDCTstat->ByteLane = ByteLane;
--                              LastTest = DQS_FAIL;            /* Analyze the 
results */
--                              LastTestTot = DQS_FAIL;
--                              /* RnkDlySeqPassMin = 0; */
--                              /* RnkDlySeqPassMax = 0; */
--                              RnkDlyFilterMax = 0;
--                              RnkDlyFilterMin = 0;
--                              RnkDlyFilterMaxTot = 0;
--                              RnkDlyFilterMinTot = 0;
--                              for (DQSDelay = 0; DQSDelay < dqsDelay_end; 
DQSDelay++) {
--                                      if (MutualCSPassW[DQSDelay] & (1 << 
ByteLane)) {
--                                              
print_debug_dqs("\t\t\t\t\tTrainDQSPos: 321 DQSDelay ", DQSDelay, 5);
--                                              
print_debug_dqs("\t\t\t\t\tTrainDQSPos: 322 MutualCSPassW ", 
MutualCSPassW[DQSDelay], 5);
--                                              if (pDCTstat->Direction == 
DQS_READDIR)
--                                                      tmp = 0x20;
--                                              else
--                                                      tmp = 0;
--                                              if (DQSDelay >= tmp) {
--                                                      RnkDlySeqPassMax = 
DQSDelay;
--                                                      if (LastTest == 
DQS_FAIL) {
--                                                              
RnkDlySeqPassMin = DQSDelay; /* start sequential run */
--                                                      }
--                                                      if ((RnkDlySeqPassMax - 
RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)){
--                                                              RnkDlyFilterMin 
= RnkDlySeqPassMin;
--                                                              RnkDlyFilterMax 
= RnkDlySeqPassMax;
--                                                      }
--                                                      LastTest = DQS_PASS;
--                                              }
--
--                                              if (pDCTstat->Direction == 
DQS_READDIR) {
--                                                      RnkDlySeqPassMaxTot = 
DQSDelay;
--                                                      if (LastTestTot == 
DQS_FAIL)
--                                                              
RnkDlySeqPassMinTot = DQSDelay;
--                                                      if 
((RnkDlySeqPassMaxTot - 
RnkDlySeqPassMinTot)>(RnkDlyFilterMaxTot-RnkDlyFilterMinTot)){
--                                                              
RnkDlyFilterMinTot = RnkDlySeqPassMinTot;
--                                                              
RnkDlyFilterMaxTot = RnkDlySeqPassMaxTot;
--                                                      }
--                                                      LastTestTot = DQS_PASS;
--                                              }
--                                      } else {
--                                              LastTest = DQS_FAIL;
--                                              LastTestTot = DQS_FAIL;
--                                      }
--                              }
--                              print_debug_dqs("\t\t\t\tTrainDQSPos: 33 
RnkDlySeqPassMax ", RnkDlySeqPassMax, 4);
--                              if (RnkDlySeqPassMax == 0) {
--                                      Errors |= 1 << SB_NODQSPOS; /* no 
passing window */
--                              } else {
--                                      
print_debug_dqs_pair("\t\t\t\tTrainDQSPos: 34 RnkDlyFilter: ", RnkDlyFilterMin, 
" ",  RnkDlyFilterMax, 4);
--                                      if (((RnkDlyFilterMax - 
RnkDlyFilterMin) < MIN_DQS_WNDW)){
--                                              Errors |= 1 << SB_SMALLDQS;
--                                      } else {
--                                              u8 middle_dqs;
--                                              /* mctEngDQSwindow_Save_D Not 
required for arrays */
--                                              if (pDCTstat->Direction == 
DQS_READDIR)
--                                                      middle_dqs = 
MiddleDQS_D(RnkDlyFilterMinTot, RnkDlyFilterMaxTot);
--                                              else
--                                                      middle_dqs = 
MiddleDQS_D(RnkDlyFilterMin, RnkDlyFilterMax);
--                                              pDCTstat->DQSDelay = middle_dqs;
--                                              mct_SetDQSDelayCSR_D(pMCTstat, 
pDCTstat, cs_start);  /* load the register with the value */
--                                              if (pDCTstat->Direction == 
DQS_READDIR)
--                                                      
StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMinTot, 
RnkDlyFilterMaxTot); /* store the value into the data structure */
--                                              else
--                                                      
StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMin, 
RnkDlyFilterMax); /* store the value into the data structure */
--                                              
print_debug_dqs("\t\t\t\tTrainDQSPos: 42 middle_dqs : ",middle_dqs, 4);
--                                              pDCTstat->DqsRdWrPos_Saved |= 1 
<< ByteLane;
--                                      }
--                              }
--                      }
--              } /* if (pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane)) */
--      }
--/* skipLocMiddle: */
--      pDCTstat->TrainErrors = Errors;
--
--      print_debug_dqs("\t\t\tTrainDQSPos: Errors ", Errors, 3);
--}
--
--static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
--                                      u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
--{
--      pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
--              [pDCTstat->Direction]
--              [0]
--              [pDCTstat->ByteLane] = RnkDlyFilterMin;
--      pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
--              [pDCTstat->Direction]
--              [1]
--              [pDCTstat->ByteLane] = RnkDlyFilterMax;
--}
--
- static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 
ChipSel)
- {
-@@ -679,26 +834,6 @@ static void StoreDQSDatStrucVal_D(struct MCTStatStruc 
*pMCTstat,
-                                       pDCTstat->DQSDelay;
- }
- 
--static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
--                                      u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
--{
--      u8 dn;
--
--      if (pDCTstat->Direction == DQS_WRITEDIR) {
--              dn = ChipSel >> 1;
--              RnkDlyFilterMin += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
--              RnkDlyFilterMax += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
--              pDCTstat->DQSDelay += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
--      } else {
--              RnkDlyFilterMin <<= 1;
--              RnkDlyFilterMax <<= 1;
--              pDCTstat->DQSDelay <<= 1;
--      }
--      mctEngDQSwindow_Save_D(pMCTstat, pDCTstat, ChipSel, RnkDlyFilterMin, 
RnkDlyFilterMax);
--      StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
--}
--
- static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
- {
-@@ -720,33 +855,6 @@ static void GetDQSDatStrucVal_D(struct MCTStatStruc 
*pMCTstat,
- 
- /* FindDQSDatDimmVal_D is not required since we use an array */
- 
--static u8 MiddleDQS_D(u8 min, u8 max)
--{
--      u8 size;
--      size = max-min;
--      if (size % 2)
--              size++;         /* round up if the size isn't even. */
--      return ( min + (size >> 1));
--}
--
--static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat,
--                              u8 cs_start)
--{
--      print_debug_dqs("\t\tTrainReadPos ", 0, 2);
--      pDCTstat->Direction = DQS_READDIR;
--      TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
--}
--
--static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat,
--                              u8 cs_start)
--{
--      pDCTstat->Direction = DQS_WRITEDIR;
--      print_debug_dqs("\t\tTrainWritePos", 0, 2);
--      TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
--}
--
- static void proc_IOCLFLUSH_D(u32 addr_hi)
- {
-       SetTargetWTIO_D(addr_hi);
-@@ -963,30 +1071,6 @@ static void ResetTargetWTIO_D(void)
-       _WRMSR(0xc0010017, lo, hi); /* IORR0 Mask */
- }
- 
--static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat,
--                              u32 TestAddr_lo)
--{
--      /* Read a pattern of 72 bit times (per DQ), to test dram functionality.
--       * The pattern is a stress pattern which exercises both ISI and
--       * crosstalk.  The number of cache lines to fill is dependent on DCT
--       * width mode and burstlength.
--       * Mode BL  Lines Pattern no.
--       * ----+---+-------------------
--       * 64   4         9     0
--       * 64   8         9     0
--       * 64M  4         9     0
--       * 64M  8         9     0
--       * 128  4         18    1
--       * 128  8         N/A   -
--       */
--      if (pDCTstat->Pattern == 0)
--              ReadL9TestPattern(TestAddr_lo);
--      else
--              ReadL18TestPattern(TestAddr_lo);
--      _MFENCE;
--}
--
- u32 SetUpperFSbase(u32 addr_hi)
- {
-       /* Set the upper 32-bits of the Base address, 4GB aligned) for the
-@@ -1009,8 +1093,6 @@ void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index)
-       Set_NB32_index_wait(dev, index_reg, index, val);
- }
- 
--/* mctEngDQSwindow_Save_D not required with arrays */
--
- void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstatA)
- {
-@@ -1021,8 +1103,8 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
-       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-               pDCTstat = pDCTstatA + Node;
-               if (pDCTstat->DCTSysLimit) {
-+                      TrainDQSRdWrPos_D(pMCTstat, pDCTstat);
-                       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel 
+= 2) {
--                              TrainDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
-                               SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
-                       }
-               }
-@@ -1137,27 +1219,6 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
-       }
- }
- 
--/*
-- * mct_SetDQSDelayAllCSR_D:
-- * Write the Delay value to all eight byte lanes.
-- */
--static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat,
--                                      u8 cs_start)
--{
--      u8 ByteLane;
--      u8 ChipSel = cs_start;
--
--      for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) {
--              if ( mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, 
pDCTstat->Channel, ChipSel)) {
--                      for (ByteLane = 0; ByteLane < 8; ByteLane++) {
--                              pDCTstat->ByteLane = ByteLane;
--                              mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, 
ChipSel);
--                      }
--              }
--      }
--}
--
- u8 mct_RcvrRankEnabled_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat,
-                               u8 Channel, u8 ChipSel)
-@@ -1196,7 +1257,7 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
-       reg = 0x40 + (receiver << 2) + reg_off;
-       val = Get_NB32(dev, reg);
- 
--      val &= ~0x0F;
-+      val &= ~0xe007c01f;
- 
-       /* unganged mode DCT0+DCT1, sys addr of DCT1=node
-        * base+DctSelBaseAddr+local ca base*/
-@@ -1277,6 +1338,7 @@ exitGetAddrWNoError:
-       print_debug_dqs("mct_GetMCTSysAddr_D: base_addr ", val, 2);
-       print_debug_dqs("mct_GetMCTSysAddr_D: valid ", *valid, 2);
-       print_debug_dqs("mct_GetMCTSysAddr_D: status ", pDCTstat->Status, 2);
-+      print_debug_dqs("mct_GetMCTSysAddr_D: SysBase ", pDCTstat->DCTSysBase, 
2);
-       print_debug_dqs("mct_GetMCTSysAddr_D: HoleBase ", 
pDCTstat->DCTHoleBase, 2);
-       print_debug_dqs("mct_GetMCTSysAddr_D: Cachetop ", 
pMCTstat->Sub4GCacheTop, 2);
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-index 528c782..60bc01d 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -25,7 +26,6 @@ static void EnableZQcalibration(struct MCTStatStruc 
*pMCTstat, struct DCTStatStr
- static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
- static void PrepareC_DCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
--static void MultiplyDelay(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
- static void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- static void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- 
-@@ -154,7 +154,6 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
-               Clear_OnDimmMirror(pMCTstat, pDCTstat);
-               SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
-               DisableAutoRefresh_D(pMCTstat, pDCTstat);
--              MultiplyDelay(pMCTstat, pDCTstat, dct);
-               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
-                       if (DIMMValid & (1 << (dimm << 1)))
-                               AgesaHwWlPhase1(pDCTstat->C_MCTPtr, 
pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
-@@ -162,6 +161,9 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
-       }
- }
- 
-+/* Write Levelization Training
-+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
-+ */
- static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat)
- {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
-index 3d625de..596fb23 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -201,12 +202,13 @@ static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 
*pMtrrAddr, u16 MtrrType)
- 
- void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA)
- {
--/* UMA memory size may need splitting the MTRR configuration into two
--  Before training use NB_BottomIO or the physical memory size to set the 
MTRRs.
--  After training, add UMAMemTyping function to reconfigure the MTRRs based on
--  NV_BottomUMA (for UMA systems only).
--  This two-step process allows all memory to be cached for training
--*/
-+      /* UMA memory size may need splitting the MTRR configuration into two
-+       * Before training use NB_BottomIO or the physical memory size to set 
the MTRRs.
-+       * After training, add UMAMemTyping function to reconfigure the MTRRs 
based on
-+       * NV_BottomUMA (for UMA systems only).
-+       * This two-step process allows all memory to be cached for training
-+      */
-+
-       u32 Bottom32bIO, Cache32bTOP;
-       u32 val;
-       u32 addr;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
-index 013a1b9..6f97061 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -140,7 +141,7 @@ void InterleaveNodes_D(struct MCTStatStruc *pMCTstat,
-       }
- 
-       if (DoIntlv) {
--              MCTMemClr_D(pMCTstat,pDCTstatA);
-+              MCTMemClr_D(pMCTstat, pDCTstatA);
-               /* Program Interleaving enabled on Node 0 map only.*/
-               MemSize0 <<= bsf(Nodes);        /* MemSize=MemSize*2 (or 4, or 
8) */
-               Dct0MemSize <<= bsf(Nodes);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-index da2f372..cda9c6b 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -36,10 +37,10 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
-               val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78);
- 
-               val &= 7;
--              val = ((~val) & 0xFF) + 1;
-+              val = ((~val) & 0xff) + 1;
-               val += 6;
--              val &= 0xFF;
--              misc2 &= 0xFFF8FFFF;
-+              val &= 0x7;
-+              misc2 &= 0xfff8ffff;
-               misc2 |= val << 16;     /* DataTxFifoWrDly */
-               if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
-                       misc2 |= 1 << 7; /* ProgOdtEn */
-@@ -52,11 +53,15 @@ void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat)
-       u32 val;
- 
-       if (pDCTstat->LogicalCPUID & (AMD_DR_Cx)) {
--              Set_NB32(pDCTstat->dev_dct, 0x11C, 0x0CE00FC0 | 1 << 29/* 
FlushWrOnStpGnt */);
-+              /* Revision C */
-+              Set_NB32(pDCTstat->dev_dct, 0x11c, 0x0ce00fc0 | 1 << 29/* 
FlushWrOnStpGnt */);
-+      }
- 
--              val = Get_NB32(pDCTstat->dev_dct, 0x1B0);
--              val &= 0xFFFFF8C0;
-+      if (pDCTstat->LogicalCPUID & (AMD_DR_Cx)) {
-+              val = Get_NB32(pDCTstat->dev_dct, 0x1b0);
-+              val &= ~0x73f;
-               val |= 0x101;   /* BKDG recommended settings */
--              Set_NB32(pDCTstat->dev_dct, 0x1B0, val);
-+
-+              Set_NB32(pDCTstat->dev_dct, 0x1b0, val);
-       }
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index 6de2f4e..b21b96a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -172,6 +173,7 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
-                       ret |= 1 << 11;
-       }
- 
-+      /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
-       if (dword & (1 << 13))
-               ret |= 1 << 12;
- 
-@@ -199,7 +201,8 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
-       /* program MrsAddress[6:4,2]=read CAS latency
-          (CL):based on F2x[1,0]88[Tcl] */
-       dword2 = Get_NB32(dev, reg_off + 0x88);
--      ret |= (dword2 & 0xF) << 4; /* F2x88[3:0] to MrsAddress[6:4,2]=xxx0b */
-+      ret |= (dword2 & 0x7) << 4;             /* F2x88[2:0] to 
MrsAddress[6:4] */
-+      ret |= ((dword2 & 0x8) >> 3) << 2;      /* F2x88[3] to MrsAddress[2] */
- 
-       /* program MrsAddress[12]=0 (PPD):slow exit */
-       if (dword & (1 << 23))
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 8e5c268..91e8f77 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -24,25 +25,13 @@
- 
- static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Pass);
--static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat,
--                                      u8 rcvrEnDly, u8 Channel,
--                                      u8 receiver, u8 Pass);
--static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat,
--                                      u32 addr, u8 channel,
--                                      u8 pattern, u8 Pass);
- static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
-                                        struct DCTStatStruc *pDCTstat);
- static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Channel);
- static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Channel);
--static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat,
--                              u8 RcvrEnDly, u8 where,
--                              u8 Channel, u8 Receiver,
--                              u32 dev, u32 index_reg,
--                              u8 Addl_Index, u8 Pass);
--static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 
DQSRcvEnDly);
-+static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, 
u16 DQSRcvEnDly);
- static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat, u8 dct);
- static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat);
-@@ -50,17 +39,17 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc 
*pDCTstat);
- /* Warning:  These must be located so they do not cross a logical 16-bit
-    segment boundary! */
- static const u32 TestPattern0_D[] = {
--      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
--      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
--      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
--      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
--};
--static const u32 TestPattern1_D[] = {
-       0x55555555, 0x55555555, 0x55555555, 0x55555555,
-       0x55555555, 0x55555555, 0x55555555, 0x55555555,
-       0x55555555, 0x55555555, 0x55555555, 0x55555555,
-       0x55555555, 0x55555555, 0x55555555, 0x55555555,
- };
-+static const u32 TestPattern1_D[] = {
-+      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
-+      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
-+      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
-+      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
-+};
- static const u32 TestPattern2_D[] = {
-       0x12345678, 0x87654321, 0x23456789, 0x98765432,
-       0x59385824, 0x30496724, 0x24490795, 0x99938733,
-@@ -104,16 +93,87 @@ void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat,
-               dqsTrainRcvrEn_SW(pMCTstat, pDCTstat, Pass);
- }
- 
-+static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t dword;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+              uint32_t wdt_reg;
-+              if ((lane == 0) || (lane == 1))
-+                      wdt_reg = 0x30;
-+              if ((lane == 2) || (lane == 3))
-+                      wdt_reg = 0x31;
-+              if ((lane == 4) || (lane == 5))
-+                      wdt_reg = 0x40;
-+              if ((lane == 6) || (lane == 7))
-+                      wdt_reg = 0x41;
-+              if (lane == 8)
-+                      wdt_reg = 0x32;
-+              wdt_reg += dimm * 3;
-+              dword = Get_NB32_index_wait(dev, index_reg, wdt_reg);
-+              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1))
-+                      current_total_delay[lane] = (dword & 0x00ff0000) >> 16;
-+              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0))
-+                      current_total_delay[lane] = dword & 0x000000ff;
-+      }
-+}
-+
-+static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t dword;
-+
-+      for (lane = 0; lane < 8; lane++) {
-+              uint32_t ret_reg;
-+              if ((lane == 0) || (lane == 1))
-+                      ret_reg = 0x10;
-+              if ((lane == 2) || (lane == 3))
-+                      ret_reg = 0x11;
-+              if ((lane == 4) || (lane == 5))
-+                      ret_reg = 0x20;
-+              if ((lane == 6) || (lane == 7))
-+                      ret_reg = 0x21;
-+              ret_reg += dimm * 3;
-+              dword = Get_NB32_index_wait(dev, index_reg, ret_reg);
-+              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
-+                      dword &= ~(0x1ff << 16);
-+                      dword |= (current_total_delay[lane] & 0x1ff) << 16;
-+              }
-+              if ((lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
-+                      dword &= ~0x1ff;
-+                      dword |= current_total_delay[lane] & 0x1ff;
-+              }
-+              Set_NB32_index_wait(dev, index_reg, ret_reg, dword);
-+      }
-+}
-+
-+static uint32_t convert_testaddr_and_channel_to_address(struct DCTStatStruc 
*pDCTstat, uint32_t testaddr, uint8_t channel)
-+{
-+      SetUpperFSbase(testaddr);
-+      testaddr <<= 8;
-+
-+      if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) {
-+              testaddr += 8;  /* second channel */
-+      }
-+
-+      return testaddr;
-+}
-+
-+/* DQS Receiver Enable Training
-+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
-+ */
- static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Pass)
- {
--      u8 Channel, RcvrEnDly, RcvrEnDlyRmin;
--      u8 Test0, Test1, CurrTest, CurrTestSide0, CurrTestSide1;
--      u8 CTLRMaxDelay, _2Ranks, PatternA, PatternB;
-+      u8 Channel;
-+      u8 _2Ranks;
-       u8 Addl_Index = 0;
-       u8 Receiver;
-       u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
--      u8 RcvrEnDlyLimit, Final_Value, MaxDelay_CH[2];
-+      u8 Final_Value;
-+      u16 CTLRMaxDelay;
-+      u16 MaxDelay_CH[2];
-       u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B;
-       u32 PatternBuffer[64+4]; /* FIXME: need increase 8? */
-       u32 Errors;
-@@ -127,9 +187,20 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-       u32 cr4;
-       u32 lo, hi;
- 
-+      uint32_t dword;
-+      uint8_t rank;
-+      uint8_t lane;
-+      uint16_t current_total_delay[MAX_BYTE_LANES];
-+      uint16_t candidate_total_delay[8];
-+      uint8_t data_test_pass_sr[2][8];        /* [rank][lane] */
-+      uint8_t data_test_pass[8];              /* [lane] */
-+      uint8_t data_test_pass_prev[8];         /* [lane] */
-+      uint8_t window_det_toggle[8];
-+      uint8_t trained[8];
-+      uint64_t result_qword1;
-+      uint64_t result_qword2;
-+
-       u8 valid;
--      u32 tmp;
--      u8 LastTest;
- 
-       print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
-       print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
-@@ -181,33 +252,103 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
- 
-       Errors = 0;
-       dev = pDCTstat->dev_dct;
--      CTLRMaxDelay = 0;
- 
-       for (Channel = 0; Channel < 2; Channel++) {
-               print_debug_dqs("\tTrainRcvEn51: Node ", pDCTstat->Node_ID, 1);
-               print_debug_dqs("\tTrainRcvEn51: Channel ", Channel, 1);
-               pDCTstat->Channel = Channel;
- 
-+              CTLRMaxDelay = 0;
-               MaxDelay_CH[Channel] = 0;
-               index_reg = 0x98 + 0x100 * Channel;
- 
-               Receiver = mct_InitReceiver_D(pDCTstat, Channel);
--              /* There are four receiver pairs, loosely associated with 
chipselects. */
-+              /* There are four receiver pairs, loosely associated with 
chipselects.
-+               * This is essentially looping over each DIMM.
-+               */
-               for (; Receiver < 8; Receiver += 2) {
-                       Addl_Index = (Receiver >> 1) * 3 + 0x10;
--                      LastTest = DQS_FAIL;
--
--                      /* mct_ModifyIndex_D */
--                      RcvrEnDlyRmin = RcvrEnDlyLimit = 0xff;
- 
-                       print_debug_dqs("\t\tTrainRcvEnd52: index ", 
Addl_Index, 2);
- 
--                      if(!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
-                               continue;
-                       }
- 
-+                      /* Clear data structures */
-+                      for (lane = 0; lane < 8; lane++) {
-+                              data_test_pass_prev[lane] = 0;
-+                              trained[lane] = 0;
-+                      }
-+
-+                      /* 2.8.9.9.2 (1, 6)
-+                       * Retrieve gross and fine timing fields from write DQS 
registers
-+                       */
-+                      
read_dqs_write_timing_control_registers(current_total_delay, dev, (Receiver >> 
1), index_reg);
-+
-+                      /* 2.8.9.9.2 (1)
-+                       * Program the Write Data Timing and Write ECC Timing 
register to
-+                       * the values stored in the DQS Write Timing Control 
register
-+                       * for each lane
-+                       */
-+                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                              uint32_t wdt_reg;
-+
-+                              /* Calculate Write Data Timing register 
location */
-+                              if ((lane == 0) || (lane == 1) || (lane == 2) 
|| (lane == 3))
-+                                      wdt_reg = 0x1;
-+                              if ((lane == 4) || (lane == 5) || (lane == 6) 
|| (lane == 7))
-+                                      wdt_reg = 0x2;
-+                              if (lane == 8)
-+                                      wdt_reg = 0x3;
-+                              wdt_reg |= ((Receiver / 2) << 8);
-+
-+                              /* Set Write Data Timing register values */
-+                              dword = Get_NB32_index_wait(dev, index_reg, 
wdt_reg);
-+                              if ((lane == 7) || (lane == 3)) {
-+                                      dword &= ~(0x7f << 24);
-+                                      dword |= (current_total_delay[lane] & 
0x7f) << 24;
-+                              }
-+                              if ((lane == 6) || (lane == 2)) {
-+                                      dword &= ~(0x7f << 16);
-+                                      dword |= (current_total_delay[lane] & 
0x7f) << 16;
-+                              }
-+                              if ((lane == 5) || (lane == 1)) {
-+                                      dword &= ~(0x7f << 8);
-+                                      dword |= (current_total_delay[lane] & 
0x7f) << 8;
-+                              }
-+                              if ((lane == 8) || (lane == 4) || (lane == 0)) {
-+                                      dword &= ~0x7f;
-+                                      dword |= current_total_delay[lane] & 
0x7f;
-+                              }
-+                              Set_NB32_index_wait(dev, index_reg, wdt_reg, 
dword);
-+                      }
-+
-+                      /* 2.8.9.9.2 (2)
-+                       * Program the Read DQS Timing Control and the Read DQS 
ECC Timing Control registers
-+                       * to 1/2 MEMCLK for all lanes
-+                       */
-+                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                              uint32_t rdt_reg;
-+                              if ((lane == 0) || (lane == 1) || (lane == 2) 
|| (lane == 3))
-+                                      rdt_reg = 0x5;
-+                              if ((lane == 4) || (lane == 5) || (lane == 6) 
|| (lane == 7))
-+                                      rdt_reg = 0x6;
-+                              if (lane == 8)
-+                                      rdt_reg = 0x7;
-+                              rdt_reg |= ((Receiver / 2) << 8);
-+                              if (lane == 8)
-+                                      dword = 0x0000003f;
-+                              else
-+                                      dword = 0x3f3f3f3f;
-+                              Set_NB32_index_wait(dev, index_reg, rdt_reg, 
dword);
-+                      }
-+
-+                      /* 2.8.9.9.2 (3)
-+                       * Select two test addresses for each rank present
-+                       */
-                       TestAddr0 = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, 
Channel, Receiver, &valid);
--                      if(!valid) {    /* Address not supported on current CS 
*/
-+                      if (!valid) {   /* Address not supported on current CS 
*/
-                               continue;
-                       }
- 
-@@ -229,171 +370,214 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1 ", 
TestAddr1, 2);
-                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", 
TestAddr1B, 2);
- 
--                      /*
--                       * Get starting RcvrEnDly value
-+                      /* 2.8.9.9.2 (4, 5)
-+                       * Write 1 cache line of the appropriate test pattern 
to each test addresse
-                        */
--                      RcvrEnDly = mct_Get_Start_RcvrEnDly_1Pass(Pass);
-+                      mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, 
0); /* rank 0 of DIMM, testpattern 0 */
-+                      mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0B, 1); /* rank 0 of DIMM, testpattern 1 */
-+                      if (_2Ranks) {
-+                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr1, 0); /*rank 1 of DIMM, testpattern 0 */
-+                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr1B, 1); /*rank 1 of DIMM, testpattern 1 */
-+                      }
- 
--                      /* mct_GetInitFlag_D*/
--                      if (Pass == FirstPass) {
--                              pDCTstat->DqsRcvEn_Pass = 0;
--                      } else {
--                              pDCTstat->DqsRcvEn_Pass=0xFF;
-+#if DQS_TRAIN_DEBUG > 0
-+                      for (lane = 0; lane < 8; lane++) {
-+                              print_debug_dqs("\t\tTrainRcvEn54: lane: ", 
lane, 2);
-+                              print_debug_dqs("\t\tTrainRcvEn54: 
current_total_delay ", current_total_delay[lane], 2);
-                       }
--                      pDCTstat->DqsRcvEn_Saved = 0;
-+#endif
- 
-+                      /* 2.8.9.9.2 (6)
-+                       * Write gross and fine timing fields to read DQS 
registers
-+                       */
-+                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+
-+                      /* 2.8.9.9.2 (7)
-+                       * Loop over all delay values up to 1 MEMCLK (0x40 
delay steps) from the initial delay values
-+                       *
-+                       * FIXME
-+                       * It is not clear if training should be discontinued 
if any test failures occur in the first
-+                       * 1 MEMCLK window, or if it should be discontinued if 
no successes occur in the first 1 MEMCLK
-+                       * window.  Therefore, loop over up to 2 MEMCLK (0x80 
delay steps) to be on the safe side.
-+                       */
-+                      uint16_t current_delay_step;
- 
--                      while(RcvrEnDly < RcvrEnDlyLimit) {     /* sweep Delay 
value here */
--                              print_debug_dqs("\t\t\tTrainRcvEn541: RcvrEnDly 
", RcvrEnDly, 3);
-+                      for (current_delay_step = 0; current_delay_step < 0x80; 
current_delay_step++) {
-+                              print_debug_dqs("\t\t\tTrainRcvEn541: 
current_delay_step ", current_delay_step, 3);
- 
--                              /* callback not required
--                              if(mct_AdjustDelay_D(pDCTstat, RcvrEnDly))
--                                      goto skipDly;
-+                              /* 2.8.9.9.2 (7 D)
-+                              * Terminate if all lanes are trained
-                               */
-+                              uint8_t all_lanes_trained = 1;
-+                              for (lane = 0; lane < 8; lane++)
-+                                      if (!trained[lane])
-+                                              all_lanes_trained = 0;
- 
--                              /* Odd steps get another pattern such that even
--                               and odd steps alternate. The pointers to the
--                               patterns will be swaped at the end of the loop
--                               so that they correspond. */
--                              if(RcvrEnDly & 1) {
--                                      PatternA = 1;
--                                      PatternB = 0;
--                              } else {
--                                      /* Even step */
--                                      PatternA = 0;
--                                      PatternB = 1;
--                              }
--
--                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0, PatternA); /* rank 0 of DIMM, testpattern 0 */
--                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0B, PatternB); /* rank 0 of DIMM, testpattern 1 */
--                              if(_2Ranks) {
--                                      mct_Write1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr1, PatternA); /*rank 1 of DIMM, testpattern 0 */
--                                      mct_Write1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr1B, PatternB); /*rank 1 of DIMM, testpattern 1 */
--                              }
--
--                              mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, 0, 
Channel, Receiver, dev, index_reg, Addl_Index, Pass);
--
--                              CurrTest = DQS_FAIL;
--                              CurrTestSide0 = DQS_FAIL;
--                              CurrTestSide1 = DQS_FAIL;
--
--                              mct_Read1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0); /*cache fills */
--                              Test0 = mct_CompareTestPatternQW0_D(pMCTstat, 
pDCTstat, TestAddr0, Channel, PatternA, Pass);/* ROM vs cache compare */
--                              proc_IOCLFLUSH_D(TestAddr0);
--                              ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
--
--                              print_debug_dqs("\t\t\tTrainRcvEn542: Test0 
result ", Test0, 3);
--
--                              /* != 0x00 mean pass */
--
--                              if(Test0 == DQS_PASS) {
--                                      mct_Read1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr0B);        /*cache fills */
--                                      /* ROM vs cache compare */
--                                      Test1 = 
mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr0B, Channel, PatternB, 
Pass);
--                                      proc_IOCLFLUSH_D(TestAddr0B);
--                                      ResetDCTWrPtr_D(dev, index_reg, 
Addl_Index);
--
--                                      print_debug_dqs("\t\t\tTrainRcvEn543: 
Test1 result ", Test1, 3);
-+                              if (all_lanes_trained)
-+                                      break;
- 
--                                      if(Test1 == DQS_PASS) {
--                                              CurrTestSide0 = DQS_PASS;
-+                              /* 2.8.9.9.2 (7 A)
-+                              * Loop over all ranks
-+                              */
-+                              for (rank = 0; rank < (_2Ranks + 1); rank++) {
-+                                      /* 2.8.9.9.2 (7 A a-d)
-+                                       * Read the first test address of the 
current rank
-+                                       * Store the first data beat for 
analysis
-+                                       * Reset read pointer in the DRAM 
controller FIFO
-+                                       * Read the second test address of the 
current rank
-+                                       * Store the first data beat for 
analysis
-+                                       * Reset read pointer in the DRAM 
controller FIFO
-+                                       */
-+                                      if (rank & 1) {
-+                                              /* 2.8.9.9.2 (7 D)
-+                                               * Invert read instructions to 
alternate data read order on the bus
-+                                               */
-+                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
-+                                              result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
-+                                              result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                                      } else {
-+                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
-+                                              result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
-+                                              result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-                                       }
--                              }
--                              if(_2Ranks) {
--                                      mct_Read1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr1); /*cache fills */
--                                      /* ROM vs cache compare */
--                                      Test0 = 
mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1, Channel, PatternA, 
Pass);
--                                      proc_IOCLFLUSH_D(TestAddr1);
--                                      ResetDCTWrPtr_D(dev, index_reg, 
Addl_Index);
--
--                                      print_debug_dqs("\t\t\tTrainRcvEn544: 
Test0 result ", Test0, 3);
--
--                                      if(Test0 == DQS_PASS) {
--                                              
mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1B);        /*cache fills */
--                                              /* ROM vs cache compare */
--                                              Test1 = 
mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1B, Channel, PatternB, 
Pass);
--                                              proc_IOCLFLUSH_D(TestAddr1B);
--                                              ResetDCTWrPtr_D(dev, index_reg, 
Addl_Index);
--
--                                              
print_debug_dqs("\t\t\tTrainRcvEn545: Test1 result ", Test1, 3);
--                                              if(Test1 == DQS_PASS) {
--                                                      CurrTestSide1 = 
DQS_PASS;
-+                                      /* 2.8.9.9.2 (7 A e)
-+                                       * Compare both read patterns and flag 
passing ranks/lanes
-+                                       */
-+                                      uint8_t result_lane_byte1;
-+                                      uint8_t result_lane_byte2;
-+                                      for (lane = 0; lane < 8; lane++) {
-+                                              if (trained[lane] == 1) {
-+#if DQS_TRAIN_DEBUG > 0
-+                                                      
print_debug_dqs("\t\t\t\t\t\t\t\t lane already trained: ", lane, 4);
-+#endif
-+                                                      continue;
-                                               }
-+
-+                                              result_lane_byte1 = 
(result_qword1 >> (lane * 8)) & 0xff;
-+                                              result_lane_byte2 = 
(result_qword2 >> (lane * 8)) & 0xff;
-+                                              if ((result_lane_byte1 == 0x55) 
&& (result_lane_byte2 == 0xaa))
-+                                                      
data_test_pass_sr[rank][lane] = 1;
-+                                              else
-+                                                      
data_test_pass_sr[rank][lane] = 0;
-+#if DQS_TRAIN_DEBUG > 0
-+                                              
print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", 0x55, "  |  ", result_lane_byte1, 4);
-+                                              
print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", 0xaa, "  |  ", result_lane_byte2, 4);
-+#endif
-                                       }
-                               }
- 
--                              if(_2Ranks) {
--                                      if ((CurrTestSide0 == DQS_PASS) && 
(CurrTestSide1 == DQS_PASS)) {
--                                              CurrTest = DQS_PASS;
-+                              /* 2.8.9.9.2 (7 B)
-+                               * If DIMM is dual rank, only use delays that 
pass testing for both ranks
-+                               */
-+                              for (lane = 0; lane < 8; lane++) {
-+                                      if (_2Ranks) {
-+                                              if 
((data_test_pass_sr[0][lane]) && (data_test_pass_sr[1][lane]))
-+                                                      data_test_pass[lane] = 
1;
-+                                              else
-+                                                      data_test_pass[lane] = 
0;
-+                                      } else {
-+                                              data_test_pass[lane] = 
data_test_pass_sr[0][lane];
-                                       }
--                              } else if (CurrTestSide0 == DQS_PASS) {
--                                      CurrTest = DQS_PASS;
-                               }
- 
--                              /* record first pass DqsRcvEn to stack */
--                              valid = mct_SavePassRcvEnDly_D(pDCTstat, 
RcvrEnDly, Channel, Receiver, Pass);
-+                              /* 2.8.9.9.2 (7 E)
-+                               * For each lane, update the DQS receiver delay 
setting in support of next iteration
-+                               */
-+                              for (lane = 0; lane < 8; lane++) {
-+                                      if (trained[lane] == 1)
-+                                              continue;
-+
-+                                      /* 2.8.9.9.2 (7 C a)
-+                                       * Save the total delay of the first 
success after a failure for later use
-+                                       */
-+                                      if ((data_test_pass[lane] == 1) && 
(data_test_pass_prev[lane] == 0)) {
-+                                              candidate_total_delay[lane] = 
current_total_delay[lane];
-+                                              window_det_toggle[lane] = 0;
-+                                      }
- 
--                              /* Break(1:RevF,2:DR) or not(0) FIXME: This 
comment deosn't make sense */
--                              if(valid == 2 || (LastTest == DQS_FAIL && valid 
== 1)) {
--                                      RcvrEnDlyRmin = RcvrEnDly;
--                                      break;
-+                                      /* 2.8.9.9.2 (7 C b)
-+                                       * If the current delay failed testing 
add 1/8 UI to the current delay
-+                                       */
-+                                      if (data_test_pass[lane] == 0)
-+                                              current_total_delay[lane] += 
0x4;
-+
-+                                      /* 2.8.9.9.2 (7 C c)
-+                                       * If the current delay passed testing 
alternately add either 1/32 UI or 1/4 UI to the current delay
-+                                       * If 1.25 UI of delay have been added 
with no failures the lane is considered trained
-+                                       */
-+                                      if (data_test_pass[lane] == 1) {
-+                                              /* See if lane is trained */
-+                                              if ((current_total_delay[lane] 
- candidate_total_delay[lane]) >= 0x28) {
-+                                                      trained[lane] = 1;
-+
-+                                                      /* Calculate and set 
final lane delay value
-+                                                       * The final delay is 
the candidate delay + 7/8 UI
-+                                                       */
-+                                                      
current_total_delay[lane] = candidate_total_delay[lane] + 0x1c;
-+                                              } else {
-+                                                      if 
(window_det_toggle[lane] == 0) {
-+                                                              
current_total_delay[lane] += 0x1;
-+                                                              
window_det_toggle[lane] = 1;
-+                                                      } else {
-+                                                              
current_total_delay[lane] += 0x8;
-+                                                              
window_det_toggle[lane] = 0;
-+                                                      }
-+                                              }
-+                                      }
-                               }
- 
--                              LastTest = CurrTest;
--
--                              /* swap the rank 0 pointers */
--                              tmp = TestAddr0;
--                              TestAddr0 = TestAddr0B;
--                              TestAddr0B = tmp;
--
--                              /* swap the rank 1 pointers */
--                              tmp = TestAddr1;
--                              TestAddr1 = TestAddr1B;
--                              TestAddr1B = tmp;
--
--                              print_debug_dqs("\t\t\tTrainRcvEn56: RcvrEnDly 
", RcvrEnDly, 3);
-+                              /* Update delays in hardware */
-+                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
- 
--                              RcvrEnDly++;
--
--                      }       /* while RcvrEnDly */
--
--                      print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDly ", 
RcvrEnDly, 2);
--                      print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyRmin ", 
RcvrEnDlyRmin, 3);
--                      print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyLimit ", 
RcvrEnDlyLimit, 3);
--                      if(RcvrEnDlyRmin == RcvrEnDlyLimit) {
--                              /* no passing window */
--                              pDCTstat->ErrStatus |= 1 << SB_NORCVREN;
--                              Errors |= 1 << SB_NORCVREN;
--                              pDCTstat->ErrCode = SC_FatalErr;
-+                              /* Save previous results for comparison in the 
next iteration */
-+                              for (lane = 0; lane < 8; lane++)
-+                                      data_test_pass_prev[lane] = 
data_test_pass[lane];
-                       }
- 
--                      if(RcvrEnDly > (RcvrEnDlyLimit - 1)) {
--                              /* passing window too narrow, too far delayed*/
--                              pDCTstat->ErrStatus |= 1 << SB_SmallRCVR;
--                              Errors |= 1 << SB_SmallRCVR;
--                              pDCTstat->ErrCode = SC_FatalErr;
--                              RcvrEnDly = RcvrEnDlyLimit - 1;
--                              pDCTstat->CSTrainFail |= 1 << Receiver;
--                              pDCTstat->DimmTrainFail |= 1 << (Receiver + 
Channel);
--                      }
--
--                      /* CHB_D0_B0_RCVRDLY set in mct_Average_RcvrEnDly_Pass 
*/
--                      mct_Average_RcvrEnDly_Pass(pDCTstat, RcvrEnDly, 
RcvrEnDlyLimit, Channel, Receiver, Pass);
-+#if DQS_TRAIN_DEBUG > 0
-+                      for (lane = 0; lane < 8; lane++)
-+                              print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
-+#endif
- 
--                      mct_SetFinalRcvrEnDly_D(pDCTstat, RcvrEnDly, 
Final_Value, Channel, Receiver, dev, index_reg, Addl_Index, Pass);
-+                      /* Find highest delay value and save for later use */
-+                      for (lane = 0; lane < 8; lane++)
-+                              if (current_total_delay[lane] > CTLRMaxDelay)
-+                                      CTLRMaxDelay = 
current_total_delay[lane];
- 
--                      if(pDCTstat->ErrStatus & (1 << SB_SmallRCVR)) {
--                              Errors |= 1 << SB_SmallRCVR;
-+                      /* See if any lanes failed training, and set error 
flags appropriately
-+                       * For all trained lanes, save delay values for later 
use
-+                       */
-+                      for (lane = 0; lane < 8; lane++) {
-+                              if (trained[lane]) {
-+                                      
pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1][lane] = 
current_total_delay[lane];
-+                              } else {
-+                                      printk(BIOS_WARNING, "TrainRcvrEn: 
WARNING: Lane %d of receiver %d on channel %d failed training!\n", lane, 
Receiver, Channel);
-+
-+                                      /* Set error flags */
-+                                      pDCTstat->ErrStatus |= 1 << SB_NORCVREN;
-+                                      Errors |= 1 << SB_NORCVREN;
-+                                      pDCTstat->ErrCode = SC_FatalErr;
-+                                      pDCTstat->CSTrainFail |= 1 << Receiver;
-+                                      pDCTstat->DimmTrainFail |= 1 << 
(Receiver + Channel);
-+                              }
-                       }
- 
--                      RcvrEnDly += Pass1MemClkDly;
--                      if(RcvrEnDly > CTLRMaxDelay) {
--                              CTLRMaxDelay = RcvrEnDly;
--                      }
-+                      /* 2.8.9.9.2 (8)
-+                       * Flush the receiver FIFO
-+                       * Write one full cache line of non-0x55/0xaa data to 
one of the test addresses, then read it back to flush the FIFO
-+                       */
- 
--              }       /* while Receiver */
-+                      WriteLNTestPattern(TestAddr0 << 8, (uint8_t 
*)TestPattern2_D, 1);
-+                      mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0);
-+              }
-               MaxDelay_CH[Channel] = CTLRMaxDelay;
--      }       /* for Channel */
-+      }
- 
-       CTLRMaxDelay = MaxDelay_CH[0];
-       if (MaxDelay_CH[1] > CTLRMaxDelay)
-@@ -428,31 +612,31 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
- 
- #if DQS_TRAIN_DEBUG > 0
-       {
--              u8 Channel;
-+              u8 ChannelDTD;
-               printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
--              for(Channel = 0; Channel<2; Channel++) {
-+              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
-                       printk(BIOS_DEBUG, "Channel:%x: %x\n",
--                             Channel, pDCTstat->CH_MaxRdLat[Channel]);
-+                             ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]);
-               }
-       }
- #endif
- 
- #if DQS_TRAIN_DEBUG > 0
-       {
--              u8 val;
--              u8 Channel, Receiver;
-+              u16 valDTD;
-+              u8 ChannelDTD, ReceiverDTD;
-               u8 i;
--              u8 *p;
-+              u16 *p;
- 
-               printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
--              for(Channel = 0; Channel < 2; Channel++) {
--                      printk(BIOS_DEBUG, "Channel:%x\n", Channel);
--                      for(Receiver = 0; Receiver<8; Receiver+=2) {
--                              printk(BIOS_DEBUG, "\t\tReceiver:%x:", 
Receiver);
--                              p = 
pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
-+              for(ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
-+                      printk(BIOS_DEBUG, "Channel:%x\n", ChannelDTD);
-+                      for(ReceiverDTD = 0; ReceiverDTD<8; ReceiverDTD+=2) {
-+                              printk(BIOS_DEBUG, "\t\tReceiver:%x:", 
ReceiverDTD);
-+                              p = 
pDCTstat->CH_D_B_RCVRDLY[ChannelDTD][ReceiverDTD>>1];
-                               for (i=0;i<8; i++) {
--                                      val  = p[i];
--                                      printk(BIOS_DEBUG, "%x ", val);
-+                                      valDTD = p[i];
-+                                      printk(BIOS_DEBUG, " %03x", valDTD);
-                               }
-                               printk(BIOS_DEBUG, "\n");
-                       }
-@@ -475,15 +659,6 @@ u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 
dct)
-       }
- }
- 
--static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 
RcvrEnDly, u8 where, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 
Addl_Index, u8 Pass/*, u8 *p*/)
--{
--      /*
--       * Program final DqsRcvEnDly to additional index for DQS receiver
--       *  enabled delay
--       */
--      mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, where, Channel, Receiver, dev, 
index_reg, Addl_Index, Pass);
--}
--
- static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat)
- {
-       u8 ch_end, ch;
-@@ -514,17 +689,20 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc 
*pDCTstat)
-  * Function only used once so it was inlined.
-  */
- 
--void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly,
-+/* Set F2x[1, 0]9C_x[2B:10] DRAM DQS Receiver Enable Timing Control Registers
-+ * See BKDG Rev. 3.62 page 268 for more information
-+ */
-+void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly,
-                       u8 FinalValue, u8 Channel, u8 Receiver, u32 dev,
-                       u32 index_reg, u8 Addl_Index, u8 Pass)
- {
-       u32 index;
-       u8 i;
--      u8 *p;
-+      u16 *p;
-       u32 val;
- 
--      if(RcvrEnDly == 0xFE) {
--              /*set the boudary flag */
-+      if(RcvrEnDly == 0x1fe) {
-+              /*set the boundary flag */
-               pDCTstat->Status |= 1 << SB_DQSRcvLimit;
-       }
- 
-@@ -543,27 +721,57 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u8 RcvrEnDly,
-               val = Get_NB32_index_wait(dev, index_reg, index);
-               if(i & 1) {
-                       /* odd byte lane */
--                      val &= ~(0xFF << 16);
--                      val |= (RcvrEnDly << 16);
-+                      val &= ~(0x1ff << 16);
-+                      val |= ((RcvrEnDly & 0x1ff) << 16);
-               } else {
-                       /* even byte lane */
--                      val &= ~0xFF;
--                      val |= RcvrEnDly;
-+                      val &= ~0x1ff;
-+                      val |= (RcvrEnDly & 0x1ff);
-               }
-               Set_NB32_index_wait(dev, index_reg, index, val);
-       }
- 
- }
- 
--static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 
DQSRcvEnDly)
-+/* Calculate MaxRdLatency
-+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.5
-+ */
-+static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, 
u16 DQSRcvEnDly)
- {
-       u32 dev;
-       u32 reg;
--      u16 SubTotal;
-+      u32 SubTotal;
-       u32 index_reg;
-       u32 reg_off;
-       u32 val;
--      u32 valx;
-+
-+      uint8_t cpu_val_n;
-+      uint8_t cpu_val_p;
-+
-+      u16 freq_tab[] = {400, 533, 667, 800};
-+
-+      /* Set up processor-dependent values */
-+      if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
-+              /* Revision D and above */
-+              cpu_val_n = 4;
-+              cpu_val_p = 29;
-+      } else if (pDCTstat->LogicalCPUID & AMD_DR_Cx) {
-+              /* Revision C */
-+              uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+              if ((package_type == PT_L1)             /* Socket F (1207) */
-+                      || (package_type == PT_M2)      /* Socket AM3 */
-+                      || (package_type == PT_S1)) {   /* Socket S1g<x> */
-+                      cpu_val_n = 10;
-+                      cpu_val_p = 11;
-+              } else {
-+                      cpu_val_n = 4;
-+                      cpu_val_p = 29;
-+              }
-+      } else {
-+              /* Revision B and below */
-+              cpu_val_n = 10;
-+              cpu_val_p = 11;
-+      }
- 
-       if(pDCTstat->GangedMode)
-               Channel = 0;
-@@ -598,49 +806,32 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u8 DQ
-       val = Get_NB32(dev, 0x78 + reg_off);
-       SubTotal += 8 - (val & 0x0f);
- 
--      /* Convert bits 7-5 (also referred to as the course delay) of
-+      /* Convert bits 7-5 (also referred to as the coarse delay) of
-        * the current (or worst case) DQS receiver enable delay to
-        * 1/2 MEMCLKs units, rounding up, and add this to the sub-total.
-        */
--      SubTotal += DQSRcvEnDly >> 5;   /*BOZO-no rounding up */
-+      SubTotal += DQSRcvEnDly >> 5;   /* Retrieve gross delay portion of 
value */
- 
--      /* Add 5.5 to the sub-total. 5.5 represents part of the
-+      /* Add "P" to the sub-total. "P" represents part of the
-        * processor specific constant delay value in the DRAM
-        * clock domain.
-        */
-       SubTotal <<= 1;         /*scale 1/2 MemClk to 1/4 MemClk */
--      SubTotal += 11;         /*add 5.5 1/2MemClk */
-+      SubTotal += cpu_val_p;  /*add "P" 1/2MemClk */
-+      SubTotal >>= 1;         /*scale 1/4 MemClk back to 1/2 MemClk */
- 
-       /* Convert the sub-total (in 1/2 MEMCLKs) to northbridge
--       * clocks (NCLKs) as follows (assuming DDR400 and assuming
--       * that no P-state or link speed changes have occurred).
-+       * clocks (NCLKs)
-        */
-+      SubTotal *= 200 * ((Get_NB32(pDCTstat->dev_nbmisc, 0xd4) & 0x1f) + 4);
-+      SubTotal /= freq_tab[((Get_NB32(pDCTstat->dev_dct, 0x94 + reg_off) & 
0x7) - 3)];
-+      SubTotal = (SubTotal + (2 - 1)) / 2;    /* Round up */
- 
--      /* New formula:
--       * SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
--      val = Get_NB32(dev, 0x94 + reg_off);
--
--      /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
--      val &= 7;
--      if (val >= 3) {
--              val <<= 1;
--      } else
--              val += 3;
--      valx = val << 2;
--
--      val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4);
--      SubTotal *= ((val & 0x1f) + 4 ) * 3;
--
--      SubTotal /= valx;
--      if (SubTotal % valx) {  /* round up */
--              SubTotal++;
--      }
--
--      /* Add 5 NCLKs to the sub-total. 5 represents part of the
-+      /* Add "N" NCLKs to the sub-total. "N" represents part of the
-        * processor specific constant value in the northbridge
-        * clock domain.
-        */
--      SubTotal += 5;
-+      SubTotal += (cpu_val_n) / 2;
- 
-       pDCTstat->CH_MaxRdLat[Channel] = SubTotal;
-       if(pDCTstat->GangedMode) {
-@@ -659,143 +850,6 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u8 DQ
-       Set_NB32(dev, reg, val);
- }
- 
--static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat,
--                      u8 rcvrEnDly, u8 Channel,
--                      u8 receiver, u8 Pass)
--{
--      u8 i;
--      u8 mask_Saved, mask_Pass;
--      u8 *p;
--
--      /* calculate dimm offset
--       * not needed for CH_D_B_RCVRDLY array
--       */
--
--      /* cmp if there has new DqsRcvEnDly to be recorded */
--      mask_Pass = pDCTstat->DqsRcvEn_Pass;
--
--      if(Pass == SecondPass) {
--              mask_Pass = ~mask_Pass;
--      }
--
--      mask_Saved = pDCTstat->DqsRcvEn_Saved;
--      if(mask_Pass != mask_Saved) {
--
--              /* find desired stack offset according to channel/dimm/byte */
--              if(Pass == SecondPass) {
--                      /* FIXME: SecondPass is never used for Barcelona p = 
pDCTstat->CH_D_B_RCVRDLY_1[Channel][receiver>>1]; */
--                      p = 0; /* Keep the compiler happy. */
--              } else {
--                      mask_Saved &= mask_Pass;
--                      p = pDCTstat->CH_D_B_RCVRDLY[Channel][receiver>>1];
--              }
--              for(i=0; i < 8; i++) {
--                      /* cmp per byte lane */
--                      if(mask_Pass & (1 << i)) {
--                              if(!(mask_Saved & (1 << i))) {
--                                      /* save RcvEnDly to stack, according to
--                                      the related Dimm/byte lane */
--                                      p[i] = (u8)rcvrEnDly;
--                                      mask_Saved |= 1 << i;
--                              }
--                      }
--              }
--              pDCTstat->DqsRcvEn_Saved = mask_Saved;
--      }
--      return mct_SaveRcvEnDly_D_1Pass(pDCTstat, Pass);
--}
--
--static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat,
--                                      u32 addr, u8 channel,
--                                      u8 pattern, u8 Pass)
--{
--      /* Compare only the first beat of data.  Since target addrs are cache
--       * line aligned, the Channel parameter is used to determine which
--       * cache QW to compare.
--       */
--
--      u8 *test_buf;
--      u8 i;
--      u8 result;
--      u8 value;
--
--      if(Pass == FirstPass) {
--              if(pattern==1) {
--                      test_buf = (u8 *)TestPattern1_D;
--              } else {
--                      test_buf = (u8 *)TestPattern0_D;
--              }
--      } else {                /* Second Pass */
--              test_buf = (u8 *)TestPattern2_D;
--      }
--
--      SetUpperFSbase(addr);
--      addr <<= 8;
--
--      if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) {
--              addr += 8;      /* second channel */
--              test_buf += 8;
--      }
--
--      print_debug_dqs_pair("\t\t\t\t\t\t  test_buf = ", (u32)test_buf, "  |  
addr_lo = ", addr,  4);
--      for (i=0; i<8; i++, addr ++) {
--              value = read32_fs(addr);
--              print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", test_buf[i], "  |  ", 
value, 4);
--
--              if (value == test_buf[i]) {
--                      pDCTstat->DqsRcvEn_Pass |= (1<<i);
--              } else {
--                      pDCTstat->DqsRcvEn_Pass &= ~(1<<i);
--              }
--      }
--
--      result = DQS_FAIL;
--
--      if (Pass == FirstPass) {
--              /* if first pass, at least one byte lane pass
--               * ,then DQS_PASS=1 and will set to related reg.
--               */
--              if(pDCTstat->DqsRcvEn_Pass != 0) {
--                      result = DQS_PASS;
--              } else {
--                      result = DQS_FAIL;
--              }
--
--      } else {
--              /* if second pass, at least one byte lane fail
--               * ,then DQS_FAIL=1 and will set to related reg.
--               */
--              if(pDCTstat->DqsRcvEn_Pass != 0xFF) {
--                      result = DQS_FAIL;
--              } else {
--                      result = DQS_PASS;
--              }
--      }
--
--      /* if second pass, we can't find the fail until FFh,
--       * then let it fail to save the final delay
--       */
--      if((Pass == SecondPass) && (pDCTstat->Status & (1 << SB_DQSRcvLimit))) {
--              result = DQS_FAIL;
--              pDCTstat->DqsRcvEn_Pass = 0;
--      }
--
--      /* second pass needs to be inverted
--       * FIXME? this could be inverted in the above code to start with...
--       */
--      if(Pass == SecondPass) {
--              if (result == DQS_PASS) {
--                      result = DQS_FAIL;
--              } else if (result == DQS_FAIL) { /* FIXME: doesn't need to be 
else if */
--                      result = DQS_PASS;
--              }
--      }
--
--
--      return result;
--}
--
- static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat)
- {
-@@ -854,7 +908,7 @@ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 
Channel)
-       u32 index_reg;
-       u32 index;
-       u8 ChipSel;
--      u8 *p;
-+      u16 *p;
-       u32 val;
- 
-       dev = pDCTstat->dev_dct;
-@@ -884,7 +938,7 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
- 
-       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
-               if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, ChipSel)) 
{
--                      u8 *p;
-+                      u16 *p;
-                       p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
- 
-                       /* DQS Delay Value of Data Bytelane
-@@ -920,6 +974,10 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
-       SetEccDQSRcvrEn_D(pDCTstat, Channel);
- }
- 
-+/* 2.8.9.9.4
-+ * ECC Byte Lane Training
-+ * DQS Receiver Enable Delay
-+ */
- void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstatA)
- {
-@@ -1017,7 +1075,9 @@ static void fenceDynTraining_D(struct MCTStatStruc 
*pMCTstat,
-               avRecValue -= 3;
-       else
-       */
--      if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
-+      if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
-+              avRecValue -= 8;
-+      else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
-               avRecValue -= 8;
-       else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
-               avRecValue -= 8;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
-index c009756..f01e011 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -36,17 +37,12 @@ u32 SetupDqsPattern_1PassB(u8 pass)
-       return (u32) TestPattern0_D;
- }
- 
--u8  mct_Get_Start_RcvrEnDly_1Pass(u8 pass)
--{
--      return 0;
--}
--
--static u8 mct_Average_RcvrEnDly_1Pass(struct DCTStatStruc *pDCTstat, u8 
Channel, u8 Receiver,
-+static u16 mct_Average_RcvrEnDly_1Pass(struct DCTStatStruc *pDCTstat, u8 
Channel, u8 Receiver,
-                                       u8 Pass)
- {
--      u8 i, MaxValue;
--      u8 *p;
--      u8 val;
-+      u16 i, MaxValue;
-+      u16 *p;
-+      u16 val;
- 
-       MaxValue = 0;
-       p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1];
-@@ -76,8 +72,8 @@ u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, 
u8 pass)
-       return ret;
- }
- 
--u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
--                              u8 RcvrEnDly, u8 RcvrEnDlyLimit,
-+u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
-+                              u16 RcvrEnDly, u16 RcvrEnDlyLimit,
-                               u8 Channel, u8 Receiver, u8 Pass)
- 
- {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
-index b01889d..796febc 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -74,15 +75,15 @@ u8 mct_Get_Start_RcvrEnDly_Pass(struct DCTStatStruc 
*pDCTstat,
-       return RcvrEnDly;
- }
- 
--u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
--                              u8 RcvrEnDly, u8 RcvrEnDlyLimit,
-+u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
-+                              u16 RcvrEnDly, u16 RcvrEnDlyLimit,
-                               u8 Channel, u8 Receiver, u8 Pass)
- {
-       u8 i;
--      u8 *p;
--      u8 *p_1;
--      u8 val;
--      u8 val_1;
-+      u16 *p;
-+      u16 *p_1;
-+      u16 val;
-+      u16 val_1;
-       u8 valid = 1;
-       u8 bn;
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
-index ea5c8c7..920f514 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -191,10 +192,10 @@ static void maxRdLatencyTrain_D(struct MCTStatStruc 
*pMCTstat,
- 
- #if DQS_TRAIN_DEBUG > 0
-       {
--              u8 Channel;
-+              u8 ChannelDTD;
-               printk(BIOS_DEBUG, "maxRdLatencyTrain: CH_MaxRdLat:\n");
--              for(Channel = 0; Channel<2; Channel++) {
--                      printk(BIOS_DEBUG, "Channel: %02x: %02x\n", Channel, 
pDCTstat->CH_MaxRdLat[Channel]);
-+              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
-+                      printk(BIOS_DEBUG, "Channel: %02x: %02x\n", ChannelDTD, 
pDCTstat->CH_MaxRdLat[ChannelDTD]);
-               }
-       }
- #endif
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-index cdeae49..1c3e322 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -58,9 +59,9 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
-       pDCTstat->C_DCTPtr[dct]->LogicalCPUID = pDCTstat->LogicalCPUID;
- 
-       for (dimm = 0; dimm < MAX_DIMMS; dimm++) {
--              if (DimmValid & (1 << dimm))
-+              if (DimmValid & (1 << (dimm << 1)))
-                       pDCTstat->C_DCTPtr[dct]->DimmPresent[dimm] = 1;
--              if (Dimmx8Present & (1 << dimm))
-+              if (Dimmx8Present & (1 << (dimm << 1)))
-                       pDCTstat->C_DCTPtr[dct]->DimmX8Present[dimm] = 1;
-       }
- 
-@@ -88,9 +89,9 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
-               u8  DimmRanks;
-               if (DimmValid & (1 << (dimm << 1))) {
-                       DimmRanks = 1;
--                      if (pDCTstat->DimmDRPresent & (1 << (dimm+dct)))
-+                      if (pDCTstat->DimmDRPresent & (1 << ((dimm << 1) + 
dct)))
-                               DimmRanks = 2;
--                      else if (pDCTstat->DimmQRPresent & (1 << (dimm+dct)))
-+                      else if (pDCTstat->DimmQRPresent & (1 << ((dimm << 1) + 
dct)))
-                               DimmRanks = 4;
-               } else
-                       DimmRanks = 0;
-@@ -249,35 +250,6 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
-       }
- }
- 
--/* Multiply the previously saved delay values in Pass 1, step #5 by
--   (target frequency)/400 to find the gross and fine delay initialization
--   values at the target frequency.
-- */
--void MultiplyDelay(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, u8 dct)
--{
--      u16 index;
--      u8 Multiplier;
--      u8 gross, fine;
--      u16 total;
--
--      Multiplier = pDCTstat->TargetFreq;
--
--      for (index=0; index < MAX_BYTE_LANES*MAX_LDIMMS; index ++) {
--              gross = pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index];
--              fine = pDCTstat->C_DCTPtr[dct]->WLFineDelay[index];
--
--              total = gross << 5 | fine;
--              total *= Multiplier;
--              if (total % 3)
--                      total = total / 3 + 1;
--              else
--                      total = total / 3;
--              pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index] = (total & 0xFF) 
>> 5;
--              pDCTstat->C_DCTPtr[dct]->WLFineDelay[index] = total & 0x1F;
--      }
--}
--
- /*
-  * the DRAM controller to bring the DRAMs out of self refresh mode.
-  */
-@@ -352,9 +324,9 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
- 
-               if (!DCT1Present)
-                       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
--              else if (pDCTstat->GangedMode) {
-+              else if (pDCTstat->GangedMode)
-                       pDCTstat->CSPresent = 0;
--              } else
-+              else
-                       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[1];
- 
-               FreqChgCtrlWrd(pMCTstat, pDCTstat);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index 212a348..c76476b 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -235,6 +236,65 @@ u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
-       return MRSValue;
- }
- 
-+static uint16_t unbuffered_dimm_nominal_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank)
-+{
-+      uint16_t term;
-+
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      if (number_of_dimms == 1) {
-+              if (MaxDimmsInstallable < 3) {
-+                      term = 0x04;    /* Rtt_Nom=RZQ/4=60 Ohm */
-+              } else {
-+                      if (rank_count == 1) {
-+                              term = 0x04;    /* Rtt_Nom=RZQ/4=60 Ohm */
-+                      } else {
-+                              if (rank == 0)
-+                                      term = 0x04;    /* Rtt_Nom=RZQ/4=60 Ohm 
*/
-+                              else
-+                                      term = 0x00;    /* Rtt_Nom=OFF */
-+                      }
-+              }
-+      } else {
-+              if (frequency_index < 5)
-+                      term = 0x0044;  /* Rtt_Nom=RZQ/6=40 Ohm */
-+              else
-+                      term = 0x0204;  /* Rtt_Nom=RZQ/8=30 Ohm */
-+      }
-+
-+      return term;
-+}
-+
-+static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank)
-+{
-+      uint16_t term;
-+
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      if (number_of_dimms == 1) {
-+              if (MaxDimmsInstallable < 3) {
-+                      term = 0x00;    /* Rtt_WR=off */
-+              } else {
-+                      if (rank_count == 1)
-+                              term = 0x00;    /* Rtt_WR=off */
-+                      else
-+                              term = 0x200;   /* Rtt_WR=RZQ/4=60 Ohm */
-+              }
-+      } else {
-+              term = 0x400;   /* Rtt_WR=RZQ/2=120 Ohm */
-+      }
-+
-+      return term;
-+}
-+
- 
/*-----------------------------------------------------------------------------
-  *  void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *DCTData, u8 Dimm, 
BOOL WL)
-  *
-@@ -295,48 +355,23 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-                       tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, 
wl, MemClkFreq, rank);
-               } else {
--                      if (wl)
--                      {
--                              if (pDCTData->MaxDimmsInstalled == 1)
--                              {
--                                      if ((pDCTData->DimmRanks[dimm] == 2) && 
(rank == 0))
--                                      {
--                                              tempW1 = 0x00;  /* Rtt_Nom=OFF 
*/
--                                      }
-+                      if (wl) {
-+                              if (rank == 0) {
-+                                      /* Get Rtt_WR for the current DIMM and 
rank */
-+                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+
-+                                      /* Convert dynamic termination code to 
corresponding nominal termination code */
-+                                      if (dynamic_term == 0x200)
-+                                              tempW1 = 0x04;
-+                                      else if (dynamic_term == 0x400)
-+                                              tempW1 = 0x40;
-                                       else
--                                      {
--                                              tempW1 = 0x04;  /* 
Rtt_Nom=RZQ/4=60 Ohm */
--                                      }
--                              }
--                              else    /* 2 Dimms or more per channel */
--                              {
--                                      if ((pDCTData->DimmRanks[dimm] == 2) && 
(rank == 1))
--                                      {
--                                              tempW1 = 0x00;  /* Rtt_Nom=OFF 
*/
--                                      }
--                                      else
--                                      {
--                                              if (MemClkFreq == 6) {
--                                                      tempW1 = 0x04;  /* 
Rtt_Nom=RZQ/4=60 Ohm */
--                                              } else {
--                                                      tempW1 = 0x40;/* 
Rtt_Nom=RZQ/2=120 Ohm */
--                                              }
--                                      }
--                              }
--                      }
--                      else {  /* 1 or 4 Dimms per channel */
--                              if ((pDCTData->MaxDimmsInstalled == 1) || 
(pDCTData->MaxDimmsInstalled == 4))
--                              {
--                                      tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm 
*/
--                              }
--                              else    /* 2 or 3 Dimms per channel */
--                              {
--                                      if (MemClkFreq < 5) {
--                                              tempW1 = 0x0044;        /* 
Rtt_Nom=RZQ/6=40 Ohm */
--                                      } else {
--                                              tempW1 = 0x0204;        /* 
Rtt_Nom=RZQ/8=30 Ohm */
--                                      }
-+                                              tempW1 = 0x0;
-+                              } else {
-+                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-                               }
-+                      } else {
-+                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-                       }
-               }
-               tempW=tempW|tempW1;
-@@ -353,20 +388,22 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-                       else
-                       {
-                               /* Disable the output drivers of all other 
ranks for
--                               * the target DIMM. */
-+                               * the target DIMM.
-+                               */
-                               tempW = bitTestSet(tempW1, Qoff);
-                       }
-               }
--              /* program MrsAddress[5,1]=output driver impedance control 
(DIC):
--               * based on F2x[1,0]84[DrvImpCtrl] */
-+              /* Program MrsAddress[5,1]=output driver impedance control 
(DIC):
-+               * based on F2x[1,0]84[DrvImpCtrl]
-+               */
-               tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
-                               FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, 
DrvImpCtrlEnd);
--              if (bitTest(tempW1,1))
--              {tempW = bitTestSet(tempW, 5);}
--              if (bitTest(tempW1,0))
--              {tempW = bitTestSet(tempW, 1);}
-+              if (bitTest(tempW1, 1))
-+                      tempW = bitTestSet(tempW, 5);
-+              if (bitTest(tempW1, 0))
-+                      tempW = bitTestSet(tempW, 1);
- 
--              tempW = swapAddrBits_wl(pDCTData,tempW);
-+              tempW = swapAddrBits_wl(pDCTData, tempW);
- 
-               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
-@@ -404,29 +441,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-               if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && 
(pDCTData->Status[DCT_STATUS_REGISTERED]))
-                       tempW+=0x8;
-               /* determine Rtt_WR for WL & Normal mode */
--              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+              if (pDCTData->Status[DCT_STATUS_REGISTERED])
-                       tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, 
MemClkFreq, rank);
--              } else {
--                      if (wl)
--                      {
--                              tempW1 = 0x00;  /* Rtt_WR=off */
--                      }
--                      else
--                      {
--                              if (pDCTData->MaxDimmsInstalled == 1)
--                              {
--                                      tempW1 = 0x00;  /* Rtt_WR=off */
--                              }
--                              else
--                              {
--                                      if (MemClkFreq == 6) {
--                                              tempW1 = 0x200; /* 
Rtt_WR=RZQ/4=60 Ohm */
--                                      } else {
--                                              tempW1 = 0x400; /* Rtt_WR=RZQ/2 
*/
--                                      }
--                              }
--                      }
--              }
-+              else
-+                      tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
-               tempW=tempW|tempW1;
-               tempW = swapAddrBits_wl(pDCTData,tempW);
-               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
-@@ -483,38 +501,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-                                       }
- 
-                                       /* determine Rtt_Nom for WL & Normal 
mode */
--                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
-                                               tempW1 = 
RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
--                                      } else {
--                                              if (wl)
--                                              {
--                                                      if 
((pDCTData->DimmRanks[currDimm] == 2) && (rank == 1))
--                                                      {
--                                                              tempW1 = 0x00;  
/* Rtt_Nom=OFF */
--                                                      }
--                                                      else
--                                                      {
--                                                              if (MemClkFreq 
< 5) {
--                                                                      tempW1 
= 0x0044;/* Rtt_Nom=RZQ/6=40 Ohm */
--                                                              } else {
--                                                                      tempW1 
= 0x0204;/* Rtt_Nom=RZQ/8=30 Ohm */
--                                                              }
--                                                      }
--                                              }
--                                              else {  /* 1 or 4 Dimms per 
channel */
--                                                      if 
(pDCTData->MaxDimmsInstalled == 4)
--                                                      {
--                                                              tempW1 = 0x04;  
/* Rtt_Nom=RZQ/4=60 Ohm */
--                                                      }
--                                                      else {  /* 2 or 3 Dimms 
per channel */
--                                                              if (MemClkFreq 
< 5) {
--                                                                      tempW1 
= 0x0044;        /* Rtt_Nom=RZQ/6=40 Ohm */
--                                                              } else {
--                                                                      tempW1 
= 0x0204;        /* Rtt_Nom=RZQ/8=30 Ohm */
--                                                              }
--                                                      }
--                                              }
--                                      }
-+                                      else
-+                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-                                       tempW=tempW|tempW1;
-                                       /* program MrsAddress[5,1]=output 
driver impedance control (DIC):
-                                        * based on F2x[1,0]84[DrvImpCtrl] */
-@@ -560,22 +550,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-                                       if ((pDCTData->LogicalCPUID & 
AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
-                                               tempW+=0x8;
-                                       /* determine Rtt_WR for WL & Normal 
mode */
--                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
-                                               tempW1 = RttWrRegDimm(pMCTData, 
pDCTData, currDimm, wl, MemClkFreq, rank);
--                                      } else {
--                                              if (wl)
--                                              {
--                                                      tempW1 = 0x00;  /* 
Rtt_WR=off */
--                                              }
--                                              else
--                                              {
--                                                      if (MemClkFreq == 6) {
--                                                              tempW1 = 0x200; 
/* Rtt_WR=RZQ/4=60 Ohm */
--                                                      } else {
--                                                              tempW1 = 0x400; 
/* Rtt_WR=RZQ/2 */
--                                                      }
--                                              }
--                                      }
-+                                      else
-+                                              tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-                                       tempW=tempW|tempW1;
-                                       tempW = swapAddrBits_wl(pDCTData,tempW);
-                                       set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
-@@ -646,9 +624,14 @@ void programODT(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm)
-  */
- void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
- {
--      u8 ByteLane, Seed_Gross, Seed_Fine;
-+      u8 ByteLane, Seed_Gross, Seed_Fine, MemClkFreq;
-       u32 Value, Addr;
-       u16 Addl_Data_Offset, Addl_Data_Port;
-+      u16 freq_tab[] = {400, 533, 667, 800};
-+
-+      /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
-+      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
-+                              FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
- 
-       /* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for 
the
-        * current memory subsystem configuration.
-@@ -656,12 +639,13 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
-       programODT(pMCTData, pDCTData, dimm);
- 
-       /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
--      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
-+      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) {
-               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, 
WrLvOdtEn, (u32)1);
-+      }
-       else
-       {
--              /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 
0 for Rev.B*/
-+              /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 
0 for Rev.B */
-               if (pDCTData->DctTrain)
-               {
-                       Addl_Data_Offset=0x198;
-@@ -687,7 +671,6 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, 
u8 dimm, u8 pass)
- 
-       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
-       pMCTData->AgesaDelay(10);
--      ByteLane = 0;
-       if (pass == 1)
-       {
-               if (pDCTData->Status[DCT_STATUS_REGISTERED])
-@@ -705,10 +688,17 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
-               }
-               else
-               {
--                      Seed_Gross = 0x00;
--                      Seed_Fine = 0x1A;
-+                      if (MemClkFreq == 6) {
-+                              /* DDR-800 */
-+                              Seed_Gross = 0x00;
-+                              Seed_Fine = 0x1a;
-+                      } else {
-+                              /* Use settings for DDR-400 (interpolated from 
BKDG) */
-+                              Seed_Gross = 0x00;
-+                              Seed_Fine = 0x0d;
-+                      }
-               }
--              while(ByteLane < MAX_BYTE_LANES)
-+              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
-               {
-                       /* Program an initialization value to registers F2x[1, 
0]9C_x[51:50] and
-                        * F2x[1, 0]9C_x52 to set the gross and fine delay for 
all the byte lane fields
-@@ -720,35 +710,32 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
-                        */
-                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
-                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
--                      ByteLane++;
-               }
--      } else if (pDCTData->Status[DCT_STATUS_REGISTERED]) {           /* For 
Pass 2 */
-+      } else {                /* Pass 2 */
-               /* From BKDG, Write Leveling Seed Value. */
--              /* TODO: The unbuffered DIMMs are unstable on the code below. 
So temporarily it is
--               * only for registered DIMMs. */
-               u32 RegisterDelay, SeedTotal;
--              u8 MemClkFreq;
--              u16 freq_tab[] = {400, 533, 667, 800};
--              while(ByteLane < MAX_BYTE_LANES)
-+              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
-               {
--                      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
--                                            FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
-                       if (pDCTData->Status[DCT_STATUS_REGISTERED])
-                               RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) 
== 0) ? 0x20 : 0x30; */
-                       else
-                               RegisterDelay = 0;
--                      SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1F) |
--                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5;
-+                      SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
-+                              
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
-                       /* SeedTotalPreScaling = (the total delay value in 
F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
-                          training) - RegisterDelay. */
--                      /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 
800MHz */
--                      SeedTotal = (u16) (RegisterDelay + ((((u32) SeedTotal - 
RegisterDelay) *
--                                                           
freq_tab[MemClkFreq-3]) / 400));
--                      Seed_Gross = (SeedTotal & 0x20) != 0 ? 1 : 2;
--                      Seed_Fine = SeedTotal & 0x1F;
-+                      SeedTotal = (uint16_t) (RegisterDelay + ((((uint64_t) 
SeedTotal - RegisterDelay) *
-+                                                              
freq_tab[MemClkFreq-3] * 100) / (freq_tab[0] * 100)));
-+                      Seed_Gross = SeedTotal / 32;
-+                      Seed_Fine = SeedTotal & 0x1f;
-+                      if (Seed_Gross == 0)
-+                              Seed_Gross = 0;
-+                      else if (Seed_Gross & 0x1)
-+                              Seed_Gross = 1;
-+                      else
-+                              Seed_Gross = 2;
-                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
-                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
--                      ByteLane ++;
-               }
-       }
- 
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index ea32893..6465e13 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -49,7 +49,7 @@ static const uint16_t ddr3_limits[4] = {800, 666, 533, 400};
- static u16 mctGet_NVbits(u8 index)
- {
-       u16 val = 0;
--      int nvram;
-+      int nvram = 0;
- 
-       switch (index) {
-       case NV_PACK_TYPE:
-@@ -59,6 +59,10 @@ static u16 mctGet_NVbits(u8 index)
-               val = 1;
- #elif CONFIG_CPU_SOCKET_TYPE == 0x13  /* ASB2 */
-               val = 4;
-+#elif CONFIG_CPU_SOCKET_TYPE == 0x14  /* C32 */
-+              val = 5;
-+#elif CONFIG_CPU_SOCKET_TYPE == 0x15  /* G34 */
-+              val = 3;
- //#elif SYSTEM_TYPE == MOBILE
- //            val = 2;
- #endif
-@@ -297,6 +301,8 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
-       /* Determine the number of installed DIMMs */
-       int ch1_count = 0;
-       int ch2_count = 0;
-+      uint8_t ch1_registered = 0;
-+      uint8_t ch2_registered = 0;
-       int i;
-       for (i = 0; i < 15; i = i + 2) {
-               if (pDCTstat->DIMMValid & (1 << i))
-@@ -304,6 +310,12 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
-               if (pDCTstat->DIMMValid & (1 << (i + 1)))
-                       ch2_count++;
-       }
-+      for (i = 0; i < MAX_DIMMS_SUPPORTED; i = i + 2) {
-+              if (pDCTstat->DimmRegistered[i])
-+                      ch1_registered = 1;
-+              if (pDCTstat->DimmRegistered[i + 1])
-+                      ch2_registered = 1;
-+      }
-       if (IS_ENABLED(CONFIG_DEBUG_RAM_SETUP)) {
-               printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 1: %d DIMM(s) 
detected\n", ch1_count);
-               printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 2: %d DIMM(s) 
detected\n", ch2_count);
-@@ -413,101 +425,6 @@ static void mctHookAfterDramInit(void)
- }
- 
- #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
--static void coreDelay(u32 microseconds)
--{
--      msr_t now;
--      msr_t end;
--      u32 cycles;
--
--      /* delay ~40us
--         This seems like a hack to me...
--         It would be nice to have a central delay function. */
--
--      cycles = (microseconds * 100) << 3;  /* x8 (number of 1.25ns ticks) */
--
--        if (!(rdmsr(HWCR).lo & TSC_FREQ_SEL_MASK)) {
--            msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
--            if (!(rdmsr(0xC0010064+pstate_msr.lo).lo & NB_DID_M_ON)) {
--            cycles = cycles <<1; // half freq, double cycles
--          }
--      } // else should we keep p0 freq at the time of setting 
TSC_FREQ_SEL_MASK somewhere and check it here ?
--
--      now = rdmsr(TSC_MSR);
--        // avoid overflow when called near 2^32 ticks ~ 5.3 s boundaries
--      if (0xffffffff - cycles >= now.lo ) {
--        end.hi =  now.hi;
--          end.lo = now.lo + cycles;
--      } else {
--          end.hi = now.hi +1; //
--          end.lo = cycles - (1+(0xffffffff - now.lo));
--      }
--      do {
--          now = rdmsr(TSC_MSR);
--        } while ((now.hi < end.hi) || ((now.hi == end.hi) && (now.lo < 
end.lo)));
--}
--
--/* Erratum 350 */
--static void vErrata350(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat)
--{
--      u8 u8Channel;
--      u8 u8Receiver;
--      u32 u32Addr;
--      u8 u8Valid;
--      u32 u32DctDev;
--
--      // 1. dummy read for each installed DIMM */
--      for (u8Channel = 0; u8Channel < 2; u8Channel++) {
--              // This will be 0 for vaild DIMMS, eles 8
--              u8Receiver = mct_InitReceiver_D(pDCTstat, u8Channel);
--
--              for (; u8Receiver < 8; u8Receiver += 2) {
--                      u32Addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, 
u8Channel, u8Receiver, &u8Valid);
--
--                      if(!u8Valid) {  /* Address not supported on current CS 
*/
--                              print_t("vErrata350: Address not supported on 
current CS\n");
--                              continue;
--                      }
--                      print_t("vErrata350: dummy read \n");
--                      read32_fs(u32Addr);
--              }
--      }
--
--      print_t("vErrata350: step 2a\n");
--
--      /* 2. Write 0000_8000h to register F2x[1, 0]9C_xD080F0C. */
--      u32DctDev = pDCTstat->dev_dct;
--      Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00008000);
--      /*                                                ^--- value
--                                              ^---F2x[1, 0]9C_x0D080F0C, No 
description in BKDG.
--                                       ^----F2x[1, 0]98 DRAM Controller 
Additional Data Offset Register */
--
--      if(!pDCTstat->GangedMode) {
--              print_t("vErrata350: step 2b\n");
--              Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00008000);
--              /*                                                ^--- value
--                                                      ^---F2x[1, 
0]9C_x0D080F0C, No description in BKDG
--                                              ^----F2x[1, 0]98 DRAM 
Controller Additional Data Offset Register */
--      }
--
--      print_t("vErrata350: step 3\n");
--      /* 3. Wait at least 300 nanoseconds. */
--      coreDelay(1);
--
--      print_t("vErrata350: step 4\n");
--      /* 4. Write 0000_0000h to register F2x[1, 0]9C_xD080F0C. */
--      Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00000000);
--
--      if(!pDCTstat->GangedMode) {
--              print_t("vErrata350: step 4b\n");
--              Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00000000);
--      }
--
--      print_t("vErrata350: step 5\n");
--      /* 5. Wait at least 2 microseconds. */
--      coreDelay(2);
--
--}
--
- static void vErratum372(struct DCTStatStruc *pDCTstat)
- {
-         msr_t msr = rdmsr(NB_CFG_MSR);
-@@ -546,8 +463,7 @@ static void mctHookBeforeAnyTraining(struct MCTStatStruc 
*pMCTstat, struct DCTSt
- {
- #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
-   /* FIXME :  as of 25.6.2010 errata 350 and 372 should apply to  
((RB|BL|DA)-C[23])|(HY-D[01])|(PH-E0) but I don't find constants for all of 
them */
--      if (pDCTstatA->LogicalCPUID & AMD_DRBH_Cx) {
--              vErrata350(pMCTstat, pDCTstatA);
-+      if (pDCTstatA->LogicalCPUID & (AMD_DRBH_Cx | AMD_DR_Dx)) {
-               vErratum372(pDCTstatA);
-               vErratum414(pDCTstatA);
-       }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0008-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
 
b/resources/libreboot/patch/kgpe-d16/0008-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
new file mode 100644
index 0000000..3b3da91
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0008-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch
@@ -0,0 +1,621 @@
+From ccebca23a1e58cc82d9e2d48642ee604ebbcd3b9 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 17:46:38 -0500
+Subject: [PATCH 008/143] southbridge/amd/sr5650: Fix boot failure on ASUS
+ KGPE-D16
+
+Change-Id: Ia13ba58118a826e830a4dc6e2378b76110fcabad
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sr5650/acpi/sr5650.asl |  388 ++++++++++++++++++++++++++++
+ src/southbridge/amd/sr5650/early_setup.c   |    7 +-
+ src/southbridge/amd/sr5650/ht.c            |    3 +-
+ src/southbridge/amd/sr5650/pcie.c          |   37 ++-
+ src/southbridge/amd/sr5650/sr5650.c        |   51 ++--
+ 5 files changed, 456 insertions(+), 30 deletions(-)
+ create mode 100644 src/southbridge/amd/sr5650/acpi/sr5650.asl
+
+diff --git a/src/southbridge/amd/sr5650/acpi/sr5650.asl 
b/src/southbridge/amd/sr5650/acpi/sr5650.asl
+new file mode 100644
+index 0000000..a6ab114
+--- /dev/null
++++ b/src/southbridge/amd/sr5650/acpi/sr5650.asl
+@@ -0,0 +1,388 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2009 Advanced Micro Devices, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++Scope(\) {
++      Name(PCBA, 0xE0000000)  /* Base address of PCIe config space */
++      Name(HPBA, 0xFED00000)  /* Base address of HPET table */
++
++      /* PIC IRQ mapping registers, C00h-C01h */
++      OperationRegion(PRQM, SystemIO, 0x00000C00, 0x00000002)
++              Field(PRQM, ByteAcc, NoLock, Preserve) {
++              PRQI, 0x00000008,
++              PRQD, 0x00000008,  /* Offset: 1h */
++      }
++      IndexField(PRQI, PRQD, ByteAcc, NoLock, Preserve) {
++              PINA, 0x00000008,       /* Index 0 */
++              PINB, 0x00000008,       /* Index 1 */
++              PINC, 0x00000008,       /* Index 2 */
++              PIND, 0x00000008,       /* Index 3 */
++              AINT, 0x00000008,       /* Index 4 */
++              SINT, 0x00000008,       /* Index 5 */
++                  , 0x00000008,       /* Index 6 */
++              AAUD, 0x00000008,       /* Index 7 */
++              AMOD, 0x00000008,       /* Index 8 */
++              PINE, 0x00000008,       /* Index 9 */
++              PINF, 0x00000008,       /* Index A */
++              PING, 0x00000008,       /* Index B */
++              PINH, 0x00000008,       /* Index C */
++      }
++
++      /* PCI Error control register */
++      OperationRegion(PERC, SystemIO, 0x00000C14, 0x00000001)
++              Field(PERC, ByteAcc, NoLock, Preserve) {
++              SENS, 0x00000001,
++              PENS, 0x00000001,
++              SENE, 0x00000001,
++              PENE, 0x00000001,
++      }
++
++      Scope(\_SB) {
++              /* PCIe Configuration Space for 16 busses */
++              OperationRegion(PCFG, SystemMemory, PCBA, 0x01000000) /* Each 
bus consumes 1MB */
++                      Field(PCFG, ByteAcc, NoLock, Preserve) {
++                      /* Byte offsets are computed using the following 
technique:
++                       * ((bus number + 1) * ((device number * 8) * 4096)) + 
register offset
++                       * The 8 comes from 8 functions per device, and 4096 
bytes per function config space
++                      */
++                      Offset(0x00088024),     /* Byte offset to SATA register 
24h - Bus 0, Device 17, Function 0 */
++                      STB5, 32,
++                      Offset(0x00098042),     /* Byte offset to OHCI0 
register 42h - Bus 0, Device 19, Function 0 */
++                      PT0D, 1,
++                      PT1D, 1,
++                      PT2D, 1,
++                      PT3D, 1,
++                      PT4D, 1,
++                      PT5D, 1,
++                      PT6D, 1,
++                      PT7D, 1,
++                      PT8D, 1,
++                      PT9D, 1,
++                      Offset(0x000A0004),     /* Byte offset to SMBUS 
register 4h - Bus 0, Device 20, Function 0 */
++                      SBIE, 1,
++                      SBME, 1,
++                      Offset(0x000A0008),     /* Byte offset to SMBUS 
register 8h - Bus 0, Device 20, Function 0 */
++                      SBRI, 8,
++                      Offset(0x000A0014),     /* Byte offset to SMBUS 
register 14h - Bus 0, Device 20, Function 0 */
++                      SBB1, 32,
++                      Offset(0x000A0078),     /* Byte offset to SMBUS 
register 78h - Bus 0, Device 20, Function 0 */
++                      ,14,
++                      P92E, 1,                /* Port92 decode enable */
++              }
++
++              OperationRegion(SB5, SystemMemory, STB5, 0x1000)
++                      Field(SB5, AnyAcc, NoLock, Preserve){
++                      /* Port 0 */
++                      Offset(0x120),          /* Port 0 Task file status */
++                      P0ER, 1,
++                      , 2,
++                      P0DQ, 1,
++                      , 3,
++                      P0BY, 1,
++                      Offset(0x128),          /* Port 0 Serial ATA status */
++                      P0DD, 4,
++                      , 4,
++                      P0IS, 4,
++                      Offset(0x12C),          /* Port 0 Serial ATA control */
++                      P0DI, 4,
++                      Offset(0x130),          /* Port 0 Serial ATA error */
++                      , 16,
++                      P0PR, 1,
++
++                      /* Port 1 */
++                      offset(0x1A0),          /* Port 1 Task file status */
++                      P1ER, 1,
++                      , 2,
++                      P1DQ, 1,
++                      , 3,
++                      P1BY, 1,
++                      Offset(0x1A8),          /* Port 1 Serial ATA status */
++                      P1DD, 4,
++                      , 4,
++                      P1IS, 4,
++                      Offset(0x1AC),          /* Port 1 Serial ATA control */
++                      P1DI, 4,
++                      Offset(0x1B0),          /* Port 1 Serial ATA error */
++                      , 16,
++                      P1PR, 1,
++
++                      /* Port 2 */
++                      Offset(0x220),          /* Port 2 Task file status */
++                      P2ER, 1,
++                      , 2,
++                      P2DQ, 1,
++                      , 3,
++                      P2BY, 1,
++                      Offset(0x228),          /* Port 2 Serial ATA status */
++                      P2DD, 4,
++                      , 4,
++                      P2IS, 4,
++                      Offset(0x22C),          /* Port 2 Serial ATA control */
++                      P2DI, 4,
++                      Offset(0x230),          /* Port 2 Serial ATA error */
++                      , 16,
++                      P2PR, 1,
++
++                      /* Port 3 */
++                      Offset(0x2A0),          /* Port 3 Task file status */
++                      P3ER, 1,
++                      , 2,
++                      P3DQ, 1,
++                      , 3,
++                      P3BY, 1,
++                      Offset(0x2A8),          /* Port 3 Serial ATA status */
++                      P3DD, 4,
++                      , 4,
++                      P3IS, 4,
++                      Offset(0x2AC),          /* Port 3 Serial ATA control */
++                      P3DI, 4,
++                      Offset(0x2B0),          /* Port 3 Serial ATA error */
++                      , 16,
++                      P3PR, 1,
++              }
++
++              Method(CIRQ, 0x00, NotSerialized){
++                      Store(0, PINA)
++                      Store(0, PINB)
++                      Store(0, PINC)
++                      Store(0, PIND)
++                      Store(0, PINE)
++                      Store(0, PINF)
++                      Store(0, PING)
++                      Store(0, PINH)
++              }
++
++              /* set "A", 8259 interrupts */
++              Name (PRSA, ResourceTemplate () {
++                      IRQ(Level, ActiveLow, Exclusive) {4, 7, 10, 11, 12, 14, 
15}
++              })
++
++              Method (CRSA, 1, Serialized) {
++                      Name (LRTL, ResourceTemplate() {
++                              IRQ(Level, ActiveLow, Shared) {15}
++                      })
++                      CreateWordField(LRTL, 1, LIRQ)
++                      ShiftLeft(1, Arg0, LIRQ)
++                      Return (LRTL)
++              }
++
++              Method (SRSA, 1, Serialized) {
++                      CreateWordField(Arg0, 1, LIRQ)
++                      FindSetRightBit(LIRQ, Local0)
++                      if (Local0) {
++                              Decrement(Local0)
++                      }
++                      Return (Local0)
++              }
++
++              Device(LNKA) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 1)
++                      Method(_STA, 0) {
++                              if (PINA) {
++                                      Return(0x0B) /* LNKA is invisible */
++                              } else {
++                                      Return(0x09) /* LNKA is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PINA)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PINA))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PINA)
++                      }
++              }
++
++              Device(LNKB) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 2)
++                      Method(_STA, 0) {
++                              if (PINB) {
++                                      Return(0x0B) /* LNKB is invisible */
++                              } else {
++                                      Return(0x09) /* LNKB is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PINB)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PINB))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PINB)
++                      }
++              }
++
++              Device(LNKC) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 3)
++                      Method(_STA, 0) {
++                              if (PINC) {
++                                      Return(0x0B) /* LNKC is invisible */
++                              } else {
++                                      Return(0x09) /* LNKC is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PINC)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PINC))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PINC)
++                      }
++              }
++
++              Device(LNKD) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 4)
++                      Method(_STA, 0) {
++                              if (PIND) {
++                                      Return(0x0B) /* LNKD is invisible */
++                              } else {
++                                      Return(0x09) /* LNKD is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PIND)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PIND))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PIND)
++                      }
++              }
++
++              Device(LNKE) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 5)
++                      Method(_STA, 0) {
++                              if (PINE) {
++                                      Return(0x0B) /* LNKE is invisible */
++                              } else {
++                                      Return(0x09) /* LNKE is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PINE)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PINE))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PINE)
++                      }
++              }
++
++              Device(LNKF) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 6)
++                      Method(_STA, 0) {
++                              if (PINF) {
++                                      Return(0x0B) /* LNKF is invisible */
++                              } else {
++                                      Return(0x09) /* LNKF is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PINF)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PINF))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PINF)
++                      }
++              }
++
++              Device(LNKG) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 7)
++                      Method(_STA, 0) {
++                              if (PING) {
++                                      Return(0x0B) /* LNKG is invisible */
++                              } else {
++                                      Return(0x09) /* LNKG is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PING)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PING))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PING)
++                      }
++              }
++
++              Device(LNKH) {
++                      Name(_HID, EISAID("PNP0C0F"))
++                      Name(_UID, 8)
++                      Method(_STA, 0) {
++                              if (PINH) {
++                                      Return(0x0B) /* LNKH is invisible */
++                              } else {
++                                      Return(0x09) /* LNKH is disabled */
++                              }
++                      }
++                      Method(_DIS, 0) {
++                              Store(0, PINH)
++                      }
++                      Method(_PRS, 0) {
++                              Return (PRSA)
++                      }
++                      Method (_CRS, 0, Serialized) {
++                              Return (CRSA(PINH))
++                      }
++                      Method (_SRS, 1, Serialized) {
++                              Store (SRSA(Arg0), PINH)
++                      }
++              }
++
++      }   /* End Scope(_SB)  */
++
++}  /* End Scope(/)  */
+diff --git a/src/southbridge/amd/sr5650/early_setup.c 
b/src/southbridge/amd/sr5650/early_setup.c
+index ec555f8..664f60a 100644
+--- a/src/southbridge/amd/sr5650/early_setup.c
++++ b/src/southbridge/amd/sr5650/early_setup.c
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -504,7 +505,8 @@ void sr5650_early_setup(void)
+       /*ATINB_PrepareInit */
+       get_cpu_rev();
+ 
+-      switch (get_nb_rev(nb_dev)) {   /* PCIEMiscInit */
++      uint8_t revno = get_nb_rev(nb_dev);
++      switch (revno) {        /* PCIEMiscInit */
+       case REV_SR5650_A11:
+               printk(BIOS_INFO, "NB Revision is A11.\n");
+               break;
+@@ -514,6 +516,9 @@ void sr5650_early_setup(void)
+       case REV_SR5650_A21:
+               printk(BIOS_INFO, "NB Revision is A21.\n");
+               break;
++      default:
++              printk(BIOS_INFO, "NB Revision is %02x (Unrecognized).\n", 
revno);
++              break;
+       }
+ 
+       fam10_optimization();
+diff --git a/src/southbridge/amd/sr5650/ht.c b/src/southbridge/amd/sr5650/ht.c
+index c497107..02f4f7f 100644
+--- a/src/southbridge/amd/sr5650/ht.c
++++ b/src/southbridge/amd/sr5650/ht.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -55,7 +56,7 @@ static const apic_device_info default_apic_device_info_t [] 
= {
+       [13] = {4,     ABCD,       30}    /* Dev13 Grp4 [Int - 16..19] */
+ };
+ 
+-/* Their name are quite regular. So I undefine them. */
++/* These define names are common, so undefine them to avoid potential issues 
in other code */
+ #undef ABCD
+ #undef BCDA
+ #undef CDAB
+diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
+index 3720a61..d306b5a 100644
+--- a/src/southbridge/amd/sr5650/pcie.c
++++ b/src/southbridge/amd/sr5650/pcie.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -61,8 +62,10 @@ static void ValidatePortEn(device_t nb_dev)
+ *****************************************************************/
+ static void PciePowerOffGppPorts(device_t nb_dev, device_t dev, u32 port)
+ {
++      printk(BIOS_DEBUG, "PciePowerOffGppPorts() port %d\n", port);
+       u32 reg;
+       u16 state_save;
++      uint8_t i;
+       struct southbridge_amd_sr5650_config *cfg =
+               (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
+       u16 state = cfg->port_enable;
+@@ -72,6 +75,28 @@ static void PciePowerOffGppPorts(device_t nb_dev, device_t 
dev, u32 port)
+       state = ~state;
+       state &= (1 << 4) + (1 << 5) + (1 << 6) + (1 << 7);
+       state_save = state << 17;
++      /* Disable ports any that failed training */
++      for (i = 9; i <= 13; i++) {
++              if (!(AtiPcieCfg.PortDetect & 1 << i)) {
++                      if ((port >= 9) && (port <= 13)) {
++                              state |= (1 << (port + 7));
++                      }
++                      if (port == 9)
++                              state_save |= 1 << 25;
++                      if (port == 10)
++                              state_save |= 1 << 26;
++                      if (port == 11)
++                              state_save |= 1 << 6;
++                      if (port == 12)
++                              state_save |= 1 << 7;
++
++                      if (port == 13) {
++                              reg = nbmisc_read_index(nb_dev, 0x2a);
++                              reg |= 1 << 4;
++                              nbmisc_write_index(nb_dev, 0x2a, reg);
++                      }
++              }
++      }
+       state &= !(AtiPcieCfg.PortHp);
+       reg = nbmisc_read_index(nb_dev, 0x0c);
+       reg |= state;
+@@ -483,6 +508,8 @@ static void EnableLclkGating(device_t dev)
+ *****************************************/
+ void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, u32 port)
+ {
++      uint8_t training_ok = 1;
++
+       u32 gpp_sb_sel = 0;
+       struct southbridge_amd_sr5650_config *cfg =
+           (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
+@@ -701,6 +728,12 @@ void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, 
u32 port)
+                               printk(BIOS_DEBUG, "PcieTrainPort port=0x%x 
result=%d\n", port, res);
+                               if (res) {
+                                       AtiPcieCfg.PortDetect |= 1 << port;
++                              } else {
++                                      /* If the training failed the disable 
the bridge to prevent subsequent
++                                       * lockup on bridge configuration 
register read during the PCI bus scan
++                                       */
++                                      training_ok = 0;
++                                      dev->enabled = 0;
+                               }
+                       }
+               }
+@@ -747,8 +780,8 @@ void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, u32 
port)
+        * wait dev 0x6B bit3 clear
+        */
+ 
+-      if (port == 8){
+-              PciePowerOffGppPorts(nb_dev, dev, port); /* , This should be 
run for all ports that are not hotplug and don't detect devices */
++      if ((port == 8) || (!training_ok)) {
++              PciePowerOffGppPorts(nb_dev, dev, port);        /* This is run 
for all ports that are not hotplug and don't detect devices */
+       }
+ }
+ 
+diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
+index 441be66..75383de 100644
+--- a/src/southbridge/amd/sr5650/sr5650.c
++++ b/src/southbridge/amd/sr5650/sr5650.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -95,32 +96,30 @@ void nbpcie_ind_write_index(device_t nb_dev, u32 index, 
u32 data)
+ void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add)
+ {
+       /* K8 Function1 is address map */
+-      device_t k8_f1;
+-      device_t np = dev_find_slot(0, PCI_DEVFN(0x19, 1));
+-      u16 node;
+-
+-      for (node = 0; node < CONFIG_MAX_PHYSICAL_CPUS; node++) {
+-              k8_f1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
+-              if (!k8_f1) {
+-                      break;
+-              }
+-
+-              if (in_out) {
+-                      /* Fill MMIO limit/base pair. */
+-                      pci_write_config32(k8_f1, 0xbc,
+-                                         (((pcie_base_add + 0x10000000 -
+-                                            1) >> 8) & 0xffffff00) | 0x8 | 
(np ? 2 << 4 : 0 << 4));
+-                      pci_write_config32(k8_f1, 0xb8, (pcie_base_add >> 8) | 
0x3);
+-                      pci_write_config32(k8_f1, 0xb4,
+-                                         ((mmio_base_add + 0x10000000 -
+-                                           1) >> 8) | (np ? 2 << 4 : 0 << 4));
+-                      pci_write_config32(k8_f1, 0xb0, (mmio_base_add >> 8) | 
0x3);
+-              } else {
+-                      pci_write_config32(k8_f1, 0xb8, 0);
+-                      pci_write_config32(k8_f1, 0xbc, 0);
+-                      pci_write_config32(k8_f1, 0xb0, 0);
+-                      pci_write_config32(k8_f1, 0xb4, 0);
+-              }
++      device_t k8_f1 = dev_find_slot(0, PCI_DEVFN(0x18, 1));
++      device_t k8_f0 = dev_find_slot(0, PCI_DEVFN(0x18, 0));
++
++      if (in_out) {
++              u32 dword, sblk;
++
++              /* Get SBLink value (HyperTransport I/O Hub Link ID). */
++              dword = pci_read_config32(k8_f0, 0x64);
++              sblk = (dword >> 8) & 0x3;
++
++              /* Fill MMIO limit/base pair. */
++              pci_write_config32(k8_f1, 0xbc,
++                                 (((pcie_base_add + 0x10000000 -
++                                   1) >> 8) & 0xffffff00) | 0x80 | (sblk << 
4));
++              pci_write_config32(k8_f1, 0xb8, (pcie_base_add >> 8) | 0x3);
++              pci_write_config32(k8_f1, 0xb4,
++                                 (((mmio_base_add + 0x10000000 -
++                                   1) >> 8) & 0xffffff00) | (sblk << 4));
++              pci_write_config32(k8_f1, 0xb0, (mmio_base_add >> 8) | 0x3);
++      } else {
++              pci_write_config32(k8_f1, 0xb8, 0);
++              pci_write_config32(k8_f1, 0xbc, 0);
++              pci_write_config32(k8_f1, 0xb0, 0);
++              pci_write_config32(k8_f1, 0xb4, 0);
+       }
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0009-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
 
b/resources/libreboot/patch/kgpe-d16/0009-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
new file mode 100644
index 0000000..b66fdf3
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0009-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch
@@ -0,0 +1,832 @@
+From 9c3c40d0b53a338e7ed153b933155db1bc0cae08 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 17:50:29 -0500
+Subject: [PATCH 009/143] cpu/amd: Add initial support for AMD Socket G34
+ processors
+
+Change-Id: Iccd034f32c26513edd52ca3a11a30f61c362682d
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/Kconfig                        |    1 +
+ src/cpu/amd/Makefile.inc                   |    1 +
+ src/cpu/amd/car/post_cache_as_ram.c        |   19 ++++-
+ src/cpu/amd/model_10xxx/init_cpus.c        |   34 ++++++++-
+ src/cpu/amd/model_10xxx/model_10xxx_init.c |    2 +
+ src/cpu/amd/model_10xxx/processor_name.c   |   23 ++++++
+ src/cpu/amd/model_10xxx/ram_calc.c         |    2 +
+ src/cpu/amd/quadcore/quadcore_id.c         |   77 +++++++++++++++-----
+ src/cpu/amd/socket_G34/Kconfig             |   29 ++++++++
+ src/cpu/amd/socket_G34/Makefile.inc        |   14 ++++
+ src/cpu/amd/socket_G34/socket_G34.c        |   25 +++++++
+ src/northbridge/amd/amdfam10/northbridge.c |  102 +++++++++++++++++++++-----
+ src/northbridge/amd/amdht/ht_wrapper.c     |  107 +++++++++++++++++++++++++++-
+ src/northbridge/amd/amdht/ht_wrapper.h     |   25 +++++++
+ 14 files changed, 417 insertions(+), 44 deletions(-)
+ create mode 100644 src/cpu/amd/socket_G34/Kconfig
+ create mode 100644 src/cpu/amd/socket_G34/Makefile.inc
+ create mode 100644 src/cpu/amd/socket_G34/socket_G34.c
+ create mode 100644 src/northbridge/amd/amdht/ht_wrapper.h
+
+diff --git a/src/cpu/amd/Kconfig b/src/cpu/amd/Kconfig
+index 8286b2a..3a02043 100644
+--- a/src/cpu/amd/Kconfig
++++ b/src/cpu/amd/Kconfig
+@@ -5,6 +5,7 @@ source src/cpu/amd/socket_AM2/Kconfig
+ source src/cpu/amd/socket_AM2r2/Kconfig
+ source src/cpu/amd/socket_AM3/Kconfig
+ source src/cpu/amd/socket_C32/Kconfig
++source src/cpu/amd/socket_G34/Kconfig
+ source src/cpu/amd/socket_ASB2/Kconfig
+ source src/cpu/amd/socket_F/Kconfig
+ source src/cpu/amd/socket_F_1207/Kconfig
+diff --git a/src/cpu/amd/Makefile.inc b/src/cpu/amd/Makefile.inc
+index a73e25f..e532aba 100644
+--- a/src/cpu/amd/Makefile.inc
++++ b/src/cpu/amd/Makefile.inc
+@@ -8,6 +8,7 @@ subdirs-$(CONFIG_CPU_AMD_SOCKET_AM2R2) += socket_AM2r2
+ subdirs-$(CONFIG_CPU_AMD_SOCKET_AM3) += socket_AM3
+ subdirs-$(CONFIG_CPU_AMD_SOCKET_ASB2) += socket_ASB2
+ subdirs-$(CONFIG_CPU_AMD_SOCKET_C32_NON_AGESA) += socket_C32
++subdirs-$(CONFIG_CPU_AMD_SOCKET_G34_NON_AGESA) += socket_G34
+ subdirs-$(CONFIG_CPU_AMD_GEODE_GX2) += geode_gx2
+ subdirs-$(CONFIG_CPU_AMD_GEODE_LX) += geode_lx
+ subdirs-$(CONFIG_CPU_AMD_SOCKET_S1G1) += socket_S1G1
+diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
+index 96df3e7..230d1aa 100644
+--- a/src/cpu/amd/car/post_cache_as_ram.c
++++ b/src/cpu/amd/car/post_cache_as_ram.c
+@@ -1,4 +1,5 @@
+-/* 2005.6 by yhlu
++/* Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * 2005.6 by yhlu
+  * 2006.3 yhlu add copy data from CAR to ram
+  */
+ #include <string.h>
+@@ -46,6 +47,15 @@ static void memset_(void *d, int val, size_t len)
+       memset(d, val, len);
+ }
+ 
++static int memcmp_(void *d, const void *s, size_t len)
++{
++#if PRINTK_IN_CAR
++      printk(BIOS_SPEW, " Compare [%08x-%08x] with [%08x - %08x] ... ",
++              (u32) s, (u32) (s + len - 1), (u32) d, (u32) (d + len - 1));
++#endif
++      return memcmp(d, s, len);
++}
++
+ static void prepare_romstage_ramstack(void *resume_backup_memory)
+ {
+       size_t backup_top = backup_size();
+@@ -110,6 +120,12 @@ void post_cache_as_ram(void)
+       memcpy_(migrated_car, &_car_data_start[0], car_size);
+       print_car_debug("Done\n");
+ 
++      print_car_debug("Verifying data integrity in RAM... ");
++      if (memcmp_(migrated_car, &_car_data_start[0], car_size) == 0)
++              print_car_debug("Done\n");
++      else
++              print_car_debug("FAILED\n");
++
+       /* New stack grows right below migrated_car. */
+       print_car_debug("Switching to use RAM as stack... ");
+       cache_as_ram_switch_stack(migrated_car);
+@@ -128,6 +144,7 @@ void cache_as_ram_new_stack (void)
+       disable_cache_as_ram_bsp();
+ 
+       disable_cache();
++      /* Enable cached access to RAM in the range 1M to CONFIG_RAMTOP */
+       set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
+       enable_cache();
+ 
+diff --git a/src/cpu/amd/model_10xxx/init_cpus.c 
b/src/cpu/amd/model_10xxx/init_cpus.c
+index 4c72848..8de6d25 100644
+--- a/src/cpu/amd/model_10xxx/init_cpus.c
++++ b/src/cpu/amd/model_10xxx/init_cpus.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -67,6 +68,9 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
+       u32 nb_cfg_54;
+       int i, j;
+       u32 ApicIdCoreIdSize;
++      uint8_t rev_gte_d = 0;
++      uint8_t dual_node = 0;
++      uint32_t f3xe8;
+ 
+       /* get_nodes define in ht_wrapper.c */
+       nodes = get_nodes();
+@@ -81,6 +85,16 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
+       /* Assume that all node are same stepping, otherwise we can use use
+          nb_cfg_54 from bsp for all nodes */
+       nb_cfg_54 = read_nb_cfg_54();
++      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
++
++      if (cpuid_eax(0x80000001) >= 0x8)
++              /* Revision D or later */
++              rev_gte_d = 1;
++
++      if (rev_gte_d)
++               /* Check for dual node capability */
++              if (f3xe8 & 0x20000000)
++                      dual_node = 1;
+ 
+       ApicIdCoreIdSize = (cpuid_ecx(0x80000008) >> 12 & 0xf);
+       if (ApicIdCoreIdSize) {
+@@ -91,6 +105,8 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
+ 
+       for (i = 0; i < nodes; i++) {
+               cores_found = get_core_num_in_bsp(i);
++              if (siblings > cores_found)
++                      siblings = cores_found;
+ 
+               u32 jstart, jend;
+ 
+@@ -107,9 +123,21 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
+               }
+ 
+               for (j = jstart; j <= jend; j++) {
+-                      ap_apicid =
+-                          i * (nb_cfg_54 ? (siblings + 1) : 1) +
+-                          j * (nb_cfg_54 ? 1 : 64);
++                      if (dual_node) {
++                              ap_apicid = 0;
++                              if (nb_cfg_54) {
++                                      ap_apicid |= ((i >> 1) & 0x3) << 4;     
                /* Node ID */
++                                      ap_apicid |= ((i & 0x1) * (siblings + 
1)) + j;          /* Core ID */
++                              } else {
++                                      ap_apicid |= i & 0x3;                   
                /* Node ID */
++                                      ap_apicid |= (((i & 0x1) * (siblings + 
1)) + j) << 4;   /* Core ID */
++                              }
++                      } else {
++                              ap_apicid =
++                              i * (nb_cfg_54 ? (siblings + 1) : 1) +
++                              j * (nb_cfg_54 ? 1 : 64);
++                      }
++
+ 
+ #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET > 0)
+ #if !CONFIG_LIFT_BSP_APIC_ID
+diff --git a/src/cpu/amd/model_10xxx/model_10xxx_init.c 
b/src/cpu/amd/model_10xxx/model_10xxx_init.c
+index 590b89d..b942c1a 100644
+--- a/src/cpu/amd/model_10xxx/model_10xxx_init.c
++++ b/src/cpu/amd/model_10xxx/model_10xxx_init.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -153,6 +154,7 @@ static struct cpu_device_id cpu_table[] = {
+       { X86_VENDOR_AMD, 0x100F63 },           /* DA-C3 */
+       { X86_VENDOR_AMD, 0x100F80 },           /* HY-D0 */
+       { X86_VENDOR_AMD, 0x100F81 },           /* HY-D1 */
++      { X86_VENDOR_AMD, 0x100F91 },           /* HY-D1 */
+       { X86_VENDOR_AMD, 0x100FA0 },           /* PH-E0 */
+       { 0, 0 },
+ };
+diff --git a/src/cpu/amd/model_10xxx/processor_name.c 
b/src/cpu/amd/model_10xxx/processor_name.c
+index a25e3a9..12c45c9 100644
+--- a/src/cpu/amd/model_10xxx/processor_name.c
++++ b/src/cpu/amd/model_10xxx/processor_name.c
+@@ -157,6 +157,24 @@ static const struct str_s String2_socket_AM2[] = {
+       {0, 0, 0, NULL}
+ };
+ 
++static const struct str_s String1_socket_G34[] = {
++      {0x00, 0x07, 0x00, "AMD Opteron(tm) Processor 61"},
++      {0x00, 0x0B, 0x00, "AMD Opteron(tm) Processor 61"},
++      {0x01, 0x07, 0x01, "Embedded AMD Opteron(tm) Processor "},
++      {0, 0, 0, NULL}
++};
++
++static const struct str_s String2_socket_G34[] = {
++      {0x00, 0x07, 0x00, " HE"},
++      {0x00, 0x07, 0x01, " SE"},
++      {0x00, 0x0B, 0x00, " HE"},
++      {0x00, 0x0B, 0x01, " SE"},
++      {0x00, 0x0B, 0x0F, ""},
++      {0x01, 0x07, 0x01, " QS"},
++      {0x01, 0x07, 0x02, " KS"},
++      {0, 0, 0, NULL}
++};
++
+ static const struct str_s String1_socket_C32[] = {
+       {0x00, 0x03, 0x00, "AMD Opteron(tm) Processor 41"},
+       {0x00, 0x05, 0x00, "AMD Opteron(tm) Processor 41"},
+@@ -240,6 +258,11 @@ int init_processor_name(void)
+               str = String1_socket_AM2;
+               str2 = String2_socket_AM2;
+               break;
++      case 3:         /* G34 */
++              str = String1_socket_G34;
++              str2 = String2_socket_G34;
++              str2_checkNC = 0;
++              break;
+       case 5:         /* C32 */
+               str = String1_socket_C32;
+               str2 = String2_socket_C32;
+diff --git a/src/cpu/amd/model_10xxx/ram_calc.c 
b/src/cpu/amd/model_10xxx/ram_calc.c
+index c8637c9..46ccdbd 100644
+--- a/src/cpu/amd/model_10xxx/ram_calc.c
++++ b/src/cpu/amd/model_10xxx/ram_calc.c
+@@ -26,6 +26,7 @@
+ 
+ #include "ram_calc.h"
+ 
++#if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
+ uint64_t get_uma_memory_size(uint64_t topmem)
+ {
+       uint64_t uma_size = 0;
+@@ -50,3 +51,4 @@ void *cbmem_top(void)
+ 
+       return (void *) topmem - get_uma_memory_size(topmem);
+ }
++#endif
+diff --git a/src/cpu/amd/quadcore/quadcore_id.c 
b/src/cpu/amd/quadcore/quadcore_id.c
+index cf45196..c5921de 100644
+--- a/src/cpu/amd/quadcore/quadcore_id.c
++++ b/src/cpu/amd/quadcore/quadcore_id.c
+@@ -1,6 +1,7 @@
+ /*
+  * This file is part of the coreboot project.
+  *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -37,33 +38,71 @@ u32 get_initial_apicid(void)
+       return ((cpuid_ebx(1) >> 24) & 0xff);
+ }
+ 
+-//called by amd_siblings too
+-#define CORE_ID_BIT 2
+-#define NODE_ID_BIT 6
++/* Called by amd_siblings (ramstage) as well */
+ struct node_core_id get_node_core_id(u32 nb_cfg_54)
+ {
+       struct node_core_id id;
+-      u32 core_id_bits;
++      uint8_t apicid;
++      uint8_t rev_gte_d = 0;
++      uint8_t dual_node = 0;
++      uint32_t f3xe8;
+ 
+-      u32 ApicIdCoreIdSize = (cpuid_ecx(0x80000008)>>12 & 0xf);
+-      if(ApicIdCoreIdSize) {
+-              core_id_bits = ApicIdCoreIdSize;
+-      } else {
+-              core_id_bits = CORE_ID_BIT; //quad core
+-      }
++#ifdef __PRE_RAM__
++      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
++#else
++      f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
++#endif
++
++      if (cpuid_eax(0x80000001) >= 0x8)
++              /* Revision D or later */
++              rev_gte_d = 1;
+ 
+-      // get the apicid via cpuid(1) ebx[31:24]
++      if (rev_gte_d)
++               /* Check for dual node capability */
++              if (f3xe8 & 0x20000000)
++                      dual_node = 1;
++
++      /* Get the apicid via cpuid(1) ebx[31:24]
++       * The apicid format varies based on processor revision
++       */
++      apicid = (cpuid_ebx(1) >> 24) & 0xff;
+       if( nb_cfg_54) {
+-              // when NB_CFG[54] is set, nodeid = ebx[31:26], coreid = 
ebx[25:24]
+-              id.coreid = (cpuid_ebx(1) >> 24) & 0xff;
+-              id.nodeid = (id.coreid>>core_id_bits);
+-              id.coreid &= ((1<<core_id_bits)-1);
++              if (rev_gte_d && dual_node) {
++                      id.coreid = apicid & 0xf;
++                      id.nodeid = (apicid & 0x30) >> 4;
++              } else if (rev_gte_d && !dual_node) {
++                      id.coreid = apicid & 0x7;
++                      id.nodeid = (apicid & 0x38) >> 3;
++              } else {
++                      id.coreid = apicid & 0x3;
++                      id.nodeid = (apicid & 0x1c) >> 2;
++              }
+       } else {
+-              // when NB_CFG[54] is clear, nodeid = ebx[29:24], coreid = 
ebx[31:30]
+-              id.nodeid = (cpuid_ebx(1) >> 24) & 0xff;
+-              id.coreid = (id.nodeid>>NODE_ID_BIT);
+-              id.nodeid &= ((1<<NODE_ID_BIT)-1);
++              if (rev_gte_d && dual_node) {
++                      id.coreid = (apicid & 0xf0) >> 4;
++                      id.nodeid = apicid & 0x3;
++              } else if (rev_gte_d && !dual_node) {
++                      id.coreid = (apicid & 0xe0) >> 5;
++                      id.nodeid = apicid & 0x7;
++              } else {
++                      id.coreid = (apicid & 0x60) >> 5;
++                      id.nodeid = apicid & 0x7;
++              }
+       }
++
++      if (rev_gte_d && dual_node) {
++              /* Coreboot expects each separate processor die to be on a 
different nodeid.
++               * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
++               */
++              uint8_t core_count = (((f3xe8 & 0x00008000) >> 13) | ((f3xe8 & 
0x00003000) >> 12)) + 1;
++
++              id.nodeid = id.nodeid * 2;
++              if (id.coreid >= core_count) {
++                      id.nodeid += 1;
++                      id.coreid = id.coreid - core_count;
++              }
++      }
++
+       return id;
+ }
+ 
+diff --git a/src/cpu/amd/socket_G34/Kconfig b/src/cpu/amd/socket_G34/Kconfig
+new file mode 100644
+index 0000000..abc9726
+--- /dev/null
++++ b/src/cpu/amd/socket_G34/Kconfig
+@@ -0,0 +1,29 @@
++config CPU_AMD_SOCKET_G34_NON_AGESA
++      bool
++      select CPU_AMD_MODEL_10XXX
++      select PCI_IO_CFG_EXT
++      select X86_AMD_FIXED_MTRRS
++
++if CPU_AMD_SOCKET_G34_NON_AGESA
++
++config CPU_SOCKET_TYPE
++      hex
++      default 0x15
++
++config EXT_RT_TBL_SUPPORT
++      bool
++      default n
++
++config CBB
++      hex
++      default 0x0
++
++config CDB
++      hex
++      default 0x18
++
++config XIP_ROM_SIZE
++      hex
++      default 0x80000
++
++endif
+diff --git a/src/cpu/amd/socket_G34/Makefile.inc 
b/src/cpu/amd/socket_G34/Makefile.inc
+new file mode 100644
+index 0000000..a8e1333
+--- /dev/null
++++ b/src/cpu/amd/socket_G34/Makefile.inc
+@@ -0,0 +1,14 @@
++ramstage-y += socket_G34.c
++subdirs-y += ../model_10xxx
++subdirs-y += ../quadcore
++subdirs-y += ../mtrr
++subdirs-y += ../microcode
++subdirs-y += ../../x86/tsc
++subdirs-y += ../../x86/lapic
++subdirs-y += ../../x86/cache
++subdirs-y += ../../x86/pae
++subdirs-y += ../../x86/mtrr
++subdirs-y += ../../x86/smm
++subdirs-y += ../smm
++
++cpu_incs-y += $(src)/cpu/amd/car/cache_as_ram.inc
+diff --git a/src/cpu/amd/socket_G34/socket_G34.c 
b/src/cpu/amd/socket_G34/socket_G34.c
+new file mode 100644
+index 0000000..90f7b8c
+--- /dev/null
++++ b/src/cpu/amd/socket_G34/socket_G34.c
+@@ -0,0 +1,25 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <device/device.h>
++
++struct chip_operations cpu_amd_socket_G34_ops = {
++      CHIP_NAME("socket G34")
++};
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 6d91cbd..74cecc8 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -187,6 +187,43 @@ static void ht_route_link(struct bus *link, scan_state 
mode)
+       }
+ }
+ 
++static void amd_g34_fixup(struct bus *link, device_t dev)
++{
++      uint32_t nodeid = amdfam10_nodeid(dev);
++      uint8_t rev_gte_d = 0;
++      uint8_t dual_node = 0;
++      uint32_t f3xe8;
++
++      if (cpuid_eax(0x80000001) >= 0x8)
++              /* Revision D or later */
++              rev_gte_d = 1;
++
++      if (rev_gte_d) {
++              f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
++
++              /* Check for dual node capability */
++              if (f3xe8 & 0x20000000)
++                      dual_node = 1;
++
++              if (dual_node) {
++                      /* Each G34 processor contains a defective HT link.
++                      * See the BKDG Rev 3.62 section 2.7.1.5 for details.
++                      */
++                      f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 
0xe8);
++                      uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 
30);
++                      if (internal_node_number == 0) {
++                              /* Node 0 */
++                              if (link->link_num == 6)        /* Link 2 
Sublink 1 */
++                                      printk(BIOS_DEBUG, 
"amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT 
link\n", nodeid, internal_node_number);
++                      } else {
++                              /* Node 1 */
++                              if (link->link_num == 5)        /* Link 1 
Sublink 1 */
++                                      printk(BIOS_DEBUG, 
"amdfam10_scan_chain(): node %d (internal node ID %d): skipping defective HT 
link\n", nodeid, internal_node_number);
++                      }
++              }
++      }
++}
++
+ static void amdfam10_scan_chain(struct bus *link)
+ {
+               unsigned int next_unitid;
+@@ -277,8 +314,11 @@ static void amdfam10_scan_chains(device_t dev)
+       trim_ht_chain(dev);
+ 
+       for (link = dev->link_list; link; link = link->next) {
+-              if (link->ht_link_up)
++              if (link->ht_link_up) {
++                      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
++                              amd_g34_fixup(link, dev);
+                       amdfam10_scan_chain(link);
++              }
+       }
+ }
+ 
+@@ -323,8 +363,7 @@ static struct resource *amdfam10_find_iopair(device_t dev, 
unsigned nodeid, unsi
+               if (result == 1) {
+                       /* I have been allocated this one */
+                       break;
+-              }
+-              else if (result > 1) {
++              } else if (result > 1) {
+                       /* I have a free register pair */
+                       free_reg = reg;
+               }
+@@ -357,8 +396,7 @@ static struct resource *amdfam10_find_mempair(device_t 
dev, u32 nodeid, u32 link
+               if (result == 1) {
+                       /* I have been allocated this one */
+                       break;
+-              }
+-              else if (result > 1) {
++              } else if (result > 1) {
+                       /* I have a free register pair */
+                       free_reg = reg;
+               }
+@@ -473,8 +511,7 @@ static void amdfam10_set_resource(device_t dev, struct 
resource *resource,
+ 
+               set_io_addr_reg(dev, nodeid, link_num, reg, rbase>>8, rend>>8);
+               store_conf_io_addr(nodeid, link_num, reg, (resource->index >> 
24), rbase>>8, rend>>8);
+-      }
+-      else if (resource->flags & IORESOURCE_MEM) {
++      } else if (resource->flags & IORESOURCE_MEM) {
+               set_mmio_addr_reg(nodeid, link_num, reg, (resource->index 
>>24), rbase>>8, rend>>8, sysconf.nodes) ;// [39:8]
+               store_conf_mmio_addr(nodeid, link_num, reg, (resource->index 
>>24), rbase>>8, rend>>8);
+       }
+@@ -799,8 +836,7 @@ static void amdfam10_domain_set_resources(device_t dev)
+                       }
+                       if ((basek + sizek) <= 4*1024*1024) {
+                               sizek = 0;
+-                      }
+-                      else {
++                      } else {
+                               basek = 4*1024*1024;
+                               sizek -= (4*1024*1024 - mmio_basek);
+                       }
+@@ -977,8 +1013,7 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
+                               if (dimm_size_bytes > 0x800000000) {
+                                       t->size = 0x7FFF;
+                                       t->extended_size = dimm_size_bytes;
+-                              }
+-                              else {
++                              } else {
+                                       t->size = dimm_size_bytes / (1024*1024);
+                                       t->size &= (~0x8000);   /* size 
specified in megabytes */
+                               }
+@@ -1005,8 +1040,7 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
+                               t->part_number = smbios_add_string(t->eos, 
mem_info->dct_stat[node].DimmPartNumber[slot]);
+                               if 
(mem_info->dct_stat[node].DimmSerialNumber[slot] == 0) {
+                                       t->serial_number = 
smbios_add_string(t->eos, "None");
+-                              }
+-                              else {
++                              } else {
+                                       snprintf(string_buffer, sizeof 
(string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
+                                       t->serial_number = 
smbios_add_string(t->eos, string_buffer);
+                               }
+@@ -1108,8 +1142,7 @@ static void add_more_links(device_t dev, unsigned 
total_links)
+                       memset(link, 0, links*sizeof(*link));
+                       last->next = link;
+               }
+-      }
+-      else {
++      } else {
+               link = malloc(total_links*sizeof(*link));
+               memset(link, 0, total_links*sizeof(*link));
+               dev->link_list = link;
+@@ -1244,6 +1277,10 @@ static void cpu_bus_scan(device_t dev)
+               unsigned busn, devn;
+               struct bus *pbus;
+ 
++              uint8_t rev_gte_d = 0;
++              uint8_t dual_node = 0;
++              uint32_t f3xe8;
++
+               busn = CONFIG_CBB;
+               devn = CONFIG_CDB+i;
+               pbus = dev_mc->bus;
+@@ -1268,6 +1305,7 @@ static void cpu_bus_scan(device_t dev)
+                       }
+               }
+ 
++
+               /* Ok, We need to set the links for that device.
+                * otherwise the device under it will not be scanned
+                */
+@@ -1279,6 +1317,17 @@ static void cpu_bus_scan(device_t dev)
+               if (cdb_dev)
+                       add_more_links(cdb_dev, 4);
+ 
++              f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
++
++              if (cpuid_eax(0x80000001) >= 0x8)
++                      /* Revision D or later */
++                      rev_gte_d = 1;
++
++              if (rev_gte_d)
++                      /* Check for dual node capability */
++                      if (f3xe8 & 0x20000000)
++                              dual_node = 1;
++
+               cores_found = 0; // one core
+               cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
+               int enable_node = cdb_dev && cdb_dev->enabled;
+@@ -1290,6 +1339,9 @@ static void cpu_bus_scan(device_t dev)
+                       printk(BIOS_DEBUG, "  %s siblings=%d\n", 
dev_path(cdb_dev), cores_found);
+               }
+ 
++              if (siblings > cores_found)
++                      siblings = cores_found;
++
+               u32 jj;
+               if(disable_siblings) {
+                       jj = 0;
+@@ -1299,7 +1351,20 @@ static void cpu_bus_scan(device_t dev)
+               }
+ 
+               for (j = 0; j <=jj; j++ ) {
+-                      u32 apic_id = i * (nb_cfg_54?(siblings+1):1) + j * 
(nb_cfg_54?1:64); // ?
++                      u32 apic_id;
++
++                      if (dual_node) {
++                              apic_id = 0;
++                              if (nb_cfg_54) {
++                                      apic_id |= ((i >> 1) & 0x3) << 4;       
                /* Node ID */
++                                      apic_id |= ((i & 0x1) * (siblings + 1)) 
+ j;            /* Core ID */
++                              } else {
++                                      apic_id |= i & 0x3;                     
                /* Node ID */
++                                      apic_id |= (((i & 0x1) * (siblings + 
1)) + j) << 4;     /* Core ID */
++                              }
++                      } else {
++                              apic_id = i * (nb_cfg_54?(siblings+1):1) + j * 
(nb_cfg_54?1:64); // ?
++                      }
+ 
+ #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
+                       if(sysconf.enabled_apic_ext_id) {
+@@ -1311,7 +1376,7 @@ static void cpu_bus_scan(device_t dev)
+                       device_t cpu = add_cpu_device(cpu_bus, apic_id, 
enable_node);
+                       if (cpu)
+                               amd_cpu_topology(cpu, i, j);
+-              } //j
++              }
+       }
+ }
+ 
+@@ -1356,8 +1421,7 @@ static void root_complex_enable_dev(struct device *dev)
+       /* Set the operations if it is a special bus type */
+       if (dev->path.type == DEVICE_PATH_DOMAIN) {
+               dev->ops = &pci_domain_ops;
+-      }
+-      else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
++      } else if (dev->path.type == DEVICE_PATH_CPU_CLUSTER) {
+               dev->ops = &cpu_bus_ops;
+       }
+ }
+diff --git a/src/northbridge/amd/amdht/ht_wrapper.c 
b/src/northbridge/amd/amdht/ht_wrapper.c
+index 36fe60b..389b1b1 100644
+--- a/src/northbridge/amd/amdht/ht_wrapper.c
++++ b/src/northbridge/amd/amdht/ht_wrapper.c
+@@ -22,6 +22,8 @@
+ #include <console/console.h>
+ #include <northbridge/amd/amdfam10/amdfam10.h>
+ 
++#include "ht_wrapper.h"
++
+ /*----------------------------------------------------------------------------
+  *                    TYPEDEFS, DEFINITIONS AND MACROS
+  *
+@@ -113,6 +115,20 @@ void getAmdTopolist(u8 ***p)
+       *p = (u8 **)amd_topo_list;
+ }
+ 
++/**
++ * BOOL AMD_CB_IgnoreLink(u8 Node, u8 Link)
++ * Description:
++ *    This routine is used to ignore connected yet faulty HT links,
++ *    such as those present in a G34 processor package.
++ *
++ * Parameters:
++ *    @param[in]  node   = The node on which this chain is located
++ *    @param[in]  link   = The link on the host for this chain
++ */
++static BOOL AMD_CB_IgnoreLink (u8 node, u8 link)
++{
++      return 0;
++}
+ 
+ /**
+  * void amd_ht_init(struct sys_info *sysinfo)
+@@ -128,7 +144,7 @@ static void amd_ht_init(struct sys_info *sysinfo)
+               0,      // u8 AutoBusStart;
+               32,     // u8 AutoBusMax;
+               6,      // u8 AutoBusIncrement;
+-              NULL,   // BOOL (*AMD_CB_IgnoreLink)();
++              AMD_CB_IgnoreLink,              // BOOL (*AMD_CB_IgnoreLink)();
+               NULL,   // BOOL (*AMD_CB_OverrideBusNumbers)();
+               AMD_CB_ManualBUIDSwapList,      // BOOL 
(*AMD_CB_ManualBUIDSwapList)();
+               NULL,   // void (*AMD_CB_DeviceCapOverride)();
+@@ -146,6 +162,93 @@ static void amd_ht_init(struct sys_info *sysinfo)
+       printk(BIOS_DEBUG, "Enter amd_ht_init()\n");
+       amdHtInitialize(&ht_wrapper);
+       printk(BIOS_DEBUG, "Exit amd_ht_init()\n");
++}
+ 
+-
++/**
++ * void amd_ht_fixup(struct sys_info *sysinfo)
++ *
++ *  AMD HT fixup
++ *
++ */
++void amd_ht_fixup(struct sys_info *sysinfo) {
++      printk(BIOS_DEBUG, "amd_ht_fixup()\n");
++      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX)) {
++              uint8_t rev_gte_d = 0;
++              uint8_t dual_node = 0;
++              uint32_t f3xe8;
++              uint32_t family;
++              uint32_t model;
++
++              family = model = cpuid_eax(0x80000001);
++              model = ((model & 0xf0000) >> 16) | ((model & 0xf0) >> 4);
++
++              if (model >= 0x8)
++                      /* Revision D or later */
++                      rev_gte_d = 1;
++
++              if (rev_gte_d) {
++                      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
++
++                      /* Check for dual node capability */
++                      if (f3xe8 & 0x20000000)
++                              dual_node = 1;
++
++                      if (dual_node) {
++                              /* Each G34 processor contains a defective HT 
link.
++                              * See the BKDG Rev 3.62 section 2.7.1.5 for 
details.
++                              */
++                              uint8_t node;
++                              uint8_t node_count = get_nodes();
++                              uint32_t dword;
++                              for (node = 0; node < node_count; node++) {
++                                      f3xe8 = 
pci_read_config32(NODE_PCI(node, 3), 0xe8);
++                                      uint8_t internal_node_number = ((f3xe8 
& 0xc0000000) >> 30);
++                                      printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link\n", node, 
internal_node_number);
++                                      if (internal_node_number == 0) {
++                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xd8) & 0x1;
++                                              if (package_link_3_connected) {
++                                                      /* Set WidthIn and 
WidthOut to 0 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xc4);
++                                                      dword &= ~0x77000000;
++                                                      
pci_write_config32(NODE_PCI(node, 0), 0xc4, dword);
++                                                      /* Set Ganged to 1 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x178);
++                                                      dword |= 0x00000001;
++                                                      
pci_write_config32(NODE_PCI(node, 0), 0x178, dword);
++                                              } else {
++                                                      /* Set ConnDly to 1 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
++                                                      dword |= 0x00000100;
++                                                      
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
++                                                      /* Set TransOff and 
EndOfChain to 1 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xc4);
++                                                      dword |= 0x000000c0;
++                                                      
pci_write_config32(NODE_PCI(node, 4), 0xc4, dword);
++                                              }
++                                      } else if (internal_node_number == 1) {
++                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xb8) & 0x1;
++                                              if (package_link_3_connected) {
++                                                      /* Set WidthIn and 
WidthOut to 0 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xa4);
++                                                      dword &= ~0x77000000;
++                                                      
pci_write_config32(NODE_PCI(node, 0), 0xa4, dword);
++                                                      /* Set Ganged to 1 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x174);
++                                                      dword |= 0x00000001;
++                                                      
pci_write_config32(NODE_PCI(node, 0), 0x174, dword);
++                                              } else {
++                                                      /* Set ConnDly to 1 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
++                                                      dword |= 0x00000100;
++                                                      
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
++                                                      /* Set TransOff and 
EndOfChain to 1 */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xa4);
++                                                      dword |= 0x000000c0;
++                                                      
pci_write_config32(NODE_PCI(node, 4), 0xa4, dword);
++                                              }
++                                      }
++                              }
++                      }
++              }
++      }
+ }
+diff --git a/src/northbridge/amd/amdht/ht_wrapper.h 
b/src/northbridge/amd/amdht/ht_wrapper.h
+new file mode 100644
+index 0000000..3e9d957
+--- /dev/null
++++ b/src/northbridge/amd/amdht/ht_wrapper.h
+@@ -0,0 +1,25 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc.
++ */
++
++#ifndef AMD_HT_WRAPPER_H
++#define AMD_HT_WRAPPER_H
++
++void amd_ht_fixup(struct sys_info *sysinfo);
++
++#endif
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0009-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
 
b/resources/libreboot/patch/kgpe-d16/0009-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
deleted file mode 100644
index 877d6b0..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0009-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
+++ /dev/null
@@ -1,95 +0,0 @@
-From 008cfb1a5e464a79af252b34086b1eb28d8b3420 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 8 Sep 2015 16:08:45 -0500
-Subject: [PATCH 009/139] northbridge/amd/amdmct/mct_ddr3: Fix curly brace
- style violations
-
-Change-Id: Ic27d404a7ed76b58043037e8b66097db6d664501
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 37 ++++++++-------------------
- 1 file changed, 10 insertions(+), 27 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index c76476b..9f42d54 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -818,28 +818,19 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
- 
-               tempB = 0;
-               offsetAddr = (u8)(3 * dimm);
--              if (ByteLane < 2)
--              {
-+              if (ByteLane < 2) {
-                       tempB = (u8)(16 * ByteLane);
-                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01;
--              }
--              else if (ByteLane <4)
--              {
-+              } else if (ByteLane <4) {
-                       tempB = (u8)(16 * ByteLane);
-                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 1;
--              }
--              else if (ByteLane <6)
--              {
-+              } else if (ByteLane <6) {
-                       tempB = (u8)(16 * ByteLane);
-                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45;
--              }
--              else if (ByteLane <8)
--              {
-+              } else if (ByteLane <8) {
-                       tempB = (u8)(16 * ByteLane);
-                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 + 1;
--              }
--              else
--              {
-+              } else {
-                       tempB = 0;
-                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 2;
-               }
-@@ -883,19 +874,14 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm)
-       u32 addr, fine, gross;
-       tempB = 0;
-       index = (u8)(MAX_BYTE_LANES*dimm);
--      if (ByteLane < 4)
--      {
-+      if (ByteLane < 4) {
-               tempB = (u8)(8 * ByteLane);
-               addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;
--      }
--      else if (ByteLane < 8)
--      {
-+      } else if (ByteLane < 8) {
-               tempB1 = (u8)(ByteLane - 4);
-               tempB = (u8)(8 * tempB1);
-               addr = DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH;
--      }
--      else
--      {
-+      } else {
-               tempB = 0;
-               addr = DRAM_CONT_ADD_ECC_PHASE_REC_CTRL;
-       }
-@@ -911,16 +897,13 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm)
-       /* Adjust seed gross delay overflow (greater than 3):
-        * - Adjust the trained gross delay to the original seed gross delay.
-        */
--      if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
--      {
-+      if (pDCTData->WLGrossDelay[index+ByteLane] >= 3) {
-               gross += pDCTData->WLGrossDelay[index+ByteLane];
-               if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
-                       gross -= 1;
-               else
-                       gross -= 2;
--      }
--      else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
--      {
-+      } else if ((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 
3)) {
-               /* If seed gross delay is 0 but PRE result gross delay is 3, it 
is negative.
-                * We will then round the negative number to 0.
-                */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
 
b/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
deleted file mode 100644
index d5a8941..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-From 5e830015eefae9024835e76c81715821a55b0853 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:00:27 -0500
-Subject: [PATCH 010/139] northbridge/amd/amdfam10: Limit maximum RAM clock to
- BKDG recommendations
-
-Change-Id: I45eb03a4b351e458e8448245896743bd6fa57637
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/raminit_amdmct.c | 46 +++++++++++++++++++++++----
- src/northbridge/amd/amdmct/wrappers/mcti_d.c  |  2 +-
- 2 files changed, 41 insertions(+), 7 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-index a585fae..3f33eba 100644
---- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
-+++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-@@ -44,29 +44,58 @@ static  void print_tf(const char *func, const char *strval)
- #endif
- }
- 
--static uint16_t mct_MaxLoadFreq(uint8_t count, uint16_t freq)
-+static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t 
freq)
- {
-       /* Return limited maximum RAM frequency */
-       if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
--              if (IS_ENABLED(CONFIG_DIMM_REGISTERED)) {
-+              if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
-                       /* K10 BKDG Rev. 3.62 Table 53 */
-                       if (count > 2) {
-                               /* Limit to DDR2-533 */
-                               if (freq > 266) {
-                                       freq = 266;
--                                      print_tf(__func__, ": More than 2 DIMMs 
on channel; limiting to DDR2-533\n");
-+                                      print_tf(__func__, ": More than 2 
registered DIMMs on channel; limiting to DDR2-533\n");
-                               }
-                       }
--              }
--              else {
-+              } else {
-                       /* K10 BKDG Rev. 3.62 Table 52 */
-                       if (count > 1) {
-                               /* Limit to DDR2-800 */
-                               if (freq > 400) {
-                                       freq = 400;
--                                      print_tf(__func__, ": More than 1 DIMM 
on channel; limiting to DDR2-800\n");
-+                                      print_tf(__func__, ": More than 1 
unbuffered DIMM on channel; limiting to DDR2-800\n");
-+                              }
-+                      }
-+              }
-+      } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+              if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
-+                      /* K10 BKDG Rev. 3.62 Table 34 */
-+                      if (count > 2) {
-+                              /* Limit to DDR3-800 */
-+                              if (freq > 400) {
-+                                      freq = 400;
-+                                      print_tf(__func__, ": More than 2 
registered DIMMs on channel; limiting to DDR3-800\n");
-+                              }
-+                      } else if (count == 2) {
-+                              /* Limit to DDR3-1066 */
-+                              if (freq > 533) {
-+                                      freq = 533;
-+                                      print_tf(__func__, ": 2 registered 
DIMMs on channel; limiting to DDR3-1066\n");
-+                              }
-+                      } else {
-+                              /* Limit to DDR3-1333 */
-+                              if (freq > 666) {
-+                                      freq = 666;
-+                                      print_tf(__func__, ": 1 registered DIMM 
on channel; limiting to DDR3-1333\n");
-                               }
-                       }
-+              } else {
-+                      /* K10 BKDG Rev. 3.62 Table 33 */
-+                      /* Limit to DDR3-1333 */
-+                      if (freq > 666) {
-+                              freq = 666;
-+                              print_tf(__func__, ": unbuffered DIMMs on 
channel; limiting to DDR3-1333\n");
-+                      }
-               }
-       }
- 
-@@ -120,6 +149,9 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint16_t 
freq)
- //C32
- #elif CONFIG_CPU_SOCKET_TYPE == 0x14
- #include "../amdmct/mct_ddr3/mctardk5.c"
-+//G34
-+#elif CONFIG_CPU_SOCKET_TYPE == 0x15
-+#include "../amdmct/mct_ddr3/mctardk5.c"
- #endif
- 
- #else  /* DDR2 */
-@@ -207,6 +239,7 @@ static void raminit_amdmct(struct sys_info *sysinfo)
-       printk(BIOS_DEBUG, "raminit_amdmct end:\n");
- }
- 
-+#if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
- static void amdmct_cbmem_store_info(struct sys_info *sysinfo)
- {
-       if (!sysinfo)
-@@ -245,3 +278,4 @@ static void amdmct_cbmem_store_info(struct sys_info 
*sysinfo)
-       }
- #endif
- }
-+#endif
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index 6465e13..47260f2 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -322,7 +322,7 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
-       }
- 
-       /* Set limits if needed */
--      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
pDCTstat->PresetmaxFreq);
-+      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
(ch1_registered || ch2_registered), pDCTstat->PresetmaxFreq);
- }
- 
- #ifdef UNUSED_CODE
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
 
b/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
new file mode 100644
index 0000000..c3abdee
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch
@@ -0,0 +1,3454 @@
+From b79a652d746bc186b0de559aa237462e7ba09109 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 17:55:58 -0500
+Subject: [PATCH 010/143] northbridge/amd/amdmct: Fix broken AMD K10 DDR3
+ memory initalization
+
+Change-Id: Iab690db769e820600693ad1170085623b177b94e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/raminit_amdmct.c   |    2 +
+ src/northbridge/amd/amdmct/mct/mct_d.c          |    1 -
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c     |  177 ++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h     |    8 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h |   87 +--
+ src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c  |    6 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c  |  806 ++++++++++++-----------
+ src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c    |    6 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c  |   14 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c  |    3 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctproc.c   |   19 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c    |    5 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c    |  800 +++++++++++-----------
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c  |   18 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c  |   13 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c   |    7 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctwl.c     |   42 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c   |  267 ++++----
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c    |  110 +---
+ 19 files changed, 1252 insertions(+), 1139 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+index a0d47f4..a585fae 100644
+--- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
++++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+@@ -28,12 +28,14 @@ static  void print_tx(const char *strval, u32 val)
+ }
+ #endif
+ 
++#if (CONFIG_DIMM_SUPPORT & 0x000F)!=0x0005 /* not needed for AMD_FAM10_DDR3 */
+ static  void print_t(const char *strval)
+ {
+ #if CONFIG_DEBUG_RAM_SETUP
+       printk(BIOS_DEBUG, "%s", strval);
+ #endif
+ }
++#endif
+ 
+ static  void print_tf(const char *func, const char *strval)
+ {
+diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c 
b/src/northbridge/amd/amdmct/mct/mct_d.c
+index 3dec934..88910e2 100644
+--- a/src/northbridge/amd/amdmct/mct/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct/mct_d.c
+@@ -542,7 +542,6 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+               pDCTstat = pDCTstatA + Node;
+               devx = pDCTstat->dev_map;
+               DramSelBaseAddr = 0;
+-              pDCTstat = pDCTstatA + Node;
+               if (!pDCTstat->GangedMode) {
+                       DramSelBaseAddr = pDCTstat->NodeSysLimit - 
pDCTstat->DCTSysLimit;
+                       /*In unganged mode, we must add DCT0 and DCT1 to 
DCTSysLimit */
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 71a6be8..fa59d71 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -214,6 +214,8 @@ static const u8 Table_DQSRcvEn_Offset[] = 
{0x00,0x01,0x10,0x11,0x2};
+ static const u8 Tab_L1CLKDis[]  = {0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 
0x04};
+ static const u8 Tab_AM3CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
0x00};
+ static const u8 Tab_S1CLKDis[]  = {0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00};
++static const u8 Tab_C32CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
0x00};   /* Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */
++static const u8 Tab_G34CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 
0x00};   /* Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */
+ static const u8 Tab_ManualCLKDis[]= {0x10, 0x04, 0x08, 0x20, 0x00, 0x00, 
0x00, 0x00};
+ 
+ static const u8 Table_Comp_Rise_Slew_20x[] = {7, 3, 2, 2, 0xFF};
+@@ -277,6 +279,11 @@ restartinit:
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               struct DCTStatStruc *pDCTstat;
+               pDCTstat = pDCTstatA + Node;
++
++              /* Zero out data structures to avoid false detection of DIMMs */
++              memset(pDCTstat, 0, sizeof(struct DCTStatStruc));
++
++              /* Initialize data structures */
+               pDCTstat->Node_ID = Node;
+               pDCTstat->dev_host = PA_HOST(Node);
+               pDCTstat->dev_map = PA_MAP(Node);
+@@ -284,17 +291,22 @@ restartinit:
+               pDCTstat->dev_nbmisc = PA_NBMISC(Node);
+               pDCTstat->NodeSysBase = node_sys_base;
+ 
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node %d\n", 
Node);
+               mct_init(pMCTstat, pDCTstat);
+               mctNodeIDDebugPort_D();
+               pDCTstat->NodePresent = NodePresent_D(Node);
+               if (pDCTstat->NodePresent) {            /* See if Node is 
there*/
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
+                       clear_legacy_Mode(pMCTstat, pDCTstat);
+                       pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
+ 
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
+                       mct_InitialMCT_D(pMCTstat, pDCTstat);
+ 
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
+                       mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
+ 
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_initDCT\n");
+                       mct_initDCT(pMCTstat, pDCTstat);
+                       if (pDCTstat->ErrCode == SC_FatalErr) {
+                               goto fatalexit;         /* any fatal errors?*/
+@@ -345,6 +357,7 @@ restartinit:
+ 
+       mct_FinalMCT_D(pMCTstat, pDCTstatA);
+       printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", 
pMCTstat->GStatus);
++
+       return;
+ 
+ fatalexit:
+@@ -560,7 +573,6 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+               pDCTstat = pDCTstatA + Node;
+               devx = pDCTstat->dev_map;
+               DramSelBaseAddr = 0;
+-              pDCTstat = pDCTstatA + Node; /* ??? */
+               if (!pDCTstat->GangedMode) {
+                       DramSelBaseAddr = pDCTstat->NodeSysLimit - 
pDCTstat->DCTSysLimit;
+                       /*In unganged mode, we must add DCT0 and DCT1 to 
DCTSysLimit */
+@@ -645,6 +657,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+               devx = pDCTstat->dev_map;
+ 
+               if (pDCTstat->NodePresent) {
++                      printk(BIOS_DEBUG, " Copy dram map from Node 0 to Node 
%02x \n", Node);
+                       reg = 0x40;             /*Dram Base 0*/
+                       do {
+                               val = Get_NB32(dev, reg);
+@@ -1162,7 +1175,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ 
+       /* Program DRAM Timing values */
+       DramTimingLo = 0;       /* Dram Timing Low init */
+-      val = pDCTstat->CASL - 2; /* pDCTstat.CASL to reg. definition */
++      val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
+       DramTimingLo |= val;
+ 
+       val = pDCTstat->Trcd - Bias_TrcdT;
+@@ -1406,18 +1419,16 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+       else if (tCKproposed16x <= 24) {
+               pDCTstat->TargetFreq = 6;
+               tCKproposed16x = 24;
+-      }
+-      else if (tCKproposed16x <= 30) {
++      } else if (tCKproposed16x <= 30) {
+               pDCTstat->TargetFreq = 5;
+               tCKproposed16x = 30;
+-      }
+-      else {
++      } else {
+               pDCTstat->TargetFreq = 4;
+               tCKproposed16x = 40;
+       }
+       /* Running through this loop twice:
+          - First time find tCL at target frequency
+-         - Second tim find tCL at 400MHz */
++         - Second time find tCL at 400MHz */
+ 
+       for (;;) {
+               CLT_Fail = 0;
+@@ -1451,7 +1462,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+                       CLT_Fail = 1;
+               /* get CL and T */
+               if (!CLT_Fail) {
+-                      bytex = CLactual - 2;
++                      bytex = CLactual;
+                       if (tCKproposed16x == 20)
+                               byte = 7;
+                       else if (tCKproposed16x == 24)
+@@ -1632,7 +1643,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+               val = 0x0f; /* recommended setting (default) */
+       DramConfigHi |= val << 24;
+ 
+-      if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Bx))
++      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx))
+               DramConfigHi |= 1 << DcqArbBypassEn;
+ 
+       /* Build MemClkDis Value from Dram Timing Lo and
+@@ -1657,6 +1668,10 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+                               p = Tab_L1CLKDis;
+                       else if (byte == PT_M2 || byte == PT_AS)
+                               p = Tab_AM3CLKDis;
++                      else if (byte == PT_C3)
++                              p = Tab_C32CLKDis;
++                      else if (byte == PT_GR)
++                              p = Tab_G34CLKDis;
+                       else
+                               p = Tab_S1CLKDis;
+ 
+@@ -2102,8 +2117,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                               if (byte == JED_RDIMM || byte == JED_MiniRDIMM) 
{
+                                       RegDIMMPresent |= 1 << i;
+                                       pDCTstat->DimmRegistered[i] = 1;
+-                              }
+-                              else {
++                              } else {
+                                       pDCTstat->DimmRegistered[i] = 0;
+                               }
+                               /* Check ECC capable */
+@@ -2977,9 +2991,9 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+               } else {        /* For Dx CPU */
+                       val = 0x0CE00F00 | 1 << 29/* FlushWrOnStpGnt */;
+                       if (!(pDCTstat->GangedMode))
+-                              val |= 0x20; /* MctWrLimit =  8 for Unganed 
mode */
++                              val |= 0x20; /* MctWrLimit =  8 for Unganged 
mode */
+                       else
+-                              val |= 0x40; /* MctWrLimit =  16 for ganed mode 
*/
++                              val |= 0x40; /* MctWrLimit =  16 for ganged 
mode */
+                       Set_NB32(pDCTstat->dev_dct, 0x11C, val);
+ 
+                       val = Get_NB32(pDCTstat->dev_dct, 0x1B0);
+@@ -3414,6 +3428,138 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
+                       Set_NB32(dev,  0x98 + reg_off, 0x0D000030);
+                       Set_NB32(dev,  0x9C + reg_off, dword);
+                       Set_NB32(dev,  0x98 + reg_off, 0x4D040F30);
++
++                      /* FIXME
++                       * Mainboards need to be able to specify the maximum 
number of DIMMs installable per channel
++                       * For now assume a maximum of 2 DIMMs per channel can 
be installed
++                       */
++                      uint8_t MaxDimmsInstallable = 2;
++
++                      /* Obtain number of DIMMs on channel */
++                      uint8_t dimm_count = pDCTstat->MAdimms[i];
++                      uint8_t rank_count_dimm0;
++                      uint8_t rank_count_dimm1;
++                      uint32_t odt_pattern_0;
++                      uint32_t odt_pattern_1;
++                      uint32_t odt_pattern_2;
++                      uint32_t odt_pattern_3;
++
++                      /* Select appropriate ODT pattern for installed DIMMs
++                       * Refer to the BKDG Rev. 3.62, page 120 onwards
++                       */
++                      if 
(pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) {
++                              if (MaxDimmsInstallable == 2) {
++                                      if (dimm_count == 1) {
++                                              /* 1 DIMM detected */
++                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
++                                              if (rank_count_dimm1 == 1) {
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x00020000;
++                                              } else if (rank_count_dimm1 == 
2) {
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x02080000;
++                                              } else if (rank_count_dimm1 == 
4) {
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x020a0000;
++                                                      odt_pattern_3 = 
0x080a0000;
++                                              } else {
++                                                      /* Fallback */
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x00000000;
++                                              }
++                                      } else {
++                                              /* 2 DIMMs detected */
++                                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[0];
++                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
++                                              if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x01010202;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x09030603;
++                                              } else if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 == 4)) {
++                                                      odt_pattern_0 = 
0x01010000;
++                                                      odt_pattern_1 = 
0x01010a0a;
++                                                      odt_pattern_2 = 
0x01090000;
++                                                      odt_pattern_3 = 
0x01030e0b;
++                                              } else if ((rank_count_dimm0 == 
4) && (rank_count_dimm1 < 4)) {
++                                                      odt_pattern_0 = 
0x00000202;
++                                                      odt_pattern_1 = 
0x05050202;
++                                                      odt_pattern_2 = 
0x00000206;
++                                                      odt_pattern_3 = 
0x0d070203;
++                                              } else if ((rank_count_dimm0 == 
4) && (rank_count_dimm1 == 4)) {
++                                                      odt_pattern_0 = 
0x05050a0a;
++                                                      odt_pattern_1 = 
0x05050a0a;
++                                                      odt_pattern_2 = 
0x050d0a0e;
++                                                      odt_pattern_3 = 
0x05070a0b;
++                                              } else {
++                                                      /* Fallback */
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x00000000;
++                                              }
++                                      }
++                              } else {
++                                      /* FIXME
++                                       * 3 DIMMs per channel UNIMPLEMENTED
++                                       */
++                                      odt_pattern_0 = 0x00000000;
++                                      odt_pattern_1 = 0x00000000;
++                                      odt_pattern_2 = 0x00000000;
++                                      odt_pattern_3 = 0x00000000;
++                              }
++                      } else {
++                              if (MaxDimmsInstallable == 2) {
++                                      if (dimm_count == 1) {
++                                              /* 1 DIMM detected */
++                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
++                                              if (rank_count_dimm1 == 1) {
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x00020000;
++                                              } else if (rank_count_dimm1 == 
2) {
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x02080000;
++                                              } else {
++                                                      /* Fallback */
++                                                      odt_pattern_0 = 
0x00000000;
++                                                      odt_pattern_1 = 
0x00000000;
++                                                      odt_pattern_2 = 
0x00000000;
++                                                      odt_pattern_3 = 
0x00000000;
++                                              }
++                                      } else {
++                                              /* 2 DIMMs detected */
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x01010202;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x09030603;
++                                      }
++                              } else {
++                                      /* FIXME
++                                       * 3 DIMMs per channel UNIMPLEMENTED
++                                       */
++                                      odt_pattern_0 = 0x00000000;
++                                      odt_pattern_1 = 0x00000000;
++                                      odt_pattern_2 = 0x00000000;
++                                      odt_pattern_3 = 0x00000000;
++                              }
++                      }
++
++                      /* Program ODT pattern */
++                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x180, 
odt_pattern_1);
++                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x181, 
odt_pattern_0);
++                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x182, 
odt_pattern_3);
++                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x183, 
odt_pattern_2);
+               }
+       }
+ }
+@@ -3657,6 +3803,7 @@ static void mct_BeforeDQSTrain_D(struct MCTStatStruc 
*pMCTstat,
+       }
+ }
+ 
++/* Erratum 350 */
+ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+@@ -3692,11 +3839,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc 
*pMCTstat,
+                               mct_Read1LTestPattern_D(pMCTstat, pDCTstat, 
addr);      /* cache fills */
+ 
+                               /* Write 0000_8000h to register 
F2x[1,0]9C_xD080F0C */
+-                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0x4D080F0C, 0x00008000);
++                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00008000);
+                               mct_Wait(80); /* wait >= 300ns */
+ 
+                               /* Write 0000_0000h to register 
F2x[1,0]9C_xD080F0C */
+-                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0x4D080F0C, 0x00000000);
++                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00000000);
+                               mct_Wait(800); /* wait >= 2us */
+                               break;
+                       }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index e2d7aa8..219aa42 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -499,7 +499,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+               /* CHB DIMM0 Byte 0 - 7  TxDqs */
+               /* CHB DIMM1 Byte 0 - 7  TxDqs */
+               /* CHB DIMM1 Byte 0 - 7  TxDqs */
+-      u8 CH_D_B_RCVRDLY[2][4][8];     /* [A/B] [DIMM0-3] [DQS] */
++      u16 CH_D_B_RCVRDLY[2][4][8];    /* [A/B] [DIMM0-3] [DQS] */
+               /* CHA DIMM 0 Receiver Enable Delay*/
+               /* CHA DIMM 1 Receiver Enable Delay*/
+               /* CHA DIMM 2 Receiver Enable Delay*/
+@@ -509,7 +509,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+               /* CHB DIMM 1 Receiver Enable Delay*/
+               /* CHB DIMM 2 Receiver Enable Delay*/
+               /* CHB DIMM 3 Receiver Enable Delay*/
+-      u8 CH_D_BC_RCVRDLY[2][4];
++      u16 CH_D_BC_RCVRDLY[2][4];
+               /* CHA DIMM 0 - 4 Check Byte Receiver Enable Delay*/
+               /* CHB DIMM 0 - 4 Check Byte Receiver Enable Delay*/
+       u8 DIMMValidDCT[2];     /* DIMM# in DCT0*/
+@@ -769,7 +769,7 @@ u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass);
+ u32 SetupDqsPattern_1PassA(u8 Pass);
+ u32 SetupDqsPattern_1PassB(u8 Pass);
+ u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
+-u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 
RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
++u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, 
u16 RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
+ void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ u32 mctGetLogicalCPUID(u32 Node);
+@@ -779,7 +779,7 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTs
+ void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,struct DCTStatStruc 
*pDCTstatA);
+-void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 
FinalValue, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 
Pass);
++void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, u8 
FinalValue, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 
Pass);
+ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel);
+ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u32 dct);
+ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
+index 60f98bc..c40ea1a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -103,10 +104,10 @@ static void proc_CLFLUSH(u32 addr_hi)
+ 
+       __asm__ volatile (
+               /* clflush fs:[eax] */
+-              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
+-               "clflush %%fs:(%0)\n\t"
++              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
++              "clflush %%fs:(%0)\n\t"
+               "mfence\n\t"
+-               ::"a" (addr_hi<<8)
++              ::"a" (addr_hi<<8)
+       );
+ }
+ 
+@@ -141,6 +142,24 @@ static u32 read32_fs(u32 addr_lo)
+       return value;
+ }
+ 
++static uint64_t read64_fs(uint32_t addr_lo)
++{
++      uint64_t value = 0;
++      uint32_t value_lo;
++      uint32_t value_hi;
++
++      __asm__ volatile (
++              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
++              "mfence\n\t"
++              "movl %%fs:(%2), %0\n\t"
++              "movl %%fs:(%3), %1\n\t"
++              :"=c"(value_lo), "=d"(value_hi): "a" (addr_lo), "b" (addr_lo + 
4) : "memory"
++      );
++      value |= value_lo;
++      value |= ((uint64_t)value_hi) << 32;
++      return value;
++}
++
+ #ifdef UNUSED_CODE
+ static u8 read8_fs(u32 addr_lo)
+ {
+@@ -210,68 +229,6 @@ static __attribute__((noinline)) void 
FlushDQSTestPattern_L18(u32 addr_lo)
+       );
+ }
+ 
+-static void ReadL18TestPattern(u32 addr_lo)
+-{
+-      /* set fs and use fs prefix to access the mem */
+-      __asm__ volatile (
+-              "outb %%al, $0xed\n\t"                  /* _EXECFENCE */
+-              "movl %%fs:-128(%%esi), %%eax\n\t"      /* TestAddr cache line 
*/
+-              "movl %%fs:-64(%%esi), %%eax\n\t"       /* +1 */
+-              "movl %%fs:(%%esi), %%eax\n\t"          /* +2 */
+-              "movl %%fs:64(%%esi), %%eax\n\t"        /* +3 */
+-
+-              "movl %%fs:-128(%%edi), %%eax\n\t"      /* +4 */
+-              "movl %%fs:-64(%%edi), %%eax\n\t"       /* +5 */
+-              "movl %%fs:(%%edi), %%eax\n\t"          /* +6 */
+-              "movl %%fs:64(%%edi), %%eax\n\t"        /* +7 */
+-
+-              "movl %%fs:-128(%%ebx), %%eax\n\t"      /* +8 */
+-              "movl %%fs:-64(%%ebx), %%eax\n\t"       /* +9 */
+-              "movl %%fs:(%%ebx), %%eax\n\t"          /* +10 */
+-              "movl %%fs:64(%%ebx), %%eax\n\t"        /* +11 */
+-
+-              "movl %%fs:-128(%%ecx), %%eax\n\t"      /* +12 */
+-              "movl %%fs:-64(%%ecx), %%eax\n\t"       /* +13 */
+-              "movl %%fs:(%%ecx), %%eax\n\t"          /* +14 */
+-              "movl %%fs:64(%%ecx), %%eax\n\t"        /* +15 */
+-
+-              "movl %%fs:-128(%%edx), %%eax\n\t"      /* +16 */
+-              "movl %%fs:-64(%%edx), %%eax\n\t"       /* +17 */
+-              "mfence\n\t"
+-
+-               :: "a"(0), "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
+-                  "d" (addr_lo +128+16*64), "S"(addr_lo+128),
+-                  "D"(addr_lo+128+4*64)
+-      );
+-
+-}
+-
+-static void ReadL9TestPattern(u32 addr_lo)
+-{
+-
+-      /* set fs and use fs prefix to access the mem */
+-      __asm__ volatile (
+-              "outb %%al, $0xed\n\t"                  /* _EXECFENCE */
+-
+-              "movl %%fs:-128(%%ecx), %%eax\n\t"      /* TestAddr cache line 
*/
+-              "movl %%fs:-64(%%ecx), %%eax\n\t"       /* +1 */
+-              "movl %%fs:(%%ecx), %%eax\n\t"          /* +2 */
+-              "movl %%fs:64(%%ecx), %%eax\n\t"        /* +3 */
+-
+-              "movl %%fs:-128(%%edx), %%eax\n\t"      /* +4 */
+-              "movl %%fs:-64(%%edx), %%eax\n\t"       /* +5 */
+-              "movl %%fs:(%%edx), %%eax\n\t"          /* +6 */
+-              "movl %%fs:64(%%edx), %%eax\n\t"        /* +7 */
+-
+-              "movl %%fs:-128(%%ebx), %%eax\n\t"      /* +8 */
+-              "mfence\n\t"
+-
+-               :: "a"(0), "b" (addr_lo+128+8*64), "c"(addr_lo+128),
+-                  "d"(addr_lo+128+4*64)
+-      );
+-
+-}
+-
+ static void ReadMaxRdLat1CLTestPattern_D(u32 addr)
+ {
+       SetUpperFSbase(addr);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
+index ae1654c..99a2628 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -17,7 +18,7 @@
+  * Foundation, Inc.
+  */
+ 
+-/* The socket type F (1207), Fr2, G (1207) are not tested.
++/* The socket type Fr2, G (1207) are not tested.
+  */
+ 
+ static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
+@@ -79,8 +80,7 @@ static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 
MAAload,
+                       else
+                               *AddrTmgCTL = 0x00353935;
+               }
+-      }
+-      else {
++      } else {
+               if(Speed == 4) {
+                       *AddrTmgCTL = 0x00000000;
+                       if (MAAdimms == 3)
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index 404727b..cc2f43a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -22,13 +23,6 @@ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
+                               u8 scale, u8 ChipSel);
+ static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 ChipSel);
+-static u8 MiddleDQS_D(u8 min, u8 max);
+-static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat,
+-                              u8 cs_start);
+-static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat,
+-                              u8 cs_start);
+ static void WriteDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u32 TestAddr_lo);
+@@ -43,31 +37,19 @@ static void FlushDQSTestPattern_D(struct DCTStatStruc 
*pDCTstat,
+                                       u32 addr_lo);
+ static void SetTargetWTIO_D(u32 TestAddr);
+ static void ResetTargetWTIO_D(void);
+-static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat,
+-                                      u32 TestAddr_lo);
+-static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
+-                                      u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
+ void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index);
+ u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat,
+                                       u8 ChipSel);
+-static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat,
+-                                      u8 cs_start);
+ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel,
+                               u8 receiver, u8 *valid);
+ static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u32 *buffer);
+-
+-static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
+-                                    u8 RnkDlyFilterMin, u8 RnkDlyFilterMax);
++static void proc_IOCLFLUSH_D(u32 addr_hi);
+ 
+ static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, u8 ChipSel);
+ 
+@@ -286,20 +268,99 @@ static void CalcEccDQSPos_D(struct MCTStatStruc 
*pMCTstat,
+       pDCTstat->DQSDelay = (u8)DQSDelay;
+ }
+ 
++static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
++{
++      uint32_t dword;
++
++      /* Lanes 0 - 3 */
++      dword = Get_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8));
++      dword &= ~0x7f7f7f7f;
++      dword |= (delay[3] & 0x7f) << 24;
++      dword |= (delay[2] & 0x7f) << 16;
++      dword |= (delay[1] & 0x7f) << 8;
++      dword |= delay[0] & 0x7f;
++      Set_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8), dword);
++
++      /* Lanes 4 - 7 */
++      dword = Get_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8));
++      dword &= ~0x7f7f7f7f;
++      dword |= (delay[7] & 0x7f) << 24;
++      dword |= (delay[6] & 0x7f) << 16;
++      dword |= (delay[5] & 0x7f) << 8;
++      dword |= delay[4] & 0x7f;
++      Set_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8), dword);
++
++      /* Lane 8 (ECC) */
++      dword = Get_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8));
++      dword &= ~0x0000007f;
++      dword |= delay[8] & 0x7f;
++      Set_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8), dword);
++}
++
++static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
++{
++      uint32_t dword;
++
++      /* Lanes 0 - 3 */
++      dword = Get_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8));
++      dword &= ~0x3f3f3f3f;
++      dword |= (delay[3] & 0x3f) << 24;
++      dword |= (delay[2] & 0x3f) << 16;
++      dword |= (delay[1] & 0x3f) << 8;
++      dword |= delay[0] & 0x3f;
++      Set_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8), dword);
++
++      /* Lanes 4 - 7 */
++      dword = Get_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8));
++      dword &= ~0x3f3f3f3f;
++      dword |= (delay[7] & 0x3f) << 24;
++      dword |= (delay[6] & 0x3f) << 16;
++      dword |= (delay[5] & 0x3f) << 8;
++      dword |= delay[4] & 0x3f;
++      Set_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8), dword);
++
++      /* Lane 8 (ECC) */
++      dword = Get_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8));
++      dword &= ~0x0000003f;
++      dword |= delay[8] & 0x3f;
++      Set_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8), dword);
++}
++
++/* DQS Position Training
++ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.3
++ */
+ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat,
+-                              u8 cs_start)
++                              struct DCTStatStruc *pDCTstat)
+ {
+       u32 Errors;
+-      u8 Channel, DQSWrDelay;
++      u8 Channel;
++      u8 Receiver;
+       u8 _DisableDramECC = 0;
+-      u32 PatternBuffer[292];
++      u32 PatternBuffer[304]; /* 288 + 16 */
+       u8 _Wrap32Dis = 0, _SSE2 = 0;
+-      u8 dqsWrDelay_end;
+ 
++      u32 dev;
+       u32 addr;
++      u8 valid;
+       u32 cr4;
+       u32 lo, hi;
++      u32 index_reg;
++      uint32_t TestAddr;
++
++      uint8_t dual_rank;
++      uint8_t iter;
++      uint8_t lane;
++      uint16_t bytelane_test_results;
++      uint16_t current_write_dqs_delay[MAX_BYTE_LANES];
++      uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
++      uint16_t write_dqs_delay_stepping_done[MAX_BYTE_LANES];
++      uint8_t dqs_read_results_array[2][MAX_BYTE_LANES][64];          /* 
[rank][lane][step] */
++      uint8_t dqs_write_results_array[2][MAX_BYTE_LANES][128];        /* 
[rank][lane][step] */
++
++      uint8_t last_pos = 0;
++      uint8_t cur_count = 0;
++      uint8_t best_pos = 0;
++      uint8_t best_count = 0;
+ 
+       print_debug_dqs("\nTrainDQSRdWrPos: Node_ID ", pDCTstat->Node_ID, 0);
+       cr4 = read_cr4();
+@@ -323,50 +384,363 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+       SetupDqsPattern_D(pMCTstat, pDCTstat, PatternBuffer);
+ 
+       /* mct_BeforeTrainDQSRdWrPos_D */
+-      dqsWrDelay_end = 0x20;
++
++      dev = pDCTstat->dev_dct;
++      pDCTstat->Direction = DQS_READDIR;
++
++      /* 2.8.9.9.3 (2)
++       * Loop over each channel, lane, and rank
++       */
++
++      /* NOTE
++       * The BKDG originally stated to iterate over lane, then rank, however 
this process is quite slow
++       * compared to an equivalent loop over rank, then lane as the latter 
allows multiple lanes to be
++       * tested simultaneously, thus improving performance by around 8x.
++       */
+ 
+       Errors = 0;
+       for (Channel = 0; Channel < 2; Channel++) {
+-              print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ",Channel, 1);
++              print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ", Channel, 1);
+               pDCTstat->Channel = Channel;
+ 
+               if (pDCTstat->DIMMValidDCT[Channel] == 0)       /* 
mct_BeforeTrainDQSRdWrPos_D */
+                       continue;
+-              pDCTstat->DqsRdWrPos_Saved = 0;
+-              for ( DQSWrDelay = 0; DQSWrDelay < dqsWrDelay_end; 
DQSWrDelay++) {
+-                      pDCTstat->DQSDelay = DQSWrDelay;
+-                      pDCTstat->Direction = DQS_WRITEDIR;
+-                      mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
+-
+-                      print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DQSWrDelay ", 
DQSWrDelay, 2);
+-                      TrainReadDQS_D(pMCTstat, pDCTstat, cs_start);
+-                      print_debug_dqs("\t\tTrainDQSRdWrPos: 21 
DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 2);
+-                      if (pDCTstat->DqsRdWrPos_Saved == 0xFF)
+-                              break;
+-
+-                      print_debug_dqs("\t\tTrainDQSRdWrPos: 22 TrainErrors 
",pDCTstat->TrainErrors, 2);
+-                      if (pDCTstat->TrainErrors == 0) {
++
++              index_reg = 0x98 + 0x100 * Channel;
++
++              dual_rank = 0;
++              Receiver = mct_InitReceiver_D(pDCTstat, Channel);
++              /* There are four receiver pairs, loosely associated with 
chipselects.
++              * This is essentially looping over each rank of each DIMM.
++              */
++              for (; Receiver < 8; Receiver++) {
++                      if ((Receiver & 0x1) == 0) {
++                              /* Even rank of DIMM */
++                              if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, 
Channel, Receiver+1))
++                                      dual_rank = 1;
++                              else
++                                      dual_rank = 0;
++                      }
++
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
++                              continue;
++                      }
++
++                      /* Select the base test address for the current rank */
++                      TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, 
Channel, Receiver, &valid);
++                      if (!valid) {   /* Address not supported on current CS 
*/
++                              continue;
++                      }
++
++                      print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 14 TestAddr 
", TestAddr, 4);
++                      SetUpperFSbase(TestAddr);       /* fs:eax=far ptr to 
target */
++
++                      print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 12 Receiver 
", Receiver, 2);
++
++                      /* 2.8.9.9.3 (DRAM Write Data Timing Loop)
++                       * Iterate over all possible DQS delay values (0x0 - 
0x7f)
++                       */
++                      uint8_t test_write_dqs_delay = 0;
++                      uint8_t test_read_dqs_delay = 0;
++                      uint8_t passing_dqs_delay_found[MAX_BYTE_LANES];
++
++                      /* Initialize variables */
++                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                              current_write_dqs_delay[lane] = 0;
++                              passing_dqs_delay_found[lane] = 0;
++                              write_dqs_delay_stepping_done[lane] = 0;
++                      }
++
++                      for (test_write_dqs_delay = 0; test_write_dqs_delay < 
128; test_write_dqs_delay++) {
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 16 
test_write_dqs_delay ", test_write_dqs_delay, 6);
++
++                              /* Break out of loop if passing window already 
found, */
++                              if (write_dqs_delay_stepping_done[0] && 
write_dqs_delay_stepping_done[1]
++                                      && write_dqs_delay_stepping_done[2] && 
write_dqs_delay_stepping_done[3]
++                                      && write_dqs_delay_stepping_done[4] && 
write_dqs_delay_stepping_done[5]
++                                      && write_dqs_delay_stepping_done[6] && 
write_dqs_delay_stepping_done[7])
+                                       break;
++
++                              /* Commit the current Write Data Timing 
settings to the hardware registers */
++                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
++
++                              /* Write the DRAM training pattern to the base 
test address */
++                              WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
++
++                              /* 2.8.9.9.3 (DRAM Read DQS Timing Control Loop)
++                               * Iterate over all possible DQS delay values 
(0x0 - 0x3f)
++                               */
++                              for (test_read_dqs_delay = 0; 
test_read_dqs_delay < 64; test_read_dqs_delay++) {
++                                      
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 test_read_dqs_delay ", 
test_read_dqs_delay, 6);
++
++                                      /* Initialize Read DQS Timing Control 
settings for this iteration */
++                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++)
++                                              if 
(!write_dqs_delay_stepping_done[lane])
++                                                      
current_read_dqs_delay[lane] = test_read_dqs_delay;
++
++                                      /* Commit the current Read DQS Timing 
Control settings to the hardware registers */
++                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
++
++                                      /* Initialize test result variable */
++                                      bytelane_test_results = 0xff;
++
++                                      /* Read the DRAM training pattern from 
the base test address three times
++                                       * NOTE
++                                       * While the BKDG states to read three 
times this is probably excessive!
++                                       * Decrease training time by only 
reading the test pattern once per iteration
++                                       */
++                                      for (iter = 0; iter < 1; iter++) {
++                                              /* Flush caches */
++                                              SetTargetWTIO_D(TestAddr);
++                                              FlushDQSTestPattern_D(pDCTstat, 
TestAddr << 8);
++                                              ResetTargetWTIO_D();
++
++                                              /* Read and compare pattern */
++                                              bytelane_test_results &= 
(CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8) & 0xff); /* [Lane 7 
:: Lane 0] 0=fail, 1=pass */
++
++                                              /* If all lanes have already 
failed testing bypass remaining re-read attempt(s) */
++                                              if (bytelane_test_results == 
0x0)
++                                                      break;
++                                      }
++
++                                      /* Store any lanes that passed testing 
for later use */
++                                      for (lane = 0; lane < 8; lane++)
++                                              if 
(!write_dqs_delay_stepping_done[lane])
++                                                      
dqs_read_results_array[Receiver & 0x1][lane][test_read_dqs_delay] = 
(!!(bytelane_test_results & (1 << lane)));
++
++                                      
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 162 bytelane_test_results ", 
bytelane_test_results, 6);
++                              }
++
++                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                                      if (write_dqs_delay_stepping_done[lane])
++                                              continue;
++
++                                      /* Determine location and length of 
longest consecutive string of passing values
++                                       * Output is stored in best_pos and 
best_count
++                                       */
++                                      last_pos = 0;
++                                      cur_count = 0;
++                                      best_pos = 0;
++                                      best_count = 0;
++                                      for (iter = 0; iter < 64; iter++) {
++                                              if 
((dqs_read_results_array[Receiver & 0x1][lane][iter]) && (iter < 63)) {
++                                                      /* Pass */
++                                                      cur_count++;
++                                              } else {
++                                                      /* Failure or end of 
loop */
++                                                      if (cur_count > 
best_count) {
++                                                              best_count = 
cur_count;
++                                                              best_pos = 
last_pos;
++                                                      }
++                                                      cur_count = 0;
++                                                      last_pos = iter;
++                                              }
++                                      }
++
++                                      if (best_count > 2) {
++                                              /* Exit the DRAM Write Data 
Timing Loop after programming the Read DQS Timing Control
++                                               * register with the center of 
the passing window
++                                               */
++                                              current_read_dqs_delay[lane] = 
(best_pos + (best_count / 2));
++                                              passing_dqs_delay_found[lane] = 
1;
++
++                                              /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
++                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
++
++                                              /* Exit the DRAM Write Data 
Timing Loop */
++                                              
write_dqs_delay_stepping_done[lane] = 1;
++
++                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 largest passing region ", 
best_count, 4);
++                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 largest passing region start ", 
best_pos, 4);
++                                      }
++
++                                      /* Increment the DQS Write Delay value 
if needed for the next DRAM Write Data Timing Loop iteration */
++                                      if 
(!write_dqs_delay_stepping_done[lane])
++                                              current_write_dqs_delay[lane]++;
++                              }
+                       }
+-                      Errors |= pDCTstat->TrainErrors;
+-              }
+ 
+-              pDCTstat->DqsRdWrPos_Saved = 0;
+-              if (DQSWrDelay < dqsWrDelay_end) {
+-                      Errors = 0;
++                      /* Flag failure(s) if present */
++                      for (lane = 0; lane < 8; lane++) {
++                              if (!passing_dqs_delay_found[lane]) {
++                                      
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 121 Unable to find passing region for 
lane ", lane, 2);
++
++                                      /* Flag absence of passing window */
++                                      Errors |= 1 << SB_NODQSPOS;
++                              }
++                      }
++
++                      /* Iterate over all possible Write Data Timing values 
(0x0 - 0x7f)
++                       * Note that the Read DQS Timing Control was calibrated 
/ centered in the prior nested loop
++                       */
++                      for (test_write_dqs_delay = 0; test_write_dqs_delay < 
128; test_write_dqs_delay++) {
++                              /* Initialize Write Data Timing settings for 
this iteration */
++                              for (lane = 0; lane < MAX_BYTE_LANES; lane++)
++                                      current_write_dqs_delay[lane] = 
test_write_dqs_delay;
++
++                              /* Commit the current Write Data Timing 
settings to the hardware registers */
++                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
++
++                              /* Write the DRAM training pattern to the base 
test address */
++                              WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
++
++                              /* Flush caches */
++                              SetTargetWTIO_D(TestAddr);
++                              FlushDQSTestPattern_D(pDCTstat, TestAddr << 8);
++                              ResetTargetWTIO_D();
++
++                              /* Read and compare pattern from the base test 
address */
++                              bytelane_test_results = 
(CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8) & 0xff); /* [Lane 7 
:: Lane 0] 0=fail, 1=pass */
++
++                              /* Store any lanes that passed testing for 
later use */
++                              for (lane = 0; lane < 8; lane++)
++                                      dqs_write_results_array[Receiver & 
0x1][lane][test_write_dqs_delay] = (!!(bytelane_test_results & (1 << lane)));
++                      }
++
++                      for (lane = 0; lane < 8; lane++) {
++                              if ((!dual_rank) || (dual_rank && (Receiver & 
0x1))) {
++
++#ifdef PRINT_PASS_FAIL_BITMAPS
++                                      for (iter = 0; iter < 64; iter++) {
++                                              if 
(dqs_read_results_array[0][lane][iter])
++                                                      printk(BIOS_DEBUG, "+");
++                                              else
++                                                      printk(BIOS_DEBUG, ".");
++                                      }
++                                      printk(BIOS_DEBUG, "\n");
++                                      for (iter = 0; iter < 64; iter++) {
++                                              if 
(dqs_read_results_array[1][lane][iter])
++                                                      printk(BIOS_DEBUG, "+");
++                                              else
++                                                      printk(BIOS_DEBUG, ".");
++                                      }
++                                      printk(BIOS_DEBUG, "\n\n");
++                                      for (iter = 0; iter < 128; iter++) {
++                                              if 
(dqs_write_results_array[0][lane][iter])
++                                                      printk(BIOS_DEBUG, "+");
++                                              else
++                                                      printk(BIOS_DEBUG, ".");
++                                      }
++                                      printk(BIOS_DEBUG, "\n");
++                                      for (iter = 0; iter < 128; iter++) {
++                                              if 
(dqs_write_results_array[1][lane][iter])
++                                                      printk(BIOS_DEBUG, "+");
++                                              else
++                                                      printk(BIOS_DEBUG, ".");
++                                      }
++                                      printk(BIOS_DEBUG, "\n\n");
++#endif
++
++                                      /* Base rank of single-rank DIMM, or 
odd rank of dual-rank DIMM */
++                                      if (dual_rank) {
++                                              /* Intersect the passing 
windows of both ranks */
++                                              for (iter = 0; iter < 64; 
iter++)
++                                                      if 
(!dqs_read_results_array[1][lane][iter])
++                                                              
dqs_read_results_array[0][lane][iter] = 0;
++                                              for (iter = 0; iter < 128; 
iter++)
++                                                      if 
(!dqs_write_results_array[1][lane][iter])
++                                                              
dqs_write_results_array[0][lane][iter] = 0;
++                                      }
++
++                                      /* Determine location and length of 
longest consecutive string of passing values for read DQS timing
++                                       * Output is stored in best_pos and 
best_count
++                                       */
++                                      last_pos = 0;
++                                      cur_count = 0;
++                                      best_pos = 0;
++                                      best_count = 0;
++                                      for (iter = 0; iter < 64; iter++) {
++                                              if 
((dqs_read_results_array[0][lane][iter]) && (iter < 63)) {
++                                                      /* Pass */
++                                                      cur_count++;
++                                              } else {
++                                                      /* Failure or end of 
loop */
++                                                      if (cur_count > 
best_count) {
++                                                              best_count = 
cur_count;
++                                                              best_pos = 
last_pos;
++                                                      }
++                                                      cur_count = 0;
++                                                      last_pos = iter;
++                                              }
++                                      }
++                                      
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 largest read passing region ", 
best_count, 4);
++                                      if (best_count > 0) {
++                                              if (best_count < MIN_DQS_WNDW) {
++                                                      /* Flag excessively 
small passing window */
++                                                      Errors |= 1 << 
SB_SMALLDQS;
++                                              }
++
++                                              /* Find the center of the 
passing window */
++                                              current_read_dqs_delay[lane] = 
(best_pos + (best_count / 2));
++
++                                              /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
++                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
++
++                                              /* Save the final Read DQS 
Timing Control settings for later use */
++                                              
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_READDIR][lane] = 
current_read_dqs_delay[lane];
++                                      } else {
++                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 122 Unable to find read passing 
region for lane ", lane, 2);
++
++                                              /* Flag absence of passing 
window */
++                                              Errors |= 1 << SB_NODQSPOS;
++                                      }
++
++                                      /* Determine location and length of 
longest consecutive string of passing values for write DQS timing
++                                       * Output is stored in best_pos and 
best_count
++                                       */
++                                      last_pos = 0;
++                                      cur_count = 0;
++                                      best_pos = 0;
++                                      best_count = 0;
++                                      for (iter = 0; iter < 128; iter++) {
++                                              if 
((dqs_write_results_array[0][lane][iter]) && (iter < 127)) {
++                                                      /* Pass */
++                                                      cur_count++;
++                                              } else {
++                                                      /* Failure or end of 
loop */
++                                                      if (cur_count > 
best_count) {
++                                                              best_count = 
cur_count;
++                                                              best_pos = 
last_pos;
++                                                      }
++                                                      cur_count = 0;
++                                                      last_pos = iter;
++                                              }
++                                      }
++                                      
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 largest write passing region ", 
best_count, 4);
++                                      if (best_count > 0) {
++                                              if (best_count < MIN_DQS_WNDW) {
++                                                      /* Flag excessively 
small passing window */
++                                                      Errors |= 1 << 
SB_SMALLDQS;
++                                              }
++
++                                              /* Find the center of the 
passing window */
++                                              current_write_dqs_delay[lane] = 
(best_pos + (best_count / 2));
++
++                                              /* Commit the current Write 
Data Timing settings to the hardware registers */
++                                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
++
++                                              /* Save the final Write Data 
Timing settings for later use */
++                                              
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_WRITEDIR][lane] = 
current_write_dqs_delay[lane];
++                                      } else {
++                                              
print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 123 Unable to find write passing 
region for lane ", lane, 2);
++
++                                              /* Flag absence of passing 
window */
++                                              Errors |= 1 << SB_NODQSPOS;
++                                      }
++                              }
++                      }
+ 
+-                      print_debug_dqs("\tTrainDQSRdWrPos: 231 DQSWrDelay ", 
DQSWrDelay, 1);
+-                      TrainWriteDQS_D(pMCTstat, pDCTstat, cs_start);
+               }
+-              print_debug_dqs("\tTrainDQSRdWrPos: 232 Errors ", Errors, 1);
+-              pDCTstat->ErrStatus |= Errors;
+       }
+ 
++      pDCTstat->TrainErrors |= Errors;
++      pDCTstat->ErrStatus |= Errors;
++
+ #if DQS_TRAIN_DEBUG > 0
+       {
+               u8 val;
+               u8 i;
+-              u8 Channel, Receiver, Dir;
++              u8 ChannelDTD, ReceiverDTD, Dir;
+               u8 *p;
+ 
+               for (Dir = 0; Dir < 2; Dir++) {
+@@ -375,14 +749,14 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+                       } else {
+                               printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS RD:\n");
+                       }
+-                      for (Channel = 0; Channel < 2; Channel++) {
+-                              printk(BIOS_DEBUG, "Channel: %02x\n", Channel);
+-                              for (Receiver = cs_start; Receiver < (cs_start 
+ 2); Receiver += 2) {
+-                                      printk(BIOS_DEBUG, "\t\tReceiver: %02x: 
", Receiver);
+-                                      p = 
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][Dir];
++                      for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
++                              printk(BIOS_DEBUG, "Channel: %02x\n", 
ChannelDTD);
++                              for (ReceiverDTD = 0; ReceiverDTD < 
MAX_CS_SUPPORTED; ReceiverDTD += 2) {
++                                      printk(BIOS_DEBUG, "\t\tReceiver: 
%02x:", ReceiverDTD);
++                                      p = 
pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
+                                       for (i=0;i<8; i++) {
+                                               val  = p[i];
+-                                              printk(BIOS_DEBUG, "%02x ", 
val);
++                                              printk(BIOS_DEBUG, " %02x", 
val);
+                                       }
+                                       printk(BIOS_DEBUG, "\n");
+                               }
+@@ -437,225 +811,6 @@ static void SetupDqsPattern_D(struct MCTStatStruc 
*pMCTstat,
+       pDCTstat->PtrPatternBufA = (u32)buf;
+ }
+ 
+-static void TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat,
+-                              u8 cs_start)
+-{
+-      u32 Errors;
+-      u8 ChipSel, DQSDelay;
+-      u8 RnkDlySeqPassMin=0, RnkDlySeqPassMax=0xFF, RnkDlyFilterMin=0, 
RnkDlyFilterMax=0xFF;
+-      u8 RnkDlySeqPassMinTot=0, RnkDlySeqPassMaxTot=0xFF, 
RnkDlyFilterMinTot=0, RnkDlyFilterMaxTot=0xFF;
+-      u8 LastTest ,LastTestTot;
+-      u32 TestAddr;
+-      u8 ByteLane;
+-      u8 MutualCSPassW[128];
+-      u8 BanksPresent;
+-      u8 dqsDelay_end;
+-      u8 tmp, valid, tmp1;
+-      u16 word;
+-
+-      /* MutualCSPassW: each byte represents a bitmap of pass/fail per
+-       * ByteLane.  The indext within MutualCSPassW is the delay value
+-       * given the results.
+-       */
+-      print_debug_dqs("\t\t\tTrainDQSPos begin ", 0, 3);
+-
+-      Errors = 0;
+-      BanksPresent = 0;
+-
+-      dqsDelay_end = 32;
+-      /* Bitmapped status per delay setting, 0xff=All positions
+-       * passing (1= PASS). Set the entire array.
+-       */
+-      for (DQSDelay=0; DQSDelay<128; DQSDelay++) {
+-              MutualCSPassW[DQSDelay] = 0xFF;
+-      }
+-
+-      for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) { /* 
logical register chipselects 0..7 */
+-              print_debug_dqs("\t\t\t\tTrainDQSPos: 11 ChipSel ", ChipSel, 4);
+-
+-              if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, 
pDCTstat->Channel, ChipSel)) {
+-                      print_debug_dqs("\t\t\t\tmct_RcvrRankEnabled_D CS not 
enabled ", ChipSel, 4);
+-                      continue;
+-              }
+-
+-              BanksPresent = 1;       /* flag for at least one bank is 
present */
+-              TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, 
pDCTstat->Channel, ChipSel, &valid);
+-              if (!valid) {
+-                      print_debug_dqs("\t\t\t\tAddress not supported on 
current CS ", TestAddr, 4);
+-                      continue;
+-              }
+-
+-              print_debug_dqs("\t\t\t\tTrainDQSPos: 12 TestAddr ", TestAddr, 
4);
+-              SetUpperFSbase(TestAddr);       /* fs:eax=far ptr to target */
+-
+-              if (pDCTstat->Direction == DQS_READDIR) {
+-                      print_debug_dqs("\t\t\t\tTrainDQSPos: 13 for read ", 0, 
4);
+-                      WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 
8);
+-              }
+-
+-              for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) {
+-                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 141 DQSDelay ", 
DQSDelay, 5);
+-
+-                      tmp = 0xFF;
+-                      tmp1 = DQSDelay;
+-                      if (pDCTstat->Direction == DQS_READDIR) {
+-                              tmp &= MutualCSPassW[DQSDelay];
+-                              tmp1 += dqsDelay_end;
+-                      }
+-                      tmp &= MutualCSPassW[tmp1];
+-
+-                      if (tmp == 0) {
+-                              continue;/* skip current delay value if other 
chipselects have failed all 8 bytelanes */
+-                      }
+-
+-                      pDCTstat->DQSDelay = DQSDelay;
+-                      mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start);
+-                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 142 
MutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+-
+-                      if (pDCTstat->Direction == DQS_WRITEDIR) {
+-                              print_debug_dqs("\t\t\t\t\tTrainDQSPos: 143 for 
write", 0, 5);
+-                              WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
+-                      }
+-
+-                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 Pattern ", 
pDCTstat->Pattern, 5);
+-                      ReadDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8);
+-                      /* print_debug_dqs("\t\t\t\t\tTrainDQSPos: 145 
MutualCSPassW ", MutualCSPassW[DQSDelay], 5); */
+-                      word = CompareDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8); /* 0=fail, 1=pass */
+-                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 1 
", word, 3);
+-
+-                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 
DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 3);
+-                      word &= ~(pDCTstat->DqsRdWrPos_Saved); /* mask out 
bytelanes that already passed */
+-                      word &= ~(pDCTstat->DqsRdWrPos_Saved << 8);
+-                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 2 
", word, 3);
+-
+-                      tmp = DQSDelay;
+-                      if (pDCTstat->Direction == DQS_READDIR) {
+-                              MutualCSPassW[tmp] &= word >> 8;
+-                              tmp += dqsDelay_end;
+-                      }
+-                      MutualCSPassW[tmp] &= word & 0xFF;
+-
+-                      print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 
\tMutualCSPassW ", MutualCSPassW[DQSDelay], 5);
+-
+-                      SetTargetWTIO_D(TestAddr);
+-                      FlushDQSTestPattern_D(pDCTstat, TestAddr << 8);
+-                      ResetTargetWTIO_D();
+-              }
+-
+-      }
+-
+-      if (pDCTstat->Direction == DQS_READDIR) {
+-              dqsDelay_end <<= 1;
+-      }
+-
+-      if (BanksPresent) {
+-              #if 0           /* show the bitmap */
+-              for (ByteLane = 0; ByteLane < 8; ByteLane++) { /* just print 
ByteLane 0 */
+-                      for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) 
{
+-                              if (!(MutualCSPassW[DQSDelay] &(1 << 
ByteLane))) {
+-                                      printk(BIOS_DEBUG, ".");
+-                              } else {
+-                                      printk(BIOS_DEBUG, "*");
+-                              }
+-                      }
+-                      printk(BIOS_DEBUG, "\n");
+-              }
+-              #endif
+-              for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+-                      print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane 
",ByteLane, 4);
+-                      if (!(pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane))) {
+-                              pDCTstat->ByteLane = ByteLane;
+-                              LastTest = DQS_FAIL;            /* Analyze the 
results */
+-                              LastTestTot = DQS_FAIL;
+-                              /* RnkDlySeqPassMin = 0; */
+-                              /* RnkDlySeqPassMax = 0; */
+-                              RnkDlyFilterMax = 0;
+-                              RnkDlyFilterMin = 0;
+-                              RnkDlyFilterMaxTot = 0;
+-                              RnkDlyFilterMinTot = 0;
+-                              for (DQSDelay = 0; DQSDelay < dqsDelay_end; 
DQSDelay++) {
+-                                      if (MutualCSPassW[DQSDelay] & (1 << 
ByteLane)) {
+-                                              
print_debug_dqs("\t\t\t\t\tTrainDQSPos: 321 DQSDelay ", DQSDelay, 5);
+-                                              
print_debug_dqs("\t\t\t\t\tTrainDQSPos: 322 MutualCSPassW ", 
MutualCSPassW[DQSDelay], 5);
+-                                              if (pDCTstat->Direction == 
DQS_READDIR)
+-                                                      tmp = 0x20;
+-                                              else
+-                                                      tmp = 0;
+-                                              if (DQSDelay >= tmp) {
+-                                                      RnkDlySeqPassMax = 
DQSDelay;
+-                                                      if (LastTest == 
DQS_FAIL) {
+-                                                              
RnkDlySeqPassMin = DQSDelay; /* start sequential run */
+-                                                      }
+-                                                      if ((RnkDlySeqPassMax - 
RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)){
+-                                                              RnkDlyFilterMin 
= RnkDlySeqPassMin;
+-                                                              RnkDlyFilterMax 
= RnkDlySeqPassMax;
+-                                                      }
+-                                                      LastTest = DQS_PASS;
+-                                              }
+-
+-                                              if (pDCTstat->Direction == 
DQS_READDIR) {
+-                                                      RnkDlySeqPassMaxTot = 
DQSDelay;
+-                                                      if (LastTestTot == 
DQS_FAIL)
+-                                                              
RnkDlySeqPassMinTot = DQSDelay;
+-                                                      if 
((RnkDlySeqPassMaxTot - 
RnkDlySeqPassMinTot)>(RnkDlyFilterMaxTot-RnkDlyFilterMinTot)){
+-                                                              
RnkDlyFilterMinTot = RnkDlySeqPassMinTot;
+-                                                              
RnkDlyFilterMaxTot = RnkDlySeqPassMaxTot;
+-                                                      }
+-                                                      LastTestTot = DQS_PASS;
+-                                              }
+-                                      } else {
+-                                              LastTest = DQS_FAIL;
+-                                              LastTestTot = DQS_FAIL;
+-                                      }
+-                              }
+-                              print_debug_dqs("\t\t\t\tTrainDQSPos: 33 
RnkDlySeqPassMax ", RnkDlySeqPassMax, 4);
+-                              if (RnkDlySeqPassMax == 0) {
+-                                      Errors |= 1 << SB_NODQSPOS; /* no 
passing window */
+-                              } else {
+-                                      
print_debug_dqs_pair("\t\t\t\tTrainDQSPos: 34 RnkDlyFilter: ", RnkDlyFilterMin, 
" ",  RnkDlyFilterMax, 4);
+-                                      if (((RnkDlyFilterMax - 
RnkDlyFilterMin) < MIN_DQS_WNDW)){
+-                                              Errors |= 1 << SB_SMALLDQS;
+-                                      } else {
+-                                              u8 middle_dqs;
+-                                              /* mctEngDQSwindow_Save_D Not 
required for arrays */
+-                                              if (pDCTstat->Direction == 
DQS_READDIR)
+-                                                      middle_dqs = 
MiddleDQS_D(RnkDlyFilterMinTot, RnkDlyFilterMaxTot);
+-                                              else
+-                                                      middle_dqs = 
MiddleDQS_D(RnkDlyFilterMin, RnkDlyFilterMax);
+-                                              pDCTstat->DQSDelay = middle_dqs;
+-                                              mct_SetDQSDelayCSR_D(pMCTstat, 
pDCTstat, cs_start);  /* load the register with the value */
+-                                              if (pDCTstat->Direction == 
DQS_READDIR)
+-                                                      
StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMinTot, 
RnkDlyFilterMaxTot); /* store the value into the data structure */
+-                                              else
+-                                                      
StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMin, 
RnkDlyFilterMax); /* store the value into the data structure */
+-                                              
print_debug_dqs("\t\t\t\tTrainDQSPos: 42 middle_dqs : ",middle_dqs, 4);
+-                                              pDCTstat->DqsRdWrPos_Saved |= 1 
<< ByteLane;
+-                                      }
+-                              }
+-                      }
+-              } /* if (pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane)) */
+-      }
+-/* skipLocMiddle: */
+-      pDCTstat->TrainErrors = Errors;
+-
+-      print_debug_dqs("\t\t\tTrainDQSPos: Errors ", Errors, 3);
+-}
+-
+-static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
+-                                      u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
+-{
+-      pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
+-              [pDCTstat->Direction]
+-              [0]
+-              [pDCTstat->ByteLane] = RnkDlyFilterMin;
+-      pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel]
+-              [pDCTstat->Direction]
+-              [1]
+-              [pDCTstat->ByteLane] = RnkDlyFilterMax;
+-}
+-
+ static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 
ChipSel)
+ {
+@@ -679,26 +834,6 @@ static void StoreDQSDatStrucVal_D(struct MCTStatStruc 
*pMCTstat,
+                                       pDCTstat->DQSDelay;
+ }
+ 
+-static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, u8 
ChipSel,
+-                                      u8 RnkDlyFilterMin, u8 RnkDlyFilterMax)
+-{
+-      u8 dn;
+-
+-      if (pDCTstat->Direction == DQS_WRITEDIR) {
+-              dn = ChipSel >> 1;
+-              RnkDlyFilterMin += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
+-              RnkDlyFilterMax += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
+-              pDCTstat->DQSDelay += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane];
+-      } else {
+-              RnkDlyFilterMin <<= 1;
+-              RnkDlyFilterMax <<= 1;
+-              pDCTstat->DQSDelay <<= 1;
+-      }
+-      mctEngDQSwindow_Save_D(pMCTstat, pDCTstat, ChipSel, RnkDlyFilterMin, 
RnkDlyFilterMax);
+-      StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+-}
+-
+ static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
+ {
+@@ -720,33 +855,6 @@ static void GetDQSDatStrucVal_D(struct MCTStatStruc 
*pMCTstat,
+ 
+ /* FindDQSDatDimmVal_D is not required since we use an array */
+ 
+-static u8 MiddleDQS_D(u8 min, u8 max)
+-{
+-      u8 size;
+-      size = max-min;
+-      if (size % 2)
+-              size++;         /* round up if the size isn't even. */
+-      return ( min + (size >> 1));
+-}
+-
+-static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat,
+-                              u8 cs_start)
+-{
+-      print_debug_dqs("\t\tTrainReadPos ", 0, 2);
+-      pDCTstat->Direction = DQS_READDIR;
+-      TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
+-}
+-
+-static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat,
+-                              u8 cs_start)
+-{
+-      pDCTstat->Direction = DQS_WRITEDIR;
+-      print_debug_dqs("\t\tTrainWritePos", 0, 2);
+-      TrainDQSPos_D(pMCTstat, pDCTstat, cs_start);
+-}
+-
+ static void proc_IOCLFLUSH_D(u32 addr_hi)
+ {
+       SetTargetWTIO_D(addr_hi);
+@@ -963,30 +1071,6 @@ static void ResetTargetWTIO_D(void)
+       _WRMSR(0xc0010017, lo, hi); /* IORR0 Mask */
+ }
+ 
+-static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat,
+-                              u32 TestAddr_lo)
+-{
+-      /* Read a pattern of 72 bit times (per DQ), to test dram functionality.
+-       * The pattern is a stress pattern which exercises both ISI and
+-       * crosstalk.  The number of cache lines to fill is dependent on DCT
+-       * width mode and burstlength.
+-       * Mode BL  Lines Pattern no.
+-       * ----+---+-------------------
+-       * 64   4         9     0
+-       * 64   8         9     0
+-       * 64M  4         9     0
+-       * 64M  8         9     0
+-       * 128  4         18    1
+-       * 128  8         N/A   -
+-       */
+-      if (pDCTstat->Pattern == 0)
+-              ReadL9TestPattern(TestAddr_lo);
+-      else
+-              ReadL18TestPattern(TestAddr_lo);
+-      _MFENCE;
+-}
+-
+ u32 SetUpperFSbase(u32 addr_hi)
+ {
+       /* Set the upper 32-bits of the Base address, 4GB aligned) for the
+@@ -1009,8 +1093,6 @@ void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index)
+       Set_NB32_index_wait(dev, index_reg, index, val);
+ }
+ 
+-/* mctEngDQSwindow_Save_D not required with arrays */
+-
+ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+ {
+@@ -1021,8 +1103,8 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               if (pDCTstat->DCTSysLimit) {
++                      TrainDQSRdWrPos_D(pMCTstat, pDCTstat);
+                       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel 
+= 2) {
+-                              TrainDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
+                               SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
+                       }
+               }
+@@ -1137,27 +1219,6 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
+       }
+ }
+ 
+-/*
+- * mct_SetDQSDelayAllCSR_D:
+- * Write the Delay value to all eight byte lanes.
+- */
+-static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat,
+-                                      u8 cs_start)
+-{
+-      u8 ByteLane;
+-      u8 ChipSel = cs_start;
+-
+-      for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) {
+-              if ( mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, 
pDCTstat->Channel, ChipSel)) {
+-                      for (ByteLane = 0; ByteLane < 8; ByteLane++) {
+-                              pDCTstat->ByteLane = ByteLane;
+-                              mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, 
ChipSel);
+-                      }
+-              }
+-      }
+-}
+-
+ u8 mct_RcvrRankEnabled_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u8 Channel, u8 ChipSel)
+@@ -1196,7 +1257,7 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
+       reg = 0x40 + (receiver << 2) + reg_off;
+       val = Get_NB32(dev, reg);
+ 
+-      val &= ~0x0F;
++      val &= ~0xe007c01f;
+ 
+       /* unganged mode DCT0+DCT1, sys addr of DCT1=node
+        * base+DctSelBaseAddr+local ca base*/
+@@ -1277,6 +1338,7 @@ exitGetAddrWNoError:
+       print_debug_dqs("mct_GetMCTSysAddr_D: base_addr ", val, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: valid ", *valid, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: status ", pDCTstat->Status, 2);
++      print_debug_dqs("mct_GetMCTSysAddr_D: SysBase ", pDCTstat->DCTSysBase, 
2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: HoleBase ", 
pDCTstat->DCTHoleBase, 2);
+       print_debug_dqs("mct_GetMCTSysAddr_D: Cachetop ", 
pMCTstat->Sub4GCacheTop, 2);
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+index 528c782..60bc01d 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -25,7 +26,6 @@ static void EnableZQcalibration(struct MCTStatStruc 
*pMCTstat, struct DCTStatStr
+ static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
+ static void PrepareC_DCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
+-static void MultiplyDelay(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
+ static void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ static void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ 
+@@ -154,7 +154,6 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
+               Clear_OnDimmMirror(pMCTstat, pDCTstat);
+               SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
+               DisableAutoRefresh_D(pMCTstat, pDCTstat);
+-              MultiplyDelay(pMCTstat, pDCTstat, dct);
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
+                       if (DIMMValid & (1 << (dimm << 1)))
+                               AgesaHwWlPhase1(pDCTstat->C_MCTPtr, 
pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
+@@ -162,6 +161,9 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
+       }
+ }
+ 
++/* Write Levelization Training
++ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
++ */
+ static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+ {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
+index 3d625de..596fb23 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -201,12 +202,13 @@ static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 
*pMtrrAddr, u16 MtrrType)
+ 
+ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA)
+ {
+-/* UMA memory size may need splitting the MTRR configuration into two
+-  Before training use NB_BottomIO or the physical memory size to set the 
MTRRs.
+-  After training, add UMAMemTyping function to reconfigure the MTRRs based on
+-  NV_BottomUMA (for UMA systems only).
+-  This two-step process allows all memory to be cached for training
+-*/
++      /* UMA memory size may need splitting the MTRR configuration into two
++       * Before training use NB_BottomIO or the physical memory size to set 
the MTRRs.
++       * After training, add UMAMemTyping function to reconfigure the MTRRs 
based on
++       * NV_BottomUMA (for UMA systems only).
++       * This two-step process allows all memory to be cached for training
++      */
++
+       u32 Bottom32bIO, Cache32bTOP;
+       u32 val;
+       u32 addr;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
+index 013a1b9..6f97061 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -140,7 +141,7 @@ void InterleaveNodes_D(struct MCTStatStruc *pMCTstat,
+       }
+ 
+       if (DoIntlv) {
+-              MCTMemClr_D(pMCTstat,pDCTstatA);
++              MCTMemClr_D(pMCTstat, pDCTstatA);
+               /* Program Interleaving enabled on Node 0 map only.*/
+               MemSize0 <<= bsf(Nodes);        /* MemSize=MemSize*2 (or 4, or 
8) */
+               Dct0MemSize <<= bsf(Nodes);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+index da2f372..cda9c6b 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -36,10 +37,10 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
+               val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78);
+ 
+               val &= 7;
+-              val = ((~val) & 0xFF) + 1;
++              val = ((~val) & 0xff) + 1;
+               val += 6;
+-              val &= 0xFF;
+-              misc2 &= 0xFFF8FFFF;
++              val &= 0x7;
++              misc2 &= 0xfff8ffff;
+               misc2 |= val << 16;     /* DataTxFifoWrDly */
+               if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
+                       misc2 |= 1 << 7; /* ProgOdtEn */
+@@ -52,11 +53,15 @@ void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat)
+       u32 val;
+ 
+       if (pDCTstat->LogicalCPUID & (AMD_DR_Cx)) {
+-              Set_NB32(pDCTstat->dev_dct, 0x11C, 0x0CE00FC0 | 1 << 29/* 
FlushWrOnStpGnt */);
++              /* Revision C */
++              Set_NB32(pDCTstat->dev_dct, 0x11c, 0x0ce00fc0 | 1 << 29/* 
FlushWrOnStpGnt */);
++      }
+ 
+-              val = Get_NB32(pDCTstat->dev_dct, 0x1B0);
+-              val &= 0xFFFFF8C0;
++      if (pDCTstat->LogicalCPUID & (AMD_DR_Cx)) {
++              val = Get_NB32(pDCTstat->dev_dct, 0x1b0);
++              val &= ~0x73f;
+               val |= 0x101;   /* BKDG recommended settings */
+-              Set_NB32(pDCTstat->dev_dct, 0x1B0, val);
++
++              Set_NB32(pDCTstat->dev_dct, 0x1b0, val);
+       }
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 6de2f4e..b21b96a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -172,6 +173,7 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+                       ret |= 1 << 11;
+       }
+ 
++      /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
+       if (dword & (1 << 13))
+               ret |= 1 << 12;
+ 
+@@ -199,7 +201,8 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
+       /* program MrsAddress[6:4,2]=read CAS latency
+          (CL):based on F2x[1,0]88[Tcl] */
+       dword2 = Get_NB32(dev, reg_off + 0x88);
+-      ret |= (dword2 & 0xF) << 4; /* F2x88[3:0] to MrsAddress[6:4,2]=xxx0b */
++      ret |= (dword2 & 0x7) << 4;             /* F2x88[2:0] to 
MrsAddress[6:4] */
++      ret |= ((dword2 & 0x8) >> 3) << 2;      /* F2x88[3] to MrsAddress[2] */
+ 
+       /* program MrsAddress[12]=0 (PPD):slow exit */
+       if (dword & (1 << 23))
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 8e5c268..91e8f77 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -24,25 +25,13 @@
+ 
+ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Pass);
+-static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat,
+-                                      u8 rcvrEnDly, u8 Channel,
+-                                      u8 receiver, u8 Pass);
+-static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat,
+-                                      u32 addr, u8 channel,
+-                                      u8 pattern, u8 Pass);
+ static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                                        struct DCTStatStruc *pDCTstat);
+ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel);
+ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel);
+-static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat,
+-                              u8 RcvrEnDly, u8 where,
+-                              u8 Channel, u8 Receiver,
+-                              u32 dev, u32 index_reg,
+-                              u8 Addl_Index, u8 Pass);
+-static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 
DQSRcvEnDly);
++static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, 
u16 DQSRcvEnDly);
+ static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat);
+@@ -50,17 +39,17 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc 
*pDCTstat);
+ /* Warning:  These must be located so they do not cross a logical 16-bit
+    segment boundary! */
+ static const u32 TestPattern0_D[] = {
+-      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+-      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+-      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+-      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
+-};
+-static const u32 TestPattern1_D[] = {
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+       0x55555555, 0x55555555, 0x55555555, 0x55555555,
+ };
++static const u32 TestPattern1_D[] = {
++      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
++      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
++      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
++      0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
++};
+ static const u32 TestPattern2_D[] = {
+       0x12345678, 0x87654321, 0x23456789, 0x98765432,
+       0x59385824, 0x30496724, 0x24490795, 0x99938733,
+@@ -104,16 +93,87 @@ void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat,
+               dqsTrainRcvrEn_SW(pMCTstat, pDCTstat, Pass);
+ }
+ 
++static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
++{
++      uint8_t lane;
++      uint32_t dword;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++              uint32_t wdt_reg;
++              if ((lane == 0) || (lane == 1))
++                      wdt_reg = 0x30;
++              if ((lane == 2) || (lane == 3))
++                      wdt_reg = 0x31;
++              if ((lane == 4) || (lane == 5))
++                      wdt_reg = 0x40;
++              if ((lane == 6) || (lane == 7))
++                      wdt_reg = 0x41;
++              if (lane == 8)
++                      wdt_reg = 0x32;
++              wdt_reg += dimm * 3;
++              dword = Get_NB32_index_wait(dev, index_reg, wdt_reg);
++              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1))
++                      current_total_delay[lane] = (dword & 0x00ff0000) >> 16;
++              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0))
++                      current_total_delay[lane] = dword & 0x000000ff;
++      }
++}
++
++static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
++{
++      uint8_t lane;
++      uint32_t dword;
++
++      for (lane = 0; lane < 8; lane++) {
++              uint32_t ret_reg;
++              if ((lane == 0) || (lane == 1))
++                      ret_reg = 0x10;
++              if ((lane == 2) || (lane == 3))
++                      ret_reg = 0x11;
++              if ((lane == 4) || (lane == 5))
++                      ret_reg = 0x20;
++              if ((lane == 6) || (lane == 7))
++                      ret_reg = 0x21;
++              ret_reg += dimm * 3;
++              dword = Get_NB32_index_wait(dev, index_reg, ret_reg);
++              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
++                      dword &= ~(0x1ff << 16);
++                      dword |= (current_total_delay[lane] & 0x1ff) << 16;
++              }
++              if ((lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
++                      dword &= ~0x1ff;
++                      dword |= current_total_delay[lane] & 0x1ff;
++              }
++              Set_NB32_index_wait(dev, index_reg, ret_reg, dword);
++      }
++}
++
++static uint32_t convert_testaddr_and_channel_to_address(struct DCTStatStruc 
*pDCTstat, uint32_t testaddr, uint8_t channel)
++{
++      SetUpperFSbase(testaddr);
++      testaddr <<= 8;
++
++      if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) {
++              testaddr += 8;  /* second channel */
++      }
++
++      return testaddr;
++}
++
++/* DQS Receiver Enable Training
++ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
++ */
+ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Pass)
+ {
+-      u8 Channel, RcvrEnDly, RcvrEnDlyRmin;
+-      u8 Test0, Test1, CurrTest, CurrTestSide0, CurrTestSide1;
+-      u8 CTLRMaxDelay, _2Ranks, PatternA, PatternB;
++      u8 Channel;
++      u8 _2Ranks;
+       u8 Addl_Index = 0;
+       u8 Receiver;
+       u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
+-      u8 RcvrEnDlyLimit, Final_Value, MaxDelay_CH[2];
++      u8 Final_Value;
++      u16 CTLRMaxDelay;
++      u16 MaxDelay_CH[2];
+       u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B;
+       u32 PatternBuffer[64+4]; /* FIXME: need increase 8? */
+       u32 Errors;
+@@ -127,9 +187,20 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+       u32 cr4;
+       u32 lo, hi;
+ 
++      uint32_t dword;
++      uint8_t rank;
++      uint8_t lane;
++      uint16_t current_total_delay[MAX_BYTE_LANES];
++      uint16_t candidate_total_delay[8];
++      uint8_t data_test_pass_sr[2][8];        /* [rank][lane] */
++      uint8_t data_test_pass[8];              /* [lane] */
++      uint8_t data_test_pass_prev[8];         /* [lane] */
++      uint8_t window_det_toggle[8];
++      uint8_t trained[8];
++      uint64_t result_qword1;
++      uint64_t result_qword2;
++
+       u8 valid;
+-      u32 tmp;
+-      u8 LastTest;
+ 
+       print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
+       print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
+@@ -181,33 +252,103 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+ 
+       Errors = 0;
+       dev = pDCTstat->dev_dct;
+-      CTLRMaxDelay = 0;
+ 
+       for (Channel = 0; Channel < 2; Channel++) {
+               print_debug_dqs("\tTrainRcvEn51: Node ", pDCTstat->Node_ID, 1);
+               print_debug_dqs("\tTrainRcvEn51: Channel ", Channel, 1);
+               pDCTstat->Channel = Channel;
+ 
++              CTLRMaxDelay = 0;
+               MaxDelay_CH[Channel] = 0;
+               index_reg = 0x98 + 0x100 * Channel;
+ 
+               Receiver = mct_InitReceiver_D(pDCTstat, Channel);
+-              /* There are four receiver pairs, loosely associated with 
chipselects. */
++              /* There are four receiver pairs, loosely associated with 
chipselects.
++               * This is essentially looping over each DIMM.
++               */
+               for (; Receiver < 8; Receiver += 2) {
+                       Addl_Index = (Receiver >> 1) * 3 + 0x10;
+-                      LastTest = DQS_FAIL;
+-
+-                      /* mct_ModifyIndex_D */
+-                      RcvrEnDlyRmin = RcvrEnDlyLimit = 0xff;
+ 
+                       print_debug_dqs("\t\tTrainRcvEnd52: index ", 
Addl_Index, 2);
+ 
+-                      if(!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
+                               continue;
+                       }
+ 
++                      /* Clear data structures */
++                      for (lane = 0; lane < 8; lane++) {
++                              data_test_pass_prev[lane] = 0;
++                              trained[lane] = 0;
++                      }
++
++                      /* 2.8.9.9.2 (1, 6)
++                       * Retrieve gross and fine timing fields from write DQS 
registers
++                       */
++                      
read_dqs_write_timing_control_registers(current_total_delay, dev, (Receiver >> 
1), index_reg);
++
++                      /* 2.8.9.9.2 (1)
++                       * Program the Write Data Timing and Write ECC Timing 
register to
++                       * the values stored in the DQS Write Timing Control 
register
++                       * for each lane
++                       */
++                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                              uint32_t wdt_reg;
++
++                              /* Calculate Write Data Timing register 
location */
++                              if ((lane == 0) || (lane == 1) || (lane == 2) 
|| (lane == 3))
++                                      wdt_reg = 0x1;
++                              if ((lane == 4) || (lane == 5) || (lane == 6) 
|| (lane == 7))
++                                      wdt_reg = 0x2;
++                              if (lane == 8)
++                                      wdt_reg = 0x3;
++                              wdt_reg |= ((Receiver / 2) << 8);
++
++                              /* Set Write Data Timing register values */
++                              dword = Get_NB32_index_wait(dev, index_reg, 
wdt_reg);
++                              if ((lane == 7) || (lane == 3)) {
++                                      dword &= ~(0x7f << 24);
++                                      dword |= (current_total_delay[lane] & 
0x7f) << 24;
++                              }
++                              if ((lane == 6) || (lane == 2)) {
++                                      dword &= ~(0x7f << 16);
++                                      dword |= (current_total_delay[lane] & 
0x7f) << 16;
++                              }
++                              if ((lane == 5) || (lane == 1)) {
++                                      dword &= ~(0x7f << 8);
++                                      dword |= (current_total_delay[lane] & 
0x7f) << 8;
++                              }
++                              if ((lane == 8) || (lane == 4) || (lane == 0)) {
++                                      dword &= ~0x7f;
++                                      dword |= current_total_delay[lane] & 
0x7f;
++                              }
++                              Set_NB32_index_wait(dev, index_reg, wdt_reg, 
dword);
++                      }
++
++                      /* 2.8.9.9.2 (2)
++                       * Program the Read DQS Timing Control and the Read DQS 
ECC Timing Control registers
++                       * to 1/2 MEMCLK for all lanes
++                       */
++                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                              uint32_t rdt_reg;
++                              if ((lane == 0) || (lane == 1) || (lane == 2) 
|| (lane == 3))
++                                      rdt_reg = 0x5;
++                              if ((lane == 4) || (lane == 5) || (lane == 6) 
|| (lane == 7))
++                                      rdt_reg = 0x6;
++                              if (lane == 8)
++                                      rdt_reg = 0x7;
++                              rdt_reg |= ((Receiver / 2) << 8);
++                              if (lane == 8)
++                                      dword = 0x0000003f;
++                              else
++                                      dword = 0x3f3f3f3f;
++                              Set_NB32_index_wait(dev, index_reg, rdt_reg, 
dword);
++                      }
++
++                      /* 2.8.9.9.2 (3)
++                       * Select two test addresses for each rank present
++                       */
+                       TestAddr0 = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, 
Channel, Receiver, &valid);
+-                      if(!valid) {    /* Address not supported on current CS 
*/
++                      if (!valid) {   /* Address not supported on current CS 
*/
+                               continue;
+                       }
+ 
+@@ -229,171 +370,214 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1 ", 
TestAddr1, 2);
+                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", 
TestAddr1B, 2);
+ 
+-                      /*
+-                       * Get starting RcvrEnDly value
++                      /* 2.8.9.9.2 (4, 5)
++                       * Write 1 cache line of the appropriate test pattern 
to each test addresse
+                        */
+-                      RcvrEnDly = mct_Get_Start_RcvrEnDly_1Pass(Pass);
++                      mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, 
0); /* rank 0 of DIMM, testpattern 0 */
++                      mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0B, 1); /* rank 0 of DIMM, testpattern 1 */
++                      if (_2Ranks) {
++                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr1, 0); /*rank 1 of DIMM, testpattern 0 */
++                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr1B, 1); /*rank 1 of DIMM, testpattern 1 */
++                      }
+ 
+-                      /* mct_GetInitFlag_D*/
+-                      if (Pass == FirstPass) {
+-                              pDCTstat->DqsRcvEn_Pass = 0;
+-                      } else {
+-                              pDCTstat->DqsRcvEn_Pass=0xFF;
++#if DQS_TRAIN_DEBUG > 0
++                      for (lane = 0; lane < 8; lane++) {
++                              print_debug_dqs("\t\tTrainRcvEn54: lane: ", 
lane, 2);
++                              print_debug_dqs("\t\tTrainRcvEn54: 
current_total_delay ", current_total_delay[lane], 2);
+                       }
+-                      pDCTstat->DqsRcvEn_Saved = 0;
++#endif
+ 
++                      /* 2.8.9.9.2 (6)
++                       * Write gross and fine timing fields to read DQS 
registers
++                       */
++                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++
++                      /* 2.8.9.9.2 (7)
++                       * Loop over all delay values up to 1 MEMCLK (0x40 
delay steps) from the initial delay values
++                       *
++                       * FIXME
++                       * It is not clear if training should be discontinued 
if any test failures occur in the first
++                       * 1 MEMCLK window, or if it should be discontinued if 
no successes occur in the first 1 MEMCLK
++                       * window.  Therefore, loop over up to 2 MEMCLK (0x80 
delay steps) to be on the safe side.
++                       */
++                      uint16_t current_delay_step;
+ 
+-                      while(RcvrEnDly < RcvrEnDlyLimit) {     /* sweep Delay 
value here */
+-                              print_debug_dqs("\t\t\tTrainRcvEn541: RcvrEnDly 
", RcvrEnDly, 3);
++                      for (current_delay_step = 0; current_delay_step < 0x80; 
current_delay_step++) {
++                              print_debug_dqs("\t\t\tTrainRcvEn541: 
current_delay_step ", current_delay_step, 3);
+ 
+-                              /* callback not required
+-                              if(mct_AdjustDelay_D(pDCTstat, RcvrEnDly))
+-                                      goto skipDly;
++                              /* 2.8.9.9.2 (7 D)
++                              * Terminate if all lanes are trained
+                               */
++                              uint8_t all_lanes_trained = 1;
++                              for (lane = 0; lane < 8; lane++)
++                                      if (!trained[lane])
++                                              all_lanes_trained = 0;
+ 
+-                              /* Odd steps get another pattern such that even
+-                               and odd steps alternate. The pointers to the
+-                               patterns will be swaped at the end of the loop
+-                               so that they correspond. */
+-                              if(RcvrEnDly & 1) {
+-                                      PatternA = 1;
+-                                      PatternB = 0;
+-                              } else {
+-                                      /* Even step */
+-                                      PatternA = 0;
+-                                      PatternB = 1;
+-                              }
+-
+-                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0, PatternA); /* rank 0 of DIMM, testpattern 0 */
+-                              mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0B, PatternB); /* rank 0 of DIMM, testpattern 1 */
+-                              if(_2Ranks) {
+-                                      mct_Write1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr1, PatternA); /*rank 1 of DIMM, testpattern 0 */
+-                                      mct_Write1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr1B, PatternB); /*rank 1 of DIMM, testpattern 1 */
+-                              }
+-
+-                              mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, 0, 
Channel, Receiver, dev, index_reg, Addl_Index, Pass);
+-
+-                              CurrTest = DQS_FAIL;
+-                              CurrTestSide0 = DQS_FAIL;
+-                              CurrTestSide1 = DQS_FAIL;
+-
+-                              mct_Read1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0); /*cache fills */
+-                              Test0 = mct_CompareTestPatternQW0_D(pMCTstat, 
pDCTstat, TestAddr0, Channel, PatternA, Pass);/* ROM vs cache compare */
+-                              proc_IOCLFLUSH_D(TestAddr0);
+-                              ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
+-
+-                              print_debug_dqs("\t\t\tTrainRcvEn542: Test0 
result ", Test0, 3);
+-
+-                              /* != 0x00 mean pass */
+-
+-                              if(Test0 == DQS_PASS) {
+-                                      mct_Read1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr0B);        /*cache fills */
+-                                      /* ROM vs cache compare */
+-                                      Test1 = 
mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr0B, Channel, PatternB, 
Pass);
+-                                      proc_IOCLFLUSH_D(TestAddr0B);
+-                                      ResetDCTWrPtr_D(dev, index_reg, 
Addl_Index);
+-
+-                                      print_debug_dqs("\t\t\tTrainRcvEn543: 
Test1 result ", Test1, 3);
++                              if (all_lanes_trained)
++                                      break;
+ 
+-                                      if(Test1 == DQS_PASS) {
+-                                              CurrTestSide0 = DQS_PASS;
++                              /* 2.8.9.9.2 (7 A)
++                              * Loop over all ranks
++                              */
++                              for (rank = 0; rank < (_2Ranks + 1); rank++) {
++                                      /* 2.8.9.9.2 (7 A a-d)
++                                       * Read the first test address of the 
current rank
++                                       * Store the first data beat for 
analysis
++                                       * Reset read pointer in the DRAM 
controller FIFO
++                                       * Read the second test address of the 
current rank
++                                       * Store the first data beat for 
analysis
++                                       * Reset read pointer in the DRAM 
controller FIFO
++                                       */
++                                      if (rank & 1) {
++                                              /* 2.8.9.9.2 (7 D)
++                                               * Invert read instructions to 
alternate data read order on the bus
++                                               */
++                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
++                                              result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
++                                              result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                                      } else {
++                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
++                                              result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                                              proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
++                                              result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
+                                       }
+-                              }
+-                              if(_2Ranks) {
+-                                      mct_Read1LTestPattern_D(pMCTstat, 
pDCTstat, TestAddr1); /*cache fills */
+-                                      /* ROM vs cache compare */
+-                                      Test0 = 
mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1, Channel, PatternA, 
Pass);
+-                                      proc_IOCLFLUSH_D(TestAddr1);
+-                                      ResetDCTWrPtr_D(dev, index_reg, 
Addl_Index);
+-
+-                                      print_debug_dqs("\t\t\tTrainRcvEn544: 
Test0 result ", Test0, 3);
+-
+-                                      if(Test0 == DQS_PASS) {
+-                                              
mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1B);        /*cache fills */
+-                                              /* ROM vs cache compare */
+-                                              Test1 = 
mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1B, Channel, PatternB, 
Pass);
+-                                              proc_IOCLFLUSH_D(TestAddr1B);
+-                                              ResetDCTWrPtr_D(dev, index_reg, 
Addl_Index);
+-
+-                                              
print_debug_dqs("\t\t\tTrainRcvEn545: Test1 result ", Test1, 3);
+-                                              if(Test1 == DQS_PASS) {
+-                                                      CurrTestSide1 = 
DQS_PASS;
++                                      /* 2.8.9.9.2 (7 A e)
++                                       * Compare both read patterns and flag 
passing ranks/lanes
++                                       */
++                                      uint8_t result_lane_byte1;
++                                      uint8_t result_lane_byte2;
++                                      for (lane = 0; lane < 8; lane++) {
++                                              if (trained[lane] == 1) {
++#if DQS_TRAIN_DEBUG > 0
++                                                      
print_debug_dqs("\t\t\t\t\t\t\t\t lane already trained: ", lane, 4);
++#endif
++                                                      continue;
+                                               }
++
++                                              result_lane_byte1 = 
(result_qword1 >> (lane * 8)) & 0xff;
++                                              result_lane_byte2 = 
(result_qword2 >> (lane * 8)) & 0xff;
++                                              if ((result_lane_byte1 == 0x55) 
&& (result_lane_byte2 == 0xaa))
++                                                      
data_test_pass_sr[rank][lane] = 1;
++                                              else
++                                                      
data_test_pass_sr[rank][lane] = 0;
++#if DQS_TRAIN_DEBUG > 0
++                                              
print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", 0x55, "  |  ", result_lane_byte1, 4);
++                                              
print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", 0xaa, "  |  ", result_lane_byte2, 4);
++#endif
+                                       }
+                               }
+ 
+-                              if(_2Ranks) {
+-                                      if ((CurrTestSide0 == DQS_PASS) && 
(CurrTestSide1 == DQS_PASS)) {
+-                                              CurrTest = DQS_PASS;
++                              /* 2.8.9.9.2 (7 B)
++                               * If DIMM is dual rank, only use delays that 
pass testing for both ranks
++                               */
++                              for (lane = 0; lane < 8; lane++) {
++                                      if (_2Ranks) {
++                                              if 
((data_test_pass_sr[0][lane]) && (data_test_pass_sr[1][lane]))
++                                                      data_test_pass[lane] = 
1;
++                                              else
++                                                      data_test_pass[lane] = 
0;
++                                      } else {
++                                              data_test_pass[lane] = 
data_test_pass_sr[0][lane];
+                                       }
+-                              } else if (CurrTestSide0 == DQS_PASS) {
+-                                      CurrTest = DQS_PASS;
+                               }
+ 
+-                              /* record first pass DqsRcvEn to stack */
+-                              valid = mct_SavePassRcvEnDly_D(pDCTstat, 
RcvrEnDly, Channel, Receiver, Pass);
++                              /* 2.8.9.9.2 (7 E)
++                               * For each lane, update the DQS receiver delay 
setting in support of next iteration
++                               */
++                              for (lane = 0; lane < 8; lane++) {
++                                      if (trained[lane] == 1)
++                                              continue;
++
++                                      /* 2.8.9.9.2 (7 C a)
++                                       * Save the total delay of the first 
success after a failure for later use
++                                       */
++                                      if ((data_test_pass[lane] == 1) && 
(data_test_pass_prev[lane] == 0)) {
++                                              candidate_total_delay[lane] = 
current_total_delay[lane];
++                                              window_det_toggle[lane] = 0;
++                                      }
+ 
+-                              /* Break(1:RevF,2:DR) or not(0) FIXME: This 
comment deosn't make sense */
+-                              if(valid == 2 || (LastTest == DQS_FAIL && valid 
== 1)) {
+-                                      RcvrEnDlyRmin = RcvrEnDly;
+-                                      break;
++                                      /* 2.8.9.9.2 (7 C b)
++                                       * If the current delay failed testing 
add 1/8 UI to the current delay
++                                       */
++                                      if (data_test_pass[lane] == 0)
++                                              current_total_delay[lane] += 
0x4;
++
++                                      /* 2.8.9.9.2 (7 C c)
++                                       * If the current delay passed testing 
alternately add either 1/32 UI or 1/4 UI to the current delay
++                                       * If 1.25 UI of delay have been added 
with no failures the lane is considered trained
++                                       */
++                                      if (data_test_pass[lane] == 1) {
++                                              /* See if lane is trained */
++                                              if ((current_total_delay[lane] 
- candidate_total_delay[lane]) >= 0x28) {
++                                                      trained[lane] = 1;
++
++                                                      /* Calculate and set 
final lane delay value
++                                                       * The final delay is 
the candidate delay + 7/8 UI
++                                                       */
++                                                      
current_total_delay[lane] = candidate_total_delay[lane] + 0x1c;
++                                              } else {
++                                                      if 
(window_det_toggle[lane] == 0) {
++                                                              
current_total_delay[lane] += 0x1;
++                                                              
window_det_toggle[lane] = 1;
++                                                      } else {
++                                                              
current_total_delay[lane] += 0x8;
++                                                              
window_det_toggle[lane] = 0;
++                                                      }
++                                              }
++                                      }
+                               }
+ 
+-                              LastTest = CurrTest;
+-
+-                              /* swap the rank 0 pointers */
+-                              tmp = TestAddr0;
+-                              TestAddr0 = TestAddr0B;
+-                              TestAddr0B = tmp;
+-
+-                              /* swap the rank 1 pointers */
+-                              tmp = TestAddr1;
+-                              TestAddr1 = TestAddr1B;
+-                              TestAddr1B = tmp;
+-
+-                              print_debug_dqs("\t\t\tTrainRcvEn56: RcvrEnDly 
", RcvrEnDly, 3);
++                              /* Update delays in hardware */
++                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
+ 
+-                              RcvrEnDly++;
+-
+-                      }       /* while RcvrEnDly */
+-
+-                      print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDly ", 
RcvrEnDly, 2);
+-                      print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyRmin ", 
RcvrEnDlyRmin, 3);
+-                      print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyLimit ", 
RcvrEnDlyLimit, 3);
+-                      if(RcvrEnDlyRmin == RcvrEnDlyLimit) {
+-                              /* no passing window */
+-                              pDCTstat->ErrStatus |= 1 << SB_NORCVREN;
+-                              Errors |= 1 << SB_NORCVREN;
+-                              pDCTstat->ErrCode = SC_FatalErr;
++                              /* Save previous results for comparison in the 
next iteration */
++                              for (lane = 0; lane < 8; lane++)
++                                      data_test_pass_prev[lane] = 
data_test_pass[lane];
+                       }
+ 
+-                      if(RcvrEnDly > (RcvrEnDlyLimit - 1)) {
+-                              /* passing window too narrow, too far delayed*/
+-                              pDCTstat->ErrStatus |= 1 << SB_SmallRCVR;
+-                              Errors |= 1 << SB_SmallRCVR;
+-                              pDCTstat->ErrCode = SC_FatalErr;
+-                              RcvrEnDly = RcvrEnDlyLimit - 1;
+-                              pDCTstat->CSTrainFail |= 1 << Receiver;
+-                              pDCTstat->DimmTrainFail |= 1 << (Receiver + 
Channel);
+-                      }
+-
+-                      /* CHB_D0_B0_RCVRDLY set in mct_Average_RcvrEnDly_Pass 
*/
+-                      mct_Average_RcvrEnDly_Pass(pDCTstat, RcvrEnDly, 
RcvrEnDlyLimit, Channel, Receiver, Pass);
++#if DQS_TRAIN_DEBUG > 0
++                      for (lane = 0; lane < 8; lane++)
++                              print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
++#endif
+ 
+-                      mct_SetFinalRcvrEnDly_D(pDCTstat, RcvrEnDly, 
Final_Value, Channel, Receiver, dev, index_reg, Addl_Index, Pass);
++                      /* Find highest delay value and save for later use */
++                      for (lane = 0; lane < 8; lane++)
++                              if (current_total_delay[lane] > CTLRMaxDelay)
++                                      CTLRMaxDelay = 
current_total_delay[lane];
+ 
+-                      if(pDCTstat->ErrStatus & (1 << SB_SmallRCVR)) {
+-                              Errors |= 1 << SB_SmallRCVR;
++                      /* See if any lanes failed training, and set error 
flags appropriately
++                       * For all trained lanes, save delay values for later 
use
++                       */
++                      for (lane = 0; lane < 8; lane++) {
++                              if (trained[lane]) {
++                                      
pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1][lane] = 
current_total_delay[lane];
++                              } else {
++                                      printk(BIOS_WARNING, "TrainRcvrEn: 
WARNING: Lane %d of receiver %d on channel %d failed training!\n", lane, 
Receiver, Channel);
++
++                                      /* Set error flags */
++                                      pDCTstat->ErrStatus |= 1 << SB_NORCVREN;
++                                      Errors |= 1 << SB_NORCVREN;
++                                      pDCTstat->ErrCode = SC_FatalErr;
++                                      pDCTstat->CSTrainFail |= 1 << Receiver;
++                                      pDCTstat->DimmTrainFail |= 1 << 
(Receiver + Channel);
++                              }
+                       }
+ 
+-                      RcvrEnDly += Pass1MemClkDly;
+-                      if(RcvrEnDly > CTLRMaxDelay) {
+-                              CTLRMaxDelay = RcvrEnDly;
+-                      }
++                      /* 2.8.9.9.2 (8)
++                       * Flush the receiver FIFO
++                       * Write one full cache line of non-0x55/0xaa data to 
one of the test addresses, then read it back to flush the FIFO
++                       */
+ 
+-              }       /* while Receiver */
++                      WriteLNTestPattern(TestAddr0 << 8, (uint8_t 
*)TestPattern2_D, 1);
++                      mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0);
++              }
+               MaxDelay_CH[Channel] = CTLRMaxDelay;
+-      }       /* for Channel */
++      }
+ 
+       CTLRMaxDelay = MaxDelay_CH[0];
+       if (MaxDelay_CH[1] > CTLRMaxDelay)
+@@ -428,31 +612,31 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+ 
+ #if DQS_TRAIN_DEBUG > 0
+       {
+-              u8 Channel;
++              u8 ChannelDTD;
+               printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
+-              for(Channel = 0; Channel<2; Channel++) {
++              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
+                       printk(BIOS_DEBUG, "Channel:%x: %x\n",
+-                             Channel, pDCTstat->CH_MaxRdLat[Channel]);
++                             ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]);
+               }
+       }
+ #endif
+ 
+ #if DQS_TRAIN_DEBUG > 0
+       {
+-              u8 val;
+-              u8 Channel, Receiver;
++              u16 valDTD;
++              u8 ChannelDTD, ReceiverDTD;
+               u8 i;
+-              u8 *p;
++              u16 *p;
+ 
+               printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
+-              for(Channel = 0; Channel < 2; Channel++) {
+-                      printk(BIOS_DEBUG, "Channel:%x\n", Channel);
+-                      for(Receiver = 0; Receiver<8; Receiver+=2) {
+-                              printk(BIOS_DEBUG, "\t\tReceiver:%x:", 
Receiver);
+-                              p = 
pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
++              for(ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
++                      printk(BIOS_DEBUG, "Channel:%x\n", ChannelDTD);
++                      for(ReceiverDTD = 0; ReceiverDTD<8; ReceiverDTD+=2) {
++                              printk(BIOS_DEBUG, "\t\tReceiver:%x:", 
ReceiverDTD);
++                              p = 
pDCTstat->CH_D_B_RCVRDLY[ChannelDTD][ReceiverDTD>>1];
+                               for (i=0;i<8; i++) {
+-                                      val  = p[i];
+-                                      printk(BIOS_DEBUG, "%x ", val);
++                                      valDTD = p[i];
++                                      printk(BIOS_DEBUG, " %03x", valDTD);
+                               }
+                               printk(BIOS_DEBUG, "\n");
+                       }
+@@ -475,15 +659,6 @@ u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 
dct)
+       }
+ }
+ 
+-static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 
RcvrEnDly, u8 where, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 
Addl_Index, u8 Pass/*, u8 *p*/)
+-{
+-      /*
+-       * Program final DqsRcvEnDly to additional index for DQS receiver
+-       *  enabled delay
+-       */
+-      mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, where, Channel, Receiver, dev, 
index_reg, Addl_Index, Pass);
+-}
+-
+ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat)
+ {
+       u8 ch_end, ch;
+@@ -514,17 +689,20 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc 
*pDCTstat)
+  * Function only used once so it was inlined.
+  */
+ 
+-void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly,
++/* Set F2x[1, 0]9C_x[2B:10] DRAM DQS Receiver Enable Timing Control Registers
++ * See BKDG Rev. 3.62 page 268 for more information
++ */
++void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly,
+                       u8 FinalValue, u8 Channel, u8 Receiver, u32 dev,
+                       u32 index_reg, u8 Addl_Index, u8 Pass)
+ {
+       u32 index;
+       u8 i;
+-      u8 *p;
++      u16 *p;
+       u32 val;
+ 
+-      if(RcvrEnDly == 0xFE) {
+-              /*set the boudary flag */
++      if(RcvrEnDly == 0x1fe) {
++              /*set the boundary flag */
+               pDCTstat->Status |= 1 << SB_DQSRcvLimit;
+       }
+ 
+@@ -543,27 +721,57 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u8 RcvrEnDly,
+               val = Get_NB32_index_wait(dev, index_reg, index);
+               if(i & 1) {
+                       /* odd byte lane */
+-                      val &= ~(0xFF << 16);
+-                      val |= (RcvrEnDly << 16);
++                      val &= ~(0x1ff << 16);
++                      val |= ((RcvrEnDly & 0x1ff) << 16);
+               } else {
+                       /* even byte lane */
+-                      val &= ~0xFF;
+-                      val |= RcvrEnDly;
++                      val &= ~0x1ff;
++                      val |= (RcvrEnDly & 0x1ff);
+               }
+               Set_NB32_index_wait(dev, index_reg, index, val);
+       }
+ 
+ }
+ 
+-static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 
DQSRcvEnDly)
++/* Calculate MaxRdLatency
++ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.5
++ */
++static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, 
u16 DQSRcvEnDly)
+ {
+       u32 dev;
+       u32 reg;
+-      u16 SubTotal;
++      u32 SubTotal;
+       u32 index_reg;
+       u32 reg_off;
+       u32 val;
+-      u32 valx;
++
++      uint8_t cpu_val_n;
++      uint8_t cpu_val_p;
++
++      u16 freq_tab[] = {400, 533, 667, 800};
++
++      /* Set up processor-dependent values */
++      if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
++              /* Revision D and above */
++              cpu_val_n = 4;
++              cpu_val_p = 29;
++      } else if (pDCTstat->LogicalCPUID & AMD_DR_Cx) {
++              /* Revision C */
++              uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++              if ((package_type == PT_L1)             /* Socket F (1207) */
++                      || (package_type == PT_M2)      /* Socket AM3 */
++                      || (package_type == PT_S1)) {   /* Socket S1g<x> */
++                      cpu_val_n = 10;
++                      cpu_val_p = 11;
++              } else {
++                      cpu_val_n = 4;
++                      cpu_val_p = 29;
++              }
++      } else {
++              /* Revision B and below */
++              cpu_val_n = 10;
++              cpu_val_p = 11;
++      }
+ 
+       if(pDCTstat->GangedMode)
+               Channel = 0;
+@@ -598,49 +806,32 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u8 DQ
+       val = Get_NB32(dev, 0x78 + reg_off);
+       SubTotal += 8 - (val & 0x0f);
+ 
+-      /* Convert bits 7-5 (also referred to as the course delay) of
++      /* Convert bits 7-5 (also referred to as the coarse delay) of
+        * the current (or worst case) DQS receiver enable delay to
+        * 1/2 MEMCLKs units, rounding up, and add this to the sub-total.
+        */
+-      SubTotal += DQSRcvEnDly >> 5;   /*BOZO-no rounding up */
++      SubTotal += DQSRcvEnDly >> 5;   /* Retrieve gross delay portion of 
value */
+ 
+-      /* Add 5.5 to the sub-total. 5.5 represents part of the
++      /* Add "P" to the sub-total. "P" represents part of the
+        * processor specific constant delay value in the DRAM
+        * clock domain.
+        */
+       SubTotal <<= 1;         /*scale 1/2 MemClk to 1/4 MemClk */
+-      SubTotal += 11;         /*add 5.5 1/2MemClk */
++      SubTotal += cpu_val_p;  /*add "P" 1/2MemClk */
++      SubTotal >>= 1;         /*scale 1/4 MemClk back to 1/2 MemClk */
+ 
+       /* Convert the sub-total (in 1/2 MEMCLKs) to northbridge
+-       * clocks (NCLKs) as follows (assuming DDR400 and assuming
+-       * that no P-state or link speed changes have occurred).
++       * clocks (NCLKs)
+        */
++      SubTotal *= 200 * ((Get_NB32(pDCTstat->dev_nbmisc, 0xd4) & 0x1f) + 4);
++      SubTotal /= freq_tab[((Get_NB32(pDCTstat->dev_dct, 0x94 + reg_off) & 
0x7) - 3)];
++      SubTotal = (SubTotal + (2 - 1)) / 2;    /* Round up */
+ 
+-      /* New formula:
+-       * SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
+-      val = Get_NB32(dev, 0x94 + reg_off);
+-
+-      /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
+-      val &= 7;
+-      if (val >= 3) {
+-              val <<= 1;
+-      } else
+-              val += 3;
+-      valx = val << 2;
+-
+-      val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4);
+-      SubTotal *= ((val & 0x1f) + 4 ) * 3;
+-
+-      SubTotal /= valx;
+-      if (SubTotal % valx) {  /* round up */
+-              SubTotal++;
+-      }
+-
+-      /* Add 5 NCLKs to the sub-total. 5 represents part of the
++      /* Add "N" NCLKs to the sub-total. "N" represents part of the
+        * processor specific constant value in the northbridge
+        * clock domain.
+        */
+-      SubTotal += 5;
++      SubTotal += (cpu_val_n) / 2;
+ 
+       pDCTstat->CH_MaxRdLat[Channel] = SubTotal;
+       if(pDCTstat->GangedMode) {
+@@ -659,143 +850,6 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u8 DQ
+       Set_NB32(dev, reg, val);
+ }
+ 
+-static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat,
+-                      u8 rcvrEnDly, u8 Channel,
+-                      u8 receiver, u8 Pass)
+-{
+-      u8 i;
+-      u8 mask_Saved, mask_Pass;
+-      u8 *p;
+-
+-      /* calculate dimm offset
+-       * not needed for CH_D_B_RCVRDLY array
+-       */
+-
+-      /* cmp if there has new DqsRcvEnDly to be recorded */
+-      mask_Pass = pDCTstat->DqsRcvEn_Pass;
+-
+-      if(Pass == SecondPass) {
+-              mask_Pass = ~mask_Pass;
+-      }
+-
+-      mask_Saved = pDCTstat->DqsRcvEn_Saved;
+-      if(mask_Pass != mask_Saved) {
+-
+-              /* find desired stack offset according to channel/dimm/byte */
+-              if(Pass == SecondPass) {
+-                      /* FIXME: SecondPass is never used for Barcelona p = 
pDCTstat->CH_D_B_RCVRDLY_1[Channel][receiver>>1]; */
+-                      p = 0; /* Keep the compiler happy. */
+-              } else {
+-                      mask_Saved &= mask_Pass;
+-                      p = pDCTstat->CH_D_B_RCVRDLY[Channel][receiver>>1];
+-              }
+-              for(i=0; i < 8; i++) {
+-                      /* cmp per byte lane */
+-                      if(mask_Pass & (1 << i)) {
+-                              if(!(mask_Saved & (1 << i))) {
+-                                      /* save RcvEnDly to stack, according to
+-                                      the related Dimm/byte lane */
+-                                      p[i] = (u8)rcvrEnDly;
+-                                      mask_Saved |= 1 << i;
+-                              }
+-                      }
+-              }
+-              pDCTstat->DqsRcvEn_Saved = mask_Saved;
+-      }
+-      return mct_SaveRcvEnDly_D_1Pass(pDCTstat, Pass);
+-}
+-
+-static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat,
+-                                      u32 addr, u8 channel,
+-                                      u8 pattern, u8 Pass)
+-{
+-      /* Compare only the first beat of data.  Since target addrs are cache
+-       * line aligned, the Channel parameter is used to determine which
+-       * cache QW to compare.
+-       */
+-
+-      u8 *test_buf;
+-      u8 i;
+-      u8 result;
+-      u8 value;
+-
+-      if(Pass == FirstPass) {
+-              if(pattern==1) {
+-                      test_buf = (u8 *)TestPattern1_D;
+-              } else {
+-                      test_buf = (u8 *)TestPattern0_D;
+-              }
+-      } else {                /* Second Pass */
+-              test_buf = (u8 *)TestPattern2_D;
+-      }
+-
+-      SetUpperFSbase(addr);
+-      addr <<= 8;
+-
+-      if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) {
+-              addr += 8;      /* second channel */
+-              test_buf += 8;
+-      }
+-
+-      print_debug_dqs_pair("\t\t\t\t\t\t  test_buf = ", (u32)test_buf, "  |  
addr_lo = ", addr,  4);
+-      for (i=0; i<8; i++, addr ++) {
+-              value = read32_fs(addr);
+-              print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", test_buf[i], "  |  ", 
value, 4);
+-
+-              if (value == test_buf[i]) {
+-                      pDCTstat->DqsRcvEn_Pass |= (1<<i);
+-              } else {
+-                      pDCTstat->DqsRcvEn_Pass &= ~(1<<i);
+-              }
+-      }
+-
+-      result = DQS_FAIL;
+-
+-      if (Pass == FirstPass) {
+-              /* if first pass, at least one byte lane pass
+-               * ,then DQS_PASS=1 and will set to related reg.
+-               */
+-              if(pDCTstat->DqsRcvEn_Pass != 0) {
+-                      result = DQS_PASS;
+-              } else {
+-                      result = DQS_FAIL;
+-              }
+-
+-      } else {
+-              /* if second pass, at least one byte lane fail
+-               * ,then DQS_FAIL=1 and will set to related reg.
+-               */
+-              if(pDCTstat->DqsRcvEn_Pass != 0xFF) {
+-                      result = DQS_FAIL;
+-              } else {
+-                      result = DQS_PASS;
+-              }
+-      }
+-
+-      /* if second pass, we can't find the fail until FFh,
+-       * then let it fail to save the final delay
+-       */
+-      if((Pass == SecondPass) && (pDCTstat->Status & (1 << SB_DQSRcvLimit))) {
+-              result = DQS_FAIL;
+-              pDCTstat->DqsRcvEn_Pass = 0;
+-      }
+-
+-      /* second pass needs to be inverted
+-       * FIXME? this could be inverted in the above code to start with...
+-       */
+-      if(Pass == SecondPass) {
+-              if (result == DQS_PASS) {
+-                      result = DQS_FAIL;
+-              } else if (result == DQS_FAIL) { /* FIXME: doesn't need to be 
else if */
+-                      result = DQS_PASS;
+-              }
+-      }
+-
+-
+-      return result;
+-}
+-
+ static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+ {
+@@ -854,7 +908,7 @@ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 
Channel)
+       u32 index_reg;
+       u32 index;
+       u8 ChipSel;
+-      u8 *p;
++      u16 *p;
+       u32 val;
+ 
+       dev = pDCTstat->dev_dct;
+@@ -884,7 +938,7 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+ 
+       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
+               if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, ChipSel)) 
{
+-                      u8 *p;
++                      u16 *p;
+                       p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
+ 
+                       /* DQS Delay Value of Data Bytelane
+@@ -920,6 +974,10 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+       SetEccDQSRcvrEn_D(pDCTstat, Channel);
+ }
+ 
++/* 2.8.9.9.4
++ * ECC Byte Lane Training
++ * DQS Receiver Enable Delay
++ */
+ void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+ {
+@@ -1017,7 +1075,9 @@ static void fenceDynTraining_D(struct MCTStatStruc 
*pMCTstat,
+               avRecValue -= 3;
+       else
+       */
+-      if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
++      if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
++              avRecValue -= 8;
++      else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
+               avRecValue -= 8;
+       else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
+               avRecValue -= 8;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
+index c009756..f01e011 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -36,17 +37,12 @@ u32 SetupDqsPattern_1PassB(u8 pass)
+       return (u32) TestPattern0_D;
+ }
+ 
+-u8  mct_Get_Start_RcvrEnDly_1Pass(u8 pass)
+-{
+-      return 0;
+-}
+-
+-static u8 mct_Average_RcvrEnDly_1Pass(struct DCTStatStruc *pDCTstat, u8 
Channel, u8 Receiver,
++static u16 mct_Average_RcvrEnDly_1Pass(struct DCTStatStruc *pDCTstat, u8 
Channel, u8 Receiver,
+                                       u8 Pass)
+ {
+-      u8 i, MaxValue;
+-      u8 *p;
+-      u8 val;
++      u16 i, MaxValue;
++      u16 *p;
++      u16 val;
+ 
+       MaxValue = 0;
+       p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1];
+@@ -76,8 +72,8 @@ u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, 
u8 pass)
+       return ret;
+ }
+ 
+-u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
+-                              u8 RcvrEnDly, u8 RcvrEnDlyLimit,
++u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
++                              u16 RcvrEnDly, u16 RcvrEnDlyLimit,
+                               u8 Channel, u8 Receiver, u8 Pass)
+ 
+ {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
+index b01889d..796febc 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -74,15 +75,15 @@ u8 mct_Get_Start_RcvrEnDly_Pass(struct DCTStatStruc 
*pDCTstat,
+       return RcvrEnDly;
+ }
+ 
+-u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
+-                              u8 RcvrEnDly, u8 RcvrEnDlyLimit,
++u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
++                              u16 RcvrEnDly, u16 RcvrEnDlyLimit,
+                               u8 Channel, u8 Receiver, u8 Pass)
+ {
+       u8 i;
+-      u8 *p;
+-      u8 *p_1;
+-      u8 val;
+-      u8 val_1;
++      u16 *p;
++      u16 *p_1;
++      u16 val;
++      u16 val_1;
+       u8 valid = 1;
+       u8 bn;
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
+index ea5c8c7..920f514 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -191,10 +192,10 @@ static void maxRdLatencyTrain_D(struct MCTStatStruc 
*pMCTstat,
+ 
+ #if DQS_TRAIN_DEBUG > 0
+       {
+-              u8 Channel;
++              u8 ChannelDTD;
+               printk(BIOS_DEBUG, "maxRdLatencyTrain: CH_MaxRdLat:\n");
+-              for(Channel = 0; Channel<2; Channel++) {
+-                      printk(BIOS_DEBUG, "Channel: %02x: %02x\n", Channel, 
pDCTstat->CH_MaxRdLat[Channel]);
++              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
++                      printk(BIOS_DEBUG, "Channel: %02x: %02x\n", ChannelDTD, 
pDCTstat->CH_MaxRdLat[ChannelDTD]);
+               }
+       }
+ #endif
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+index cdeae49..1c3e322 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -58,9 +59,9 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
+       pDCTstat->C_DCTPtr[dct]->LogicalCPUID = pDCTstat->LogicalCPUID;
+ 
+       for (dimm = 0; dimm < MAX_DIMMS; dimm++) {
+-              if (DimmValid & (1 << dimm))
++              if (DimmValid & (1 << (dimm << 1)))
+                       pDCTstat->C_DCTPtr[dct]->DimmPresent[dimm] = 1;
+-              if (Dimmx8Present & (1 << dimm))
++              if (Dimmx8Present & (1 << (dimm << 1)))
+                       pDCTstat->C_DCTPtr[dct]->DimmX8Present[dimm] = 1;
+       }
+ 
+@@ -88,9 +89,9 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
+               u8  DimmRanks;
+               if (DimmValid & (1 << (dimm << 1))) {
+                       DimmRanks = 1;
+-                      if (pDCTstat->DimmDRPresent & (1 << (dimm+dct)))
++                      if (pDCTstat->DimmDRPresent & (1 << ((dimm << 1) + 
dct)))
+                               DimmRanks = 2;
+-                      else if (pDCTstat->DimmQRPresent & (1 << (dimm+dct)))
++                      else if (pDCTstat->DimmQRPresent & (1 << ((dimm << 1) + 
dct)))
+                               DimmRanks = 4;
+               } else
+                       DimmRanks = 0;
+@@ -249,35 +250,6 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+       }
+ }
+ 
+-/* Multiply the previously saved delay values in Pass 1, step #5 by
+-   (target frequency)/400 to find the gross and fine delay initialization
+-   values at the target frequency.
+- */
+-void MultiplyDelay(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, u8 dct)
+-{
+-      u16 index;
+-      u8 Multiplier;
+-      u8 gross, fine;
+-      u16 total;
+-
+-      Multiplier = pDCTstat->TargetFreq;
+-
+-      for (index=0; index < MAX_BYTE_LANES*MAX_LDIMMS; index ++) {
+-              gross = pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index];
+-              fine = pDCTstat->C_DCTPtr[dct]->WLFineDelay[index];
+-
+-              total = gross << 5 | fine;
+-              total *= Multiplier;
+-              if (total % 3)
+-                      total = total / 3 + 1;
+-              else
+-                      total = total / 3;
+-              pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index] = (total & 0xFF) 
>> 5;
+-              pDCTstat->C_DCTPtr[dct]->WLFineDelay[index] = total & 0x1F;
+-      }
+-}
+-
+ /*
+  * the DRAM controller to bring the DRAMs out of self refresh mode.
+  */
+@@ -352,9 +324,9 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+ 
+               if (!DCT1Present)
+                       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
+-              else if (pDCTstat->GangedMode) {
++              else if (pDCTstat->GangedMode)
+                       pDCTstat->CSPresent = 0;
+-              } else
++              else
+                       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[1];
+ 
+               FreqChgCtrlWrd(pMCTstat, pDCTstat);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 212a348..67d705c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -235,6 +236,65 @@ u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
+       return MRSValue;
+ }
+ 
++static uint16_t unbuffered_dimm_nominal_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank)
++{
++      uint16_t term;
++
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      if (number_of_dimms == 1) {
++              if (MaxDimmsInstallable < 3) {
++                      term = 0x04;    /* Rtt_Nom=RZQ/4=60 Ohm */
++              } else {
++                      if (rank_count == 1) {
++                              term = 0x04;    /* Rtt_Nom=RZQ/4=60 Ohm */
++                      } else {
++                              if (rank == 0)
++                                      term = 0x04;    /* Rtt_Nom=RZQ/4=60 Ohm 
*/
++                              else
++                                      term = 0x00;    /* Rtt_Nom=OFF */
++                      }
++              }
++      } else {
++              if (frequency_index < 5)
++                      term = 0x0044;  /* Rtt_Nom=RZQ/6=40 Ohm */
++              else
++                      term = 0x0204;  /* Rtt_Nom=RZQ/8=30 Ohm */
++      }
++
++      return term;
++}
++
++static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank)
++{
++      uint16_t term;
++
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      if (number_of_dimms == 1) {
++              if (MaxDimmsInstallable < 3) {
++                      term = 0x00;    /* Rtt_WR=off */
++              } else {
++                      if (rank_count == 1)
++                              term = 0x00;    /* Rtt_WR=off */
++                      else
++                              term = 0x200;   /* Rtt_WR=RZQ/4=60 Ohm */
++              }
++      } else {
++              term = 0x400;   /* Rtt_WR=RZQ/2=120 Ohm */
++      }
++
++      return term;
++}
++
+ 
/*-----------------------------------------------------------------------------
+  *  void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *DCTData, u8 Dimm, 
BOOL WL)
+  *
+@@ -295,48 +355,23 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+                       tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, 
wl, MemClkFreq, rank);
+               } else {
+-                      if (wl)
+-                      {
+-                              if (pDCTData->MaxDimmsInstalled == 1)
+-                              {
+-                                      if ((pDCTData->DimmRanks[dimm] == 2) && 
(rank == 0))
+-                                      {
+-                                              tempW1 = 0x00;  /* Rtt_Nom=OFF 
*/
+-                                      }
++                      if (wl) {
++                              if (rank == 0) {
++                                      /* Get Rtt_WR for the current DIMM and 
rank */
++                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
++
++                                      /* Convert dynamic termination code to 
corresponding nominal termination code */
++                                      if (dynamic_term == 0x200)
++                                              tempW1 = 0x04;
++                                      else if (dynamic_term == 0x400)
++                                              tempW1 = 0x40;
+                                       else
+-                                      {
+-                                              tempW1 = 0x04;  /* 
Rtt_Nom=RZQ/4=60 Ohm */
+-                                      }
+-                              }
+-                              else    /* 2 Dimms or more per channel */
+-                              {
+-                                      if ((pDCTData->DimmRanks[dimm] == 2) && 
(rank == 1))
+-                                      {
+-                                              tempW1 = 0x00;  /* Rtt_Nom=OFF 
*/
+-                                      }
+-                                      else
+-                                      {
+-                                              if (MemClkFreq == 6) {
+-                                                      tempW1 = 0x04;  /* 
Rtt_Nom=RZQ/4=60 Ohm */
+-                                              } else {
+-                                                      tempW1 = 0x40;/* 
Rtt_Nom=RZQ/2=120 Ohm */
+-                                              }
+-                                      }
+-                              }
+-                      }
+-                      else {  /* 1 or 4 Dimms per channel */
+-                              if ((pDCTData->MaxDimmsInstalled == 1) || 
(pDCTData->MaxDimmsInstalled == 4))
+-                              {
+-                                      tempW1 = 0x04;  /* Rtt_Nom=RZQ/4=60 Ohm 
*/
+-                              }
+-                              else    /* 2 or 3 Dimms per channel */
+-                              {
+-                                      if (MemClkFreq < 5) {
+-                                              tempW1 = 0x0044;        /* 
Rtt_Nom=RZQ/6=40 Ohm */
+-                                      } else {
+-                                              tempW1 = 0x0204;        /* 
Rtt_Nom=RZQ/8=30 Ohm */
+-                                      }
++                                              tempW1 = 0x0;
++                              } else {
++                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+                               }
++                      } else {
++                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+                       }
+               }
+               tempW=tempW|tempW1;
+@@ -353,20 +388,22 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+                       else
+                       {
+                               /* Disable the output drivers of all other 
ranks for
+-                               * the target DIMM. */
++                               * the target DIMM.
++                               */
+                               tempW = bitTestSet(tempW1, Qoff);
+                       }
+               }
+-              /* program MrsAddress[5,1]=output driver impedance control 
(DIC):
+-               * based on F2x[1,0]84[DrvImpCtrl] */
++              /* Program MrsAddress[5,1]=output driver impedance control 
(DIC):
++               * based on F2x[1,0]84[DrvImpCtrl]
++               */
+               tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, 
DrvImpCtrlEnd);
+-              if (bitTest(tempW1,1))
+-              {tempW = bitTestSet(tempW, 5);}
+-              if (bitTest(tempW1,0))
+-              {tempW = bitTestSet(tempW, 1);}
++              if (bitTest(tempW1, 1))
++                      tempW = bitTestSet(tempW, 5);
++              if (bitTest(tempW1, 0))
++                      tempW = bitTestSet(tempW, 1);
+ 
+-              tempW = swapAddrBits_wl(pDCTData,tempW);
++              tempW = swapAddrBits_wl(pDCTData, tempW);
+ 
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+@@ -404,29 +441,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+               if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && 
(pDCTData->Status[DCT_STATUS_REGISTERED]))
+                       tempW+=0x8;
+               /* determine Rtt_WR for WL & Normal mode */
+-              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++              if (pDCTData->Status[DCT_STATUS_REGISTERED])
+                       tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, 
MemClkFreq, rank);
+-              } else {
+-                      if (wl)
+-                      {
+-                              tempW1 = 0x00;  /* Rtt_WR=off */
+-                      }
+-                      else
+-                      {
+-                              if (pDCTData->MaxDimmsInstalled == 1)
+-                              {
+-                                      tempW1 = 0x00;  /* Rtt_WR=off */
+-                              }
+-                              else
+-                              {
+-                                      if (MemClkFreq == 6) {
+-                                              tempW1 = 0x200; /* 
Rtt_WR=RZQ/4=60 Ohm */
+-                                      } else {
+-                                              tempW1 = 0x400; /* Rtt_WR=RZQ/2 
*/
+-                                      }
+-                              }
+-                      }
+-              }
++              else
++                      tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+               tempW=tempW|tempW1;
+               tempW = swapAddrBits_wl(pDCTData,tempW);
+               set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+@@ -483,38 +501,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+                                       }
+ 
+                                       /* determine Rtt_Nom for WL & Normal 
mode */
+-                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
+                                               tempW1 = 
RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
+-                                      } else {
+-                                              if (wl)
+-                                              {
+-                                                      if 
((pDCTData->DimmRanks[currDimm] == 2) && (rank == 1))
+-                                                      {
+-                                                              tempW1 = 0x00;  
/* Rtt_Nom=OFF */
+-                                                      }
+-                                                      else
+-                                                      {
+-                                                              if (MemClkFreq 
< 5) {
+-                                                                      tempW1 
= 0x0044;/* Rtt_Nom=RZQ/6=40 Ohm */
+-                                                              } else {
+-                                                                      tempW1 
= 0x0204;/* Rtt_Nom=RZQ/8=30 Ohm */
+-                                                              }
+-                                                      }
+-                                              }
+-                                              else {  /* 1 or 4 Dimms per 
channel */
+-                                                      if 
(pDCTData->MaxDimmsInstalled == 4)
+-                                                      {
+-                                                              tempW1 = 0x04;  
/* Rtt_Nom=RZQ/4=60 Ohm */
+-                                                      }
+-                                                      else {  /* 2 or 3 Dimms 
per channel */
+-                                                              if (MemClkFreq 
< 5) {
+-                                                                      tempW1 
= 0x0044;        /* Rtt_Nom=RZQ/6=40 Ohm */
+-                                                              } else {
+-                                                                      tempW1 
= 0x0204;        /* Rtt_Nom=RZQ/8=30 Ohm */
+-                                                              }
+-                                                      }
+-                                              }
+-                                      }
++                                      else
++                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
+                                       tempW=tempW|tempW1;
+                                       /* program MrsAddress[5,1]=output 
driver impedance control (DIC):
+                                        * based on F2x[1,0]84[DrvImpCtrl] */
+@@ -560,22 +550,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+                                       if ((pDCTData->LogicalCPUID & 
AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
+                                               tempW+=0x8;
+                                       /* determine Rtt_WR for WL & Normal 
mode */
+-                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
+                                               tempW1 = RttWrRegDimm(pMCTData, 
pDCTData, currDimm, wl, MemClkFreq, rank);
+-                                      } else {
+-                                              if (wl)
+-                                              {
+-                                                      tempW1 = 0x00;  /* 
Rtt_WR=off */
+-                                              }
+-                                              else
+-                                              {
+-                                                      if (MemClkFreq == 6) {
+-                                                              tempW1 = 0x200; 
/* Rtt_WR=RZQ/4=60 Ohm */
+-                                                      } else {
+-                                                              tempW1 = 0x400; 
/* Rtt_WR=RZQ/2 */
+-                                                      }
+-                                              }
+-                                      }
++                                      else
++                                              tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
+                                       tempW=tempW|tempW1;
+                                       tempW = swapAddrBits_wl(pDCTData,tempW);
+                                       set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
+@@ -646,9 +624,14 @@ void programODT(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm)
+  */
+ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
+ {
+-      u8 ByteLane, Seed_Gross, Seed_Fine;
++      u8 ByteLane, Seed_Gross, Seed_Fine, MemClkFreq;
+       u32 Value, Addr;
+       u16 Addl_Data_Offset, Addl_Data_Port;
++      u16 freq_tab[] = {400, 533, 667, 800};
++
++      /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
++      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
++                              FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
+ 
+       /* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for 
the
+        * current memory subsystem configuration.
+@@ -656,12 +639,13 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
+       programODT(pMCTData, pDCTData, dimm);
+ 
+       /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
+-      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
++      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) {
+               set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
+                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, 
WrLvOdtEn, (u32)1);
++      }
+       else
+       {
+-              /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 
0 for Rev.B*/
++              /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 
0 for Rev.B */
+               if (pDCTData->DctTrain)
+               {
+                       Addl_Data_Offset=0x198;
+@@ -687,7 +671,6 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, 
u8 dimm, u8 pass)
+ 
+       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
+       pMCTData->AgesaDelay(10);
+-      ByteLane = 0;
+       if (pass == 1)
+       {
+               if (pDCTData->Status[DCT_STATUS_REGISTERED])
+@@ -705,10 +688,17 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
+               }
+               else
+               {
+-                      Seed_Gross = 0x00;
+-                      Seed_Fine = 0x1A;
++                      if (MemClkFreq == 6) {
++                              /* DDR-800 */
++                              Seed_Gross = 0x00;
++                              Seed_Fine = 0x1a;
++                      } else {
++                              /* Use settings for DDR-400 (interpolated from 
BKDG) */
++                              Seed_Gross = 0x00;
++                              Seed_Fine = 0x0d;
++                      }
+               }
+-              while(ByteLane < MAX_BYTE_LANES)
++              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
+               {
+                       /* Program an initialization value to registers F2x[1, 
0]9C_x[51:50] and
+                        * F2x[1, 0]9C_x52 to set the gross and fine delay for 
all the byte lane fields
+@@ -720,35 +710,32 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
+                        */
+                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
+                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
+-                      ByteLane++;
+               }
+-      } else if (pDCTData->Status[DCT_STATUS_REGISTERED]) {           /* For 
Pass 2 */
++      } else {                /* Pass 2 */
+               /* From BKDG, Write Leveling Seed Value. */
+-              /* TODO: The unbuffered DIMMs are unstable on the code below. 
So temporarily it is
+-               * only for registered DIMMs. */
+               u32 RegisterDelay, SeedTotal;
+-              u8 MemClkFreq;
+-              u16 freq_tab[] = {400, 533, 667, 800};
+-              while(ByteLane < MAX_BYTE_LANES)
++              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
+               {
+-                      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
+-                                            FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
+                       if (pDCTData->Status[DCT_STATUS_REGISTERED])
+                               RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) 
== 0) ? 0x20 : 0x30; */
+                       else
+                               RegisterDelay = 0;
+-                      SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1F) |
+-                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5;
++                      SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
++                              
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
+                       /* SeedTotalPreScaling = (the total delay value in 
F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
+                          training) - RegisterDelay. */
+-                      /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 
800MHz */
+-                      SeedTotal = (u16) (RegisterDelay + ((((u32) SeedTotal - 
RegisterDelay) *
+-                                                           
freq_tab[MemClkFreq-3]) / 400));
+-                      Seed_Gross = (SeedTotal & 0x20) != 0 ? 1 : 2;
+-                      Seed_Fine = SeedTotal & 0x1F;
++                      SeedTotal = (uint16_t) (RegisterDelay + ((((uint64_t) 
SeedTotal - RegisterDelay) *
++                                                              
freq_tab[MemClkFreq-3] * 100) / (freq_tab[0] * 100)));
++                      Seed_Gross = SeedTotal / 32;
++                      Seed_Fine = SeedTotal & 0x1f;
++                      if (Seed_Gross == 0)
++                              Seed_Gross = 0;
++                      else if (Seed_Gross & 0x1)
++                              Seed_Gross = 1;
++                      else
++                              Seed_Gross = 2;
+                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
+                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
+-                      ByteLane ++;
+               }
+       }
+ 
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index ea32893..c00cf24 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -59,6 +59,10 @@ static u16 mctGet_NVbits(u8 index)
+               val = 1;
+ #elif CONFIG_CPU_SOCKET_TYPE == 0x13  /* ASB2 */
+               val = 4;
++#elif CONFIG_CPU_SOCKET_TYPE == 0x14  /* C32 */
++              val = 5;
++#elif CONFIG_CPU_SOCKET_TYPE == 0x15  /* G34 */
++              val = 3;
+ //#elif SYSTEM_TYPE == MOBILE
+ //            val = 2;
+ #endif
+@@ -297,6 +301,8 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+       /* Determine the number of installed DIMMs */
+       int ch1_count = 0;
+       int ch2_count = 0;
++      uint8_t ch1_registered = 0;
++      uint8_t ch2_registered = 0;
+       int i;
+       for (i = 0; i < 15; i = i + 2) {
+               if (pDCTstat->DIMMValid & (1 << i))
+@@ -304,6 +310,12 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+               if (pDCTstat->DIMMValid & (1 << (i + 1)))
+                       ch2_count++;
+       }
++      for (i = 0; i < MAX_DIMMS_SUPPORTED; i = i + 2) {
++              if (pDCTstat->DimmRegistered[i])
++                      ch1_registered = 1;
++              if (pDCTstat->DimmRegistered[i + 1])
++                      ch2_registered = 1;
++      }
+       if (IS_ENABLED(CONFIG_DEBUG_RAM_SETUP)) {
+               printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 1: %d DIMM(s) 
detected\n", ch1_count);
+               printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 2: %d DIMM(s) 
detected\n", ch2_count);
+@@ -413,101 +425,6 @@ static void mctHookAfterDramInit(void)
+ }
+ 
+ #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+-static void coreDelay(u32 microseconds)
+-{
+-      msr_t now;
+-      msr_t end;
+-      u32 cycles;
+-
+-      /* delay ~40us
+-         This seems like a hack to me...
+-         It would be nice to have a central delay function. */
+-
+-      cycles = (microseconds * 100) << 3;  /* x8 (number of 1.25ns ticks) */
+-
+-        if (!(rdmsr(HWCR).lo & TSC_FREQ_SEL_MASK)) {
+-            msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
+-            if (!(rdmsr(0xC0010064+pstate_msr.lo).lo & NB_DID_M_ON)) {
+-            cycles = cycles <<1; // half freq, double cycles
+-          }
+-      } // else should we keep p0 freq at the time of setting 
TSC_FREQ_SEL_MASK somewhere and check it here ?
+-
+-      now = rdmsr(TSC_MSR);
+-        // avoid overflow when called near 2^32 ticks ~ 5.3 s boundaries
+-      if (0xffffffff - cycles >= now.lo ) {
+-        end.hi =  now.hi;
+-          end.lo = now.lo + cycles;
+-      } else {
+-          end.hi = now.hi +1; //
+-          end.lo = cycles - (1+(0xffffffff - now.lo));
+-      }
+-      do {
+-          now = rdmsr(TSC_MSR);
+-        } while ((now.hi < end.hi) || ((now.hi == end.hi) && (now.lo < 
end.lo)));
+-}
+-
+-/* Erratum 350 */
+-static void vErrata350(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat)
+-{
+-      u8 u8Channel;
+-      u8 u8Receiver;
+-      u32 u32Addr;
+-      u8 u8Valid;
+-      u32 u32DctDev;
+-
+-      // 1. dummy read for each installed DIMM */
+-      for (u8Channel = 0; u8Channel < 2; u8Channel++) {
+-              // This will be 0 for vaild DIMMS, eles 8
+-              u8Receiver = mct_InitReceiver_D(pDCTstat, u8Channel);
+-
+-              for (; u8Receiver < 8; u8Receiver += 2) {
+-                      u32Addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, 
u8Channel, u8Receiver, &u8Valid);
+-
+-                      if(!u8Valid) {  /* Address not supported on current CS 
*/
+-                              print_t("vErrata350: Address not supported on 
current CS\n");
+-                              continue;
+-                      }
+-                      print_t("vErrata350: dummy read \n");
+-                      read32_fs(u32Addr);
+-              }
+-      }
+-
+-      print_t("vErrata350: step 2a\n");
+-
+-      /* 2. Write 0000_8000h to register F2x[1, 0]9C_xD080F0C. */
+-      u32DctDev = pDCTstat->dev_dct;
+-      Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00008000);
+-      /*                                                ^--- value
+-                                              ^---F2x[1, 0]9C_x0D080F0C, No 
description in BKDG.
+-                                       ^----F2x[1, 0]98 DRAM Controller 
Additional Data Offset Register */
+-
+-      if(!pDCTstat->GangedMode) {
+-              print_t("vErrata350: step 2b\n");
+-              Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00008000);
+-              /*                                                ^--- value
+-                                                      ^---F2x[1, 
0]9C_x0D080F0C, No description in BKDG
+-                                              ^----F2x[1, 0]98 DRAM 
Controller Additional Data Offset Register */
+-      }
+-
+-      print_t("vErrata350: step 3\n");
+-      /* 3. Wait at least 300 nanoseconds. */
+-      coreDelay(1);
+-
+-      print_t("vErrata350: step 4\n");
+-      /* 4. Write 0000_0000h to register F2x[1, 0]9C_xD080F0C. */
+-      Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00000000);
+-
+-      if(!pDCTstat->GangedMode) {
+-              print_t("vErrata350: step 4b\n");
+-              Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00000000);
+-      }
+-
+-      print_t("vErrata350: step 5\n");
+-      /* 5. Wait at least 2 microseconds. */
+-      coreDelay(2);
+-
+-}
+-
+ static void vErratum372(struct DCTStatStruc *pDCTstat)
+ {
+         msr_t msr = rdmsr(NB_CFG_MSR);
+@@ -546,8 +463,7 @@ static void mctHookBeforeAnyTraining(struct MCTStatStruc 
*pMCTstat, struct DCTSt
+ {
+ #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+   /* FIXME :  as of 25.6.2010 errata 350 and 372 should apply to  
((RB|BL|DA)-C[23])|(HY-D[01])|(PH-E0) but I don't find constants for all of 
them */
+-      if (pDCTstatA->LogicalCPUID & AMD_DRBH_Cx) {
+-              vErrata350(pMCTstat, pDCTstatA);
++      if (pDCTstatA->LogicalCPUID & (AMD_DRBH_Cx | AMD_DR_Dx)) {
+               vErratum372(pDCTstatA);
+               vErratum414(pDCTstatA);
+       }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdfam10-Fix-typo-in-comment.patch
 
b/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdfam10-Fix-typo-in-comment.patch
deleted file mode 100644
index e28528b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdfam10-Fix-typo-in-comment.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 72842e77d6207be18f86c8fbc3fc398808f4d69e Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:01:31 -0500
-Subject: [PATCH 011/139] northbridge/amd/amdfam10: Fix typo in comment
-
-Change-Id: I0a9b3a66231052622c862bae32b900f52f6efba9
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/misc_control.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
-index e242e34..90a4db1 100644
---- a/src/northbridge/amd/amdfam10/misc_control.c
-+++ b/src/northbridge/amd/amdfam10/misc_control.c
-@@ -47,7 +47,7 @@
-  * The same trick can be used to augment legacy VGA resources which can
-  * be detect by generic pci reousrce allocator for VGA devices.
-  * BAD: it is more tricky than I think, the resource allocation code is
-- * implemented in a way to NOT DOING legacy VGA resource allcation on
-+ * implemented in a way to NOT DOING legacy VGA resource allocation on
-  * purpose :-(.
-  */
- static void mcf3_read_resources(device_t dev)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
 
b/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
new file mode 100644
index 0000000..df89fbc
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch
@@ -0,0 +1,95 @@
+From 55eeaf44d331c7f42a7b03f22364d6a5a6febb47 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 8 Sep 2015 16:08:45 -0500
+Subject: [PATCH 011/143] northbridge/amd/amdmct/mct_ddr3: Fix curly brace
+ style violations
+
+Change-Id: Ic27d404a7ed76b58043037e8b66097db6d664501
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c |   37 +++++++------------------
+ 1 file changed, 10 insertions(+), 27 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 67d705c..397fd77 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -818,28 +818,19 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
+ 
+               tempB = 0;
+               offsetAddr = (u8)(3 * dimm);
+-              if (ByteLane < 2)
+-              {
++              if (ByteLane < 2) {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01;
+-              }
+-              else if (ByteLane <4)
+-              {
++              } else if (ByteLane <4) {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 1;
+-              }
+-              else if (ByteLane <6)
+-              {
++              } else if (ByteLane <6) {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45;
+-              }
+-              else if (ByteLane <8)
+-              {
++              } else if (ByteLane <8) {
+                       tempB = (u8)(16 * ByteLane);
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 + 1;
+-              }
+-              else
+-              {
++              } else {
+                       tempB = 0;
+                       addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 2;
+               }
+@@ -883,19 +874,14 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm)
+       u32 addr, fine, gross;
+       tempB = 0;
+       index = (u8)(MAX_BYTE_LANES*dimm);
+-      if (ByteLane < 4)
+-      {
++      if (ByteLane < 4) {
+               tempB = (u8)(8 * ByteLane);
+               addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;
+-      }
+-      else if (ByteLane < 8)
+-      {
++      } else if (ByteLane < 8) {
+               tempB1 = (u8)(ByteLane - 4);
+               tempB = (u8)(8 * tempB1);
+               addr = DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH;
+-      }
+-      else
+-      {
++      } else {
+               tempB = 0;
+               addr = DRAM_CONT_ADD_ECC_PHASE_REC_CTRL;
+       }
+@@ -911,16 +897,13 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm)
+       /* Adjust seed gross delay overflow (greater than 3):
+        * - Adjust the trained gross delay to the original seed gross delay.
+        */
+-      if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
+-      {
++      if (pDCTData->WLGrossDelay[index+ByteLane] >= 3) {
+               gross += pDCTData->WLGrossDelay[index+ByteLane];
+               if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
+                       gross -= 1;
+               else
+                       gross -= 2;
+-      }
+-      else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
+-      {
++      } else if ((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 
3)) {
+               /* If seed gross delay is 0 but PRE result gross delay is 3, it 
is negative.
+                * We will then round the negative number to 0.
+                */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0012-device-hypertransport-Add-additional-debug-output.patch
 
b/resources/libreboot/patch/kgpe-d16/0012-device-hypertransport-Add-additional-debug-output.patch
deleted file mode 100644
index 61a3c56..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0012-device-hypertransport-Add-additional-debug-output.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 8791b352073e2738c7adfee154ffcab65ae6cdd6 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:06:52 -0500
-Subject: [PATCH 012/139] device/hypertransport: Add additional debug output
-
-Change-Id: I94b870f47581a4a2591d02eeb37627666e0f4297
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/device/hypertransport.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/device/hypertransport.c b/src/device/hypertransport.c
-index 07a320d..c76cb21 100644
---- a/src/device/hypertransport.c
-+++ b/src/device/hypertransport.c
-@@ -8,6 +8,7 @@
-  * Copyright (C) 2005-2006 Tyan
-  * (Written by Yinghai Lu <address@hidden> for Tyan)
-  * Copyright (C) 2005-2006 Stefan Reinauer <address@hidden>
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -263,6 +264,8 @@ static unsigned int do_hypertransport_scan_chain(struct 
bus *bus, unsigned min_d
-       struct ht_link prev;
-       int ht_dev_num = 0;
- 
-+      printk(BIOS_SPEW, "%s for bus %02x\n", __func__, bus->secondary);
-+
-       min_unitid = (offset_unitid) ? CONFIG_HT_CHAIN_UNITID_BASE : 1;
- 
- #if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0012-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
 
b/resources/libreboot/patch/kgpe-d16/0012-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
new file mode 100644
index 0000000..95d7433
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0012-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch
@@ -0,0 +1,121 @@
+From 2eaf40d0574de0c971af14915222d604998d3636 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:00:27 -0500
+Subject: [PATCH 012/143] northbridge/amd/amdfam10: Limit maximum RAM clock to
+ BKDG recommendations
+
+Change-Id: I45eb03a4b351e458e8448245896743bd6fa57637
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/raminit_amdmct.c |   46 +++++++++++++++++++++----
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c  |    2 +-
+ 2 files changed, 41 insertions(+), 7 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+index a585fae..3f33eba 100644
+--- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
++++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+@@ -44,29 +44,58 @@ static  void print_tf(const char *func, const char *strval)
+ #endif
+ }
+ 
+-static uint16_t mct_MaxLoadFreq(uint8_t count, uint16_t freq)
++static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t 
freq)
+ {
+       /* Return limited maximum RAM frequency */
+       if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
+-              if (IS_ENABLED(CONFIG_DIMM_REGISTERED)) {
++              if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
+                       /* K10 BKDG Rev. 3.62 Table 53 */
+                       if (count > 2) {
+                               /* Limit to DDR2-533 */
+                               if (freq > 266) {
+                                       freq = 266;
+-                                      print_tf(__func__, ": More than 2 DIMMs 
on channel; limiting to DDR2-533\n");
++                                      print_tf(__func__, ": More than 2 
registered DIMMs on channel; limiting to DDR2-533\n");
+                               }
+                       }
+-              }
+-              else {
++              } else {
+                       /* K10 BKDG Rev. 3.62 Table 52 */
+                       if (count > 1) {
+                               /* Limit to DDR2-800 */
+                               if (freq > 400) {
+                                       freq = 400;
+-                                      print_tf(__func__, ": More than 1 DIMM 
on channel; limiting to DDR2-800\n");
++                                      print_tf(__func__, ": More than 1 
unbuffered DIMM on channel; limiting to DDR2-800\n");
++                              }
++                      }
++              }
++      } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++              if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
++                      /* K10 BKDG Rev. 3.62 Table 34 */
++                      if (count > 2) {
++                              /* Limit to DDR3-800 */
++                              if (freq > 400) {
++                                      freq = 400;
++                                      print_tf(__func__, ": More than 2 
registered DIMMs on channel; limiting to DDR3-800\n");
++                              }
++                      } else if (count == 2) {
++                              /* Limit to DDR3-1066 */
++                              if (freq > 533) {
++                                      freq = 533;
++                                      print_tf(__func__, ": 2 registered 
DIMMs on channel; limiting to DDR3-1066\n");
++                              }
++                      } else {
++                              /* Limit to DDR3-1333 */
++                              if (freq > 666) {
++                                      freq = 666;
++                                      print_tf(__func__, ": 1 registered DIMM 
on channel; limiting to DDR3-1333\n");
+                               }
+                       }
++              } else {
++                      /* K10 BKDG Rev. 3.62 Table 33 */
++                      /* Limit to DDR3-1333 */
++                      if (freq > 666) {
++                              freq = 666;
++                              print_tf(__func__, ": unbuffered DIMMs on 
channel; limiting to DDR3-1333\n");
++                      }
+               }
+       }
+ 
+@@ -120,6 +149,9 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint16_t 
freq)
+ //C32
+ #elif CONFIG_CPU_SOCKET_TYPE == 0x14
+ #include "../amdmct/mct_ddr3/mctardk5.c"
++//G34
++#elif CONFIG_CPU_SOCKET_TYPE == 0x15
++#include "../amdmct/mct_ddr3/mctardk5.c"
+ #endif
+ 
+ #else  /* DDR2 */
+@@ -207,6 +239,7 @@ static void raminit_amdmct(struct sys_info *sysinfo)
+       printk(BIOS_DEBUG, "raminit_amdmct end:\n");
+ }
+ 
++#if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
+ static void amdmct_cbmem_store_info(struct sys_info *sysinfo)
+ {
+       if (!sysinfo)
+@@ -245,3 +278,4 @@ static void amdmct_cbmem_store_info(struct sys_info 
*sysinfo)
+       }
+ #endif
+ }
++#endif
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index c00cf24..444adc5 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -322,7 +322,7 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+       }
+ 
+       /* Set limits if needed */
+-      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
pDCTstat->PresetmaxFreq);
++      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
(ch1_registered || ch2_registered), pDCTstat->PresetmaxFreq);
+ }
+ 
+ #ifdef UNUSED_CODE
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0013-device-hypertransport-Add-additional-debug-output.patch
 
b/resources/libreboot/patch/kgpe-d16/0013-device-hypertransport-Add-additional-debug-output.patch
new file mode 100644
index 0000000..f769827
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0013-device-hypertransport-Add-additional-debug-output.patch
@@ -0,0 +1,35 @@
+From e74e5090163511c5e7820cee396f407f292c6b32 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:06:52 -0500
+Subject: [PATCH 013/143] device/hypertransport: Add additional debug output
+
+Change-Id: I94b870f47581a4a2591d02eeb37627666e0f4297
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/device/hypertransport.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/device/hypertransport.c b/src/device/hypertransport.c
+index 07a320d..c76cb21 100644
+--- a/src/device/hypertransport.c
++++ b/src/device/hypertransport.c
+@@ -8,6 +8,7 @@
+  * Copyright (C) 2005-2006 Tyan
+  * (Written by Yinghai Lu <address@hidden> for Tyan)
+  * Copyright (C) 2005-2006 Stefan Reinauer <address@hidden>
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -263,6 +264,8 @@ static unsigned int do_hypertransport_scan_chain(struct 
bus *bus, unsigned min_d
+       struct ht_link prev;
+       int ht_dev_num = 0;
+ 
++      printk(BIOS_SPEW, "%s for bus %02x\n", __func__, bus->secondary);
++
+       min_unitid = (offset_unitid) ? CONFIG_HT_CHAIN_UNITID_BASE : 1;
+ 
+ #if CONFIG_HT_CHAIN_END_UNITID_BASE != 0x20
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0013-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
 
b/resources/libreboot/patch/kgpe-d16/0013-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
deleted file mode 100644
index 7dc753a..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0013-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
+++ /dev/null
@@ -1,3221 +0,0 @@
-From 2515607768d1699c148a9eee0e40ccaeb8bb0650 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 30 Apr 2015 01:47:31 -0500
-Subject: [PATCH 013/139] mainboard/asus/kgpe-d16: Add initial support for the
- KGPE-D16
-
-As of this commit S3 suspend does not work on any K10 boards,
-including this board.
-
-Change-Id: Idd3971422fb2473bff7c60fe8d8161d6e20808ed
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/Kconfig          |  95 ++++
- src/mainboard/asus/kgpe-d16/Kconfig.name     |   2 +
- src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl | 367 ++++++++++++++
- src/mainboard/asus/kgpe-d16/acpi_tables.c    |  75 +++
- src/mainboard/asus/kgpe-d16/board_info.txt   |   5 +
- src/mainboard/asus/kgpe-d16/bootblock.c      |  52 ++
- src/mainboard/asus/kgpe-d16/cmos.default     |  16 +
- src/mainboard/asus/kgpe-d16/cmos.layout      | 134 +++++
- src/mainboard/asus/kgpe-d16/devicetree.cb    | 248 +++++++++
- src/mainboard/asus/kgpe-d16/dsdt.asl         | 730 +++++++++++++++++++++++++++
- src/mainboard/asus/kgpe-d16/get_bus_conf.c   | 128 +++++
- src/mainboard/asus/kgpe-d16/irq_tables.c     | 112 ++++
- src/mainboard/asus/kgpe-d16/mainboard.c      |  81 +++
- src/mainboard/asus/kgpe-d16/mb_sysconf.h     |  44 ++
- src/mainboard/asus/kgpe-d16/mptable.c        | 231 +++++++++
- src/mainboard/asus/kgpe-d16/resourcemap.c    | 284 +++++++++++
- src/mainboard/asus/kgpe-d16/romstage.c       | 422 ++++++++++++++++
- src/mainboard/asus/kgpe-d16/spd_notes.txt    |  30 ++
- 18 files changed, 3056 insertions(+)
- create mode 100644 src/mainboard/asus/kgpe-d16/Kconfig
- create mode 100644 src/mainboard/asus/kgpe-d16/Kconfig.name
- create mode 100644 src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
- create mode 100644 src/mainboard/asus/kgpe-d16/acpi_tables.c
- create mode 100644 src/mainboard/asus/kgpe-d16/board_info.txt
- create mode 100644 src/mainboard/asus/kgpe-d16/bootblock.c
- create mode 100644 src/mainboard/asus/kgpe-d16/cmos.default
- create mode 100644 src/mainboard/asus/kgpe-d16/cmos.layout
- create mode 100644 src/mainboard/asus/kgpe-d16/devicetree.cb
- create mode 100644 src/mainboard/asus/kgpe-d16/dsdt.asl
- create mode 100644 src/mainboard/asus/kgpe-d16/get_bus_conf.c
- create mode 100644 src/mainboard/asus/kgpe-d16/irq_tables.c
- create mode 100644 src/mainboard/asus/kgpe-d16/mainboard.c
- create mode 100644 src/mainboard/asus/kgpe-d16/mb_sysconf.h
- create mode 100644 src/mainboard/asus/kgpe-d16/mptable.c
- create mode 100644 src/mainboard/asus/kgpe-d16/resourcemap.c
- create mode 100644 src/mainboard/asus/kgpe-d16/romstage.c
- create mode 100644 src/mainboard/asus/kgpe-d16/spd_notes.txt
-
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-new file mode 100644
-index 0000000..95b3b5b
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -0,0 +1,95 @@
-+if BOARD_ASUS_KGPE_D16
-+
-+config BOARD_SPECIFIC_OPTIONS # dummy
-+      def_bool y
-+      select CPU_AMD_SOCKET_G34_NON_AGESA
-+      select DIMM_DDR3
-+      select DIMM_REGISTERED
-+      # select QRANK_DIMM_SUPPORT
-+      select NORTHBRIDGE_AMD_AMDFAM10
-+      select SOUTHBRIDGE_AMD_SR5650
-+      select SOUTHBRIDGE_AMD_SB700
-+      select SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
-+      select SUPERIO_NUVOTON_NCT5572D
-+      select PARALLEL_CPU_INIT
-+      select HAVE_HARD_RESET
-+      select HAVE_OPTION_TABLE
-+      select HAVE_CMOS_DEFAULT
-+      select HAVE_PIRQ_TABLE
-+      select HAVE_MP_TABLE
-+      select HAVE_ACPI_TABLES
-+      select SB_HT_CHAIN_UNITID_OFFSET_ONLY
-+      select LIFT_BSP_APIC_ID
-+      select BOARD_ROMSIZE_KB_2048
-+      select ENABLE_APIC_EXT_ID
-+      select MMCONF_SUPPORT_DEFAULT
-+      select DRIVERS_I2C_W83795
-+      select DRIVERS_ASPEED_AST2050
-+      select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG
-+
-+config MAINBOARD_DIR
-+      string
-+      default asus/kgpe-d16
-+
-+config BOOTBLOCK_MAINBOARD_INIT
-+      string
-+      default "mainboard/asus/kgpe-d16/bootblock.c"
-+
-+config DCACHE_RAM_BASE
-+      hex
-+      default 0xc2000
-+
-+config DCACHE_RAM_SIZE
-+      hex
-+      default 0x1e000
-+
-+config APIC_ID_OFFSET
-+      hex
-+      default 0
-+
-+config MAINBOARD_PART_NUMBER
-+      string
-+      default "KGPE-D16"
-+
-+config HW_MEM_HOLE_SIZEK
-+      hex
-+      default 0x100000
-+
-+config PCI_64BIT_PREF_MEM
-+      bool
-+      default n
-+
-+config MAX_CPUS
-+      int
-+      default 32
-+
-+# 2 (internal) processors per G34 socket
-+config MAX_PHYSICAL_CPUS
-+      int
-+      default 4
-+
-+config SB_HT_CHAIN_ON_BUS0
-+      int
-+      default 1
-+
-+config HT_CHAIN_UNITID_BASE
-+      hex
-+      default 0x0
-+
-+config HT_CHAIN_END_UNITID_BASE
-+      hex
-+      default 0x20
-+
-+config IRQ_SLOT_COUNT
-+      int
-+      default 13
-+
-+config ONBOARD_VGA_IS_PRIMARY
-+      bool
-+      default y
-+
-+config MAINBOARD_POWER_ON_AFTER_POWER_FAIL
-+      bool
-+      default y
-+
-+endif # BOARD_ASUS_KGPE_D16
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig.name 
b/src/mainboard/asus/kgpe-d16/Kconfig.name
-new file mode 100644
-index 0000000..bdfa31a
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig.name
-@@ -0,0 +1,2 @@
-+config BOARD_ASUS_KGPE_D16
-+      bool "KGPE-D16"
-diff --git a/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl 
b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
-new file mode 100644
-index 0000000..b3c65ca
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
-@@ -0,0 +1,367 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2009 Advanced Micro Devices, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+/*
-+ * WARNING: Sleep/Wake is a work in progress and is still somewhat flaky!
-+ */
-+
-+      /* Port 80 POST card debug */
-+      OperationRegion (DBG0, SystemIO, 0x80, One)
-+              Field (DBG0, ByteAcc, NoLock, Preserve) {
-+              DBG8, 8
-+      }
-+
-+      /* SuperIO control port */
-+      Name (SPIO, 0x2E)
-+
-+      /* SuperIO control map */
-+      OperationRegion (SPIM, SystemIO, SPIO, 0x02)
-+              Field (SPIM, ByteAcc, NoLock, Preserve) {
-+              INDX, 8,
-+              DATA, 8
-+      }
-+
-+      /* SuperIO control registers */
-+      IndexField (INDX, DATA, ByteAcc, NoLock, Preserve) {
-+              Offset (0x07),
-+              CR07, 8,                /* Logical device number */
-+              Offset (0x2C),
-+              CR2C, 8,                /* GPIO3 multiplexed pin selection */
-+              Offset (0x30),
-+              CR30, 8,                /* Logical device activation control 
register */
-+              Offset (0xE0),
-+              CRE0, 8,                /* Wake control register */
-+              Offset (0xE6),
-+              CRE6, 8,                /* Mouse wake event configuration 
register */
-+              Offset (0xF1),
-+              CRF1, 8,                /* GPIO3 data register */
-+              Offset (0xF3),
-+              CRF3, 8,                /* SUSLED mode register */
-+              Offset (0xF6),
-+              CRF6, 8,                /* SMI/PME event generation control 
register */
-+              Offset (0xF9),
-+              CRF9, 8,                /* ACPI PME configuration register */
-+      }
-+
-+      /* Power Management I/O registers */
-+      OperationRegion(PIOR, SystemIO, 0x00000CD6, 0x00000002)
-+              Field(PIOR, ByteAcc, NoLock, Preserve) {
-+              PIOI, 0x00000008,
-+              PIOD, 0x00000008,
-+      }
-+      IndexField (PIOI, PIOD, ByteAcc, NoLock, Preserve) {
-+              Offset(0x00),   /* MiscControl */
-+              , 1,
-+              T1EE, 1,
-+              T2EE, 1,
-+              Offset(0x01),   /* MiscStatus */
-+              , 1,
-+              T1E, 1,
-+              T2E, 1,
-+              Offset(0x04),   /* SmiWakeUpEventEnable3 */
-+              , 7,
-+              SSEN, 1,
-+              Offset(0x07),   /* SmiWakeUpEventStatus3 */
-+              , 7,
-+              CSSM, 1,
-+              Offset(0x10),   /* AcpiEnable */
-+              , 6,
-+              PWDE, 1,
-+              Offset(0x1C),   /* ProgramIoEnable */
-+              , 3,
-+              MKME, 1,
-+              IO3E, 1,
-+              IO2E, 1,
-+              IO1E, 1,
-+              IO0E, 1,
-+              Offset(0x1D),   /* IOMonitorStatus */
-+              , 3,
-+              MKMS, 1,
-+              IO3S, 1,
-+              IO2S, 1,
-+              IO1S, 1,
-+              IO0S,1,
-+              Offset(0x20),   /* AcpiPmEvtBlk */
-+              APEB, 16,
-+              Offset(0x36),   /* GEvtLevelConfig */
-+              , 6,
-+              ELC6, 1,
-+              ELC7, 1,
-+              Offset(0x37),   /* GPMLevelConfig0 */
-+              , 3,
-+              PLC0, 1,
-+              PLC1, 1,
-+              PLC2, 1,
-+              PLC3, 1,
-+              PLC8, 1,
-+              Offset(0x38),   /* GPMLevelConfig1 */
-+              , 1,
-+               PLC4, 1,
-+               PLC5, 1,
-+              , 1,
-+               PLC6, 1,
-+               PLC7, 1,
-+              Offset(0x3B),   /* PMEStatus1 */
-+              GP0S, 1,
-+              GM4S, 1,
-+              GM5S, 1,
-+              APS, 1,
-+              GM6S, 1,
-+              GM7S, 1,
-+              GP2S, 1,
-+              STSS, 1,
-+              Offset(0x55),   /* SoftPciRst */
-+              SPRE, 1,
-+              , 1,
-+              , 1,
-+              PNAT, 1,
-+              PWMK, 1,
-+              PWNS, 1,
-+
-+              /*      Offset(0x61), */        /*  Options_1 */
-+              /*              ,7,  */
-+              /*              R617,1, */
-+
-+              Offset(0x65),   /* UsbPMControl */
-+              , 4,
-+              URRE, 1,
-+              Offset(0x68),   /* MiscEnable68 */
-+              , 3,
-+              TMTE, 1,
-+              , 1,
-+              Offset(0x7C),   /* MiscEnable7C */
-+              , 2,
-+              BLNK, 2,
-+              Offset(0x92),   /* GEVENTIN */
-+              , 7,
-+              E7IS, 1,
-+              Offset(0x96),   /* GPM98IN */
-+              G8IS, 1,
-+              G9IS, 1,
-+              Offset(0x9A),   /* EnhanceControl */
-+              ,7,
-+              HPDE, 1,
-+              Offset(0xA8),   /* PIO7654Enable */
-+              IO4E, 1,
-+              IO5E, 1,
-+              IO6E, 1,
-+              IO7E, 1,
-+              Offset(0xA9),   /* PIO7654Status */
-+              IO4S, 1,
-+              IO5S, 1,
-+              IO6S, 1,
-+              IO7S, 1,
-+      }
-+
-+      /* PM1 Event Block
-+       * First word is PM1_Status, Second word is PM1_Enable
-+       */
-+      OperationRegion(P1EB, SystemIO, APEB, 0x04)
-+              Field(P1EB, ByteAcc, NoLock, Preserve) {
-+              TMST, 1,
-+              ,    3,
-+              BMST,    1,
-+              GBST,   1,
-+              Offset(0x01),
-+              PBST, 1,
-+              , 1,
-+              RTST, 1,
-+              , 3,
-+              PWST, 1,
-+              SPWS, 1,
-+              Offset(0x02),
-+              TMEN, 1,
-+              , 4,
-+              GBEN, 1,
-+              Offset(0x03),
-+              PBEN, 1,
-+              , 1,
-+              RTEN, 1,
-+              , 3,
-+              PWDA, 1,
-+      }
-+
-+      /* Wake status package */
-+      Name(WKST,Package(){Zero, Zero})
-+
-+      /*
-+       *  \_WAK System Wake method
-+       *
-+       *      Entry:
-+       *              Arg0=The value of the sleeping state S1=1, S2=2
-+       *
-+       *      Exit:
-+       *              Return package of 2 DWords
-+       *              Dword 1 - Status
-+       *                      0x00000000      wake succeeded
-+       *                      0x00000001      Wake was signaled but failed 
due to lack of power
-+       *                      0x00000002      Wake was signaled but failed 
due to thermal condition
-+       *              Dword 2 - Power Supply state
-+       *                      if non-zero the effective S-state the power 
supply entered
-+       */
-+      Method(\_WAK, 1) {
-+              Store (0x20, DBG8)
-+
-+              /* Set up LEDs */
-+              /* Set power LED to steady on */
-+              Store(0x3, BLNK)
-+
-+              /* Configure SuperIO for wake */
-+              /* Access SuperIO ACPI device */
-+              Store(0x87, INDX)
-+              Store(0x87, INDX)
-+              Store(0x0A, CR07)
-+
-+              if (LEqual(Arg0, One))  /* Resuming from power state S1 */
-+              {
-+                      /* Deactivate the ACPI device */
-+                      Store(Zero, CR30)
-+
-+                      /* Disable PS/2 SMI/PME events */
-+                      And(CRF6, 0xCF, CRF6)
-+              }
-+              if (Lor(LEqual(Arg0, 0x03), LEqual(Arg0, 0x04)))        /* 
Resuming from power state S3 or S4 */
-+              {
-+                      /* Disable PS/2 wake */
-+                      And(CRE0, 0x1D, CRE0)
-+                      And(CRE6, 0x7F, CRE6)
-+              }
-+
-+              /* Restore default SuperIO access */
-+              Store(0xAA, INDX)
-+
-+              Store (0x21, DBG8)
-+
-+              /* Re-enable HPET */
-+              Store(1, HPDE)
-+
-+              /* Restore PCIRST# so it resets USB */
-+              if (LEqual(Arg0, 3)){
-+                      Store(1, URRE)
-+              }
-+
-+              /* Configure southbridge for wake */
-+              /* Arbitrarily clear PciExpWakeStatus */
-+              Store(PWST, PWST)
-+
-+              Store (0x22, DBG8)
-+
-+              Notify(\_SB.PWRB, 0x02)                 /* NOTIFY_DEVICE_WAKE */
-+
-+              Return(WKST)
-+      }
-+
-+      /*
-+       * \_PTS - Prepare to Sleep method
-+       *
-+       *      Entry:
-+       *              Arg0=The value of the sleeping state S1=1, S2=2, etc
-+       *
-+       * Exit:
-+       *              -none-
-+       *
-+       * The _PTS control method is executed at the beginning of the sleep 
process
-+       * for S1-S5. The sleeping value is passed to the _PTS control method.  
This
-+       * control method may be executed a relatively long time before 
entering the
-+       * sleep state and the OS may abort the operation without notification 
to
-+       * the ACPI driver.  This method cannot modify the configuration or 
power
-+       * state of any device in the system.
-+       */
-+      Method(\_PTS, 1) {
-+              Store (Arg0, DBG8)
-+
-+              /* Set up LEDs */
-+              if (LEqual(Arg0, One))  /* Power state S1 requested */
-+              {
-+                      /* Set suspend LED to 0.25Hz toggle pulse with 50% duty 
cycle */
-+                      Store(0x2, BLNK)
-+              }
-+              if (LEqual(Arg0, 0x3))  /* Power state S3 requested */
-+              {
-+                      /* Set suspend LED to 0.25Hz toggle pulse with 25% duty 
cycle */
-+                      Store(0x1, BLNK)
-+              }
-+
-+              /* Configure SuperIO for sleep */
-+              /* Access SuperIO ACPI device */
-+              Store(0x87, INDX)
-+              Store(0x87, INDX)
-+              Store(0x0A, CR07)
-+
-+              /* Disable PS/2 wakeup and connect PANSW_IN to PANSW_OUT */
-+              And(CRE0, 0x1F, CRE0)
-+
-+              if (LEqual(Arg0, One))  /* Power state S1 requested */
-+              {
-+                      /* Activate the ACPI device */
-+                      Store(One, CR30)
-+
-+                      /* Disable SMI/PME events for:
-+                       * LPT
-+                       * FDC
-+                       * UART
-+                      Store(0x00, CRF6)
-+
-+                      /* Enable PS/2 keyboard SMI/PME events */
-+                      Or(CRF6, 0x10, CRF6)
-+
-+                      /* Enable PS/2 keyboard wake */
-+                      Or(CRE0, 0x40, CRE0)
-+
-+                      /* Enable PS/2 mouse SMI/PME events */
-+                      Or(CRF6, 0x20, CRF6)
-+
-+                      /* Enable PS/2 mouse wake  */
-+                      Or(CRE0, 0x20, CRE0)
-+              } else {
-+                      /* Enable PS/2 keyboard wake on any keypress */
-+                      Or(CRE0, 0x41, CRE0)
-+
-+                      /* Enable PS/2 mouse wake on any click  */
-+                      Or(CRE0, 0x22, CRE0)
-+                      Or(CRE6, 0x80, CRE6)
-+              }
-+
-+              /* Restore default SuperIO access */
-+              Store(0xAA, INDX)
-+
-+              Store (0x10, DBG8)
-+
-+              /* Don't allow PCIRST# to reset USB */
-+              if (LEqual(Arg0, 3)){
-+                      Store(0, URRE)
-+              }
-+
-+              /* Configure southbridge for sleep */
-+              /* Clear sleep SMI status flag and enable sleep SMI trap. */
-+              // Store(One, CSSM)     /* Set ExtEvent0 as SMI# source */
-+              // Store(One, SSEN)     /* Enable wake on external event 0 */
-+
-+              /* On older chips, clear PciExpWakeDisEn */
-+              // if (LLessEqual(SBRI, 0x13)) {
-+              //      Store(0, PWDE)
-+              // }
-+
-+              Store (0x11, DBG8)
-+
-+              /* Clear wake status structure. */
-+              Store(0, Index(WKST,0))
-+              Store(0, Index(WKST,1))
-+      }
-\ No newline at end of file
-diff --git a/src/mainboard/asus/kgpe-d16/acpi_tables.c 
b/src/mainboard/asus/kgpe-d16/acpi_tables.c
-new file mode 100644
-index 0000000..4e98dfe
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/acpi_tables.c
-@@ -0,0 +1,75 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <console/console.h>
-+#include <string.h>
-+#include <arch/acpi.h>
-+#include <arch/ioapic.h>
-+#include <device/pci.h>
-+#include <device/pci_ids.h>
-+#include <cpu/x86/msr.h>
-+#include <cpu/amd/mtrr.h>
-+#include <cpu/amd/amdfam10_sysconf.h>
-+
-+#include "mb_sysconf.h"
-+
-+unsigned long acpi_fill_madt(unsigned long current)
-+{
-+      device_t dev;
-+      u32 dword;
-+      u32 gsi_base=0;
-+      uint32_t apicid_sp5100;
-+      uint32_t apicid_sr5650;
-+      /* create all subtables for processors */
-+      current = acpi_create_madt_lapics(current);
-+
-+      apicid_sp5100 = 0x20;
-+      apicid_sr5650 = apicid_sp5100 + 1;
-+
-+      /* Write SB700 IOAPIC, only one */
-+      current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current, 
apicid_sp5100,
-+                                         IO_APIC_ADDR, gsi_base);
-+      /* IOAPIC on rs5690 */
-+      gsi_base += 24;         /* SB700 has 24 IOAPIC entries. */
-+      dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-+      if (dev) {
-+              pci_write_config32(dev, 0xF8, 0x1);
-+              dword = pci_read_config32(dev, 0xFC) & 0xfffffff0;
-+              current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) 
current, apicid_sr5650,
-+                                                 dword, gsi_base);
-+      }
-+
-+      /* bus, source, gsirq, flags */
-+      current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
-+                                              current, 0, 0, 2, 0);
-+      current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
-+                                              current, 0, 9, 9, 0xF);
-+      /* 0: mean bus 0--->ISA */
-+      /* 0: PIC 0 */
-+      /* 2: APIC 2 */
-+      /* 5 mean: 0101 --> Edge-triggered, Active high */
-+
-+      /* create all subtables for processors */
-+      current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 
0, 5, 1);
-+      current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 
1, 5, 1);
-+      /* 1: LINT1 connect to NMI */
-+
-+      return current;
-+}
-diff --git a/src/mainboard/asus/kgpe-d16/board_info.txt 
b/src/mainboard/asus/kgpe-d16/board_info.txt
-new file mode 100644
-index 0000000..788888e
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/board_info.txt
-@@ -0,0 +1,5 @@
-+Category: server
-+ROM package: PLCC-32
-+ROM protocol: LPC
-+ROM socketed: y
-+Flashrom support: y
-\ No newline at end of file
-diff --git a/src/mainboard/asus/kgpe-d16/bootblock.c 
b/src/mainboard/asus/kgpe-d16/bootblock.c
-new file mode 100644
-index 0000000..2e9d70f
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/bootblock.c
-@@ -0,0 +1,52 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2014 Edward O'Callaghan <address@hidden>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <pc80/mc146818rtc.h>
-+
-+void bootblock_mainboard_init(void)
-+{
-+      uint8_t recovery_enabled;
-+      unsigned char addr;
-+      unsigned char byte;
-+
-+      bootblock_northbridge_init();
-+      bootblock_southbridge_init();
-+
-+      /* Recovery jumper is connected to SP5100 GPIO61, and clears the GPIO 
when placed in the Recovery position */
-+      recovery_enabled = (!(pci_read_config8(PCI_DEV(0, 0x14, 0), 0x57) & 
0x1));
-+      if (recovery_enabled) {
-+#if CONFIG_USE_OPTION_TABLE
-+              /* Clear NVRAM checksum */
-+              for (addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; 
addr++) {
-+                      cmos_write(0x0, addr);
-+              }
-+
-+              /* Set fallback boot */
-+              byte = cmos_read(RTC_BOOT_BYTE);
-+              byte &= 0xfc;
-+              cmos_write(byte, RTC_BOOT_BYTE);
-+#else
-+              /* FIXME
-+               * Figure out how to recover if the option table is not 
available
-+               */
-+#endif
-+      }
-+}
-\ No newline at end of file
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-new file mode 100644
-index 0000000..cffdd03
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -0,0 +1,16 @@
-+baud_rate = 115200
-+debug_level = Spew
-+multi_core = Enable
-+slow_cpu = off
-+iommu = Disable
-+nmi = Disable
-+hypertransport_speed_limit = Auto
-+max_mem_clock = DDR3-1600
-+ECC_memory = Enable
-+ECC_redirection = Disable
-+ecc_scrub_rate = 1.28us
-+interleave_chip_selects = Enable
-+interleave_nodes = Disable
-+interleave_memory_channels = Enable
-+power_on_after_fail = On
-+boot_option = Fallback
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-new file mode 100644
-index 0000000..bcf9cd3
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -0,0 +1,134 @@
-+##
-+## This file is part of the coreboot project.
-+##
-+## Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+## Copyright (C) 2007 AMD
-+## Written by Yinghai Lu <address@hidden> for AMD.
-+##
-+## This program is free software; you can redistribute it and/or modify
-+## it under the terms of the GNU General Public License as published by
-+## the Free Software Foundation; either version 2 of the License, or
-+## (at your option) any later version.
-+##
-+## This program is distributed in the hope that it will be useful,
-+## but WITHOUT ANY WARRANTY; without even the implied warranty of
-+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+## GNU General Public License for more details.
-+##
-+## You should have received a copy of the GNU General Public License
-+## along with this program; if not, write to the Free Software
-+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+##
-+
-+entries
-+
-+0          384       r       0        reserved_memory
-+384          1       e       4        boot_option
-+385          1       e       4        last_boot
-+388          4       r       0        reboot_bits
-+393          3       e       5        baud_rate
-+396          5       e       10       ecc_scrub_rate
-+401          1       e       1        interleave_chip_selects
-+402          1       e       1        interleave_nodes
-+403          1       e       1        interleave_memory_channels
-+404          2       e       8        max_mem_clock
-+406          1       e       2        multi_core
-+412          4       e       6        debug_level
-+440          4       e       9        slow_cpu
-+444          1       e       1        nmi
-+445          1       e       1        iommu
-+446          2       e       3        power_on_after_fail
-+456          1       e       1        ECC_memory
-+457          1       e       1        ECC_redirection
-+458          4       e       11       hypertransport_speed_limit
-+728        256       h       0        user_data
-+984         16       h       0        check_sum
-+# Reserve the extended AMD configuration registers
-+1000        24       r       0        amd_reserved
-+
-+
-+
-+enumerations
-+
-+#ID value   text
-+1     0     Disable
-+1     1     Enable
-+2     0     Enable
-+2     1     Disable
-+3     0     Off
-+3     1     On
-+3     2     Last
-+4     0     Fallback
-+4     1     Normal
-+5     0     115200
-+5     1     57600
-+5     2     38400
-+5     3     19200
-+5     4     9600
-+5     5     4800
-+5     6     2400
-+5     7     1200
-+6     0     Emergency
-+6     1     Alert
-+6     2     Critical
-+6     3     Error
-+6     4     Warning
-+6     5     Notice
-+6     6     Information
-+6     7     Debug
-+6     8     Spew
-+8     0     DDR3-1600
-+8     1     DDR3-1333
-+8     2     DDR3-1066
-+8     3     DDR3-800
-+9     0     off
-+9     1     87.5%
-+9     2     75.0%
-+9     3     62.5%
-+9     4     50.0%
-+9     5     37.5%
-+9     6     25.0%
-+9     7     12.5%
-+10    0     Disabled
-+10    1     40ns
-+10    2     80ns
-+10    3     160ns
-+10    4     320ns
-+10    5     640ns
-+10    6     1.28us
-+10    7     2.56us
-+10    8     5.12us
-+10    9     10.2us
-+10    10    20.5us
-+10    11    41us
-+10    12    81.9us
-+10    13    163.8us
-+10    14    327.7us
-+10    15    655.4us
-+10    16    1.31ms
-+10    17    2.62ms
-+10    18    5.24ms
-+10    19    10.49ms
-+10    20    20.97ms
-+10    21    42ms
-+10    22    84ms
-+11    0     Auto
-+11    1     2.6GHz
-+11    2     2.4GHz
-+11    3     2.2GHz
-+11    4     2.0GHz
-+11    5     1.8GHz
-+11    6     1.6GHz
-+11    7     1.4GHz
-+11    8     1.2GHz
-+11    9     1.0GHz
-+11    10    800MHz
-+11    11    600MHz
-+11    12    500MHz
-+11    13    400MHz
-+11    14    300MHz
-+11    15    200MHz
-+
-+checksums
-+
-+checksum 392 983 984
-diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
-new file mode 100644
-index 0000000..a172d89
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
-@@ -0,0 +1,248 @@
-+chip northbridge/amd/amdfam10/root_complex    # Root complex
-+      device cpu_cluster 0 on                 # (L)APIC cluster
-+              chip cpu/amd/socket_F_1207                      # CPU socket
-+                      device lapic 0 on end                   # Local APIC of 
the CPU
-+              end
-+      end
-+      device domain 0 on                      # PCI domain
-+              subsystemid 0x1043 0x8163 inherit
-+              chip northbridge/amd/amdfam10           # Northbridge / RAM 
controller
-+                      register "maximum_memory_capacity" = "0x4000000000"     
# 256GB
-+                      device pci 18.0 on end          # Link 0 == LDT 0
-+                      device pci 18.0 on end          # Link 1 == LDT 1
-+                      device pci 18.0 on end          # Link 2 == LDT 2
-+                      device pci 18.0 on              # Link 3 == LDT 3 [SB 
on link 3]
-+                              chip southbridge/amd/sr5650             # 
Primary southbridge
-+                                      device pci 0.0 on end                   
# HT Root Complex 0x9600
-+                                      device pci 0.1 on end                   
# CLKCONFIG
-+                                      device pci 2.0 on                       
# PCIE P2P bridge 0x9603 (GPP1 Port0)
-+                                              # Slot                          
# PCI E 1 / PCI E 2
-+                                      end
-+                                      device pci 3.0 off end                  
# PCIE P2P bridge 0x960b (GPP1 Port1)
-+                                      device pci 4.0 on                       
# PCIE P2P bridge 0x9604 (GPP3a Port0)
-+                                              # PIKE SAS
-+                                      end
-+                                      device pci 5.0 off end                  
# PCIE P2P bridge 0x9605 (GPP3a Port1)
-+                                      device pci 6.0 off end                  
# PCIE P2P bridge 0x9606 (GPP3a Port2)
-+                                      device pci 7.0 off end                  
# PCIE P2P bridge 0x9607 (GPP3a Port3)
-+                                      device pci 8.0 off end                  
# NB/SB Link P2P bridge
-+                                      device pci 9.0 on                       
# Bridge (GPP3a Port4)
-+                                              # Onboard                       
# NIC A
-+                                      end
-+                                      device pci a.0 on                       
# Bridge (GPP3a Port5)
-+                                              # Onboard                       
# NIC B
-+                                      end
-+                                      device pci b.0 on                       
# Bridge (GPP2 Port0)
-+                                              # Slot                          
# PCI E 4
-+                                      end
-+                                      device pci c.0 on                       
# Bridge (GPP2 Port1)
-+                                              # Slot                          
# PCI E 5
-+                                      end
-+                                      device pci d.0 on                       
# Bridge (GPP3b Port0)
-+                                              # Slot                          
# PCI E 3
-+                                      end
-+                                      register "gpp1_configuration" = "0"     
# Configuration 16:0 default
-+                                      register "gpp2_configuration" = "1"     
# Configuration 8:8
-+                                      #register "gpp3a_configuration" = "2"   
# Configuration 4:1:1:0:0:0
-+                                      register "gpp3a_configuration" = "11"   
# Configuration 1:1:1:1:1:1
-+                                      register "port_enable" = "0x3ffc"       
# Enable all ports except 0 and 1
-+                              end
-+                              chip southbridge/amd/sb700              # 
Secondary southbridge
-+                                      device pci 11.0 on end                  
# SATA
-+                                      device pci 12.0 on end                  
# USB
-+                                      device pci 12.1 on end                  
# USB
-+                                      device pci 12.2 on end                  
# USB
-+                                      device pci 13.0 on end                  
# USB
-+                                      device pci 13.1 on end                  
# USB
-+                                      device pci 13.2 on end                  
# USB
-+                                      device pci 14.0 on end                  
# SM
-+                                      device pci 14.1 on end                  
# IDE 0x439c
-+                                      device pci 14.2 off end                 
# HDA 0x4383 (KGPE-D16 omits audio option)
-+                                      device pci 14.3 on                      
# LPC 0x439d (SMBUS primary controller)
-+                                              chip superio/nuvoton/nct5572d   
# Super I/O
-+                                                      device pnp 2e.0 off end 
# FDC; Not available on the KGPE-D16
-+                                                      device pnp 2e.1 off end 
# LPT1; Not available on the KGPE-D16
-+                                                      device pnp 2e.2 on #  
Com1
-+                                                              io 0x60 = 0x3f8
-+                                                              irq 0x70 = 4
-+                                                      end
-+                                                      device pnp 2e.3 off     
# IR: Not available on the KGPE-D16
-+                                                              io 0x60 = 0x2f8
-+                                                              irq 0x70 = 3
-+                                                      end
-+                                                      device pnp 2e.5 on      
# PS/2 keyboard & mouse
-+                                                              io 0x60 = 0x60
-+                                                              io 0x62 = 0x64
-+                                                              irq 0x70 = 1
-+                                                              irq 0x72 = 12
-+                                                      end
-+                                                      device pnp 2e.6 off     
# CIR: Not available on the KGPE-D16
-+                                                              io 0x60 = 0x100
-+                                                              irq 0x70 = 0
-+                                                      end
-+                                                      device pnp 2e.7 off end 
# GIPO689
-+                                                      device pnp 2e.8 off end 
# WDT
-+                                                      device pnp 2e.9 off end 
# GPIO235
-+                                                      device pnp 2e.a on end  
# ACPI
-+                                                      device pnp 2e.b on      
# HW Monitor
-+                                                              io 0x60 = 0x290
-+                                                              io 0x62 = 
0x0000 #  SB-TSI currently not implemented
-+                                                              irq 0x70 = 5
-+                                                      end
-+                                                      device pnp 2e.c off end 
# PECI
-+                                                      device pnp 2e.d off end 
# SUSLED
-+                                                      device pnp 2e.e off     
# CIRWKUP
-+                                                              io 0x60 = 0x0000
-+                                                              irq 0x70 = 0
-+                                                      end
-+                                                      device pnp 2e.f off end 
# GPIO_PP_OD
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-0-0-0
-+                                                      device i2c 50 on end
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-0-0-1
-+                                                      device i2c 51 on end
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-0-1-0
-+                                                      device i2c 52 on end
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-0-1-1
-+                                                      device i2c 53 on end
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-1-0-0
-+                                                      device i2c 54 on end
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-1-0-1
-+                                                      device i2c 55 on end
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-1-1-0
-+                                                      device i2c 56 on end
-+                                              end
-+                                              chip drivers/generic/generic    
# DIMM n-1-1-1
-+                                                      device i2c 57 on end
-+                                              end
-+                                              chip drivers/i2c/w83795
-+                                                      register "fanin_ctl1" = 
"0xff"                  # Enable monitoring of FANIN1 - FANIN8
-+                                                      register "fanin_ctl2" = 
"0x00"                  # Connect FANIN11 - FANIN14 to alternate functions
-+                                                      register "temp_ctl1" = 
"0x2a"                   # Enable monitoring of DTS, VSEN12, and VSEN13
-+                                                      register "temp_ctl2" = 
"0x01"                   # Enable monitoring of TD1/TR1
-+                                                      register "temp_dtse" = 
"0x03"                   # Enable DTS1 and DTS2
-+                                                      register "volt_ctl1" = 
"0xff"                   # Enable monitoring of VSEN1 - VSEN8
-+                                                      register "volt_ctl2" = 
"0xf7"                   # Enable monitoring of VSEN9 - VSEN11, 3VDD, 3VSB, and 
VBAT
-+                                                      register 
"temp1_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp1)
-+                                                      register 
"temp2_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp2)
-+                                                      register 
"temp3_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp3)
-+                                                      register 
"temp4_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp4)
-+                                                      register 
"temp5_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp5)
-+                                                      register 
"temp6_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp6)
-+                                                      register 
"temp1_source_select" = "0x00"         # Use TD1/TR1 as data source for Temp1
-+                                                      register 
"temp2_source_select" = "0x00"         # Use TD2/TR2 as data source for Temp2
-+                                                      register 
"temp3_source_select" = "0x00"         # Use TD3/TR3 as data source for Temp3
-+                                                      register 
"temp4_source_select" = "0x00"         # Use TD4/TR4 as data source for Temp4
-+                                                      register 
"temp5_source_select" = "0x00"         # Use TR5 as data source for Temp5
-+                                                      register 
"temp6_source_select" = "0x00"         # Use TR6 as data source for Temp6
-+                                                      register 
"tr1_critical_temperature" = "85"      # Set TD1/TR1 critical temperature to 
85°C
-+                                                      register 
"tr1_critical_hysteresis" = "80"       # Set TD1/TR1 critical hysteresis 
temperature to 80°C
-+                                                      register 
"tr1_warning_temperature" = "70"       # Set TD1/TR1 warning temperature to 70°C
-+                                                      register 
"tr1_warning_hysteresis" = "65"        # Set TD1/TR1 warning hysteresis 
temperature to 65°C
-+                                                      register 
"dts_critical_temperature" = "85"      # Set DTS (CPU) critical temperature to 
85°C
-+                                                      register 
"dts_critical_hysteresis" = "80"       # Set DTS (CPU) critical hysteresis 
temperature to 80°C
-+                                                      register 
"dts_warning_temperature" = "70"       # Set DTS (CPU) warning temperature to 
70°C
-+                                                      register 
"dts_warning_hysteresis" = "65"        # Set DTS (CPU) warning hysteresis 
temperature to 65°C
-+                                                      register 
"temp1_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
-+                                                      register 
"temp2_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
-+                                                      register 
"temp3_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
-+                                                      register 
"temp4_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
-+                                                      register 
"temp5_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
-+                                                      register 
"temp6_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
-+                                                      register 
"temp1_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
-+                                                      register 
"temp2_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
-+                                                      register 
"temp3_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
-+                                                      register 
"temp4_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
-+                                                      register 
"temp5_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
-+                                                      register 
"temp6_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
-+                                                      register "fan1_nonstop" 
= "7"                   # Set Fan 1 minimum speed
-+                                                      register "fan2_nonstop" 
= "7"                   # Set Fan 2 minimum speed
-+                                                      register "fan3_nonstop" 
= "7"                   # Set Fan 3 minimum speed
-+                                                      register "fan4_nonstop" 
= "7"                   # Set Fan 4 minimum speed
-+                                                      register "fan5_nonstop" 
= "7"                   # Set Fan 5 minimum speed
-+                                                      register "fan6_nonstop" 
= "7"                   # Set Fan 6 minimum speed
-+                                                      register "fan7_nonstop" 
= "7"                   # Set Fan 7 minimum speed
-+                                                      register "fan8_nonstop" 
= "7"                   # Set Fan 8 minimum speed
-+                                                      register 
"default_speed" = "100"                # All fans to full speed on power up
-+                                                      register "fan1_duty" = 
"100"                    # Fan 1 to full speed
-+                                                      register "fan2_duty" = 
"100"                    # Fan 2 to full speed
-+                                                      register "fan3_duty" = 
"100"                    # Fan 3 to full speed
-+                                                      register "fan4_duty" = 
"100"                    # Fan 4 to full speed
-+                                                      register "fan5_duty" = 
"100"                    # Fan 5 to full speed
-+                                                      register "fan6_duty" = 
"100"                    # Fan 6 to full speed
-+                                                      register "fan7_duty" = 
"100"                    # Fan 7 to full speed
-+                                                      register "fan8_duty" = 
"100"                    # Fan 8 to full speed
-+                                                      register 
"vcore1_high_limit_mv" = "1500"        # VCORE1 (Node 0) high limit to 1.5V
-+                                                      register 
"vcore1_low_limit_mv" = "900"          # VCORE1 (Node 0) low limit to 0.9V
-+                                                      register 
"vcore2_high_limit_mv" = "1500"        # VCORE2 (Node 1) high limit to 1.5V
-+                                                      register 
"vcore2_low_limit_mv" = "900"          # VCORE2 (Node 1) low limit to 0.9V
-+                                                      register 
"vsen3_high_limit_mv" = "1600"         # VSEN1 (Node 0 RAM voltage) high limit 
to 1.6V
-+                                                      register 
"vsen3_low_limit_mv" = "1100"          # VSEN1 (Node 0 RAM voltage) low limit 
to 1.1V
-+                                                      register 
"vsen4_high_limit_mv" = "1600"         # VSEN2 (Node 1 RAM voltage) high limit 
to 1.6V
-+                                                      register 
"vsen4_low_limit_mv" = "1100"          # VSEN2 (Node 1 RAM voltage) low limit 
to 1.1V
-+                                                      register 
"vsen5_high_limit_mv" = "1250"         # VSEN5 (Node 0 HT link voltage) high 
limit to 1.25V
-+                                                      register 
"vsen5_low_limit_mv" = "1150"          # VSEN5 (Node 0 HT link voltage) low 
limit to 1.15V
-+                                                      register 
"vsen6_high_limit_mv" = "1250"         # VSEN6 (Node 1 HT link voltage) high 
limit to 1.25V
-+                                                      register 
"vsen6_low_limit_mv" = "1150"          # VSEN6 (Node 1 HT link voltage) low 
limit to 1.15V
-+                                                      register 
"vsen7_high_limit_mv" = "1150"         # VSEN7 (Northbridge core voltage) high 
limit to 1.15V
-+                                                      register 
"vsen7_low_limit_mv" = "1050"          # VSEN7 (Northbridge core voltage) low 
limit to 1.05V
-+                                                      register 
"vsen8_high_limit_mv" = "1900"         # VSEN8 (+1.8V) high limit to 1.9V
-+                                                      register 
"vsen8_low_limit_mv" = "1700"          # VSEN8 (+1.8V) low limit to 1.7V
-+                                                      register 
"vsen9_high_limit_mv" = "1250"         # VSEN9 (+1.2V) high limit to 1.25V
-+                                                      register 
"vsen9_low_limit_mv" = "1150"          # VSEN9 (+1.2V) low limit to 1.15V
-+                                                      register 
"vsen10_high_limit_mv" = "1150"        # VSEN10 (+1.1V) high limit to 1.15V
-+                                                      register 
"vsen10_low_limit_mv" = "1050"         # VSEN10 (+1.1V) low limit to 1.05V
-+                                                      register 
"vsen11_high_limit_mv" = "1625"        # VSEN11 (5VSB, scaling factor ~3.2) 
high limit to 5.2V
-+                                                      register 
"vsen11_low_limit_mv" = "1500"         # VSEN11 (5VSB, scaling factor ~3.2) low 
limit to 4.8V
-+                                                      register 
"vsen12_high_limit_mv" = "1083"        # VSEN12 (+12V, scaling factor ~12) high 
limit to 13V
-+                                                      register 
"vsen12_low_limit_mv" = "917"          # VSEN12 (+12V, scaling factor ~12) low 
limit to 11V
-+                                                      register 
"vsen13_high_limit_mv" = "1625"        # VSEN13 (+5V, scaling factor ~3.2) high 
limit to 5.2V
-+                                                      register 
"vsen13_low_limit_mv" = "1500"         # VSEN13 (+5V, scaling factor ~3.2) low 
limit to 4.8V
-+                                                      register 
"vdd_high_limit_mv" = "3500"           # 3VDD high limit to 3.5V
-+                                                      register 
"vdd_low_limit_mv" = "3100"            # 3VDD low limit to 3.1V
-+                                                      register 
"vsb_high_limit_mv" = "3500"           # 3VSB high limit to 3.5V
-+                                                      register 
"vsb_low_limit_mv" = "3100"            # 3VSB low limit to 3.1V
-+                                                      register 
"vbat_high_limit_mv" = "3500"          # VBAT (+3V) high limit to 3.5V
-+                                                      register 
"vbat_low_limit_mv" = "2500"           # VBAT (+3V) low limit to 2.5V
-+                                                      register "smbus_aux" = 
"1"                      # Device located on auxiliary SMBUS controller
-+                                                      device i2c 0x2f on end
-+                                              end
-+                                      end
-+                                      device pci 14.4 on                      
# Bridge
-+                                              device pci 1.0 on end           
# VGA
-+                                              device pci 2.0 on end           
# FireWire
-+                                              device pci 3.0 on               
# Slot
-+                                                      # Slot                  
# PCI 0
-+                                              end
-+                                      end
-+                                      device pci 14.5 on end                  
# USB OHCI2 0x4399
-+                              end
-+                      end
-+                      device pci 18.1 on end
-+                      device pci 18.2 on end
-+                      device pci 18.3 on end
-+                      device pci 18.4 on end
-+                      device pci 19.0 on end          # Socket 0 node 1
-+                      device pci 19.1 on end
-+                      device pci 19.2 on end
-+                      device pci 19.3 on end
-+                      device pci 19.4 on end
-+                      device pci 1a.0 on end          # Socket 1 node 0
-+                      device pci 1a.1 on end
-+                      device pci 1a.2 on end
-+                      device pci 1a.3 on end
-+                      device pci 1a.4 on end
-+                      device pci 1b.0 on end          # Socket 1 node 1
-+                      device pci 1b.1 on end
-+                      device pci 1b.2 on end
-+                      device pci 1b.3 on end
-+                      device pci 1b.4 on end
-+              end
-+      end
-+end
-diff --git a/src/mainboard/asus/kgpe-d16/dsdt.asl 
b/src/mainboard/asus/kgpe-d16/dsdt.asl
-new file mode 100644
-index 0000000..bdd1d2d
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/dsdt.asl
-@@ -0,0 +1,730 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2005 - 2012 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2007-2009 coresystems GmbH
-+ * Copyright (C) 2004 Nick Barker <address@hidden>
-+ * Copyright (C) 2007, 2008 Rudolf Marek <address@hidden>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+/*
-+ * WARNING: Sleep/Wake is a work in progress and is still somewhat flaky!
-+ * Everything else does to the best of my knowledge... (T.P. 01/26/2015)
-+ */
-+
-+/*
-+ * ISA portions taken from QEMU acpi-dsdt.dsl.
-+ */
-+
-+/*
-+ * PCI link routing templates taken from ck804.asl and modified for this board
-+ */
-+
-+DefinitionBlock (
-+        "DSDT.AML",   /* Output filename */
-+        "DSDT",               /* Signature */
-+        0x02,         /* DSDT Revision, needs to be 2 for 64bit */
-+        "ASUS  ",     /* OEMID */
-+        "COREBOOT",   /* TABLE ID */
-+        0x00000001    /* OEM Revision */
-+        )
-+{
-+      #include "northbridge/amd/amdfam10/amdfam10_util.asl"
-+      #include "southbridge/amd/sr5650/acpi/sr5650.asl"
-+
-+      /* Some global data */
-+      Name(OSVR, 3)   /* Assume nothing. WinXp = 1, Vista = 2, Linux = 3, 
WinCE = 4 */
-+      Name(OSV, Ones) /* Assume nothing */
-+      Name(PICM, One) /* Assume APIC */
-+
-+      /* HPET control */
-+      Name (SHPB, 0xFED00000)
-+      Name (SHPL, 0x1000)
-+
-+      /* Define power states */
-+      Name (\_S0, Package () { 0x00, 0x00, 0x00, 0x00 })      /* Normal 
operation */
-+      Name (\_S1, Package () { 0x01, 0x01, 0x00, 0x00 })      /* Standby */
-+      Name (\_S2, Package () { 0x02, 0x02, 0x00, 0x00 })      /* Standby w/ 
CPU shutdown */
-+      Name (\_S3, Package () { 0x03, 0x00, 0x00, 0x00 })      /* Suspend */
-+      /* Name (\_S4, Package () { 0x04, 0x04, 0x00, 0x00 }) */
-+      Name (\_S5, Package () { 0x05, 0x05, 0x00, 0x00 })      /* Hard power 
off */
-+
-+      /* The _PIC method is called by the OS to choose between interrupt
-+              * routing via the i8259 interrupt controller or the APIC.
-+              *
-+              * _PIC is called with a parameter of 0 for i8259 configuration 
and
-+              * with a parameter of 1 for Local Apic/IOAPIC configuration.
-+              */
-+      Method (_PIC, 1, Serialized) {
-+              If (Arg0)
-+              {
-+                      \_SB.CIRQ()
-+              }
-+              Store (Arg0, PICM)
-+      }
-+
-+      /* _PR CPU0 is dynamically supplied by SSDT */
-+      /* CPU objects and _PSS entries are dynamically supplied by SSDT */
-+
-+      Scope(\_GPE) {  /* Start Scope GPE */
-+              /*  General event 3  */
-+              Method(_L03) {
-+                      /* Level-Triggered GPE */
-+                      Notify(\_SB.PWRB, 0x02)                 /* 
NOTIFY_DEVICE_WAKE */
-+              }
-+
-+              /*  General event 4  */
-+              Method(_L04) {
-+                      /* Level-Triggered GPE */
-+                      Notify (\_SB.PCI0.PBR0, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PWRB, 0x02)                /* 
NOTIFY_DEVICE_WAKE */
-+              }
-+
-+              /*  Keyboard controller PME#  */
-+              Method(_L08) {
-+                      /* Level-Triggered GPE */
-+                      Notify(\_SB.PCI0.LPC.KBD, 0x02)         /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify(\_SB.PCI0.LPC.MOU, 0x02)         /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify(\_SB.PWRB, 0x02)                 /* 
NOTIFY_DEVICE_WAKE */
-+              }
-+
-+              /*  USB controller PME#  */
-+              Method(_L0B) {
-+                      /* Level-Triggered GPE */
-+                      Notify (\_SB.PCI0.USB0, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.USB1, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.USB2, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.USB3, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.USB4, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.USB5, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.USB6, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PWRB, 0x02)                /* 
NOTIFY_DEVICE_WAKE */
-+              }
-+
-+              /*  GPIO0 or GEvent8 event  */
-+              Method(_L18) {
-+                      /* Level-Triggered GPE */
-+                      Notify (\_SB.PCI0.PCE1, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.NICA, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.NICB, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.PCE4, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.PCE5, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+                      Notify (\_SB.PCI0.PCE3, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
-+              }
-+
-+      }       /* End Scope GPE */
-+
-+      /* Root of the bus hierarchy */
-+      Scope (\_SB)
-+      {
-+              /* Top southbridge PCI device (SR5690) */
-+              Device (PCI0)
-+              {
-+                      /* BUS0 root bus */
-+
-+                      Name (_HID, EisaId ("PNP0A03"))
-+                      Name (_ADR, 0x00180001)
-+                      Name (_UID, 0x00)
-+
-+                      Name (HCIN, 0x00)  // HC1
-+
-+                      Method (_BBN, 0, NotSerialized)
-+                      {
-+                              Return (GBUS (GHCN(HCIN), GHCL(HCIN)))
-+                      }
-+
-+                      /* Operating System Capabilities Method */
-+                      Method(_OSC,4)
-+                      {
-+                              /* Let OS control everything */
-+                              Return (Arg3)
-+                      }
-+
-+                      External (BUSN)
-+                      External (MMIO)
-+                      External (PCIO)
-+                      External (SBLK)
-+                      External (TOM1)
-+                      External (HCLK)
-+                      External (SBDN)
-+                      External (HCDN)
-+                      External (CBST)
-+
-+                      /* PCI Routing Tables */
-+                      Name (PR00, Package () {
-+                              /* PIC */
-+                              /* Top southbridge device (SR5690) */
-+                              /* HT Link */
-+                              Package (0x04) { 0x0000FFFF, 0x00, LNKA, 0x00 },
-+
-+                              /* PCI-E Slot 1 (Bridge) */
-+                              Package (0x04) { 0x0002FFFF, 0x00, LNKE, 0x00 },
-+
-+                              /* NIC A (Bridge) */
-+                              Package (0x04) { 0x0009FFFF, 0x00, LNKF, 0x00 },
-+
-+                              /* NIC B (Bridge) */
-+                              Package (0x04) { 0x000AFFFF, 0x00, LNKG, 0x00 },
-+
-+                              /* PCI-E Slot 4 (Bridge) */
-+                              Package (0x04) { 0x000BFFFF, 0x00, LNKG, 0x00 },
-+
-+                              /* PCI-E Slot 5 (Bridge) */
-+                              Package (0x04) { 0x000CFFFF, 0x00, LNKG, 0x00 },
-+
-+                              /* PCI-E Slot 3 (Bridge) */
-+                              Package (0x04) { 0x000DFFFF, 0x00, LNKG, 0x00 },
-+
-+                              /* Bottom southbridge device (SP5100) */
-+                              /* SATA 0 */
-+                              Package (0x04) { 0x0011FFFF, 0x00, LNKG, 0x00 },
-+
-+                              /* USB 0 */
-+                              Package (0x04) { 0x0012FFFF, 0x00, LNKA, 0x00 },
-+                              Package (0x04) { 0x0012FFFF, 0x01, LNKB, 0x00 },
-+                              Package (0x04) { 0x0012FFFF, 0x02, LNKC, 0x00 },
-+                              Package (0x04) { 0x0012FFFF, 0x03, LNKD, 0x00 },
-+
-+                              /* USB 1 */
-+                              Package (0x04) { 0x0013FFFF, 0x00, LNKC, 0x00 },
-+                              Package (0x04) { 0x0013FFFF, 0x01, LNKD, 0x00 },
-+                              Package (0x04) { 0x0013FFFF, 0x02, LNKA, 0x00 },
-+                              Package (0x04) { 0x0013FFFF, 0x03, LNKB, 0x00 },
-+
-+                              /* SMBUS / IDE / LPC / VGA / FireWire / PCI 
Slot 0 */
-+                              Package (0x04) { 0x0014FFFF, 0x00, LNKA, 0x00 },
-+                              Package (0x04) { 0x0014FFFF, 0x01, LNKB, 0x00 },
-+                              Package (0x04) { 0x0014FFFF, 0x02, LNKC, 0x00 },
-+                              Package (0x04) { 0x0014FFFF, 0x03, LNKD, 0x00 },
-+                      })
-+
-+                      Name (AR00, Package () {
-+                              /* APIC */
-+                              /* Top southbridge device (SR5690) */
-+                              /* HT Link */
-+                              Package (0x04) { 0x0000FFFF, 0x00, 0x00, 55 },
-+
-+                              /* PCI-E Slot 1 (Bridge) */
-+                              Package (0x04) { 0x0002FFFF, 0x00, 0x00, 52 },
-+
-+                              /* NIC A (Bridge) */
-+                              Package (0x04) { 0x0009FFFF, 0x00, 0x00, 53 },
-+
-+                              /* NIC B (Bridge) */
-+                              Package (0x04) { 0x000AFFFF, 0x00, 0x00, 54 },
-+
-+                              /* PCI-E Slot 4 (Bridge) */
-+                              Package (0x04) { 0x000BFFFF, 0x00, 0x00, 54 },
-+
-+                              /* PCI-E Slot 5 (Bridge) */
-+                              Package (0x04) { 0x000CFFFF, 0x00, 0x00, 54 },
-+
-+                              /* PCI-E Slot 3 (Bridge) */
-+                              Package (0x04) { 0x000DFFFF, 0x00, 0x00, 54 },
-+
-+                              /* Bottom southbridge device (SP5100) */
-+                              /* SATA 0 */
-+                              Package (0x04) { 0x0011FFFF, 0x00, 0x00, 22 },
-+
-+                              /* USB 0 */
-+                              Package (0x04) { 0x0012FFFF, 0x00, 0x00, 16 },
-+                              Package (0x04) { 0x0012FFFF, 0x01, 0x00, 17 },
-+                              Package (0x04) { 0x0012FFFF, 0x02, 0x00, 18 },
-+                              Package (0x04) { 0x0012FFFF, 0x03, 0x00, 19 },
-+
-+                              /* USB 1 */
-+                              Package (0x04) { 0x0013FFFF, 0x00, 0x00, 18 },
-+                              Package (0x04) { 0x0013FFFF, 0x01, 0x00, 19 },
-+                              Package (0x04) { 0x0013FFFF, 0x02, 0x00, 16 },
-+                              Package (0x04) { 0x0013FFFF, 0x03, 0x00, 17 },
-+
-+                              /* SMBUS / IDE / LPC / VGA / FireWire / PCI 
Slot 0 */
-+                              Package (0x04) { 0x0014FFFF, 0x00, 0x00, 16 },
-+                              Package (0x04) { 0x0014FFFF, 0x01, 0x00, 17 },
-+                              Package (0x04) { 0x0014FFFF, 0x02, 0x00, 18 },
-+                              Package (0x04) { 0x0014FFFF, 0x03, 0x00, 19 },
-+                      })
-+
-+                      Name (PR01, Package () {
-+                              /* PIC */
-+                              Package (0x04) { 0x1FFFF, 0x00, LNKF, 0x00 },
-+                              Package (0x04) { 0x2FFFF, 0x00, LNKE, 0x00 },
-+                              Package (0x04) { 0x3FFFF, 0x00, LNKG, 0x00 },
-+                              Package (0x04) { 0x3FFFF, 0x01, LNKH, 0x00 },
-+                              Package (0x04) { 0x3FFFF, 0x02, LNKE, 0x00 },
-+                              Package (0x04) { 0x3FFFF, 0x03, LNKF, 0x00 },
-+                      })
-+
-+                      Name (AR01, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0x1FFFF, 0x00, 0x00, 21 },
-+                              Package (0x04) { 0x2FFFF, 0x00, 0x00, 20 },
-+                              Package (0x04) { 0x3FFFF, 0x00, 0x00, 22 },
-+                              Package (0x04) { 0x3FFFF, 0x01, 0x00, 23 },
-+                              Package (0x04) { 0x3FFFF, 0x02, 0x00, 20 },
-+                              Package (0x04) { 0x3FFFF, 0x03, 0x00, 21 },
-+                      })
-+
-+                      Name (PR02, Package () {
-+                              /* PIC */
-+                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
-+                      })
-+
-+                      Name (AR02, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0xFFFF, 0x00, 0x00, 24 },
-+                              Package (0x04) { 0xFFFF, 0x01, 0x00, 25 },
-+                              Package (0x04) { 0xFFFF, 0x02, 0x00, 26 },
-+                              Package (0x04) { 0xFFFF, 0x03, 0x00, 27 },
-+                      })
-+
-+                      Name (PR03, Package () {
-+                              /* PIC */
-+                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
-+                      })
-+
-+                      Name (AR03, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0xFFFF, 0x00, 0x00, 48 },
-+                              Package (0x04) { 0xFFFF, 0x01, 0x00, 49 },
-+                              Package (0x04) { 0xFFFF, 0x02, 0x00, 50 },
-+                              Package (0x04) { 0xFFFF, 0x03, 0x00, 51 },
-+                      })
-+
-+                      Name (PR04, Package () {
-+                              /* PIC */
-+                              Package (0x04) { 0xFFFF, 0x00, LNKH, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x01, LNKE, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x02, LNKF, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x03, LNKG, 0x00 },
-+                      })
-+
-+                      Name (AR04, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0xFFFF, 0x00, 0x00, 47 },
-+                              Package (0x04) { 0xFFFF, 0x01, 0x00, 44 },
-+                              Package (0x04) { 0xFFFF, 0x02, 0x00, 45 },
-+                              Package (0x04) { 0xFFFF, 0x03, 0x00, 46 },
-+                      })
-+
-+                      Name (PR05, Package () {
-+                              /* PIC */
-+                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
-+                      })
-+
-+                      Name (AR05, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0xFFFF, 0x00, 0x00, 32 },
-+                              Package (0x04) { 0xFFFF, 0x01, 0x00, 33 },
-+                              Package (0x04) { 0xFFFF, 0x02, 0x00, 34 },
-+                              Package (0x04) { 0xFFFF, 0x03, 0x00, 35 },
-+                      })
-+
-+                      Name (PR06, Package () {
-+                              /* PIC */
-+                              Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x02, LNKG, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 },
-+                      })
-+
-+                      Name (AR06, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0xFFFF, 0x00, 0x00, 36 },
-+                              Package (0x04) { 0xFFFF, 0x01, 0x00, 37 },
-+                              Package (0x04) { 0xFFFF, 0x02, 0x00, 38 },
-+                              Package (0x04) { 0xFFFF, 0x03, 0x00, 39 },
-+                      })
-+
-+                      Name (PR07, Package () {
-+                              /* PIC */
-+                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
-+                      })
-+
-+                      Name (AR07, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0xFFFF, 0x00, 0x00, 40 },
-+                              Package (0x04) { 0xFFFF, 0x01, 0x00, 41 },
-+                              Package (0x04) { 0xFFFF, 0x02, 0x00, 42 },
-+                              Package (0x04) { 0xFFFF, 0x03, 0x00, 43 },
-+                      })
-+
-+                      /* PCI Resource Tables */
-+
-+                      /* PCI Resource Settings Access */
-+                      Method (_CRS, 0, Serialized)
-+                      {
-+                              Name (BUF0, ResourceTemplate ()
-+                              {
-+                                      IO (Decode16,
-+                                      0x0CF8, // Address Range Minimum
-+                                      0x0CF8, // Address Range Maximum
-+                                      0x01,   // Address Alignment
-+                                      0x08,   // Address Length
-+                                      )
-+                                      WordIO (ResourceProducer, MinFixed, 
MaxFixed, PosDecode, EntireRange,
-+                                      0x0000, // Address Space Granularity
-+                                      0x0000, // Address Range Minimum
-+                                      0x0CF7, // Address Range Maximum
-+                                      0x0000, // Address Translation Offset
-+                                      0x0CF8, // Address Length
-+                                      ,, , TypeStatic)
-+                              })
-+                              /* Methods below use SSDT to get actual MMIO 
regs
-+                                 The IO ports are from 0xd00, optionally an 
VGA,
-+                                 otherwise the info from MMIO is used.
-+                                 \_SB.GXXX(node, link)
-+                               */
-+                              Concatenate (\_SB.GMEM (0x00, \_SB.PCI0.SBLK), 
BUF0, Local1)
-+                              Concatenate (\_SB.GIOR (0x00, \_SB.PCI0.SBLK), 
Local1, Local2)
-+                              Concatenate (\_SB.GWBN (0x00, \_SB.PCI0.SBLK), 
Local2, Local3)
-+                              Return (Local3)
-+                      }
-+
-+                      /* PCI Routing Table Access */
-+                      Method (_PRT, 0, NotSerialized) {
-+                              If (PICM) {
-+                                      Return (AR00)
-+                              } Else {
-+                                      Return (PR00)
-+                              }
-+                      }
-+
-+                      /* 0:11.0 SP5100 SATA 0 */
-+                      Device(SAT0)
-+                      {
-+                              Name (_ADR, 0x00110000)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                              #include "southbridge/amd/sb700/acpi/sata.asl"
-+                      }
-+
-+                      /* 0:12.0 SP5100 USB 0 */
-+                      Device (USB0)
-+                      {
-+                              Name (_ADR, 0x00120000)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                      }
-+
-+                      /* 0:12.1 SP5100 USB 1 */
-+                      Device (USB1)
-+                      {
-+                              Name (_ADR, 0x00120001)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                      }
-+
-+                      /* 0:12.2 SP5100 USB 2 */
-+                      Device (USB2)
-+                      {
-+                              Name (_ADR, 0x00120002)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                      }
-+
-+                      /* 0:13.0 SP5100 USB 3 */
-+                      Device (USB3)
-+                      {
-+                              Name (_ADR, 0x00130000)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                      }
-+
-+                      /* 0:13.1 SP5100 USB 4 */
-+                      Device (USB4)
-+                      {
-+                              Name (_ADR, 0x00130001)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                      }
-+
-+                      /* 0:13.2 SP5100 USB 5 */
-+                      Device (USB5)
-+                      {
-+                              Name (_ADR, 0x00130002)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                      }
-+
-+                      /* 0:14.1 SP5100 IDE Controller */
-+                      Device (IDEC)
-+                      {
-+                              Name (_ADR, 0x00140001)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                              #include "southbridge/amd/sb700/acpi/ide.asl"
-+                      }
-+
-+                      /* 0:14.3 SP5100 LPC */
-+                      Device (LPC) {
-+                              Name (_HID, EisaId ("PNP0A05"))
-+                              Name (_ADR, 0x00140003)
-+
-+                              /* PS/2 keyboard (seems to be important for 
WinXP install) */
-+                              Device (KBD)
-+                              {
-+                                      Name (_HID, EisaId ("PNP0303"))
-+                                      Name (_CID, EisaId ("PNP030B"))
-+                                      Method (_STA, 0, NotSerialized)
-+                                      {
-+                                              Return (0x0f)
-+                                      }
-+                                      Method (_CRS, 0, Serialized)
-+                                      {
-+                                              Name (TMP, ResourceTemplate () {
-+                                                      IO (Decode16, 0x0060, 
0x0060, 0x01, 0x01)
-+                                                      IO (Decode16, 0x0064, 
0x0064, 0x01, 0x01)
-+                                                      IRQNoFlags () {1}
-+                                              })
-+                                              Return (TMP)
-+                                      }
-+                              }
-+
-+                              /* PS/2 mouse */
-+                              Device (MOU)
-+                              {
-+                                      Name (_HID, EisaId ("PNP0F03"))
-+                                      Name (_CID, EisaId ("PNP0F13"))
-+                                      Method (_STA, 0, NotSerialized)
-+                                      {
-+                                              Return (0x0f)
-+                                      }
-+                                      Method (_CRS, 0, Serialized)
-+                                      {
-+                                              Name (TMP, ResourceTemplate () {
-+                                                      IRQNoFlags () {12}
-+                                              })
-+                                              Return (TMP)
-+                                      }
-+                              }
-+
-+
-+                              /* UART 1 */
-+                              Device (URT1)
-+                              {
-+                                      Name (_HID, EisaId ("PNP0501"))         
// "PNP0501" for UART
-+                                      Name(_PRW, Package () {0x03, 0x04})     
// Wake from S1-S4
-+                                      Method (_STA, 0, NotSerialized)
-+                                      {
-+                                              Return (0x0f)                   
// Always enable
-+                                      }
-+                                      Name (_PRS, ResourceTemplate() {
-+                                              StartDependentFn(0, 1) {
-+                                                      IO(Decode16, 0x3f8, 
0x3f8, 0x8, 0x8)
-+                                                      IRQNoFlags() { 4 }
-+                                              } EndDependentFn()
-+                                      })
-+                                      Method (_CRS, 0)
-+                                      {
-+                                              Return(ResourceTemplate() {
-+                                                      IO(Decode16, 0x3f8, 
0x3f8, 0x8, 0x8)
-+                                                      IRQNoFlags() { 4 }
-+                                              })
-+                                      }
-+                              }
-+
-+                              /* High Precision Event Timer */
-+                              Device (HPET)
-+                              {
-+                                      Name (_HID, EisaId ("PNP0103"))
-+                                      Name (CRS, ResourceTemplate ()
-+                                      {
-+                                              Memory32Fixed (ReadOnly,
-+                                              0x00000000,
-+                                              0x00001000,
-+                                              _Y02)
-+                                              IRQNoFlags () {0}
-+                                              IRQNoFlags () {8}
-+                                      })
-+                                      Method (_STA, 0, NotSerialized)
-+                                      {
-+                                              Return (0x0F)
-+                                      }
-+                                      Method (_CRS, 0, NotSerialized)
-+                                      {
-+                                              CreateDWordField (CRS, 
\_SB.PCI0.LPC.HPET._Y02._BAS, HPT1)
-+                                              CreateDWordField (CRS, 
\_SB.PCI0.LPC.HPET._Y02._LEN, HPT2)
-+                                              Store (SHPB, HPT1)
-+                                              Store (SHPL, HPT2)
-+                                              Return (CRS)
-+                                      }
-+
-+                              }
-+                      }
-+
-+                      /* 0:14.4 PCI Bridge */
-+                      Device (PBR0)
-+                      {
-+                              Name (_ADR, 0x00140004)                 // 
_ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR01)
-+                                      } Else {
-+                                              Return (PR01)
-+                                      }
-+                              }
-+                              Device (SLT1)
-+                              {
-+                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
-+                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
-+                              }
-+                      }
-+
-+                      /* 0:14.5 SP5100 USB 6 */
-+                      Device (USB6)
-+                      {
-+                              Name (_ADR, 0x00140005)  // _ADR: Address
-+                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
-+                      }
-+
-+                      /* 2:00.0 PCIe x16 */
-+                      Device (PCE1)
-+                      {
-+                              Name (_ADR, 0x00020000)                 // 
_ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR02)
-+                                      } Else {
-+                                              Return (PR02)
-+                                      }
-+                              }
-+                              Device (SLT1)
-+                              {
-+                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
-+                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
-+                              }
-+                      }
-+
-+                      /* 3:00.0 PCIe NIC A */
-+                      Device (NICA)
-+                      {
-+                              Name (_ADR, 0x00090000)  // _ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR03)
-+                                      } Else {
-+                                              Return (PR03)
-+                                      }
-+                              }
-+                              Device (BDC1)
-+                              {
-+                                      Name (_ADR, Zero)  // _ADR: Address
-+                              }
-+                      }
-+
-+                      /* 4:00.0 PCIe NIC B */
-+                      Device (NICB)
-+                      {
-+                              Name (_ADR, 0x000A0000)  // _ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR04)
-+                                      } Else {
-+                                              Return (PR04)
-+                                      }
-+                              }
-+                              Device (BDC2)
-+                              {
-+                                      Name (_ADR, Zero)  // _ADR: Address
-+                              }
-+                      }
-+
-+                      /* 5:00.0 PCIe x16 */
-+                      Device (PCE4)
-+                      {
-+                              Name (_ADR, 0x000B0000)                 // 
_ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR05)
-+                                      } Else {
-+                                              Return (PR05)
-+                                      }
-+                              }
-+                              Device (SLT1)
-+                              {
-+                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
-+                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
-+                              }
-+                      }
-+
-+                      /* 6:00.0 PCIe x16 */
-+                      Device (PCE5)
-+                      {
-+                              Name (_ADR, 0x000C0000)                 // 
_ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR06)
-+                                      } Else {
-+                                              Return (PR06)
-+                                      }
-+                              }
-+                              Device (SLT1)
-+                              {
-+                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
-+                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
-+                              }
-+                      }
-+
-+                      /* 7:00.0 PCIe x16 */
-+                      Device (PCE3)
-+                      {
-+                              Name (_ADR, 0x000D0000)                 // 
_ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR07)
-+                                      } Else {
-+                                              Return (PR07)
-+                                      }
-+                              }
-+                              Device (SLT1)
-+                              {
-+                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
-+                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
-+                              }
-+                      }
-+              }
-+
-+              Device (PWRB) { /* Start Power button device */
-+                      Name(_HID, EISAID("PNP0C0C"))
-+                      Name(_UID, 0xAA)
-+                      Name(_PRW, Package () {3, 0x04})        /* wake from 
S1-S4 */
-+                      Name(_STA, 0x0B) /* sata is invisible */
-+              }
-+      }
-+
-+#include "acpi/pm_ctrl.asl"
-+
-+}
-diff --git a/src/mainboard/asus/kgpe-d16/get_bus_conf.c 
b/src/mainboard/asus/kgpe-d16/get_bus_conf.c
-new file mode 100644
-index 0000000..09fa262
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/get_bus_conf.c
-@@ -0,0 +1,128 @@
-+ /*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <console/console.h>
-+#include <device/pci.h>
-+#include <device/pci_ids.h>
-+#include <string.h>
-+#include <stdint.h>
-+#include <stdlib.h>
-+#if CONFIG_LOGICAL_CPUS
-+#include <cpu/amd/multicore.h>
-+#endif
-+
-+#include <cpu/amd/amdfam10_sysconf.h>
-+
-+/* Global variables for MB layouts and these will be shared by irqtable 
mptable
-+* and acpi_tables busnum is default.
-+*/
-+u8 bus_isa;
-+u8 bus_sr5650[14];
-+u8 bus_sp5100[2];
-+u32 apicid_sp5100;
-+
-+/*
-+* Here you only need to set value in pci1234 for HT-IO that could be 
installed or not
-+* You may need to preset pci1234 for HTIO board,
-+* please refer to src/northbridge/amd/amdk8/get_sblk_pci1234.c for detail
-+*/
-+u32 pci1234x[] = {
-+      0x0000ff0,
-+};
-+
-+/*
-+* HT Chain device num, actually it is unit id base of every ht device in 
chain,
-+* assume every chain only have 4 ht device at most
-+*/
-+u32 hcdnx[] = {
-+      0x20202020,
-+};
-+
-+
-+u32 sbdn_sr5650;
-+u32 sbdn_sp5100;
-+
-+extern void get_pci1234(void);
-+
-+static u32 get_bus_conf_done = 0;
-+
-+void get_bus_conf(void)
-+{
-+      u32 apicid_base;
-+      device_t dev;
-+      int i;
-+
-+      if (get_bus_conf_done == 1)
-+              return;         /* do it only once */
-+      get_bus_conf_done = 1;
-+
-+      sysconf.hc_possible_num = ARRAY_SIZE(pci1234x);
-+      for (i = 0; i < sysconf.hc_possible_num; i++) {
-+              sysconf.pci1234[i] = pci1234x[i];
-+              sysconf.hcdn[i] = hcdnx[i];
-+      }
-+
-+      get_pci1234();
-+
-+      sysconf.sbdn = (sysconf.hcdn[0] & 0xff);
-+      sbdn_sr5650 = sysconf.sbdn;
-+      sbdn_sp5100 = 0;
-+
-+      for (i = 0; i < 2; i++) {
-+              bus_sp5100[i] = 0;
-+      }
-+      for (i = 0; i < ARRAY_SIZE(bus_sr5650); i++) {
-+              bus_sr5650[i] = 0;
-+      }
-+
-+
-+      bus_sr5650[0] = (sysconf.pci1234[0] >> 16) & 0xff;
-+      bus_sp5100[0] = bus_sr5650[0];
-+
-+
-+      /* sp5100 */
-+      dev = dev_find_slot(bus_sp5100[0], PCI_DEVFN(sbdn_sp5100 + 0x14, 4));
-+      if (dev) {
-+              bus_sp5100[1] = pci_read_config8(dev, PCI_SECONDARY_BUS);
-+              bus_isa = pci_read_config8(dev, PCI_SUBORDINATE_BUS);
-+              bus_isa++;
-+      }
-+
-+      /* sr5650 */
-+      for (i = 1; i < ARRAY_SIZE(bus_sr5650); i++) {
-+              dev = dev_find_slot(bus_sr5650[0], PCI_DEVFN(sbdn_sr5650 + i, 
0));
-+              if (dev) {
-+                      bus_sr5650[i] = pci_read_config8(dev, 
PCI_SECONDARY_BUS);
-+                      if(255 != bus_sr5650[i]) {
-+                              bus_isa = pci_read_config8(dev, 
PCI_SUBORDINATE_BUS);
-+                              bus_isa++;
-+                      }
-+              }
-+      }
-+
-+      /* I/O APICs:   APIC ID Version State   Address */
-+      bus_isa = 10;
-+#if CONFIG_LOGICAL_CPUS
-+      apicid_base = get_apicid_base(1);
-+#else
-+      apicid_base = CONFIG_MAX_PHYSICAL_CPUS;
-+#endif
-+      apicid_sp5100 = apicid_base + 0;
-+}
-diff --git a/src/mainboard/asus/kgpe-d16/irq_tables.c 
b/src/mainboard/asus/kgpe-d16/irq_tables.c
-new file mode 100644
-index 0000000..5eb4c24
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/irq_tables.c
-@@ -0,0 +1,112 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <console/console.h>
-+#include <device/pci.h>
-+#include <string.h>
-+#include <stdint.h>
-+#include <arch/pirq_routing.h>
-+
-+#include <cpu/amd/amdfam10_sysconf.h>
-+
-+static void write_pirq_info(struct irq_info *pirq_info, u8 bus, u8 devfn,
-+                          u8 link0, u16 bitmap0, u8 link1, u16 bitmap1,
-+                          u8 link2, u16 bitmap2, u8 link3, u16 bitmap3,
-+                          u8 slot, u8 rfu)
-+{
-+      pirq_info->bus = bus;
-+      pirq_info->devfn = devfn;
-+      pirq_info->irq[0].link = link0;
-+      pirq_info->irq[0].bitmap = bitmap0;
-+      pirq_info->irq[1].link = link1;
-+      pirq_info->irq[1].bitmap = bitmap1;
-+      pirq_info->irq[2].link = link2;
-+      pirq_info->irq[2].bitmap = bitmap2;
-+      pirq_info->irq[3].link = link3;
-+      pirq_info->irq[3].bitmap = bitmap3;
-+      pirq_info->slot = slot;
-+      pirq_info->rfu = rfu;
-+}
-+extern u8 bus_isa;
-+extern u8 bus_rs780[8];
-+extern u8 bus_sp5100[2];
-+extern unsigned long sbdn_sp5100;
-+
-+unsigned long write_pirq_routing_table(unsigned long addr)
-+{
-+      struct irq_routing_table *pirq;
-+      struct irq_info *pirq_info;
-+      u32 slot_num;
-+      u8 *v;
-+
-+      u8 sum = 0;
-+      int i;
-+
-+      get_bus_conf();         /* it will find out all bus num and apic that 
share with mptable.c and mptable.c and acpi_tables.c */
-+
-+      /* Align the table to be 16 byte aligned. */
-+      addr += 15;
-+      addr &= ~15;
-+
-+      /* This table must be between 0xf0000 & 0x100000 */
-+      printk(BIOS_INFO, "Writing IRQ routing tables to 0x%lx...", addr);
-+
-+      pirq = (void *)(addr);
-+      v = (u8 *) (addr);
-+
-+      pirq->signature = PIRQ_SIGNATURE;
-+      pirq->version = PIRQ_VERSION;
-+
-+      pirq->rtr_bus = bus_sp5100[0];
-+      pirq->rtr_devfn = PCI_DEVFN(0x14, 4);
-+
-+      pirq->exclusive_irqs = 0;
-+
-+      pirq->rtr_vendor = 0x1002;
-+      pirq->rtr_device = 0x4384;
-+
-+      pirq->miniport_data = 0;
-+
-+      memset(pirq->rfu, 0, sizeof(pirq->rfu));
-+
-+      pirq_info = (void *)(&pirq->checksum + 1);
-+      slot_num = 0;
-+
-+      /* pci bridge */
-+      write_pirq_info(pirq_info, bus_sp5100[0], ((sbdn_sp5100 + 0x14) << 3) | 
4,
-+                      0x1, 0xdef8, 0x2, 0xdef8, 0x3, 0xdef8, 0x4, 0xdef8, 0,
-+                      0);
-+      pirq_info++;
-+      slot_num++;
-+
-+      pirq->size = 32 + 16 * slot_num;
-+
-+      for (i = 0; i < pirq->size; i++)
-+              sum += v[i];
-+
-+      sum = pirq->checksum - sum;
-+      if (sum != pirq->checksum) {
-+              pirq->checksum = sum;
-+      }
-+
-+      printk(BIOS_INFO, "write_pirq_routing_table done.\n");
-+
-+      return (unsigned long)pirq_info;
-+}
-diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c 
b/src/mainboard/asus/kgpe-d16/mainboard.c
-new file mode 100644
-index 0000000..47ede34
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/mainboard.c
-@@ -0,0 +1,81 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <console/console.h>
-+#include <device/device.h>
-+#include <device/pci.h>
-+#include <arch/io.h>
-+#include <cpu/x86/msr.h>
-+#include <cpu/amd/mtrr.h>
-+#include <device/pci_def.h>
-+#include <southbridge/amd/sb700/sb700.h>
-+#include <southbridge/amd/sr5650/cmn.h>
-+
-+
-+void set_pcie_reset(void);
-+void set_pcie_dereset(void);
-+
-+void set_pcie_reset(void)
-+{
-+      device_t pcie_core_dev;
-+
-+      pcie_core_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-+      set_htiu_enable_bits(pcie_core_dev, 0xA8, 0xFFFFFFFF, 0x28282828);
-+      set_htiu_enable_bits(pcie_core_dev, 0xA9, 0x000000FF, 0x00000028);
-+}
-+
-+void set_pcie_dereset(void)
-+{
-+      device_t pcie_core_dev;
-+
-+      pcie_core_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-+      set_htiu_enable_bits(pcie_core_dev, 0xA8, 0xFFFFFFFF, 0x6F6F6F6F);
-+      set_htiu_enable_bits(pcie_core_dev, 0xA9, 0x000000FF, 0x0000006F);
-+}
-+
-+/*************************************************
-+* enable the dedicated function in kgpe-d16 board.
-+* This function is called earlier than sr5650_enable.
-+*************************************************/
-+static void mainboard_enable(device_t dev)
-+{
-+      printk(BIOS_INFO, "Mainboard KGPE-D16 Enable. dev=0x%p\n", dev);
-+
-+      msr_t msr, msr2;
-+
-+      /* TOP_MEM: the top of DRAM below 4G */
-+      msr = rdmsr(TOP_MEM);
-+      printk
-+          (BIOS_INFO, "%s, TOP MEM: msr.lo = 0x%08x, msr.hi = 0x%08x\n",
-+           __func__, msr.lo, msr.hi);
-+
-+      /* TOP_MEM2: the top of DRAM above 4G */
-+      msr2 = rdmsr(TOP_MEM2);
-+      printk
-+          (BIOS_INFO, "%s, TOP MEM2: msr2.lo = 0x%08x, msr2.hi = 0x%08x\n",
-+           __func__, msr2.lo, msr2.hi);
-+
-+      set_pcie_dereset();
-+      /* get_ide_dma66(); */
-+}
-+
-+struct chip_operations mainboard_ops = {
-+      .enable_dev = mainboard_enable,
-+};
-diff --git a/src/mainboard/asus/kgpe-d16/mb_sysconf.h 
b/src/mainboard/asus/kgpe-d16/mb_sysconf.h
-new file mode 100644
-index 0000000..3a407a6
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/mb_sysconf.h
-@@ -0,0 +1,44 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#ifndef MB_SYSCONF_H
-+
-+#define MB_SYSCONF_H
-+
-+struct mb_sysconf_t {
-+      u8 bus_isa;
-+      u8 bus_8132_0;
-+      u8 bus_8132_1;
-+      u8 bus_8132_2;
-+      u8 bus_8111_0;
-+      u8 bus_8111_1;
-+      u8 bus_8132a[31][3];
-+      u8 bus_8151[31][2];
-+
-+      u32 apicid_8111;
-+      u32 apicid_8132_1;
-+      u32 apicid_8132_2;
-+      u32 apicid_8132a[31][2];
-+      u32 sbdn3;
-+      u32 sbdn3a[31];
-+      u32 sbdn5[31];
-+};
-+
-+#endif
-diff --git a/src/mainboard/asus/kgpe-d16/mptable.c 
b/src/mainboard/asus/kgpe-d16/mptable.c
-new file mode 100644
-index 0000000..0279f8b
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/mptable.c
-@@ -0,0 +1,231 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <console/console.h>
-+#include <arch/smp/mpspec.h>
-+#include <device/pci.h>
-+#include <arch/io.h>
-+#include <string.h>
-+#include <stdint.h>
-+#include <cpu/amd/amdfam10_sysconf.h>
-+
-+extern u8 bus_sr5650[14];
-+extern u8 bus_sp5100[2];
-+
-+extern u32 apicid_sp5100;
-+
-+extern u32 sbdn_sr5650;
-+extern u32 sbdn_sp5100;
-+
-+
-+static void *smp_write_config_table(void *v)
-+{
-+      struct mp_config_table *mc;
-+      int bus_isa;
-+      u32 apicid_sr5650;
-+      device_t dev;
-+      uint8_t sp5100_bus_number;
-+
-+      mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);
-+
-+      mptable_init(mc, LOCAL_APIC_ADDR);
-+
-+      smp_write_processors(mc);
-+
-+      get_bus_conf();
-+
-+      apicid_sp5100 = 0x20;
-+      apicid_sr5650 = apicid_sp5100 + 1;
-+
-+      mptable_write_buses(mc, NULL, &bus_isa);
-+      /* I/O APICs:   APIC ID Version State   Address */
-+      {
-+              uint32_t *dword_ptr;
-+              uint32_t dword;
-+              uint16_t word;
-+              uint8_t byte;
-+
-+              sp5100_bus_number = 0; //bus_sp5100[0]; TODO: why bus_sp5100[0] 
use same value of bus_sr5650[0] assigned by get_pci1234(), instead of 0.
-+
-+              dev = dev_find_slot(sp5100_bus_number, PCI_DEVFN(sbdn_sp5100 + 
0x14, 0));
-+              if (dev) {
-+                      dword_ptr = (u32 *)(pci_read_config32(dev, 0x74) & 
0xfffffff0);
-+                      smp_write_ioapic(mc, apicid_sp5100, 0x11, dword_ptr);
-+
-+                      /* Initialize interrupt mapping */
-+                      /* USB 1 & 2 */
-+                      word = pci_read_config16(dev, 0xbe);
-+                      word &= ~0x3f3f;
-+                      word |= 0x0;            /* 0: INTA, ...., 7: INTH */
-+                      word |= (0x1 << 3);     /* 0: INTA, ...., 7: INTH */
-+                      word |= (0x2 << 8);     /* 0: INTA, ...., 7: INTH */
-+                      word |= (0x3 << 11);    /* 0: INTA, ...., 7: INTH */
-+                      pci_write_config16(dev, 0xbe, word);
-+
-+                      /* USB 3 */
-+                      byte = pci_read_config8(dev, 0x63);
-+                      byte &= 0xf8;
-+                      byte |= (0x2 << 4);     /* 0: INTA, ...., 7: INTH */
-+                      pci_write_config8(dev, 0x63, byte);
-+
-+                      dword = pci_read_config32(dev, 0xac);
-+
-+                      /* SATA */
-+                      dword &= ~(7 << 26);
-+                      dword |= (0x6 << 26);   /* 0: INTA, ...., 7: INTH */
-+
-+                      /* Hide IDE */
-+                      dword &= ~(0x00080000);
-+
-+                      /* dword_ptr |= 1<<22; PIC and APIC co exists */
-+                      pci_write_config32(dev, 0xac, dword);
-+
-+                      /*
-+                       * 00:12.0: PROG SATA : INT F
-+                       * 00:13.0: INTA USB_0
-+                       * 00:13.1: INTB USB_1
-+                       * 00:13.2: INTC USB_2
-+                       * 00:13.3: INTD USB_3
-+                       * 00:13.4: INTC USB_4
-+                       * 00:13.5: INTD USB2
-+                       * 00:14.1: INTA IDE
-+                       * 00:14.2: Prog HDA : INT E
-+                       * 00:14.5: INTB ACI
-+                       * 00:14.6: INTB MCI
-+                       */
-+              }
-+              dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-+              if (dev) {
-+                      pci_write_config32(dev, 0xF8, 0x1);
-+                      dword_ptr = (u32 *)(pci_read_config32(dev, 0xFC) & 
0xfffffff0);
-+                      smp_write_ioapic(mc, apicid_sr5650, 0x11, dword_ptr);
-+              }
-+      }
-+
-+      /* I/O Ints:    Type    Polarity    Trigger     Bus ID   IRQ    APIC ID 
PIN# */
-+#define IO_LOCAL_INT(type, intr, apicid, pin) \
-+      smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | 
MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin));
-+
-+      mptable_add_isa_interrupts(mc, bus_isa, apicid_sp5100, 0);
-+
-+      /* SR5650 devices */
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((2)<<2)|(0)), apicid_sr5650, 28);   /* Device 2 (LNKE) */
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((4)<<2)|(0)), apicid_sr5650, 28);   /* Device 4 (LNKF) */
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((9)<<2)|(0)), apicid_sr5650, 29);   /* Device 9 (LNKG) */
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((10)<<2)|(0)), apicid_sr5650, 30);  /* Device 10 (LNKG) */
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((11)<<2)|(0)), apicid_sr5650, 30);  /* Device 11 (LNKG) */
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((12)<<2)|(0)), apicid_sr5650, 30);  /* Device 12 (LNKG) */
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((13)<<2)|(0)), apicid_sr5650, 30);  /* Device 13 (LNKG) */
-+
-+      dev = dev_find_slot(0, PCI_DEVFN(0x2, 0));
-+      if (dev && dev->enabled) {
-+              uint8_t bus_pci = dev->link_list->secondary;
-+              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0x2)|(0)), 
apicid_sr5650, 0);    /* card behind dev2 */
-+      }
-+      dev = dev_find_slot(0, PCI_DEVFN(0x4, 0));
-+      if (dev && dev->enabled) {
-+              uint8_t bus_pci = dev->link_list->secondary;
-+              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0x4)|(0)), 
apicid_sr5650, 0);    /* PIKE */
-+      }
-+      dev = dev_find_slot(0, PCI_DEVFN(0x9, 0));
-+      if (dev && dev->enabled) {
-+              uint8_t bus_pci = dev->link_list->secondary;
-+              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0x9)|(0)), 
apicid_sr5650, 23);   /* NIC A */
-+      }
-+      dev = dev_find_slot(0, PCI_DEVFN(0xa, 0));
-+      if (dev && dev->enabled) {
-+              uint8_t bus_pci = dev->link_list->secondary;
-+              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xa)|(0)), 
apicid_sr5650, 24);   /* NIC B */
-+      }
-+      dev = dev_find_slot(0, PCI_DEVFN(0xb, 0));
-+      if (dev && dev->enabled) {
-+              uint8_t bus_pci = dev->link_list->secondary;
-+              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xb)|(0)), 
apicid_sr5650, 0);    /* card behind dev11 */
-+      }
-+      dev = dev_find_slot(0, PCI_DEVFN(0xc, 0));
-+      if (dev && dev->enabled) {
-+              uint8_t bus_pci = dev->link_list->secondary;
-+              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xc)|(0)), 
apicid_sr5650, 0);    /* card behind dev12 */
-+      }
-+      dev = dev_find_slot(0, PCI_DEVFN(0xd, 0));
-+      if (dev && dev->enabled) {
-+              uint8_t bus_pci = dev->link_list->secondary;
-+              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xd)|(0)), 
apicid_sr5650, 0);    /* card behind dev13 */
-+      }
-+
-+      /* PCI interrupts are level triggered, and are
-+       * associated with a specific bus/device/function tuple.
-+       */
-+#define PCI_INT(bus, dev, interrupt_signal, pin) \
-+      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
(bus), (((dev)<<2)|(interrupt_signal)), apicid_sp5100, (pin))
-+
-+      /* USB1 */
-+      PCI_INT(sp5100_bus_number, 0x12, 0x0, 0x10); /* OHCI0 Port 0~2 */
-+      PCI_INT(sp5100_bus_number, 0x12, 0x1, 0x11); /* OHCI1 Port 3~5 */
-+
-+      /* USB2 */
-+      PCI_INT(sp5100_bus_number, 0x13, 0x0, 0x12); /* OHCI0 Port 6~8 */
-+      PCI_INT(sp5100_bus_number, 0x13, 0x1, 0x13); /* EHCI Port 6~11 */
-+
-+      /* USB3 */
-+      PCI_INT(sp5100_bus_number, 0x14, 0x3, 0x12); /* OHCI0 Port 12~13 */
-+
-+      /* SATA */
-+      PCI_INT(sp5100_bus_number, 0x11, 0x0, 0x16); /* 6, INTG */
-+
-+      /* PCI slots */
-+      dev = dev_find_slot(0, PCI_DEVFN(0x14, 4));
-+      if (dev && dev->enabled) {
-+              u8 bus_pci = dev->link_list->secondary;
-+
-+              /* PCI_SLOT 0. */
-+              PCI_INT(bus_pci, 0x1, 0x0, 0x15);
-+              PCI_INT(bus_pci, 0x1, 0x1, 0x16);
-+              PCI_INT(bus_pci, 0x1, 0x2, 0x17);
-+              PCI_INT(bus_pci, 0x1, 0x3, 0x14);
-+
-+              /* PCI_SLOT 1. */
-+              PCI_INT(bus_pci, 0x2, 0x0, 0x14);
-+              PCI_INT(bus_pci, 0x2, 0x1, 0x15);
-+              PCI_INT(bus_pci, 0x2, 0x2, 0x16);
-+              PCI_INT(bus_pci, 0x2, 0x3, 0x17);
-+
-+              /* PCI_SLOT 2. */
-+              PCI_INT(bus_pci, 0x3, 0x0, 0x16);
-+              PCI_INT(bus_pci, 0x3, 0x1, 0x17);
-+              PCI_INT(bus_pci, 0x3, 0x2, 0x14);
-+              PCI_INT(bus_pci, 0x3, 0x3, 0x15);
-+      }
-+
-+      /*Local Ints:   Type    Polarity    Trigger     Bus ID   IRQ    APIC ID 
PIN# */
-+      IO_LOCAL_INT(mp_ExtINT, 0x0, MP_APIC_ALL, 0x0);
-+      IO_LOCAL_INT(mp_NMI, 0x0, MP_APIC_ALL, 0x1);
-+      /* There is no extension information... */
-+
-+      /* Compute the checksums */
-+      return mptable_finalize(mc);
-+}
-+
-+unsigned long write_smp_table(unsigned long addr)
-+{
-+      void *v;
-+      v = smp_write_floating_table(addr, 0);
-+      return (unsigned long)smp_write_config_table(v);
-+}
-diff --git a/src/mainboard/asus/kgpe-d16/resourcemap.c 
b/src/mainboard/asus/kgpe-d16/resourcemap.c
-new file mode 100644
-index 0000000..3e240dc
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/resourcemap.c
-@@ -0,0 +1,284 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * Copyright (C) 2007 AMD
-+ * Written by Yinghai Lu <address@hidden> for AMD.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+static void setup_mb_resource_map(void)
-+{
-+      static const unsigned int register_values[] = {
-+              /* Careful set limit registers before base registers which 
contain the enables */
-+              /* DRAM Limit i Registers
-+               * F1:0x44 i = 0
-+               * F1:0x4C i = 1
-+               * F1:0x54 i = 2
-+               * F1:0x5C i = 3
-+               * F1:0x64 i = 4
-+               * F1:0x6C i = 5
-+               * F1:0x74 i = 6
-+               * F1:0x7C i = 7
-+               * [ 2: 0] Destination Node ID
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 7: 3] Reserved
-+               * [10: 8] Interleave select
-+               *         specifies the values of A[14:12] to use with 
interleave enable.
-+               * [15:11] Reserved
-+               * [31:16] DRAM Limit Address i Bits 39-24
-+               *         This field defines the upper address bits of a 40 
bit  address
-+               *         that define the end of the DRAM region.
-+               */
-+              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x44), 0x0000f8f8, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x4C), 0x0000f8f8, 
0x00000001,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x54), 0x0000f8f8, 
0x00000002,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x5C), 0x0000f8f8, 
0x00000003,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x64), 0x0000f8f8, 
0x00000004,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x6C), 0x0000f8f8, 
0x00000005,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x74), 0x0000f8f8, 
0x00000006,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x7C), 0x0000f8f8, 
0x00000007,
-+
-+              /* DRAM Base i Registers
-+               * F1:0x40 i = 0
-+               * F1:0x48 i = 1
-+               * F1:0x50 i = 2
-+               * F1:0x58 i = 3
-+               * F1:0x60 i = 4
-+               * F1:0x68 i = 5
-+               * F1:0x70 i = 6
-+               * F1:0x78 i = 7
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads Disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes Disabled
-+               *         1 = Writes Enabled
-+               * [ 7: 2] Reserved
-+               * [10: 8] Interleave Enable
-+               *         000 = No interleave
-+               *         001 = Interleave on A[12] (2 nodes)
-+               *         010 = reserved
-+               *         011 = Interleave on A[12] and A[14] (4 nodes)
-+               *         100 = reserved
-+               *         101 = reserved
-+               *         110 = reserved
-+               *         111 = Interleve on A[12] and A[13] and A[14] (8 
nodes)
-+               * [15:11] Reserved
-+               * [31:16] DRAM Base Address i Bits 39-24
-+               *         This field defines the upper address bits of a 
40-bit address
-+               *         that define the start of the DRAM region.
-+               */
-+              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x40), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x48), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x50), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x58), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x60), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x68), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x70), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x78), 0x0000f8fc, 
0x00000000,
-+
-+              /* Memory-Mapped I/O Limit i Registers
-+               * F1:0x84 i = 0
-+               * F1:0x8C i = 1
-+               * F1:0x94 i = 2
-+               * F1:0x9C i = 3
-+               * F1:0xA4 i = 4
-+               * F1:0xAC i = 5
-+               * F1:0xB4 i = 6
-+               * F1:0xBC i = 7
-+               * [ 2: 0] Destination Node ID
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 3: 3] Reserved
-+               * [ 5: 4] Destination Link ID
-+               *         00 = Link 0
-+               *         01 = Link 1
-+               *         10 = Link 2
-+               *         11 = Link 3
-+               * [ 6: 6] Reserved
-+               * [ 7: 7] Non-Posted
-+               *         0 = CPU writes may be posted
-+               *         1 = CPU writes must be non-posted
-+               * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
-+               *         This field defines the upp adddress bits of a 40-bit 
address that
-+               *         defines the end of a memory-mapped I/O region n
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x84), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x8C), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x94), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x9C), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA4), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xAC), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB4), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xBC), 0x00000048, 
0x00000000,
-+
-+              /* Memory-Mapped I/O Base i Registers
-+               * F1:0x80 i = 0
-+               * F1:0x88 i = 1
-+               * F1:0x90 i = 2
-+               * F1:0x98 i = 3
-+               * F1:0xA0 i = 4
-+               * F1:0xA8 i = 5
-+               * F1:0xB0 i = 6
-+               * F1:0xB8 i = 7
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes disabled
-+               *         1 = Writes Enabled
-+               * [ 2: 2] Cpu Disable
-+               *         0 = Cpu can use this I/O range
-+               *         1 = Cpu requests do not use this I/O range
-+               * [ 3: 3] Lock
-+               *         0 = base/limit registers i are read/write
-+               *         1 = base/limit registers i are read-only
-+               * [ 7: 4] Reserved
-+               * [31: 8] Memory-Mapped I/O Base Address i (39-16)
-+               *         This field defines the upper address bits of a 40bit 
address
-+               *         that defines the start of memory-mapped I/O region i
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x80), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x88), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x90), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x98), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA0), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA8), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB0), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB8), 0x000000f0, 
0x00000000,
-+
-+              /* PCI I/O Limit i Registers
-+               * F1:0xC4 i = 0
-+               * F1:0xCC i = 1
-+               * F1:0xD4 i = 2
-+               * F1:0xDC i = 3
-+               * [ 2: 0] Destination Node ID
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 3: 3] Reserved
-+               * [ 5: 4] Destination Link ID
-+               *         00 = Link 0
-+               *         01 = Link 1
-+               *         10 = Link 2
-+               *         11 = Link 3
-+               * [11: 6] Reserved
-+               * [24:12] PCI I/O Limit Address i
-+               *         This field defines the end of PCI I/O region n
-+               * [31:25] Reserved
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC4), 0xFE000FC8, 
0x00fff110, /* link 3 of cpu 0 --> AMD SR5690 */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xCC), 0xFE000FC8, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD4), 0xFE000FC8, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xDC), 0xFE000FC8, 
0x00000000,
-+
-+              /* PCI I/O Base i Registers
-+               * F1:0xC0 i = 0
-+               * F1:0xC8 i = 1
-+               * F1:0xD0 i = 2
-+               * F1:0xD8 i = 3
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads Disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes Disabled
-+               *         1 = Writes Enabled
-+               * [ 3: 2] Reserved
-+               * [ 4: 4] VGA Enable
-+               *         0 = VGA matches Disabled
-+               *         1 = matches all address < 64K and where A[9:0] is in 
the
-+               *             range 3B0-3BB or 3C0-3DF independent of the base 
& limit registers
-+               * [ 5: 5] ISA Enable
-+               *         0 = ISA matches Disabled
-+               *         1 = Blocks address < 64K and in the last 768 bytes 
of eack 1K block
-+               *             from matching agains this base/limit pair
-+               * [11: 6] Reserved
-+               * [24:12] PCI I/O Base i
-+               *         This field defines the start of PCI I/O region n
-+               * [31:25] Reserved
-+               */
-+//            PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC0), 0xFE000FCC, 
0x00001013,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC8), 0xFE000FCC, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD0), 0xFE000FCC, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD8), 0xFE000FCC, 
0x00000000,
-+
-+              /* Config Base and Limit i Registers
-+               * F1:0xE0 i = 0
-+               * F1:0xE4 i = 1
-+               * F1:0xE8 i = 2
-+               * F1:0xEC i = 3
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads Disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes Disabled
-+               *         1 = Writes Enabled
-+               * [ 2: 2] Device Number Compare Enable
-+               *         0 = The ranges are based on bus number
-+               *         1 = The ranges are ranges of devices on bus 0
-+               * [ 3: 3] Reserved
-+               * [ 6: 4] Destination Node
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 7: 7] Reserved
-+               * [ 9: 8] Destination Link
-+               *         00 = Link 0
-+               *         01 = Link 1
-+               *         10 = Link 2
-+               *         11 - Link 3
-+               * [15:10] Reserved
-+               * [23:16] Bus Number Base i
-+               *         This field defines the lowest bus number in 
configuration region i
-+               * [31:24] Bus Number Limit i
-+               *         This field defines the highest bus number in 
configuration region i
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE0), 0x0000FC88, 
0x05000303, /* link 3 of cpu 0 --> AMD SR5690 */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE4), 0x0000FC88, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE8), 0x0000FC88, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xEC), 0x0000FC88, 
0x00000000,
-+
-+      };
-+
-+      int max;
-+      max = ARRAY_SIZE(register_values);
-+      setup_resource_map(register_values, max);
-+}
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-new file mode 100644
-index 0000000..9964cfe
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -0,0 +1,422 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * Copyright (C) 2007 AMD
-+ * Written by Yinghai Lu <address@hidden> for AMD.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <stdint.h>
-+#include <string.h>
-+#include <reset.h>
-+#include <device/pci_def.h>
-+#include <device/pci_ids.h>
-+#include <arch/io.h>
-+#include <device/pnp_def.h>
-+#include <cpu/x86/lapic.h>
-+#include <console/console.h>
-+#include <timestamp.h>
-+#include <lib.h>
-+#include <spd.h>
-+#include <cpu/amd/model_10xxx_rev.h>
-+#include <northbridge/amd/amdfam10/raminit.h>
-+#include <northbridge/amd/amdfam10/amdfam10.h>
-+#include "lib/delay.c"
-+#include <cpu/x86/lapic.h>
-+#include "northbridge/amd/amdfam10/reset_test.c"
-+#include <superio/nuvoton/common/nuvoton.h>
-+#include <superio/nuvoton/nct5572d/nct5572d.h>
-+#include <cpu/x86/bist.h>
-+// #include "northbridge/amd/amdk8/incoherent_ht.c"
-+#include <southbridge/amd/sb700/sb700.h>
-+#include <southbridge/amd/sb700/smbus.h>
-+#include <southbridge/amd/sr5650/sr5650.h>
-+#include "northbridge/amd/amdfam10/debug.c"
-+#include "northbridge/amd/amdfam10/setup_resource_map.c"
-+
-+#define SERIAL_DEV PNP_DEV(0x2e, NCT5572D_SP1)
-+
-+static void activate_spd_rom(const struct mem_controller *ctrl);
-+
-+static inline int spd_read_byte(unsigned device, unsigned address)
-+{
-+      return do_smbus_read_byte(SMBUS_AUX_IO_BASE, device, address);
-+}
-+
-+#include <northbridge/amd/amdfam10/amdfam10.h>
-+#include "northbridge/amd/amdfam10/raminit_sysinfo_in_ram.c"
-+#include "northbridge/amd/amdfam10/pci.c"
-+#include "resourcemap.c"
-+#include "cpu/amd/quadcore/quadcore.c"
-+
-+#include <cpu/amd/microcode.h>
-+
-+#include "cpu/amd/model_10xxx/init_cpus.c"
-+#include "northbridge/amd/amdfam10/early_ht.c"
-+
-+/*
-+ * ASUS KGPE-D16 specific SPD enable/disable magic.
-+ *
-+ * Setting SP5100 GPIOs 59 and 60 controls an SPI mux with four settings:
-+ * 0: Disabled
-+ * 1: Normal SPI access
-+ * 2: CPU0 SPD
-+ * 3: CPU1 SPD
-+ *
-+ * Disable SPD access after RAM init to allow access to standard SMBus/I2C 
offsets
-+ * which is required e.g. by lm-sensors.
-+ */
-+
-+/* Relevant GPIO register information is available in the
-+ * AMD SP5100 Register Reference Guide rev. 3.03, page 130
-+ */
-+static void switch_spd_mux(uint8_t channel)
-+{
-+      uint8_t byte;
-+
-+      byte = pci_read_config8(PCI_DEV(0, 0x14, 0), 0x54);
-+      byte &= ~0xc;                   /* Clear SPD mux GPIOs */
-+      byte &= ~0xc0;                  /* Enable SPD mux GPIO output drivers */
-+      byte |= (channel << 2) & 0xc;   /* Set SPD mux GPIOs */
-+      pci_write_config8(PCI_DEV(0, 0x14, 0), 0x54, byte);
-+}
-+
-+static const uint8_t spd_addr[] = {
-+      // Socket 0 Node 0 ("Node 0")
-+      RC00, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
-+      // Socket 0 Node 1 ("Node 1")
-+      RC00, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
-+      // Socket 1 Node 1 ("Node 2")
-+      RC01, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
-+      // Socket 1 Node 0 ("Node 3")
-+      RC01, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
-+};
-+
-+static void activate_spd_rom(const struct mem_controller *ctrl) {
-+      struct sys_info *sysinfo = &sysinfo_car;
-+
-+      printk(BIOS_DEBUG, "activate_spd_rom() for node %02x\n", ctrl->node_id);
-+      if (ctrl->node_id == 0) {
-+              printk(BIOS_DEBUG, "enable_spd_node0()\n");
-+              switch_spd_mux(0x2);
-+      } else if (ctrl->node_id == 1) {
-+              printk(BIOS_DEBUG, "enable_spd_node1()\n");
-+              switch_spd_mux((sysinfo->nodes <= 2)?0x2:0x3);
-+      } else if (ctrl->node_id == 2) {
-+              printk(BIOS_DEBUG, "enable_spd_node2()\n");
-+              switch_spd_mux((sysinfo->nodes <= 2)?0x3:0x2);
-+      } else if (ctrl->node_id == 3) {
-+              printk(BIOS_DEBUG, "enable_spd_node3()\n");
-+              switch_spd_mux(0x3);
-+      }
-+}
-+
-+/* Voltages are specified by index
-+ * Valid indicies for this platform are:
-+ * 0: 1.5V
-+ * 1: 1.35V
-+ * 2: 1.25V
-+ * 3: 1.15V
-+ */
-+static void set_ddr3_voltage(uint8_t node, uint8_t index) {
-+      uint8_t byte;
-+      uint8_t value;
-+
-+      if (index == 0)
-+              value = 0x0;
-+      else if (index == 1)
-+              value = 0x1;
-+      else if (index == 2)
-+              value = 0x4;
-+      else if (index == 3)
-+              value = 0x5;
-+      if (node == 1)
-+              value <<= 1;
-+
-+      /* Set GPIOs */
-+      byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0xd1);
-+      if (node == 0)
-+              byte &= ~0x5;
-+      if (node == 1)
-+              byte &= ~0xa;
-+      byte |= value;
-+      pci_write_config8(PCI_DEV(0, 0x14, 3), 0xd1, byte);
-+
-+      /* Enable GPIO output drivers */
-+      byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0xd0);
-+      byte &= 0x0f;
-+      pci_write_config8(PCI_DEV(0, 0x14, 3), 0xd0, byte);
-+}
-+
-+static void set_peripheral_control_lines(void) {
-+      uint8_t byte;
-+
-+      /* Enable PCICLK5 (onboard FireWire device) */
-+      outb(0x41, 0xcd6);
-+      outb(0x02, 0xcd7);
-+
-+      /* Enable the RTC AltCentury register */
-+      outb(0x41, 0xcd6);
-+      byte = inb(0xcd7);
-+      byte |= 0x10;
-+      outb(byte, 0xcd7);
-+}
-+
-+#ifdef TEST_MEMORY
-+static void execute_memory_test(void)
-+{
-+      /* Test DRAM functionality */
-+      uint32_t i;
-+      uint32_t* dataptr;
-+      printk(BIOS_DEBUG, "Writing test patterns to memory...\n");
-+      for (i=0; i < 0x1000000; i = i + 8) {
-+              dataptr = (void *)(0x300000 + i);
-+              *dataptr = 0x55555555;
-+              dataptr = (void *)(0x300000 + i + 4);
-+              *dataptr = 0xaaaaaaaa;
-+      }
-+      printk(BIOS_DEBUG, "Done!\n");
-+      printk(BIOS_DEBUG, "Testing memory...\n");
-+      uint32_t readback;
-+      for (i=0; i < 0x1000000; i = i + 8) {
-+              dataptr = (void *)(0x300000 + i);
-+              readback = *dataptr;
-+              if (readback != 0x55555555)
-+                      printk(BIOS_DEBUG, "%p: INCORRECT VALUE %08x (should 
have been %08x)\n", dataptr, readback, 0x55555555);
-+              dataptr = (void *)(0x300000 + i + 4);
-+              readback = *dataptr;
-+              if (readback != 0xaaaaaaaa)
-+                      printk(BIOS_DEBUG, "%p: INCORRECT VALUE %08x (should 
have been %08x)\n", dataptr, readback, 0xaaaaaaaa);
-+      }
-+      printk(BIOS_DEBUG, "Done!\n");
-+}
-+#endif
-+
-+void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
-+{
-+      struct sys_info *sysinfo = &sysinfo_car;
-+
-+      u32 bsp_apicid = 0, val;
-+      msr_t msr;
-+
-+      timestamp_init(timestamp_get());
-+      timestamp_add_now(TS_START_ROMSTAGE);
-+
-+      if (!cpu_init_detectedx && boot_cpu()) {
-+              /* Nothing special needs to be done to find bus 0 */
-+              /* Allow the HT devices to be found */
-+              set_bsp_node_CHtExtNodeCfgEn();
-+              enumerate_ht_chain();
-+
-+              /* SR56x0 pcie bridges block pci_locate_device() before pcie 
training.
-+               * disable all pcie bridges on SR56x0 to work around it
-+               */
-+              sr5650_disable_pcie_bridge();
-+
-+              /* Initialize southbridge */
-+              sb7xx_51xx_pci_port80();
-+
-+              /* Initialize early serial */
-+              nuvoton_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
-+              console_init();
-+      }
-+
-+      post_code(0x30);
-+
-+      if (bist == 0)
-+              bsp_apicid = init_cpus(cpu_init_detectedx, sysinfo);
-+
-+      post_code(0x32);
-+
-+      enable_sr5650_dev8();
-+      sb7xx_51xx_lpc_init();
-+
-+      if (CONFIG_MAX_PHYSICAL_CPUS != 4)
-+              printk(BIOS_WARNING, "CONFIG_MAX_PHYSICAL_CPUS is %d, but this 
is a dual socket AMD G34 board!\n", CONFIG_MAX_PHYSICAL_CPUS);
-+
-+      /* Halt if there was a built in self test failure */
-+      report_bist_failure(bist);
-+
-+      val = cpuid_eax(1);
-+      printk(BIOS_DEBUG, "BSP Family_Model: %08x\n", val);
-+      printk(BIOS_DEBUG, "*sysinfo range: [%p,%p]\n",sysinfo,sysinfo+1);
-+      printk(BIOS_DEBUG, "bsp_apicid = %02x\n", bsp_apicid);
-+      printk(BIOS_DEBUG, "cpu_init_detectedx = %08lx\n", cpu_init_detectedx);
-+
-+      /* Setup sysinfo defaults */
-+      set_sysinfo_in_ram(0);
-+
-+      update_microcode(val);
-+
-+      post_code(0x33);
-+
-+      cpuSetAMDMSR();
-+      post_code(0x34);
-+
-+      amd_ht_init(sysinfo);
-+      amd_ht_fixup(sysinfo);
-+      post_code(0x35);
-+
-+      /* Set DDR memory voltage
-+       * FIXME
-+       * This should be set based on the output of the DIMM SPDs
-+       * For now it is locked to 1.5V
-+       */
-+      set_ddr3_voltage(0, 0); /* Node 0 */
-+      set_ddr3_voltage(1, 0); /* Node 1 */
-+
-+      /* Setup nodes PCI space and start core 0 AP init. */
-+      finalize_node_setup(sysinfo);
-+
-+      /* Setup any mainboard PCI settings etc. */
-+      setup_mb_resource_map();
-+      post_code(0x36);
-+
-+      /* wait for all the APs core0 started by finalize_node_setup. */
-+      /* FIXME: A bunch of cores are going to start output to serial at once.
-+       * It would be nice to fix up prink spinlocks for ROM XIP mode.
-+       * I think it could be done by putting the spinlock flag in the cache
-+       * of the BSP located right after sysinfo.
-+       */
-+      wait_all_core0_started();
-+
-+      /* run _early_setup before soft-reset. */
-+      sr5650_early_setup();
-+      sb7xx_51xx_early_setup();
-+
-+      if (IS_ENABLED(CONFIG_SET_FIDVID)) {
-+              msr = rdmsr(0xc0010071);
-+              printk(BIOS_DEBUG, "\nBegin FIDVID MSR 0xc0010071 0x%08x 
0x%08x\n", msr.hi, msr.lo);
-+
-+              /* FIXME: The sb fid change may survive the warm reset and only 
need to be done once */
-+              enable_fid_change_on_sb(sysinfo->sbbusn, sysinfo->sbdn);
-+
-+              post_code(0x39);
-+
-+              if (!warm_reset_detect(0)) {                    // BSP is node 0
-+                      init_fidvid_bsp(bsp_apicid, sysinfo->nodes);
-+              } else {
-+                      init_fidvid_stage2(bsp_apicid, 0);      // BSP is node 0
-+              }
-+
-+              post_code(0x3A);
-+
-+              /* show final fid and vid */
-+              msr=rdmsr(0xc0010071);
-+              printk(BIOS_DEBUG, "End FIDVIDMSR 0xc0010071 0x%08x 0x%08x\n", 
msr.hi, msr.lo);
-+      }
-+
-+      if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
-+              /* Core0 on each node is configured. Now setup any additional 
cores. */
-+              printk(BIOS_DEBUG, "start_other_cores()\n");
-+              start_other_cores();
-+              post_code(0x37);
-+              wait_all_other_cores_started(bsp_apicid);
-+      }
-+
-+      post_code(0x38);
-+
-+      init_timer(); // Need to use TMICT to synconize FID/VID
-+
-+      sr5650_htinit();
-+
-+      /* Reset for HT, FIDVID, PLL and errata changes to take affect. */
-+      if (!warm_reset_detect(0)) {
-+              printk(BIOS_INFO, "...WARM RESET...\n\n\n");
-+              soft_reset();
-+              die("After soft_reset_x - shouldn't see this message!!!\n");
-+      }
-+
-+      /* Set up peripheral control lines */
-+      set_peripheral_control_lines();
-+
-+      post_code(0x3B);
-+
-+      /* It's the time to set ctrl in sysinfo now; */
-+      printk(BIOS_DEBUG, "fill_mem_ctrl() detected %d nodes\n", 
sysinfo->nodes);
-+      fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr);
-+      post_code(0x3D);
-+
-+#if 0
-+      /* FIXME
-+       * After the AMD K10 code has been converted to use
-+       * IS_ENABLED(CONFIG_DEBUG_SMBUS) uncomment this block
-+       */
-+      if (IS_ENABLED(CONFIG_DEBUG_SMBUS)) {
-+              dump_spd_registers(&cpu[0]);
-+              dump_smbus_registers();
-+      }
-+#endif
-+
-+      post_code(0x40);
-+
-+      timestamp_add_now(TS_BEFORE_INITRAM);
-+      printk(BIOS_DEBUG, "raminit_amdmct()\n");
-+      raminit_amdmct(sysinfo);
-+      timestamp_add_now(TS_AFTER_INITRAM);
-+
-+#if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
-+      cbmem_initialize_empty();
-+      post_code(0x41);
-+
-+      amdmct_cbmem_store_info(sysinfo);
-+#endif
-+
-+      printk(BIOS_DEBUG, "disable_spd()\n");
-+      switch_spd_mux(0x1);
-+
-+      sr5650_before_pci_init();
-+      sb7xx_51xx_before_pci_init();
-+
-+      /* Configure SP5100 GPIOs to match vendor settings */
-+      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x50, 0x0170);
-+      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x54, 0x0707);
-+      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x56, 0x0bb0);
-+      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x5a, 0x0ff0);
-+
-+      timestamp_add_now(TS_END_ROMSTAGE);
-+
-+#ifdef TEST_MEMORY
-+      execute_memory_test();
-+#endif
-+
-+      post_cache_as_ram();    // BSP switch stack to ram, copy then execute 
LB.
-+      post_code(0x43);        // Should never see this post code.
-+}
-+
-+/**
-+ * BOOL AMD_CB_ManualBUIDSwapList(u8 Node, u8 Link, u8 **List)
-+ * Description:
-+ *    This routine is called every time a non-coherent chain is processed.
-+ *    BUID assignment may be controlled explicitly on a non-coherent chain. 
Provide a
-+ *    swap list. The first part of the list controls the BUID assignment and 
the
-+ *    second part of the list provides the device to device linking.  Device 
orientation
-+ *    can be detected automatically, or explicitly.  See documentation for 
more details.
-+ *
-+ *    Automatic non-coherent init assigns BUIDs starting at 1 and 
incrementing sequentially
-+ *    based on each device's unit count.
-+ *
-+ * Parameters:
-+ *    @param[in]  node   = The node on which this chain is located
-+ *    @param[in]  link   = The link on the host for this chain
-+ *    @param[out] List   = supply a pointer to a list
-+ */
-+BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 **List)
-+{
-+      return 0;
-+}
-\ No newline at end of file
-diff --git a/src/mainboard/asus/kgpe-d16/spd_notes.txt 
b/src/mainboard/asus/kgpe-d16/spd_notes.txt
-new file mode 100644
-index 0000000..623a88f
---- /dev/null
-+++ b/src/mainboard/asus/kgpe-d16/spd_notes.txt
-@@ -0,0 +1,30 @@
-+====================================================================================================
-+SPD mux
-+====================================================================================================
-+                      SP5100
-+                  GPIO 60 GPIO 59
-+Disabled             0       0
-+Normal operation     0       1
-+CPU 0 SPD            1       0
-+CPU 1 SPD            1       1
-+
-+====================================================================================================
-+W83795
-+====================================================================================================
-+
-+Sensor mappings:
-+CPU_FAN1:  FAN1
-+CPU_FAN2:  FAN2
-+FRNT_FAN1: FAN3
-+FRNT_FAN2: FAN4
-+FRNT_FAN3: FAN5
-+FRNT_FAN4: FAN6
-+FRNT_FAN5: FAN7
-+REAR_FAN1: FAN8
-+
-+====================================================================================================
-+Other hardware
-+====================================================================================================
-+
-+RECOVERY1 middle pin is connected to southbridge (AMD SP5100) GPIO 61
-+Normal is HIGH, recovery is LOW.
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
 
b/resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
new file mode 100644
index 0000000..cd43042
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch
@@ -0,0 +1,3222 @@
+From 5392e9699f98451cb74a104f023ae31a6e049f7e Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 30 Apr 2015 01:47:31 -0500
+Subject: [PATCH 014/143] mainboard/asus/kgpe-d16: Add initial support for the
+ KGPE-D16
+
+As of this commit S3 suspend does not work on any K10 boards,
+including this board.
+
+Change-Id: Idd3971422fb2473bff7c60fe8d8161d6e20808ed
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/Kconfig          |   95 ++++
+ src/mainboard/asus/kgpe-d16/Kconfig.name     |    2 +
+ src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl |  367 +++++++++++++
+ src/mainboard/asus/kgpe-d16/acpi_tables.c    |   75 +++
+ src/mainboard/asus/kgpe-d16/board_info.txt   |    5 +
+ src/mainboard/asus/kgpe-d16/bootblock.c      |   52 ++
+ src/mainboard/asus/kgpe-d16/cmos.default     |   16 +
+ src/mainboard/asus/kgpe-d16/cmos.layout      |  134 +++++
+ src/mainboard/asus/kgpe-d16/devicetree.cb    |  249 +++++++++
+ src/mainboard/asus/kgpe-d16/dsdt.asl         |  730 ++++++++++++++++++++++++++
+ src/mainboard/asus/kgpe-d16/get_bus_conf.c   |  128 +++++
+ src/mainboard/asus/kgpe-d16/irq_tables.c     |  112 ++++
+ src/mainboard/asus/kgpe-d16/mainboard.c      |   81 +++
+ src/mainboard/asus/kgpe-d16/mb_sysconf.h     |   44 ++
+ src/mainboard/asus/kgpe-d16/mptable.c        |  231 ++++++++
+ src/mainboard/asus/kgpe-d16/resourcemap.c    |  284 ++++++++++
+ src/mainboard/asus/kgpe-d16/romstage.c       |  422 +++++++++++++++
+ src/mainboard/asus/kgpe-d16/spd_notes.txt    |   30 ++
+ 18 files changed, 3057 insertions(+)
+ create mode 100644 src/mainboard/asus/kgpe-d16/Kconfig
+ create mode 100644 src/mainboard/asus/kgpe-d16/Kconfig.name
+ create mode 100644 src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
+ create mode 100644 src/mainboard/asus/kgpe-d16/acpi_tables.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/board_info.txt
+ create mode 100644 src/mainboard/asus/kgpe-d16/bootblock.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/cmos.default
+ create mode 100644 src/mainboard/asus/kgpe-d16/cmos.layout
+ create mode 100644 src/mainboard/asus/kgpe-d16/devicetree.cb
+ create mode 100644 src/mainboard/asus/kgpe-d16/dsdt.asl
+ create mode 100644 src/mainboard/asus/kgpe-d16/get_bus_conf.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/irq_tables.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/mainboard.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/mb_sysconf.h
+ create mode 100644 src/mainboard/asus/kgpe-d16/mptable.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/resourcemap.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/romstage.c
+ create mode 100644 src/mainboard/asus/kgpe-d16/spd_notes.txt
+
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+new file mode 100644
+index 0000000..95b3b5b
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -0,0 +1,95 @@
++if BOARD_ASUS_KGPE_D16
++
++config BOARD_SPECIFIC_OPTIONS # dummy
++      def_bool y
++      select CPU_AMD_SOCKET_G34_NON_AGESA
++      select DIMM_DDR3
++      select DIMM_REGISTERED
++      # select QRANK_DIMM_SUPPORT
++      select NORTHBRIDGE_AMD_AMDFAM10
++      select SOUTHBRIDGE_AMD_SR5650
++      select SOUTHBRIDGE_AMD_SB700
++      select SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
++      select SUPERIO_NUVOTON_NCT5572D
++      select PARALLEL_CPU_INIT
++      select HAVE_HARD_RESET
++      select HAVE_OPTION_TABLE
++      select HAVE_CMOS_DEFAULT
++      select HAVE_PIRQ_TABLE
++      select HAVE_MP_TABLE
++      select HAVE_ACPI_TABLES
++      select SB_HT_CHAIN_UNITID_OFFSET_ONLY
++      select LIFT_BSP_APIC_ID
++      select BOARD_ROMSIZE_KB_2048
++      select ENABLE_APIC_EXT_ID
++      select MMCONF_SUPPORT_DEFAULT
++      select DRIVERS_I2C_W83795
++      select DRIVERS_ASPEED_AST2050
++      select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG
++
++config MAINBOARD_DIR
++      string
++      default asus/kgpe-d16
++
++config BOOTBLOCK_MAINBOARD_INIT
++      string
++      default "mainboard/asus/kgpe-d16/bootblock.c"
++
++config DCACHE_RAM_BASE
++      hex
++      default 0xc2000
++
++config DCACHE_RAM_SIZE
++      hex
++      default 0x1e000
++
++config APIC_ID_OFFSET
++      hex
++      default 0
++
++config MAINBOARD_PART_NUMBER
++      string
++      default "KGPE-D16"
++
++config HW_MEM_HOLE_SIZEK
++      hex
++      default 0x100000
++
++config PCI_64BIT_PREF_MEM
++      bool
++      default n
++
++config MAX_CPUS
++      int
++      default 32
++
++# 2 (internal) processors per G34 socket
++config MAX_PHYSICAL_CPUS
++      int
++      default 4
++
++config SB_HT_CHAIN_ON_BUS0
++      int
++      default 1
++
++config HT_CHAIN_UNITID_BASE
++      hex
++      default 0x0
++
++config HT_CHAIN_END_UNITID_BASE
++      hex
++      default 0x20
++
++config IRQ_SLOT_COUNT
++      int
++      default 13
++
++config ONBOARD_VGA_IS_PRIMARY
++      bool
++      default y
++
++config MAINBOARD_POWER_ON_AFTER_POWER_FAIL
++      bool
++      default y
++
++endif # BOARD_ASUS_KGPE_D16
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig.name 
b/src/mainboard/asus/kgpe-d16/Kconfig.name
+new file mode 100644
+index 0000000..bdfa31a
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/Kconfig.name
+@@ -0,0 +1,2 @@
++config BOARD_ASUS_KGPE_D16
++      bool "KGPE-D16"
+diff --git a/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl 
b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
+new file mode 100644
+index 0000000..b3c65ca
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
+@@ -0,0 +1,367 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2009 Advanced Micro Devices, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * WARNING: Sleep/Wake is a work in progress and is still somewhat flaky!
++ */
++
++      /* Port 80 POST card debug */
++      OperationRegion (DBG0, SystemIO, 0x80, One)
++              Field (DBG0, ByteAcc, NoLock, Preserve) {
++              DBG8, 8
++      }
++
++      /* SuperIO control port */
++      Name (SPIO, 0x2E)
++
++      /* SuperIO control map */
++      OperationRegion (SPIM, SystemIO, SPIO, 0x02)
++              Field (SPIM, ByteAcc, NoLock, Preserve) {
++              INDX, 8,
++              DATA, 8
++      }
++
++      /* SuperIO control registers */
++      IndexField (INDX, DATA, ByteAcc, NoLock, Preserve) {
++              Offset (0x07),
++              CR07, 8,                /* Logical device number */
++              Offset (0x2C),
++              CR2C, 8,                /* GPIO3 multiplexed pin selection */
++              Offset (0x30),
++              CR30, 8,                /* Logical device activation control 
register */
++              Offset (0xE0),
++              CRE0, 8,                /* Wake control register */
++              Offset (0xE6),
++              CRE6, 8,                /* Mouse wake event configuration 
register */
++              Offset (0xF1),
++              CRF1, 8,                /* GPIO3 data register */
++              Offset (0xF3),
++              CRF3, 8,                /* SUSLED mode register */
++              Offset (0xF6),
++              CRF6, 8,                /* SMI/PME event generation control 
register */
++              Offset (0xF9),
++              CRF9, 8,                /* ACPI PME configuration register */
++      }
++
++      /* Power Management I/O registers */
++      OperationRegion(PIOR, SystemIO, 0x00000CD6, 0x00000002)
++              Field(PIOR, ByteAcc, NoLock, Preserve) {
++              PIOI, 0x00000008,
++              PIOD, 0x00000008,
++      }
++      IndexField (PIOI, PIOD, ByteAcc, NoLock, Preserve) {
++              Offset(0x00),   /* MiscControl */
++              , 1,
++              T1EE, 1,
++              T2EE, 1,
++              Offset(0x01),   /* MiscStatus */
++              , 1,
++              T1E, 1,
++              T2E, 1,
++              Offset(0x04),   /* SmiWakeUpEventEnable3 */
++              , 7,
++              SSEN, 1,
++              Offset(0x07),   /* SmiWakeUpEventStatus3 */
++              , 7,
++              CSSM, 1,
++              Offset(0x10),   /* AcpiEnable */
++              , 6,
++              PWDE, 1,
++              Offset(0x1C),   /* ProgramIoEnable */
++              , 3,
++              MKME, 1,
++              IO3E, 1,
++              IO2E, 1,
++              IO1E, 1,
++              IO0E, 1,
++              Offset(0x1D),   /* IOMonitorStatus */
++              , 3,
++              MKMS, 1,
++              IO3S, 1,
++              IO2S, 1,
++              IO1S, 1,
++              IO0S,1,
++              Offset(0x20),   /* AcpiPmEvtBlk */
++              APEB, 16,
++              Offset(0x36),   /* GEvtLevelConfig */
++              , 6,
++              ELC6, 1,
++              ELC7, 1,
++              Offset(0x37),   /* GPMLevelConfig0 */
++              , 3,
++              PLC0, 1,
++              PLC1, 1,
++              PLC2, 1,
++              PLC3, 1,
++              PLC8, 1,
++              Offset(0x38),   /* GPMLevelConfig1 */
++              , 1,
++               PLC4, 1,
++               PLC5, 1,
++              , 1,
++               PLC6, 1,
++               PLC7, 1,
++              Offset(0x3B),   /* PMEStatus1 */
++              GP0S, 1,
++              GM4S, 1,
++              GM5S, 1,
++              APS, 1,
++              GM6S, 1,
++              GM7S, 1,
++              GP2S, 1,
++              STSS, 1,
++              Offset(0x55),   /* SoftPciRst */
++              SPRE, 1,
++              , 1,
++              , 1,
++              PNAT, 1,
++              PWMK, 1,
++              PWNS, 1,
++
++              /*      Offset(0x61), */        /*  Options_1 */
++              /*              ,7,  */
++              /*              R617,1, */
++
++              Offset(0x65),   /* UsbPMControl */
++              , 4,
++              URRE, 1,
++              Offset(0x68),   /* MiscEnable68 */
++              , 3,
++              TMTE, 1,
++              , 1,
++              Offset(0x7C),   /* MiscEnable7C */
++              , 2,
++              BLNK, 2,
++              Offset(0x92),   /* GEVENTIN */
++              , 7,
++              E7IS, 1,
++              Offset(0x96),   /* GPM98IN */
++              G8IS, 1,
++              G9IS, 1,
++              Offset(0x9A),   /* EnhanceControl */
++              ,7,
++              HPDE, 1,
++              Offset(0xA8),   /* PIO7654Enable */
++              IO4E, 1,
++              IO5E, 1,
++              IO6E, 1,
++              IO7E, 1,
++              Offset(0xA9),   /* PIO7654Status */
++              IO4S, 1,
++              IO5S, 1,
++              IO6S, 1,
++              IO7S, 1,
++      }
++
++      /* PM1 Event Block
++       * First word is PM1_Status, Second word is PM1_Enable
++       */
++      OperationRegion(P1EB, SystemIO, APEB, 0x04)
++              Field(P1EB, ByteAcc, NoLock, Preserve) {
++              TMST, 1,
++              ,    3,
++              BMST,    1,
++              GBST,   1,
++              Offset(0x01),
++              PBST, 1,
++              , 1,
++              RTST, 1,
++              , 3,
++              PWST, 1,
++              SPWS, 1,
++              Offset(0x02),
++              TMEN, 1,
++              , 4,
++              GBEN, 1,
++              Offset(0x03),
++              PBEN, 1,
++              , 1,
++              RTEN, 1,
++              , 3,
++              PWDA, 1,
++      }
++
++      /* Wake status package */
++      Name(WKST,Package(){Zero, Zero})
++
++      /*
++       *  \_WAK System Wake method
++       *
++       *      Entry:
++       *              Arg0=The value of the sleeping state S1=1, S2=2
++       *
++       *      Exit:
++       *              Return package of 2 DWords
++       *              Dword 1 - Status
++       *                      0x00000000      wake succeeded
++       *                      0x00000001      Wake was signaled but failed 
due to lack of power
++       *                      0x00000002      Wake was signaled but failed 
due to thermal condition
++       *              Dword 2 - Power Supply state
++       *                      if non-zero the effective S-state the power 
supply entered
++       */
++      Method(\_WAK, 1) {
++              Store (0x20, DBG8)
++
++              /* Set up LEDs */
++              /* Set power LED to steady on */
++              Store(0x3, BLNK)
++
++              /* Configure SuperIO for wake */
++              /* Access SuperIO ACPI device */
++              Store(0x87, INDX)
++              Store(0x87, INDX)
++              Store(0x0A, CR07)
++
++              if (LEqual(Arg0, One))  /* Resuming from power state S1 */
++              {
++                      /* Deactivate the ACPI device */
++                      Store(Zero, CR30)
++
++                      /* Disable PS/2 SMI/PME events */
++                      And(CRF6, 0xCF, CRF6)
++              }
++              if (Lor(LEqual(Arg0, 0x03), LEqual(Arg0, 0x04)))        /* 
Resuming from power state S3 or S4 */
++              {
++                      /* Disable PS/2 wake */
++                      And(CRE0, 0x1D, CRE0)
++                      And(CRE6, 0x7F, CRE6)
++              }
++
++              /* Restore default SuperIO access */
++              Store(0xAA, INDX)
++
++              Store (0x21, DBG8)
++
++              /* Re-enable HPET */
++              Store(1, HPDE)
++
++              /* Restore PCIRST# so it resets USB */
++              if (LEqual(Arg0, 3)){
++                      Store(1, URRE)
++              }
++
++              /* Configure southbridge for wake */
++              /* Arbitrarily clear PciExpWakeStatus */
++              Store(PWST, PWST)
++
++              Store (0x22, DBG8)
++
++              Notify(\_SB.PWRB, 0x02)                 /* NOTIFY_DEVICE_WAKE */
++
++              Return(WKST)
++      }
++
++      /*
++       * \_PTS - Prepare to Sleep method
++       *
++       *      Entry:
++       *              Arg0=The value of the sleeping state S1=1, S2=2, etc
++       *
++       * Exit:
++       *              -none-
++       *
++       * The _PTS control method is executed at the beginning of the sleep 
process
++       * for S1-S5. The sleeping value is passed to the _PTS control method.  
This
++       * control method may be executed a relatively long time before 
entering the
++       * sleep state and the OS may abort the operation without notification 
to
++       * the ACPI driver.  This method cannot modify the configuration or 
power
++       * state of any device in the system.
++       */
++      Method(\_PTS, 1) {
++              Store (Arg0, DBG8)
++
++              /* Set up LEDs */
++              if (LEqual(Arg0, One))  /* Power state S1 requested */
++              {
++                      /* Set suspend LED to 0.25Hz toggle pulse with 50% duty 
cycle */
++                      Store(0x2, BLNK)
++              }
++              if (LEqual(Arg0, 0x3))  /* Power state S3 requested */
++              {
++                      /* Set suspend LED to 0.25Hz toggle pulse with 25% duty 
cycle */
++                      Store(0x1, BLNK)
++              }
++
++              /* Configure SuperIO for sleep */
++              /* Access SuperIO ACPI device */
++              Store(0x87, INDX)
++              Store(0x87, INDX)
++              Store(0x0A, CR07)
++
++              /* Disable PS/2 wakeup and connect PANSW_IN to PANSW_OUT */
++              And(CRE0, 0x1F, CRE0)
++
++              if (LEqual(Arg0, One))  /* Power state S1 requested */
++              {
++                      /* Activate the ACPI device */
++                      Store(One, CR30)
++
++                      /* Disable SMI/PME events for:
++                       * LPT
++                       * FDC
++                       * UART
++                      Store(0x00, CRF6)
++
++                      /* Enable PS/2 keyboard SMI/PME events */
++                      Or(CRF6, 0x10, CRF6)
++
++                      /* Enable PS/2 keyboard wake */
++                      Or(CRE0, 0x40, CRE0)
++
++                      /* Enable PS/2 mouse SMI/PME events */
++                      Or(CRF6, 0x20, CRF6)
++
++                      /* Enable PS/2 mouse wake  */
++                      Or(CRE0, 0x20, CRE0)
++              } else {
++                      /* Enable PS/2 keyboard wake on any keypress */
++                      Or(CRE0, 0x41, CRE0)
++
++                      /* Enable PS/2 mouse wake on any click  */
++                      Or(CRE0, 0x22, CRE0)
++                      Or(CRE6, 0x80, CRE6)
++              }
++
++              /* Restore default SuperIO access */
++              Store(0xAA, INDX)
++
++              Store (0x10, DBG8)
++
++              /* Don't allow PCIRST# to reset USB */
++              if (LEqual(Arg0, 3)){
++                      Store(0, URRE)
++              }
++
++              /* Configure southbridge for sleep */
++              /* Clear sleep SMI status flag and enable sleep SMI trap. */
++              // Store(One, CSSM)     /* Set ExtEvent0 as SMI# source */
++              // Store(One, SSEN)     /* Enable wake on external event 0 */
++
++              /* On older chips, clear PciExpWakeDisEn */
++              // if (LLessEqual(SBRI, 0x13)) {
++              //      Store(0, PWDE)
++              // }
++
++              Store (0x11, DBG8)
++
++              /* Clear wake status structure. */
++              Store(0, Index(WKST,0))
++              Store(0, Index(WKST,1))
++      }
+\ No newline at end of file
+diff --git a/src/mainboard/asus/kgpe-d16/acpi_tables.c 
b/src/mainboard/asus/kgpe-d16/acpi_tables.c
+new file mode 100644
+index 0000000..4e98dfe
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/acpi_tables.c
+@@ -0,0 +1,75 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <console/console.h>
++#include <string.h>
++#include <arch/acpi.h>
++#include <arch/ioapic.h>
++#include <device/pci.h>
++#include <device/pci_ids.h>
++#include <cpu/x86/msr.h>
++#include <cpu/amd/mtrr.h>
++#include <cpu/amd/amdfam10_sysconf.h>
++
++#include "mb_sysconf.h"
++
++unsigned long acpi_fill_madt(unsigned long current)
++{
++      device_t dev;
++      u32 dword;
++      u32 gsi_base=0;
++      uint32_t apicid_sp5100;
++      uint32_t apicid_sr5650;
++      /* create all subtables for processors */
++      current = acpi_create_madt_lapics(current);
++
++      apicid_sp5100 = 0x20;
++      apicid_sr5650 = apicid_sp5100 + 1;
++
++      /* Write SB700 IOAPIC, only one */
++      current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) current, 
apicid_sp5100,
++                                         IO_APIC_ADDR, gsi_base);
++      /* IOAPIC on rs5690 */
++      gsi_base += 24;         /* SB700 has 24 IOAPIC entries. */
++      dev = dev_find_slot(0, PCI_DEVFN(0, 0));
++      if (dev) {
++              pci_write_config32(dev, 0xF8, 0x1);
++              dword = pci_read_config32(dev, 0xFC) & 0xfffffff0;
++              current += acpi_create_madt_ioapic((acpi_madt_ioapic_t *) 
current, apicid_sr5650,
++                                                 dword, gsi_base);
++      }
++
++      /* bus, source, gsirq, flags */
++      current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
++                                              current, 0, 0, 2, 0);
++      current += acpi_create_madt_irqoverride((acpi_madt_irqoverride_t *)
++                                              current, 0, 9, 9, 0xF);
++      /* 0: mean bus 0--->ISA */
++      /* 0: PIC 0 */
++      /* 2: APIC 2 */
++      /* 5 mean: 0101 --> Edge-triggered, Active high */
++
++      /* create all subtables for processors */
++      current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 
0, 5, 1);
++      current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 
1, 5, 1);
++      /* 1: LINT1 connect to NMI */
++
++      return current;
++}
+diff --git a/src/mainboard/asus/kgpe-d16/board_info.txt 
b/src/mainboard/asus/kgpe-d16/board_info.txt
+new file mode 100644
+index 0000000..788888e
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/board_info.txt
+@@ -0,0 +1,5 @@
++Category: server
++ROM package: PLCC-32
++ROM protocol: LPC
++ROM socketed: y
++Flashrom support: y
+\ No newline at end of file
+diff --git a/src/mainboard/asus/kgpe-d16/bootblock.c 
b/src/mainboard/asus/kgpe-d16/bootblock.c
+new file mode 100644
+index 0000000..2e9d70f
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/bootblock.c
+@@ -0,0 +1,52 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2014 Edward O'Callaghan <address@hidden>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <pc80/mc146818rtc.h>
++
++void bootblock_mainboard_init(void)
++{
++      uint8_t recovery_enabled;
++      unsigned char addr;
++      unsigned char byte;
++
++      bootblock_northbridge_init();
++      bootblock_southbridge_init();
++
++      /* Recovery jumper is connected to SP5100 GPIO61, and clears the GPIO 
when placed in the Recovery position */
++      recovery_enabled = (!(pci_read_config8(PCI_DEV(0, 0x14, 0), 0x57) & 
0x1));
++      if (recovery_enabled) {
++#if CONFIG_USE_OPTION_TABLE
++              /* Clear NVRAM checksum */
++              for (addr = LB_CKS_RANGE_START; addr <= LB_CKS_RANGE_END; 
addr++) {
++                      cmos_write(0x0, addr);
++              }
++
++              /* Set fallback boot */
++              byte = cmos_read(RTC_BOOT_BYTE);
++              byte &= 0xfc;
++              cmos_write(byte, RTC_BOOT_BYTE);
++#else
++              /* FIXME
++               * Figure out how to recover if the option table is not 
available
++               */
++#endif
++      }
++}
+\ No newline at end of file
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+new file mode 100644
+index 0000000..cffdd03
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -0,0 +1,16 @@
++baud_rate = 115200
++debug_level = Spew
++multi_core = Enable
++slow_cpu = off
++iommu = Disable
++nmi = Disable
++hypertransport_speed_limit = Auto
++max_mem_clock = DDR3-1600
++ECC_memory = Enable
++ECC_redirection = Disable
++ecc_scrub_rate = 1.28us
++interleave_chip_selects = Enable
++interleave_nodes = Disable
++interleave_memory_channels = Enable
++power_on_after_fail = On
++boot_option = Fallback
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+new file mode 100644
+index 0000000..bcf9cd3
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -0,0 +1,134 @@
++##
++## This file is part of the coreboot project.
++##
++## Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++## Copyright (C) 2007 AMD
++## Written by Yinghai Lu <address@hidden> for AMD.
++##
++## This program is free software; you can redistribute it and/or modify
++## it under the terms of the GNU General Public License as published by
++## the Free Software Foundation; either version 2 of the License, or
++## (at your option) any later version.
++##
++## This program is distributed in the hope that it will be useful,
++## but WITHOUT ANY WARRANTY; without even the implied warranty of
++## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++## GNU General Public License for more details.
++##
++## You should have received a copy of the GNU General Public License
++## along with this program; if not, write to the Free Software
++## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++##
++
++entries
++
++0          384       r       0        reserved_memory
++384          1       e       4        boot_option
++385          1       e       4        last_boot
++388          4       r       0        reboot_bits
++393          3       e       5        baud_rate
++396          5       e       10       ecc_scrub_rate
++401          1       e       1        interleave_chip_selects
++402          1       e       1        interleave_nodes
++403          1       e       1        interleave_memory_channels
++404          2       e       8        max_mem_clock
++406          1       e       2        multi_core
++412          4       e       6        debug_level
++440          4       e       9        slow_cpu
++444          1       e       1        nmi
++445          1       e       1        iommu
++446          2       e       3        power_on_after_fail
++456          1       e       1        ECC_memory
++457          1       e       1        ECC_redirection
++458          4       e       11       hypertransport_speed_limit
++728        256       h       0        user_data
++984         16       h       0        check_sum
++# Reserve the extended AMD configuration registers
++1000        24       r       0        amd_reserved
++
++
++
++enumerations
++
++#ID value   text
++1     0     Disable
++1     1     Enable
++2     0     Enable
++2     1     Disable
++3     0     Off
++3     1     On
++3     2     Last
++4     0     Fallback
++4     1     Normal
++5     0     115200
++5     1     57600
++5     2     38400
++5     3     19200
++5     4     9600
++5     5     4800
++5     6     2400
++5     7     1200
++6     0     Emergency
++6     1     Alert
++6     2     Critical
++6     3     Error
++6     4     Warning
++6     5     Notice
++6     6     Information
++6     7     Debug
++6     8     Spew
++8     0     DDR3-1600
++8     1     DDR3-1333
++8     2     DDR3-1066
++8     3     DDR3-800
++9     0     off
++9     1     87.5%
++9     2     75.0%
++9     3     62.5%
++9     4     50.0%
++9     5     37.5%
++9     6     25.0%
++9     7     12.5%
++10    0     Disabled
++10    1     40ns
++10    2     80ns
++10    3     160ns
++10    4     320ns
++10    5     640ns
++10    6     1.28us
++10    7     2.56us
++10    8     5.12us
++10    9     10.2us
++10    10    20.5us
++10    11    41us
++10    12    81.9us
++10    13    163.8us
++10    14    327.7us
++10    15    655.4us
++10    16    1.31ms
++10    17    2.62ms
++10    18    5.24ms
++10    19    10.49ms
++10    20    20.97ms
++10    21    42ms
++10    22    84ms
++11    0     Auto
++11    1     2.6GHz
++11    2     2.4GHz
++11    3     2.2GHz
++11    4     2.0GHz
++11    5     1.8GHz
++11    6     1.6GHz
++11    7     1.4GHz
++11    8     1.2GHz
++11    9     1.0GHz
++11    10    800MHz
++11    11    600MHz
++11    12    500MHz
++11    13    400MHz
++11    14    300MHz
++11    15    200MHz
++
++checksums
++
++checksum 392 983 984
+diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
+new file mode 100644
+index 0000000..f4769fd
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
+@@ -0,0 +1,249 @@
++chip northbridge/amd/amdfam10/root_complex    # Root complex
++      device cpu_cluster 0 on                 # (L)APIC cluster
++              chip cpu/amd/socket_F_1207                      # CPU socket
++                      device lapic 0 on end                   # Local APIC of 
the CPU
++              end
++      end
++      device domain 0 on                      # PCI domain
++              subsystemid 0x1043 0x8163 inherit
++              chip northbridge/amd/amdfam10           # Northbridge / RAM 
controller
++                      register "maximum_memory_capacity" = "0x4000000000"     
# 256GB
++                      device pci 18.0 on end          # Link 0 == LDT 0
++                      device pci 18.0 on end          # Link 1 == LDT 1
++                      device pci 18.0 on end          # Link 2 == LDT 2
++                      device pci 18.0 on              # Link 3 == LDT 3 [SB 
on link 3]
++                              chip southbridge/amd/sr5650             # 
Primary southbridge
++                                      device pci 0.0 on end                   
# HT Root Complex 0x9600
++                                      device pci 0.1 on end                   
# CLKCONFIG
++                                      device pci 2.0 on                       
# PCIE P2P bridge 0x9603 (GPP1 Port0)
++                                              # Slot                          
# PCI E 1 / PCI E 2
++                                      end
++                                      device pci 3.0 off end                  
# PCIE P2P bridge 0x960b (GPP1 Port1)
++                                      device pci 4.0 on                       
# PCIE P2P bridge 0x9604 (GPP3a Port0)
++                                              # PIKE SAS
++                                      end
++                                      device pci 5.0 off end                  
# PCIE P2P bridge 0x9605 (GPP3a Port1)
++                                      device pci 6.0 off end                  
# PCIE P2P bridge 0x9606 (GPP3a Port2)
++                                      device pci 7.0 off end                  
# PCIE P2P bridge 0x9607 (GPP3a Port3)
++                                      device pci 8.0 off end                  
# NB/SB Link P2P bridge
++                                      device pci 9.0 on                       
# Bridge (GPP3a Port4)
++                                              # Onboard                       
# NIC A
++                                      end
++                                      device pci a.0 on                       
# Bridge (GPP3a Port5)
++                                              # Onboard                       
# NIC B
++                                      end
++                                      device pci b.0 on                       
# Bridge (GPP2 Port0)
++                                              # Slot                          
# PCI E 4
++                                      end
++                                      device pci c.0 on                       
# Bridge (GPP2 Port1)
++                                              # Slot                          
# PCI E 5
++                                      end
++                                      device pci d.0 on                       
# Bridge (GPP3b Port0)
++                                              # Slot                          
# PCI E 3
++                                      end
++                                      register "gpp1_configuration" = "0"     
# Configuration 16:0 default
++                                      register "gpp2_configuration" = "1"     
# Configuration 8:8
++                                      #register "gpp3a_configuration" = "2"   
# Configuration 4:1:1:0:0:0
++                                      register "gpp3a_configuration" = "11"   
# Configuration 1:1:1:1:1:1
++                                      register "port_enable" = "0x3ffc"       
# Enable all ports except 0 and 1
++                              end
++                              chip southbridge/amd/sb700              # 
Secondary southbridge
++                                      device pci 11.0 on end                  
# SATA
++                                      device pci 12.0 on end                  
# USB
++                                      device pci 12.1 on end                  
# USB
++                                      device pci 12.2 on end                  
# USB
++                                      device pci 13.0 on end                  
# USB
++                                      device pci 13.1 on end                  
# USB
++                                      device pci 13.2 on end                  
# USB
++                                      device pci 14.0 on                      
# SM
++                                              chip drivers/generic/generic    
# DIMM n-0-0-0
++                                                      device i2c 50 on end
++                                              end
++                                              chip drivers/generic/generic    
# DIMM n-0-0-1
++                                                      device i2c 51 on end
++                                              end
++                                              chip drivers/generic/generic    
# DIMM n-0-1-0
++                                                      device i2c 52 on end
++                                              end
++                                              chip drivers/generic/generic    
# DIMM n-0-1-1
++                                                      device i2c 53 on end
++                                              end
++                                              chip drivers/generic/generic    
# DIMM n-1-0-0
++                                                      device i2c 54 on end
++                                              end
++                                              chip drivers/generic/generic    
# DIMM n-1-0-1
++                                                      device i2c 55 on end
++                                              end
++                                              chip drivers/generic/generic    
# DIMM n-1-1-0
++                                                      device i2c 56 on end
++                                              end
++                                              chip drivers/generic/generic    
# DIMM n-1-1-1
++                                                      device i2c 57 on end
++                                              end
++                                              chip drivers/i2c/w83795
++                                                      register "fanin_ctl1" = 
"0xff"                  # Enable monitoring of FANIN1 - FANIN8
++                                                      register "fanin_ctl2" = 
"0x00"                  # Connect FANIN11 - FANIN14 to alternate functions
++                                                      register "temp_ctl1" = 
"0x2a"                   # Enable monitoring of DTS, VSEN12, and VSEN13
++                                                      register "temp_ctl2" = 
"0x01"                   # Enable monitoring of TD1/TR1
++                                                      register "temp_dtse" = 
"0x03"                   # Enable DTS1 and DTS2
++                                                      register "volt_ctl1" = 
"0xff"                   # Enable monitoring of VSEN1 - VSEN8
++                                                      register "volt_ctl2" = 
"0xf7"                   # Enable monitoring of VSEN9 - VSEN11, 3VDD, 3VSB, and 
VBAT
++                                                      register 
"temp1_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp1)
++                                                      register 
"temp2_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp2)
++                                                      register 
"temp3_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp3)
++                                                      register 
"temp4_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp4)
++                                                      register 
"temp5_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp5)
++                                                      register 
"temp6_fan_select" = "0x00"            # All fans to manual mode (no dependence 
on Temp6)
++                                                      register 
"temp1_source_select" = "0x00"         # Use TD1/TR1 as data source for Temp1
++                                                      register 
"temp2_source_select" = "0x00"         # Use TD2/TR2 as data source for Temp2
++                                                      register 
"temp3_source_select" = "0x00"         # Use TD3/TR3 as data source for Temp3
++                                                      register 
"temp4_source_select" = "0x00"         # Use TD4/TR4 as data source for Temp4
++                                                      register 
"temp5_source_select" = "0x00"         # Use TR5 as data source for Temp5
++                                                      register 
"temp6_source_select" = "0x00"         # Use TR6 as data source for Temp6
++                                                      register 
"tr1_critical_temperature" = "85"      # Set TD1/TR1 critical temperature to 
85°C
++                                                      register 
"tr1_critical_hysteresis" = "80"       # Set TD1/TR1 critical hysteresis 
temperature to 80°C
++                                                      register 
"tr1_warning_temperature" = "70"       # Set TD1/TR1 warning temperature to 70°C
++                                                      register 
"tr1_warning_hysteresis" = "65"        # Set TD1/TR1 warning hysteresis 
temperature to 65°C
++                                                      register 
"dts_critical_temperature" = "85"      # Set DTS (CPU) critical temperature to 
85°C
++                                                      register 
"dts_critical_hysteresis" = "80"       # Set DTS (CPU) critical hysteresis 
temperature to 80°C
++                                                      register 
"dts_warning_temperature" = "70"       # Set DTS (CPU) warning temperature to 
70°C
++                                                      register 
"dts_warning_hysteresis" = "65"        # Set DTS (CPU) warning hysteresis 
temperature to 65°C
++                                                      register 
"temp1_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp2_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp3_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp4_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp5_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp6_critical_temperature" = "80"    # Set Temp1 critical temperature to 80°C
++                                                      register 
"temp1_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp2_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp3_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp4_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp5_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register 
"temp6_target_temperature" = "80"      # Set Temp1 target temperature to 80°C
++                                                      register "fan1_nonstop" 
= "7"                   # Set Fan 1 minimum speed
++                                                      register "fan2_nonstop" 
= "7"                   # Set Fan 2 minimum speed
++                                                      register "fan3_nonstop" 
= "7"                   # Set Fan 3 minimum speed
++                                                      register "fan4_nonstop" 
= "7"                   # Set Fan 4 minimum speed
++                                                      register "fan5_nonstop" 
= "7"                   # Set Fan 5 minimum speed
++                                                      register "fan6_nonstop" 
= "7"                   # Set Fan 6 minimum speed
++                                                      register "fan7_nonstop" 
= "7"                   # Set Fan 7 minimum speed
++                                                      register "fan8_nonstop" 
= "7"                   # Set Fan 8 minimum speed
++                                                      register 
"default_speed" = "100"                # All fans to full speed on power up
++                                                      register "fan1_duty" = 
"100"                    # Fan 1 to full speed
++                                                      register "fan2_duty" = 
"100"                    # Fan 2 to full speed
++                                                      register "fan3_duty" = 
"100"                    # Fan 3 to full speed
++                                                      register "fan4_duty" = 
"100"                    # Fan 4 to full speed
++                                                      register "fan5_duty" = 
"100"                    # Fan 5 to full speed
++                                                      register "fan6_duty" = 
"100"                    # Fan 6 to full speed
++                                                      register "fan7_duty" = 
"100"                    # Fan 7 to full speed
++                                                      register "fan8_duty" = 
"100"                    # Fan 8 to full speed
++                                                      register 
"vcore1_high_limit_mv" = "1500"        # VCORE1 (Node 0) high limit to 1.5V
++                                                      register 
"vcore1_low_limit_mv" = "900"          # VCORE1 (Node 0) low limit to 0.9V
++                                                      register 
"vcore2_high_limit_mv" = "1500"        # VCORE2 (Node 1) high limit to 1.5V
++                                                      register 
"vcore2_low_limit_mv" = "900"          # VCORE2 (Node 1) low limit to 0.9V
++                                                      register 
"vsen3_high_limit_mv" = "1600"         # VSEN1 (Node 0 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen3_low_limit_mv" = "1100"          # VSEN1 (Node 0 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen4_high_limit_mv" = "1600"         # VSEN2 (Node 1 RAM voltage) high limit 
to 1.6V
++                                                      register 
"vsen4_low_limit_mv" = "1100"          # VSEN2 (Node 1 RAM voltage) low limit 
to 1.1V
++                                                      register 
"vsen5_high_limit_mv" = "1250"         # VSEN5 (Node 0 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen5_low_limit_mv" = "1150"          # VSEN5 (Node 0 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen6_high_limit_mv" = "1250"         # VSEN6 (Node 1 HT link voltage) high 
limit to 1.25V
++                                                      register 
"vsen6_low_limit_mv" = "1150"          # VSEN6 (Node 1 HT link voltage) low 
limit to 1.15V
++                                                      register 
"vsen7_high_limit_mv" = "1150"         # VSEN7 (Northbridge core voltage) high 
limit to 1.15V
++                                                      register 
"vsen7_low_limit_mv" = "1050"          # VSEN7 (Northbridge core voltage) low 
limit to 1.05V
++                                                      register 
"vsen8_high_limit_mv" = "1900"         # VSEN8 (+1.8V) high limit to 1.9V
++                                                      register 
"vsen8_low_limit_mv" = "1700"          # VSEN8 (+1.8V) low limit to 1.7V
++                                                      register 
"vsen9_high_limit_mv" = "1250"         # VSEN9 (+1.2V) high limit to 1.25V
++                                                      register 
"vsen9_low_limit_mv" = "1150"          # VSEN9 (+1.2V) low limit to 1.15V
++                                                      register 
"vsen10_high_limit_mv" = "1150"        # VSEN10 (+1.1V) high limit to 1.15V
++                                                      register 
"vsen10_low_limit_mv" = "1050"         # VSEN10 (+1.1V) low limit to 1.05V
++                                                      register 
"vsen11_high_limit_mv" = "1625"        # VSEN11 (5VSB, scaling factor ~3.2) 
high limit to 5.2V
++                                                      register 
"vsen11_low_limit_mv" = "1500"         # VSEN11 (5VSB, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vsen12_high_limit_mv" = "1083"        # VSEN12 (+12V, scaling factor ~12) high 
limit to 13V
++                                                      register 
"vsen12_low_limit_mv" = "917"          # VSEN12 (+12V, scaling factor ~12) low 
limit to 11V
++                                                      register 
"vsen13_high_limit_mv" = "1625"        # VSEN13 (+5V, scaling factor ~3.2) high 
limit to 5.2V
++                                                      register 
"vsen13_low_limit_mv" = "1500"         # VSEN13 (+5V, scaling factor ~3.2) low 
limit to 4.8V
++                                                      register 
"vdd_high_limit_mv" = "3500"           # 3VDD high limit to 3.5V
++                                                      register 
"vdd_low_limit_mv" = "3100"            # 3VDD low limit to 3.1V
++                                                      register 
"vsb_high_limit_mv" = "3500"           # 3VSB high limit to 3.5V
++                                                      register 
"vsb_low_limit_mv" = "3100"            # 3VSB low limit to 3.1V
++                                                      register 
"vbat_high_limit_mv" = "3500"          # VBAT (+3V) high limit to 3.5V
++                                                      register 
"vbat_low_limit_mv" = "2500"           # VBAT (+3V) low limit to 2.5V
++                                                      register "smbus_aux" = 
"1"                      # Device located on auxiliary SMBUS controller
++                                                      device i2c 0x2f on end
++                                              end
++                                      end
++                                      device pci 14.1 on end                  
# IDE 0x439c
++                                      device pci 14.2 off end                 
# HDA 0x4383 (KGPE-D16 omits audio option)
++                                      device pci 14.3 on                      
# LPC 0x439d (SMBUS primary controller)
++                                              chip superio/nuvoton/nct5572d   
# Super I/O
++                                                      device pnp 2e.0 off end 
# FDC; Not available on the KGPE-D16
++                                                      device pnp 2e.1 off end 
# LPT1; Not available on the KGPE-D16
++                                                      device pnp 2e.2 on #  
Com1
++                                                              io 0x60 = 0x3f8
++                                                              irq 0x70 = 4
++                                                      end
++                                                      device pnp 2e.3 off     
# IR: Not available on the KGPE-D16
++                                                              io 0x60 = 0x2f8
++                                                              irq 0x70 = 3
++                                                      end
++                                                      device pnp 2e.5 on      
# PS/2 keyboard & mouse
++                                                              io 0x60 = 0x60
++                                                              io 0x62 = 0x64
++                                                              irq 0x70 = 1
++                                                              irq 0x72 = 12
++                                                      end
++                                                      device pnp 2e.6 off     
# CIR: Not available on the KGPE-D16
++                                                              io 0x60 = 0x100
++                                                              irq 0x70 = 0
++                                                      end
++                                                      device pnp 2e.7 off end 
# GIPO689
++                                                      device pnp 2e.8 off end 
# WDT
++                                                      device pnp 2e.9 off end 
# GPIO235
++                                                      device pnp 2e.a on end  
# ACPI
++                                                      device pnp 2e.b on      
# HW Monitor
++                                                              io 0x60 = 0x290
++                                                              io 0x62 = 
0x0000 #  SB-TSI currently not implemented
++                                                              irq 0x70 = 5
++                                                      end
++                                                      device pnp 2e.c off end 
# PECI
++                                                      device pnp 2e.d off end 
# SUSLED
++                                                      device pnp 2e.e off     
# CIRWKUP
++                                                              io 0x60 = 0x0000
++                                                              irq 0x70 = 0
++                                                      end
++                                                      device pnp 2e.f off end 
# GPIO_PP_OD
++                                              end
++                                      end
++                                      device pci 14.4 on                      
# Bridge
++                                              device pci 1.0 on end           
# VGA
++                                              device pci 2.0 on end           
# FireWire
++                                              device pci 3.0 on               
# Slot
++                                                      # Slot                  
# PCI 0
++                                              end
++                                      end
++                                      device pci 14.5 on end                  
# USB OHCI2 0x4399
++                              end
++                      end
++                      device pci 18.1 on end
++                      device pci 18.2 on end
++                      device pci 18.3 on end
++                      device pci 18.4 on end
++                      device pci 19.0 on end          # Socket 0 node 1
++                      device pci 19.1 on end
++                      device pci 19.2 on end
++                      device pci 19.3 on end
++                      device pci 19.4 on end
++                      device pci 1a.0 on end          # Socket 1 node 0
++                      device pci 1a.1 on end
++                      device pci 1a.2 on end
++                      device pci 1a.3 on end
++                      device pci 1a.4 on end
++                      device pci 1b.0 on end          # Socket 1 node 1
++                      device pci 1b.1 on end
++                      device pci 1b.2 on end
++                      device pci 1b.3 on end
++                      device pci 1b.4 on end
++              end
++      end
++end
+diff --git a/src/mainboard/asus/kgpe-d16/dsdt.asl 
b/src/mainboard/asus/kgpe-d16/dsdt.asl
+new file mode 100644
+index 0000000..bdd1d2d
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/dsdt.asl
+@@ -0,0 +1,730 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2005 - 2012 Advanced Micro Devices, Inc.
++ * Copyright (C) 2007-2009 coresystems GmbH
++ * Copyright (C) 2004 Nick Barker <address@hidden>
++ * Copyright (C) 2007, 2008 Rudolf Marek <address@hidden>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++/*
++ * WARNING: Sleep/Wake is a work in progress and is still somewhat flaky!
++ * Everything else does to the best of my knowledge... (T.P. 01/26/2015)
++ */
++
++/*
++ * ISA portions taken from QEMU acpi-dsdt.dsl.
++ */
++
++/*
++ * PCI link routing templates taken from ck804.asl and modified for this board
++ */
++
++DefinitionBlock (
++        "DSDT.AML",   /* Output filename */
++        "DSDT",               /* Signature */
++        0x02,         /* DSDT Revision, needs to be 2 for 64bit */
++        "ASUS  ",     /* OEMID */
++        "COREBOOT",   /* TABLE ID */
++        0x00000001    /* OEM Revision */
++        )
++{
++      #include "northbridge/amd/amdfam10/amdfam10_util.asl"
++      #include "southbridge/amd/sr5650/acpi/sr5650.asl"
++
++      /* Some global data */
++      Name(OSVR, 3)   /* Assume nothing. WinXp = 1, Vista = 2, Linux = 3, 
WinCE = 4 */
++      Name(OSV, Ones) /* Assume nothing */
++      Name(PICM, One) /* Assume APIC */
++
++      /* HPET control */
++      Name (SHPB, 0xFED00000)
++      Name (SHPL, 0x1000)
++
++      /* Define power states */
++      Name (\_S0, Package () { 0x00, 0x00, 0x00, 0x00 })      /* Normal 
operation */
++      Name (\_S1, Package () { 0x01, 0x01, 0x00, 0x00 })      /* Standby */
++      Name (\_S2, Package () { 0x02, 0x02, 0x00, 0x00 })      /* Standby w/ 
CPU shutdown */
++      Name (\_S3, Package () { 0x03, 0x00, 0x00, 0x00 })      /* Suspend */
++      /* Name (\_S4, Package () { 0x04, 0x04, 0x00, 0x00 }) */
++      Name (\_S5, Package () { 0x05, 0x05, 0x00, 0x00 })      /* Hard power 
off */
++
++      /* The _PIC method is called by the OS to choose between interrupt
++              * routing via the i8259 interrupt controller or the APIC.
++              *
++              * _PIC is called with a parameter of 0 for i8259 configuration 
and
++              * with a parameter of 1 for Local Apic/IOAPIC configuration.
++              */
++      Method (_PIC, 1, Serialized) {
++              If (Arg0)
++              {
++                      \_SB.CIRQ()
++              }
++              Store (Arg0, PICM)
++      }
++
++      /* _PR CPU0 is dynamically supplied by SSDT */
++      /* CPU objects and _PSS entries are dynamically supplied by SSDT */
++
++      Scope(\_GPE) {  /* Start Scope GPE */
++              /*  General event 3  */
++              Method(_L03) {
++                      /* Level-Triggered GPE */
++                      Notify(\_SB.PWRB, 0x02)                 /* 
NOTIFY_DEVICE_WAKE */
++              }
++
++              /*  General event 4  */
++              Method(_L04) {
++                      /* Level-Triggered GPE */
++                      Notify (\_SB.PCI0.PBR0, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PWRB, 0x02)                /* 
NOTIFY_DEVICE_WAKE */
++              }
++
++              /*  Keyboard controller PME#  */
++              Method(_L08) {
++                      /* Level-Triggered GPE */
++                      Notify(\_SB.PCI0.LPC.KBD, 0x02)         /* 
NOTIFY_DEVICE_WAKE */
++                      Notify(\_SB.PCI0.LPC.MOU, 0x02)         /* 
NOTIFY_DEVICE_WAKE */
++                      Notify(\_SB.PWRB, 0x02)                 /* 
NOTIFY_DEVICE_WAKE */
++              }
++
++              /*  USB controller PME#  */
++              Method(_L0B) {
++                      /* Level-Triggered GPE */
++                      Notify (\_SB.PCI0.USB0, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.USB1, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.USB2, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.USB3, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.USB4, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.USB5, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.USB6, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PWRB, 0x02)                /* 
NOTIFY_DEVICE_WAKE */
++              }
++
++              /*  GPIO0 or GEvent8 event  */
++              Method(_L18) {
++                      /* Level-Triggered GPE */
++                      Notify (\_SB.PCI0.PCE1, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.NICA, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.NICB, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.PCE4, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.PCE5, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++                      Notify (\_SB.PCI0.PCE3, 0x02)           /* 
NOTIFY_DEVICE_WAKE */
++              }
++
++      }       /* End Scope GPE */
++
++      /* Root of the bus hierarchy */
++      Scope (\_SB)
++      {
++              /* Top southbridge PCI device (SR5690) */
++              Device (PCI0)
++              {
++                      /* BUS0 root bus */
++
++                      Name (_HID, EisaId ("PNP0A03"))
++                      Name (_ADR, 0x00180001)
++                      Name (_UID, 0x00)
++
++                      Name (HCIN, 0x00)  // HC1
++
++                      Method (_BBN, 0, NotSerialized)
++                      {
++                              Return (GBUS (GHCN(HCIN), GHCL(HCIN)))
++                      }
++
++                      /* Operating System Capabilities Method */
++                      Method(_OSC,4)
++                      {
++                              /* Let OS control everything */
++                              Return (Arg3)
++                      }
++
++                      External (BUSN)
++                      External (MMIO)
++                      External (PCIO)
++                      External (SBLK)
++                      External (TOM1)
++                      External (HCLK)
++                      External (SBDN)
++                      External (HCDN)
++                      External (CBST)
++
++                      /* PCI Routing Tables */
++                      Name (PR00, Package () {
++                              /* PIC */
++                              /* Top southbridge device (SR5690) */
++                              /* HT Link */
++                              Package (0x04) { 0x0000FFFF, 0x00, LNKA, 0x00 },
++
++                              /* PCI-E Slot 1 (Bridge) */
++                              Package (0x04) { 0x0002FFFF, 0x00, LNKE, 0x00 },
++
++                              /* NIC A (Bridge) */
++                              Package (0x04) { 0x0009FFFF, 0x00, LNKF, 0x00 },
++
++                              /* NIC B (Bridge) */
++                              Package (0x04) { 0x000AFFFF, 0x00, LNKG, 0x00 },
++
++                              /* PCI-E Slot 4 (Bridge) */
++                              Package (0x04) { 0x000BFFFF, 0x00, LNKG, 0x00 },
++
++                              /* PCI-E Slot 5 (Bridge) */
++                              Package (0x04) { 0x000CFFFF, 0x00, LNKG, 0x00 },
++
++                              /* PCI-E Slot 3 (Bridge) */
++                              Package (0x04) { 0x000DFFFF, 0x00, LNKG, 0x00 },
++
++                              /* Bottom southbridge device (SP5100) */
++                              /* SATA 0 */
++                              Package (0x04) { 0x0011FFFF, 0x00, LNKG, 0x00 },
++
++                              /* USB 0 */
++                              Package (0x04) { 0x0012FFFF, 0x00, LNKA, 0x00 },
++                              Package (0x04) { 0x0012FFFF, 0x01, LNKB, 0x00 },
++                              Package (0x04) { 0x0012FFFF, 0x02, LNKC, 0x00 },
++                              Package (0x04) { 0x0012FFFF, 0x03, LNKD, 0x00 },
++
++                              /* USB 1 */
++                              Package (0x04) { 0x0013FFFF, 0x00, LNKC, 0x00 },
++                              Package (0x04) { 0x0013FFFF, 0x01, LNKD, 0x00 },
++                              Package (0x04) { 0x0013FFFF, 0x02, LNKA, 0x00 },
++                              Package (0x04) { 0x0013FFFF, 0x03, LNKB, 0x00 },
++
++                              /* SMBUS / IDE / LPC / VGA / FireWire / PCI 
Slot 0 */
++                              Package (0x04) { 0x0014FFFF, 0x00, LNKA, 0x00 },
++                              Package (0x04) { 0x0014FFFF, 0x01, LNKB, 0x00 },
++                              Package (0x04) { 0x0014FFFF, 0x02, LNKC, 0x00 },
++                              Package (0x04) { 0x0014FFFF, 0x03, LNKD, 0x00 },
++                      })
++
++                      Name (AR00, Package () {
++                              /* APIC */
++                              /* Top southbridge device (SR5690) */
++                              /* HT Link */
++                              Package (0x04) { 0x0000FFFF, 0x00, 0x00, 55 },
++
++                              /* PCI-E Slot 1 (Bridge) */
++                              Package (0x04) { 0x0002FFFF, 0x00, 0x00, 52 },
++
++                              /* NIC A (Bridge) */
++                              Package (0x04) { 0x0009FFFF, 0x00, 0x00, 53 },
++
++                              /* NIC B (Bridge) */
++                              Package (0x04) { 0x000AFFFF, 0x00, 0x00, 54 },
++
++                              /* PCI-E Slot 4 (Bridge) */
++                              Package (0x04) { 0x000BFFFF, 0x00, 0x00, 54 },
++
++                              /* PCI-E Slot 5 (Bridge) */
++                              Package (0x04) { 0x000CFFFF, 0x00, 0x00, 54 },
++
++                              /* PCI-E Slot 3 (Bridge) */
++                              Package (0x04) { 0x000DFFFF, 0x00, 0x00, 54 },
++
++                              /* Bottom southbridge device (SP5100) */
++                              /* SATA 0 */
++                              Package (0x04) { 0x0011FFFF, 0x00, 0x00, 22 },
++
++                              /* USB 0 */
++                              Package (0x04) { 0x0012FFFF, 0x00, 0x00, 16 },
++                              Package (0x04) { 0x0012FFFF, 0x01, 0x00, 17 },
++                              Package (0x04) { 0x0012FFFF, 0x02, 0x00, 18 },
++                              Package (0x04) { 0x0012FFFF, 0x03, 0x00, 19 },
++
++                              /* USB 1 */
++                              Package (0x04) { 0x0013FFFF, 0x00, 0x00, 18 },
++                              Package (0x04) { 0x0013FFFF, 0x01, 0x00, 19 },
++                              Package (0x04) { 0x0013FFFF, 0x02, 0x00, 16 },
++                              Package (0x04) { 0x0013FFFF, 0x03, 0x00, 17 },
++
++                              /* SMBUS / IDE / LPC / VGA / FireWire / PCI 
Slot 0 */
++                              Package (0x04) { 0x0014FFFF, 0x00, 0x00, 16 },
++                              Package (0x04) { 0x0014FFFF, 0x01, 0x00, 17 },
++                              Package (0x04) { 0x0014FFFF, 0x02, 0x00, 18 },
++                              Package (0x04) { 0x0014FFFF, 0x03, 0x00, 19 },
++                      })
++
++                      Name (PR01, Package () {
++                              /* PIC */
++                              Package (0x04) { 0x1FFFF, 0x00, LNKF, 0x00 },
++                              Package (0x04) { 0x2FFFF, 0x00, LNKE, 0x00 },
++                              Package (0x04) { 0x3FFFF, 0x00, LNKG, 0x00 },
++                              Package (0x04) { 0x3FFFF, 0x01, LNKH, 0x00 },
++                              Package (0x04) { 0x3FFFF, 0x02, LNKE, 0x00 },
++                              Package (0x04) { 0x3FFFF, 0x03, LNKF, 0x00 },
++                      })
++
++                      Name (AR01, Package () {
++                              /* APIC */
++                              Package (0x04) { 0x1FFFF, 0x00, 0x00, 21 },
++                              Package (0x04) { 0x2FFFF, 0x00, 0x00, 20 },
++                              Package (0x04) { 0x3FFFF, 0x00, 0x00, 22 },
++                              Package (0x04) { 0x3FFFF, 0x01, 0x00, 23 },
++                              Package (0x04) { 0x3FFFF, 0x02, 0x00, 20 },
++                              Package (0x04) { 0x3FFFF, 0x03, 0x00, 21 },
++                      })
++
++                      Name (PR02, Package () {
++                              /* PIC */
++                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
++                      })
++
++                      Name (AR02, Package () {
++                              /* APIC */
++                              Package (0x04) { 0xFFFF, 0x00, 0x00, 24 },
++                              Package (0x04) { 0xFFFF, 0x01, 0x00, 25 },
++                              Package (0x04) { 0xFFFF, 0x02, 0x00, 26 },
++                              Package (0x04) { 0xFFFF, 0x03, 0x00, 27 },
++                      })
++
++                      Name (PR03, Package () {
++                              /* PIC */
++                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
++                      })
++
++                      Name (AR03, Package () {
++                              /* APIC */
++                              Package (0x04) { 0xFFFF, 0x00, 0x00, 48 },
++                              Package (0x04) { 0xFFFF, 0x01, 0x00, 49 },
++                              Package (0x04) { 0xFFFF, 0x02, 0x00, 50 },
++                              Package (0x04) { 0xFFFF, 0x03, 0x00, 51 },
++                      })
++
++                      Name (PR04, Package () {
++                              /* PIC */
++                              Package (0x04) { 0xFFFF, 0x00, LNKH, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x01, LNKE, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x02, LNKF, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x03, LNKG, 0x00 },
++                      })
++
++                      Name (AR04, Package () {
++                              /* APIC */
++                              Package (0x04) { 0xFFFF, 0x00, 0x00, 47 },
++                              Package (0x04) { 0xFFFF, 0x01, 0x00, 44 },
++                              Package (0x04) { 0xFFFF, 0x02, 0x00, 45 },
++                              Package (0x04) { 0xFFFF, 0x03, 0x00, 46 },
++                      })
++
++                      Name (PR05, Package () {
++                              /* PIC */
++                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
++                      })
++
++                      Name (AR05, Package () {
++                              /* APIC */
++                              Package (0x04) { 0xFFFF, 0x00, 0x00, 32 },
++                              Package (0x04) { 0xFFFF, 0x01, 0x00, 33 },
++                              Package (0x04) { 0xFFFF, 0x02, 0x00, 34 },
++                              Package (0x04) { 0xFFFF, 0x03, 0x00, 35 },
++                      })
++
++                      Name (PR06, Package () {
++                              /* PIC */
++                              Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x02, LNKG, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 },
++                      })
++
++                      Name (AR06, Package () {
++                              /* APIC */
++                              Package (0x04) { 0xFFFF, 0x00, 0x00, 36 },
++                              Package (0x04) { 0xFFFF, 0x01, 0x00, 37 },
++                              Package (0x04) { 0xFFFF, 0x02, 0x00, 38 },
++                              Package (0x04) { 0xFFFF, 0x03, 0x00, 39 },
++                      })
++
++                      Name (PR07, Package () {
++                              /* PIC */
++                              Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
++                      })
++
++                      Name (AR07, Package () {
++                              /* APIC */
++                              Package (0x04) { 0xFFFF, 0x00, 0x00, 40 },
++                              Package (0x04) { 0xFFFF, 0x01, 0x00, 41 },
++                              Package (0x04) { 0xFFFF, 0x02, 0x00, 42 },
++                              Package (0x04) { 0xFFFF, 0x03, 0x00, 43 },
++                      })
++
++                      /* PCI Resource Tables */
++
++                      /* PCI Resource Settings Access */
++                      Method (_CRS, 0, Serialized)
++                      {
++                              Name (BUF0, ResourceTemplate ()
++                              {
++                                      IO (Decode16,
++                                      0x0CF8, // Address Range Minimum
++                                      0x0CF8, // Address Range Maximum
++                                      0x01,   // Address Alignment
++                                      0x08,   // Address Length
++                                      )
++                                      WordIO (ResourceProducer, MinFixed, 
MaxFixed, PosDecode, EntireRange,
++                                      0x0000, // Address Space Granularity
++                                      0x0000, // Address Range Minimum
++                                      0x0CF7, // Address Range Maximum
++                                      0x0000, // Address Translation Offset
++                                      0x0CF8, // Address Length
++                                      ,, , TypeStatic)
++                              })
++                              /* Methods below use SSDT to get actual MMIO 
regs
++                                 The IO ports are from 0xd00, optionally an 
VGA,
++                                 otherwise the info from MMIO is used.
++                                 \_SB.GXXX(node, link)
++                               */
++                              Concatenate (\_SB.GMEM (0x00, \_SB.PCI0.SBLK), 
BUF0, Local1)
++                              Concatenate (\_SB.GIOR (0x00, \_SB.PCI0.SBLK), 
Local1, Local2)
++                              Concatenate (\_SB.GWBN (0x00, \_SB.PCI0.SBLK), 
Local2, Local3)
++                              Return (Local3)
++                      }
++
++                      /* PCI Routing Table Access */
++                      Method (_PRT, 0, NotSerialized) {
++                              If (PICM) {
++                                      Return (AR00)
++                              } Else {
++                                      Return (PR00)
++                              }
++                      }
++
++                      /* 0:11.0 SP5100 SATA 0 */
++                      Device(SAT0)
++                      {
++                              Name (_ADR, 0x00110000)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                              #include "southbridge/amd/sb700/acpi/sata.asl"
++                      }
++
++                      /* 0:12.0 SP5100 USB 0 */
++                      Device (USB0)
++                      {
++                              Name (_ADR, 0x00120000)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                      }
++
++                      /* 0:12.1 SP5100 USB 1 */
++                      Device (USB1)
++                      {
++                              Name (_ADR, 0x00120001)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                      }
++
++                      /* 0:12.2 SP5100 USB 2 */
++                      Device (USB2)
++                      {
++                              Name (_ADR, 0x00120002)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                      }
++
++                      /* 0:13.0 SP5100 USB 3 */
++                      Device (USB3)
++                      {
++                              Name (_ADR, 0x00130000)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                      }
++
++                      /* 0:13.1 SP5100 USB 4 */
++                      Device (USB4)
++                      {
++                              Name (_ADR, 0x00130001)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                      }
++
++                      /* 0:13.2 SP5100 USB 5 */
++                      Device (USB5)
++                      {
++                              Name (_ADR, 0x00130002)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                      }
++
++                      /* 0:14.1 SP5100 IDE Controller */
++                      Device (IDEC)
++                      {
++                              Name (_ADR, 0x00140001)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                              #include "southbridge/amd/sb700/acpi/ide.asl"
++                      }
++
++                      /* 0:14.3 SP5100 LPC */
++                      Device (LPC) {
++                              Name (_HID, EisaId ("PNP0A05"))
++                              Name (_ADR, 0x00140003)
++
++                              /* PS/2 keyboard (seems to be important for 
WinXP install) */
++                              Device (KBD)
++                              {
++                                      Name (_HID, EisaId ("PNP0303"))
++                                      Name (_CID, EisaId ("PNP030B"))
++                                      Method (_STA, 0, NotSerialized)
++                                      {
++                                              Return (0x0f)
++                                      }
++                                      Method (_CRS, 0, Serialized)
++                                      {
++                                              Name (TMP, ResourceTemplate () {
++                                                      IO (Decode16, 0x0060, 
0x0060, 0x01, 0x01)
++                                                      IO (Decode16, 0x0064, 
0x0064, 0x01, 0x01)
++                                                      IRQNoFlags () {1}
++                                              })
++                                              Return (TMP)
++                                      }
++                              }
++
++                              /* PS/2 mouse */
++                              Device (MOU)
++                              {
++                                      Name (_HID, EisaId ("PNP0F03"))
++                                      Name (_CID, EisaId ("PNP0F13"))
++                                      Method (_STA, 0, NotSerialized)
++                                      {
++                                              Return (0x0f)
++                                      }
++                                      Method (_CRS, 0, Serialized)
++                                      {
++                                              Name (TMP, ResourceTemplate () {
++                                                      IRQNoFlags () {12}
++                                              })
++                                              Return (TMP)
++                                      }
++                              }
++
++
++                              /* UART 1 */
++                              Device (URT1)
++                              {
++                                      Name (_HID, EisaId ("PNP0501"))         
// "PNP0501" for UART
++                                      Name(_PRW, Package () {0x03, 0x04})     
// Wake from S1-S4
++                                      Method (_STA, 0, NotSerialized)
++                                      {
++                                              Return (0x0f)                   
// Always enable
++                                      }
++                                      Name (_PRS, ResourceTemplate() {
++                                              StartDependentFn(0, 1) {
++                                                      IO(Decode16, 0x3f8, 
0x3f8, 0x8, 0x8)
++                                                      IRQNoFlags() { 4 }
++                                              } EndDependentFn()
++                                      })
++                                      Method (_CRS, 0)
++                                      {
++                                              Return(ResourceTemplate() {
++                                                      IO(Decode16, 0x3f8, 
0x3f8, 0x8, 0x8)
++                                                      IRQNoFlags() { 4 }
++                                              })
++                                      }
++                              }
++
++                              /* High Precision Event Timer */
++                              Device (HPET)
++                              {
++                                      Name (_HID, EisaId ("PNP0103"))
++                                      Name (CRS, ResourceTemplate ()
++                                      {
++                                              Memory32Fixed (ReadOnly,
++                                              0x00000000,
++                                              0x00001000,
++                                              _Y02)
++                                              IRQNoFlags () {0}
++                                              IRQNoFlags () {8}
++                                      })
++                                      Method (_STA, 0, NotSerialized)
++                                      {
++                                              Return (0x0F)
++                                      }
++                                      Method (_CRS, 0, NotSerialized)
++                                      {
++                                              CreateDWordField (CRS, 
\_SB.PCI0.LPC.HPET._Y02._BAS, HPT1)
++                                              CreateDWordField (CRS, 
\_SB.PCI0.LPC.HPET._Y02._LEN, HPT2)
++                                              Store (SHPB, HPT1)
++                                              Store (SHPL, HPT2)
++                                              Return (CRS)
++                                      }
++
++                              }
++                      }
++
++                      /* 0:14.4 PCI Bridge */
++                      Device (PBR0)
++                      {
++                              Name (_ADR, 0x00140004)                 // 
_ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR01)
++                                      } Else {
++                                              Return (PR01)
++                                      }
++                              }
++                              Device (SLT1)
++                              {
++                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
++                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
++                              }
++                      }
++
++                      /* 0:14.5 SP5100 USB 6 */
++                      Device (USB6)
++                      {
++                              Name (_ADR, 0x00140005)  // _ADR: Address
++                              Name(_PRW, Package () {0x05, 0x04})     // Wake 
from S1-S4
++                      }
++
++                      /* 2:00.0 PCIe x16 */
++                      Device (PCE1)
++                      {
++                              Name (_ADR, 0x00020000)                 // 
_ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR02)
++                                      } Else {
++                                              Return (PR02)
++                                      }
++                              }
++                              Device (SLT1)
++                              {
++                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
++                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
++                              }
++                      }
++
++                      /* 3:00.0 PCIe NIC A */
++                      Device (NICA)
++                      {
++                              Name (_ADR, 0x00090000)  // _ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR03)
++                                      } Else {
++                                              Return (PR03)
++                                      }
++                              }
++                              Device (BDC1)
++                              {
++                                      Name (_ADR, Zero)  // _ADR: Address
++                              }
++                      }
++
++                      /* 4:00.0 PCIe NIC B */
++                      Device (NICB)
++                      {
++                              Name (_ADR, 0x000A0000)  // _ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR04)
++                                      } Else {
++                                              Return (PR04)
++                                      }
++                              }
++                              Device (BDC2)
++                              {
++                                      Name (_ADR, Zero)  // _ADR: Address
++                              }
++                      }
++
++                      /* 5:00.0 PCIe x16 */
++                      Device (PCE4)
++                      {
++                              Name (_ADR, 0x000B0000)                 // 
_ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR05)
++                                      } Else {
++                                              Return (PR05)
++                                      }
++                              }
++                              Device (SLT1)
++                              {
++                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
++                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
++                              }
++                      }
++
++                      /* 6:00.0 PCIe x16 */
++                      Device (PCE5)
++                      {
++                              Name (_ADR, 0x000C0000)                 // 
_ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR06)
++                                      } Else {
++                                              Return (PR06)
++                                      }
++                              }
++                              Device (SLT1)
++                              {
++                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
++                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
++                              }
++                      }
++
++                      /* 7:00.0 PCIe x16 */
++                      Device (PCE3)
++                      {
++                              Name (_ADR, 0x000D0000)                 // 
_ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR07)
++                                      } Else {
++                                              Return (PR07)
++                                      }
++                              }
++                              Device (SLT1)
++                              {
++                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
++                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
++                              }
++                      }
++              }
++
++              Device (PWRB) { /* Start Power button device */
++                      Name(_HID, EISAID("PNP0C0C"))
++                      Name(_UID, 0xAA)
++                      Name(_PRW, Package () {3, 0x04})        /* wake from 
S1-S4 */
++                      Name(_STA, 0x0B) /* sata is invisible */
++              }
++      }
++
++#include "acpi/pm_ctrl.asl"
++
++}
+diff --git a/src/mainboard/asus/kgpe-d16/get_bus_conf.c 
b/src/mainboard/asus/kgpe-d16/get_bus_conf.c
+new file mode 100644
+index 0000000..09fa262
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/get_bus_conf.c
+@@ -0,0 +1,128 @@
++ /*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <console/console.h>
++#include <device/pci.h>
++#include <device/pci_ids.h>
++#include <string.h>
++#include <stdint.h>
++#include <stdlib.h>
++#if CONFIG_LOGICAL_CPUS
++#include <cpu/amd/multicore.h>
++#endif
++
++#include <cpu/amd/amdfam10_sysconf.h>
++
++/* Global variables for MB layouts and these will be shared by irqtable 
mptable
++* and acpi_tables busnum is default.
++*/
++u8 bus_isa;
++u8 bus_sr5650[14];
++u8 bus_sp5100[2];
++u32 apicid_sp5100;
++
++/*
++* Here you only need to set value in pci1234 for HT-IO that could be 
installed or not
++* You may need to preset pci1234 for HTIO board,
++* please refer to src/northbridge/amd/amdk8/get_sblk_pci1234.c for detail
++*/
++u32 pci1234x[] = {
++      0x0000ff0,
++};
++
++/*
++* HT Chain device num, actually it is unit id base of every ht device in 
chain,
++* assume every chain only have 4 ht device at most
++*/
++u32 hcdnx[] = {
++      0x20202020,
++};
++
++
++u32 sbdn_sr5650;
++u32 sbdn_sp5100;
++
++extern void get_pci1234(void);
++
++static u32 get_bus_conf_done = 0;
++
++void get_bus_conf(void)
++{
++      u32 apicid_base;
++      device_t dev;
++      int i;
++
++      if (get_bus_conf_done == 1)
++              return;         /* do it only once */
++      get_bus_conf_done = 1;
++
++      sysconf.hc_possible_num = ARRAY_SIZE(pci1234x);
++      for (i = 0; i < sysconf.hc_possible_num; i++) {
++              sysconf.pci1234[i] = pci1234x[i];
++              sysconf.hcdn[i] = hcdnx[i];
++      }
++
++      get_pci1234();
++
++      sysconf.sbdn = (sysconf.hcdn[0] & 0xff);
++      sbdn_sr5650 = sysconf.sbdn;
++      sbdn_sp5100 = 0;
++
++      for (i = 0; i < 2; i++) {
++              bus_sp5100[i] = 0;
++      }
++      for (i = 0; i < ARRAY_SIZE(bus_sr5650); i++) {
++              bus_sr5650[i] = 0;
++      }
++
++
++      bus_sr5650[0] = (sysconf.pci1234[0] >> 16) & 0xff;
++      bus_sp5100[0] = bus_sr5650[0];
++
++
++      /* sp5100 */
++      dev = dev_find_slot(bus_sp5100[0], PCI_DEVFN(sbdn_sp5100 + 0x14, 4));
++      if (dev) {
++              bus_sp5100[1] = pci_read_config8(dev, PCI_SECONDARY_BUS);
++              bus_isa = pci_read_config8(dev, PCI_SUBORDINATE_BUS);
++              bus_isa++;
++      }
++
++      /* sr5650 */
++      for (i = 1; i < ARRAY_SIZE(bus_sr5650); i++) {
++              dev = dev_find_slot(bus_sr5650[0], PCI_DEVFN(sbdn_sr5650 + i, 
0));
++              if (dev) {
++                      bus_sr5650[i] = pci_read_config8(dev, 
PCI_SECONDARY_BUS);
++                      if(255 != bus_sr5650[i]) {
++                              bus_isa = pci_read_config8(dev, 
PCI_SUBORDINATE_BUS);
++                              bus_isa++;
++                      }
++              }
++      }
++
++      /* I/O APICs:   APIC ID Version State   Address */
++      bus_isa = 10;
++#if CONFIG_LOGICAL_CPUS
++      apicid_base = get_apicid_base(1);
++#else
++      apicid_base = CONFIG_MAX_PHYSICAL_CPUS;
++#endif
++      apicid_sp5100 = apicid_base + 0;
++}
+diff --git a/src/mainboard/asus/kgpe-d16/irq_tables.c 
b/src/mainboard/asus/kgpe-d16/irq_tables.c
+new file mode 100644
+index 0000000..5eb4c24
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/irq_tables.c
+@@ -0,0 +1,112 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <console/console.h>
++#include <device/pci.h>
++#include <string.h>
++#include <stdint.h>
++#include <arch/pirq_routing.h>
++
++#include <cpu/amd/amdfam10_sysconf.h>
++
++static void write_pirq_info(struct irq_info *pirq_info, u8 bus, u8 devfn,
++                          u8 link0, u16 bitmap0, u8 link1, u16 bitmap1,
++                          u8 link2, u16 bitmap2, u8 link3, u16 bitmap3,
++                          u8 slot, u8 rfu)
++{
++      pirq_info->bus = bus;
++      pirq_info->devfn = devfn;
++      pirq_info->irq[0].link = link0;
++      pirq_info->irq[0].bitmap = bitmap0;
++      pirq_info->irq[1].link = link1;
++      pirq_info->irq[1].bitmap = bitmap1;
++      pirq_info->irq[2].link = link2;
++      pirq_info->irq[2].bitmap = bitmap2;
++      pirq_info->irq[3].link = link3;
++      pirq_info->irq[3].bitmap = bitmap3;
++      pirq_info->slot = slot;
++      pirq_info->rfu = rfu;
++}
++extern u8 bus_isa;
++extern u8 bus_rs780[8];
++extern u8 bus_sp5100[2];
++extern unsigned long sbdn_sp5100;
++
++unsigned long write_pirq_routing_table(unsigned long addr)
++{
++      struct irq_routing_table *pirq;
++      struct irq_info *pirq_info;
++      u32 slot_num;
++      u8 *v;
++
++      u8 sum = 0;
++      int i;
++
++      get_bus_conf();         /* it will find out all bus num and apic that 
share with mptable.c and mptable.c and acpi_tables.c */
++
++      /* Align the table to be 16 byte aligned. */
++      addr += 15;
++      addr &= ~15;
++
++      /* This table must be between 0xf0000 & 0x100000 */
++      printk(BIOS_INFO, "Writing IRQ routing tables to 0x%lx...", addr);
++
++      pirq = (void *)(addr);
++      v = (u8 *) (addr);
++
++      pirq->signature = PIRQ_SIGNATURE;
++      pirq->version = PIRQ_VERSION;
++
++      pirq->rtr_bus = bus_sp5100[0];
++      pirq->rtr_devfn = PCI_DEVFN(0x14, 4);
++
++      pirq->exclusive_irqs = 0;
++
++      pirq->rtr_vendor = 0x1002;
++      pirq->rtr_device = 0x4384;
++
++      pirq->miniport_data = 0;
++
++      memset(pirq->rfu, 0, sizeof(pirq->rfu));
++
++      pirq_info = (void *)(&pirq->checksum + 1);
++      slot_num = 0;
++
++      /* pci bridge */
++      write_pirq_info(pirq_info, bus_sp5100[0], ((sbdn_sp5100 + 0x14) << 3) | 
4,
++                      0x1, 0xdef8, 0x2, 0xdef8, 0x3, 0xdef8, 0x4, 0xdef8, 0,
++                      0);
++      pirq_info++;
++      slot_num++;
++
++      pirq->size = 32 + 16 * slot_num;
++
++      for (i = 0; i < pirq->size; i++)
++              sum += v[i];
++
++      sum = pirq->checksum - sum;
++      if (sum != pirq->checksum) {
++              pirq->checksum = sum;
++      }
++
++      printk(BIOS_INFO, "write_pirq_routing_table done.\n");
++
++      return (unsigned long)pirq_info;
++}
+diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c 
b/src/mainboard/asus/kgpe-d16/mainboard.c
+new file mode 100644
+index 0000000..47ede34
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/mainboard.c
+@@ -0,0 +1,81 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <console/console.h>
++#include <device/device.h>
++#include <device/pci.h>
++#include <arch/io.h>
++#include <cpu/x86/msr.h>
++#include <cpu/amd/mtrr.h>
++#include <device/pci_def.h>
++#include <southbridge/amd/sb700/sb700.h>
++#include <southbridge/amd/sr5650/cmn.h>
++
++
++void set_pcie_reset(void);
++void set_pcie_dereset(void);
++
++void set_pcie_reset(void)
++{
++      device_t pcie_core_dev;
++
++      pcie_core_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
++      set_htiu_enable_bits(pcie_core_dev, 0xA8, 0xFFFFFFFF, 0x28282828);
++      set_htiu_enable_bits(pcie_core_dev, 0xA9, 0x000000FF, 0x00000028);
++}
++
++void set_pcie_dereset(void)
++{
++      device_t pcie_core_dev;
++
++      pcie_core_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
++      set_htiu_enable_bits(pcie_core_dev, 0xA8, 0xFFFFFFFF, 0x6F6F6F6F);
++      set_htiu_enable_bits(pcie_core_dev, 0xA9, 0x000000FF, 0x0000006F);
++}
++
++/*************************************************
++* enable the dedicated function in kgpe-d16 board.
++* This function is called earlier than sr5650_enable.
++*************************************************/
++static void mainboard_enable(device_t dev)
++{
++      printk(BIOS_INFO, "Mainboard KGPE-D16 Enable. dev=0x%p\n", dev);
++
++      msr_t msr, msr2;
++
++      /* TOP_MEM: the top of DRAM below 4G */
++      msr = rdmsr(TOP_MEM);
++      printk
++          (BIOS_INFO, "%s, TOP MEM: msr.lo = 0x%08x, msr.hi = 0x%08x\n",
++           __func__, msr.lo, msr.hi);
++
++      /* TOP_MEM2: the top of DRAM above 4G */
++      msr2 = rdmsr(TOP_MEM2);
++      printk
++          (BIOS_INFO, "%s, TOP MEM2: msr2.lo = 0x%08x, msr2.hi = 0x%08x\n",
++           __func__, msr2.lo, msr2.hi);
++
++      set_pcie_dereset();
++      /* get_ide_dma66(); */
++}
++
++struct chip_operations mainboard_ops = {
++      .enable_dev = mainboard_enable,
++};
+diff --git a/src/mainboard/asus/kgpe-d16/mb_sysconf.h 
b/src/mainboard/asus/kgpe-d16/mb_sysconf.h
+new file mode 100644
+index 0000000..3a407a6
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/mb_sysconf.h
+@@ -0,0 +1,44 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef MB_SYSCONF_H
++
++#define MB_SYSCONF_H
++
++struct mb_sysconf_t {
++      u8 bus_isa;
++      u8 bus_8132_0;
++      u8 bus_8132_1;
++      u8 bus_8132_2;
++      u8 bus_8111_0;
++      u8 bus_8111_1;
++      u8 bus_8132a[31][3];
++      u8 bus_8151[31][2];
++
++      u32 apicid_8111;
++      u32 apicid_8132_1;
++      u32 apicid_8132_2;
++      u32 apicid_8132a[31][2];
++      u32 sbdn3;
++      u32 sbdn3a[31];
++      u32 sbdn5[31];
++};
++
++#endif
+diff --git a/src/mainboard/asus/kgpe-d16/mptable.c 
b/src/mainboard/asus/kgpe-d16/mptable.c
+new file mode 100644
+index 0000000..0279f8b
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/mptable.c
+@@ -0,0 +1,231 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <console/console.h>
++#include <arch/smp/mpspec.h>
++#include <device/pci.h>
++#include <arch/io.h>
++#include <string.h>
++#include <stdint.h>
++#include <cpu/amd/amdfam10_sysconf.h>
++
++extern u8 bus_sr5650[14];
++extern u8 bus_sp5100[2];
++
++extern u32 apicid_sp5100;
++
++extern u32 sbdn_sr5650;
++extern u32 sbdn_sp5100;
++
++
++static void *smp_write_config_table(void *v)
++{
++      struct mp_config_table *mc;
++      int bus_isa;
++      u32 apicid_sr5650;
++      device_t dev;
++      uint8_t sp5100_bus_number;
++
++      mc = (void *)(((char *)v) + SMP_FLOATING_TABLE_LEN);
++
++      mptable_init(mc, LOCAL_APIC_ADDR);
++
++      smp_write_processors(mc);
++
++      get_bus_conf();
++
++      apicid_sp5100 = 0x20;
++      apicid_sr5650 = apicid_sp5100 + 1;
++
++      mptable_write_buses(mc, NULL, &bus_isa);
++      /* I/O APICs:   APIC ID Version State   Address */
++      {
++              uint32_t *dword_ptr;
++              uint32_t dword;
++              uint16_t word;
++              uint8_t byte;
++
++              sp5100_bus_number = 0; //bus_sp5100[0]; TODO: why bus_sp5100[0] 
use same value of bus_sr5650[0] assigned by get_pci1234(), instead of 0.
++
++              dev = dev_find_slot(sp5100_bus_number, PCI_DEVFN(sbdn_sp5100 + 
0x14, 0));
++              if (dev) {
++                      dword_ptr = (u32 *)(pci_read_config32(dev, 0x74) & 
0xfffffff0);
++                      smp_write_ioapic(mc, apicid_sp5100, 0x11, dword_ptr);
++
++                      /* Initialize interrupt mapping */
++                      /* USB 1 & 2 */
++                      word = pci_read_config16(dev, 0xbe);
++                      word &= ~0x3f3f;
++                      word |= 0x0;            /* 0: INTA, ...., 7: INTH */
++                      word |= (0x1 << 3);     /* 0: INTA, ...., 7: INTH */
++                      word |= (0x2 << 8);     /* 0: INTA, ...., 7: INTH */
++                      word |= (0x3 << 11);    /* 0: INTA, ...., 7: INTH */
++                      pci_write_config16(dev, 0xbe, word);
++
++                      /* USB 3 */
++                      byte = pci_read_config8(dev, 0x63);
++                      byte &= 0xf8;
++                      byte |= (0x2 << 4);     /* 0: INTA, ...., 7: INTH */
++                      pci_write_config8(dev, 0x63, byte);
++
++                      dword = pci_read_config32(dev, 0xac);
++
++                      /* SATA */
++                      dword &= ~(7 << 26);
++                      dword |= (0x6 << 26);   /* 0: INTA, ...., 7: INTH */
++
++                      /* Hide IDE */
++                      dword &= ~(0x00080000);
++
++                      /* dword_ptr |= 1<<22; PIC and APIC co exists */
++                      pci_write_config32(dev, 0xac, dword);
++
++                      /*
++                       * 00:12.0: PROG SATA : INT F
++                       * 00:13.0: INTA USB_0
++                       * 00:13.1: INTB USB_1
++                       * 00:13.2: INTC USB_2
++                       * 00:13.3: INTD USB_3
++                       * 00:13.4: INTC USB_4
++                       * 00:13.5: INTD USB2
++                       * 00:14.1: INTA IDE
++                       * 00:14.2: Prog HDA : INT E
++                       * 00:14.5: INTB ACI
++                       * 00:14.6: INTB MCI
++                       */
++              }
++              dev = dev_find_slot(0, PCI_DEVFN(0, 0));
++              if (dev) {
++                      pci_write_config32(dev, 0xF8, 0x1);
++                      dword_ptr = (u32 *)(pci_read_config32(dev, 0xFC) & 
0xfffffff0);
++                      smp_write_ioapic(mc, apicid_sr5650, 0x11, dword_ptr);
++              }
++      }
++
++      /* I/O Ints:    Type    Polarity    Trigger     Bus ID   IRQ    APIC ID 
PIN# */
++#define IO_LOCAL_INT(type, intr, apicid, pin) \
++      smp_write_lintsrc(mc, (type), MP_IRQ_TRIGGER_EDGE | 
MP_IRQ_POLARITY_HIGH, bus_isa, (intr), (apicid), (pin));
++
++      mptable_add_isa_interrupts(mc, bus_isa, apicid_sp5100, 0);
++
++      /* SR5650 devices */
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((2)<<2)|(0)), apicid_sr5650, 28);   /* Device 2 (LNKE) */
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((4)<<2)|(0)), apicid_sr5650, 28);   /* Device 4 (LNKF) */
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((9)<<2)|(0)), apicid_sr5650, 29);   /* Device 9 (LNKG) */
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((10)<<2)|(0)), apicid_sr5650, 30);  /* Device 10 (LNKG) */
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((11)<<2)|(0)), apicid_sr5650, 30);  /* Device 11 (LNKG) */
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((12)<<2)|(0)), apicid_sr5650, 30);  /* Device 12 (LNKG) */
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
0, (((13)<<2)|(0)), apicid_sr5650, 30);  /* Device 13 (LNKG) */
++
++      dev = dev_find_slot(0, PCI_DEVFN(0x2, 0));
++      if (dev && dev->enabled) {
++              uint8_t bus_pci = dev->link_list->secondary;
++              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0x2)|(0)), 
apicid_sr5650, 0);    /* card behind dev2 */
++      }
++      dev = dev_find_slot(0, PCI_DEVFN(0x4, 0));
++      if (dev && dev->enabled) {
++              uint8_t bus_pci = dev->link_list->secondary;
++              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0x4)|(0)), 
apicid_sr5650, 0);    /* PIKE */
++      }
++      dev = dev_find_slot(0, PCI_DEVFN(0x9, 0));
++      if (dev && dev->enabled) {
++              uint8_t bus_pci = dev->link_list->secondary;
++              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0x9)|(0)), 
apicid_sr5650, 23);   /* NIC A */
++      }
++      dev = dev_find_slot(0, PCI_DEVFN(0xa, 0));
++      if (dev && dev->enabled) {
++              uint8_t bus_pci = dev->link_list->secondary;
++              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xa)|(0)), 
apicid_sr5650, 24);   /* NIC B */
++      }
++      dev = dev_find_slot(0, PCI_DEVFN(0xb, 0));
++      if (dev && dev->enabled) {
++              uint8_t bus_pci = dev->link_list->secondary;
++              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xb)|(0)), 
apicid_sr5650, 0);    /* card behind dev11 */
++      }
++      dev = dev_find_slot(0, PCI_DEVFN(0xc, 0));
++      if (dev && dev->enabled) {
++              uint8_t bus_pci = dev->link_list->secondary;
++              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xc)|(0)), 
apicid_sr5650, 0);    /* card behind dev12 */
++      }
++      dev = dev_find_slot(0, PCI_DEVFN(0xd, 0));
++      if (dev && dev->enabled) {
++              uint8_t bus_pci = dev->link_list->secondary;
++              smp_write_intsrc(mc, mp_INT, 
MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, bus_pci, (((0)<<0xd)|(0)), 
apicid_sr5650, 0);    /* card behind dev13 */
++      }
++
++      /* PCI interrupts are level triggered, and are
++       * associated with a specific bus/device/function tuple.
++       */
++#define PCI_INT(bus, dev, interrupt_signal, pin) \
++      smp_write_intsrc(mc, mp_INT, MP_IRQ_TRIGGER_LEVEL|MP_IRQ_POLARITY_LOW, 
(bus), (((dev)<<2)|(interrupt_signal)), apicid_sp5100, (pin))
++
++      /* USB1 */
++      PCI_INT(sp5100_bus_number, 0x12, 0x0, 0x10); /* OHCI0 Port 0~2 */
++      PCI_INT(sp5100_bus_number, 0x12, 0x1, 0x11); /* OHCI1 Port 3~5 */
++
++      /* USB2 */
++      PCI_INT(sp5100_bus_number, 0x13, 0x0, 0x12); /* OHCI0 Port 6~8 */
++      PCI_INT(sp5100_bus_number, 0x13, 0x1, 0x13); /* EHCI Port 6~11 */
++
++      /* USB3 */
++      PCI_INT(sp5100_bus_number, 0x14, 0x3, 0x12); /* OHCI0 Port 12~13 */
++
++      /* SATA */
++      PCI_INT(sp5100_bus_number, 0x11, 0x0, 0x16); /* 6, INTG */
++
++      /* PCI slots */
++      dev = dev_find_slot(0, PCI_DEVFN(0x14, 4));
++      if (dev && dev->enabled) {
++              u8 bus_pci = dev->link_list->secondary;
++
++              /* PCI_SLOT 0. */
++              PCI_INT(bus_pci, 0x1, 0x0, 0x15);
++              PCI_INT(bus_pci, 0x1, 0x1, 0x16);
++              PCI_INT(bus_pci, 0x1, 0x2, 0x17);
++              PCI_INT(bus_pci, 0x1, 0x3, 0x14);
++
++              /* PCI_SLOT 1. */
++              PCI_INT(bus_pci, 0x2, 0x0, 0x14);
++              PCI_INT(bus_pci, 0x2, 0x1, 0x15);
++              PCI_INT(bus_pci, 0x2, 0x2, 0x16);
++              PCI_INT(bus_pci, 0x2, 0x3, 0x17);
++
++              /* PCI_SLOT 2. */
++              PCI_INT(bus_pci, 0x3, 0x0, 0x16);
++              PCI_INT(bus_pci, 0x3, 0x1, 0x17);
++              PCI_INT(bus_pci, 0x3, 0x2, 0x14);
++              PCI_INT(bus_pci, 0x3, 0x3, 0x15);
++      }
++
++      /*Local Ints:   Type    Polarity    Trigger     Bus ID   IRQ    APIC ID 
PIN# */
++      IO_LOCAL_INT(mp_ExtINT, 0x0, MP_APIC_ALL, 0x0);
++      IO_LOCAL_INT(mp_NMI, 0x0, MP_APIC_ALL, 0x1);
++      /* There is no extension information... */
++
++      /* Compute the checksums */
++      return mptable_finalize(mc);
++}
++
++unsigned long write_smp_table(unsigned long addr)
++{
++      void *v;
++      v = smp_write_floating_table(addr, 0);
++      return (unsigned long)smp_write_config_table(v);
++}
+diff --git a/src/mainboard/asus/kgpe-d16/resourcemap.c 
b/src/mainboard/asus/kgpe-d16/resourcemap.c
+new file mode 100644
+index 0000000..3e240dc
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/resourcemap.c
+@@ -0,0 +1,284 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * Copyright (C) 2007 AMD
++ * Written by Yinghai Lu <address@hidden> for AMD.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++static void setup_mb_resource_map(void)
++{
++      static const unsigned int register_values[] = {
++              /* Careful set limit registers before base registers which 
contain the enables */
++              /* DRAM Limit i Registers
++               * F1:0x44 i = 0
++               * F1:0x4C i = 1
++               * F1:0x54 i = 2
++               * F1:0x5C i = 3
++               * F1:0x64 i = 4
++               * F1:0x6C i = 5
++               * F1:0x74 i = 6
++               * F1:0x7C i = 7
++               * [ 2: 0] Destination Node ID
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 7: 3] Reserved
++               * [10: 8] Interleave select
++               *         specifies the values of A[14:12] to use with 
interleave enable.
++               * [15:11] Reserved
++               * [31:16] DRAM Limit Address i Bits 39-24
++               *         This field defines the upper address bits of a 40 
bit  address
++               *         that define the end of the DRAM region.
++               */
++              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x44), 0x0000f8f8, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x4C), 0x0000f8f8, 
0x00000001,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x54), 0x0000f8f8, 
0x00000002,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x5C), 0x0000f8f8, 
0x00000003,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x64), 0x0000f8f8, 
0x00000004,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x6C), 0x0000f8f8, 
0x00000005,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x74), 0x0000f8f8, 
0x00000006,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x7C), 0x0000f8f8, 
0x00000007,
++
++              /* DRAM Base i Registers
++               * F1:0x40 i = 0
++               * F1:0x48 i = 1
++               * F1:0x50 i = 2
++               * F1:0x58 i = 3
++               * F1:0x60 i = 4
++               * F1:0x68 i = 5
++               * F1:0x70 i = 6
++               * F1:0x78 i = 7
++               * [ 0: 0] Read Enable
++               *         0 = Reads Disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes Disabled
++               *         1 = Writes Enabled
++               * [ 7: 2] Reserved
++               * [10: 8] Interleave Enable
++               *         000 = No interleave
++               *         001 = Interleave on A[12] (2 nodes)
++               *         010 = reserved
++               *         011 = Interleave on A[12] and A[14] (4 nodes)
++               *         100 = reserved
++               *         101 = reserved
++               *         110 = reserved
++               *         111 = Interleve on A[12] and A[13] and A[14] (8 
nodes)
++               * [15:11] Reserved
++               * [31:16] DRAM Base Address i Bits 39-24
++               *         This field defines the upper address bits of a 
40-bit address
++               *         that define the start of the DRAM region.
++               */
++              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x40), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x48), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x50), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x58), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x60), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x68), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x70), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x78), 0x0000f8fc, 
0x00000000,
++
++              /* Memory-Mapped I/O Limit i Registers
++               * F1:0x84 i = 0
++               * F1:0x8C i = 1
++               * F1:0x94 i = 2
++               * F1:0x9C i = 3
++               * F1:0xA4 i = 4
++               * F1:0xAC i = 5
++               * F1:0xB4 i = 6
++               * F1:0xBC i = 7
++               * [ 2: 0] Destination Node ID
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 3: 3] Reserved
++               * [ 5: 4] Destination Link ID
++               *         00 = Link 0
++               *         01 = Link 1
++               *         10 = Link 2
++               *         11 = Link 3
++               * [ 6: 6] Reserved
++               * [ 7: 7] Non-Posted
++               *         0 = CPU writes may be posted
++               *         1 = CPU writes must be non-posted
++               * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
++               *         This field defines the upp adddress bits of a 40-bit 
address that
++               *         defines the end of a memory-mapped I/O region n
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x84), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x8C), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x94), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x9C), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA4), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xAC), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB4), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xBC), 0x00000048, 
0x00000000,
++
++              /* Memory-Mapped I/O Base i Registers
++               * F1:0x80 i = 0
++               * F1:0x88 i = 1
++               * F1:0x90 i = 2
++               * F1:0x98 i = 3
++               * F1:0xA0 i = 4
++               * F1:0xA8 i = 5
++               * F1:0xB0 i = 6
++               * F1:0xB8 i = 7
++               * [ 0: 0] Read Enable
++               *         0 = Reads disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes disabled
++               *         1 = Writes Enabled
++               * [ 2: 2] Cpu Disable
++               *         0 = Cpu can use this I/O range
++               *         1 = Cpu requests do not use this I/O range
++               * [ 3: 3] Lock
++               *         0 = base/limit registers i are read/write
++               *         1 = base/limit registers i are read-only
++               * [ 7: 4] Reserved
++               * [31: 8] Memory-Mapped I/O Base Address i (39-16)
++               *         This field defines the upper address bits of a 40bit 
address
++               *         that defines the start of memory-mapped I/O region i
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x80), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x88), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x90), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x98), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA0), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA8), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB0), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB8), 0x000000f0, 
0x00000000,
++
++              /* PCI I/O Limit i Registers
++               * F1:0xC4 i = 0
++               * F1:0xCC i = 1
++               * F1:0xD4 i = 2
++               * F1:0xDC i = 3
++               * [ 2: 0] Destination Node ID
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 3: 3] Reserved
++               * [ 5: 4] Destination Link ID
++               *         00 = Link 0
++               *         01 = Link 1
++               *         10 = Link 2
++               *         11 = Link 3
++               * [11: 6] Reserved
++               * [24:12] PCI I/O Limit Address i
++               *         This field defines the end of PCI I/O region n
++               * [31:25] Reserved
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC4), 0xFE000FC8, 
0x00fff110, /* link 3 of cpu 0 --> AMD SR5690 */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xCC), 0xFE000FC8, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD4), 0xFE000FC8, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xDC), 0xFE000FC8, 
0x00000000,
++
++              /* PCI I/O Base i Registers
++               * F1:0xC0 i = 0
++               * F1:0xC8 i = 1
++               * F1:0xD0 i = 2
++               * F1:0xD8 i = 3
++               * [ 0: 0] Read Enable
++               *         0 = Reads Disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes Disabled
++               *         1 = Writes Enabled
++               * [ 3: 2] Reserved
++               * [ 4: 4] VGA Enable
++               *         0 = VGA matches Disabled
++               *         1 = matches all address < 64K and where A[9:0] is in 
the
++               *             range 3B0-3BB or 3C0-3DF independent of the base 
& limit registers
++               * [ 5: 5] ISA Enable
++               *         0 = ISA matches Disabled
++               *         1 = Blocks address < 64K and in the last 768 bytes 
of eack 1K block
++               *             from matching agains this base/limit pair
++               * [11: 6] Reserved
++               * [24:12] PCI I/O Base i
++               *         This field defines the start of PCI I/O region n
++               * [31:25] Reserved
++               */
++//            PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC0), 0xFE000FCC, 
0x00001013,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC8), 0xFE000FCC, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD0), 0xFE000FCC, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD8), 0xFE000FCC, 
0x00000000,
++
++              /* Config Base and Limit i Registers
++               * F1:0xE0 i = 0
++               * F1:0xE4 i = 1
++               * F1:0xE8 i = 2
++               * F1:0xEC i = 3
++               * [ 0: 0] Read Enable
++               *         0 = Reads Disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes Disabled
++               *         1 = Writes Enabled
++               * [ 2: 2] Device Number Compare Enable
++               *         0 = The ranges are based on bus number
++               *         1 = The ranges are ranges of devices on bus 0
++               * [ 3: 3] Reserved
++               * [ 6: 4] Destination Node
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 7: 7] Reserved
++               * [ 9: 8] Destination Link
++               *         00 = Link 0
++               *         01 = Link 1
++               *         10 = Link 2
++               *         11 - Link 3
++               * [15:10] Reserved
++               * [23:16] Bus Number Base i
++               *         This field defines the lowest bus number in 
configuration region i
++               * [31:24] Bus Number Limit i
++               *         This field defines the highest bus number in 
configuration region i
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE0), 0x0000FC88, 
0x05000303, /* link 3 of cpu 0 --> AMD SR5690 */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE4), 0x0000FC88, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE8), 0x0000FC88, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xEC), 0x0000FC88, 
0x00000000,
++
++      };
++
++      int max;
++      max = ARRAY_SIZE(register_values);
++      setup_resource_map(register_values, max);
++}
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+new file mode 100644
+index 0000000..9964cfe
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -0,0 +1,422 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * Copyright (C) 2007 AMD
++ * Written by Yinghai Lu <address@hidden> for AMD.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <stdint.h>
++#include <string.h>
++#include <reset.h>
++#include <device/pci_def.h>
++#include <device/pci_ids.h>
++#include <arch/io.h>
++#include <device/pnp_def.h>
++#include <cpu/x86/lapic.h>
++#include <console/console.h>
++#include <timestamp.h>
++#include <lib.h>
++#include <spd.h>
++#include <cpu/amd/model_10xxx_rev.h>
++#include <northbridge/amd/amdfam10/raminit.h>
++#include <northbridge/amd/amdfam10/amdfam10.h>
++#include "lib/delay.c"
++#include <cpu/x86/lapic.h>
++#include "northbridge/amd/amdfam10/reset_test.c"
++#include <superio/nuvoton/common/nuvoton.h>
++#include <superio/nuvoton/nct5572d/nct5572d.h>
++#include <cpu/x86/bist.h>
++// #include "northbridge/amd/amdk8/incoherent_ht.c"
++#include <southbridge/amd/sb700/sb700.h>
++#include <southbridge/amd/sb700/smbus.h>
++#include <southbridge/amd/sr5650/sr5650.h>
++#include "northbridge/amd/amdfam10/debug.c"
++#include "northbridge/amd/amdfam10/setup_resource_map.c"
++
++#define SERIAL_DEV PNP_DEV(0x2e, NCT5572D_SP1)
++
++static void activate_spd_rom(const struct mem_controller *ctrl);
++
++static inline int spd_read_byte(unsigned device, unsigned address)
++{
++      return do_smbus_read_byte(SMBUS_AUX_IO_BASE, device, address);
++}
++
++#include <northbridge/amd/amdfam10/amdfam10.h>
++#include "northbridge/amd/amdfam10/raminit_sysinfo_in_ram.c"
++#include "northbridge/amd/amdfam10/pci.c"
++#include "resourcemap.c"
++#include "cpu/amd/quadcore/quadcore.c"
++
++#include <cpu/amd/microcode.h>
++
++#include "cpu/amd/model_10xxx/init_cpus.c"
++#include "northbridge/amd/amdfam10/early_ht.c"
++
++/*
++ * ASUS KGPE-D16 specific SPD enable/disable magic.
++ *
++ * Setting SP5100 GPIOs 59 and 60 controls an SPI mux with four settings:
++ * 0: Disabled
++ * 1: Normal SPI access
++ * 2: CPU0 SPD
++ * 3: CPU1 SPD
++ *
++ * Disable SPD access after RAM init to allow access to standard SMBus/I2C 
offsets
++ * which is required e.g. by lm-sensors.
++ */
++
++/* Relevant GPIO register information is available in the
++ * AMD SP5100 Register Reference Guide rev. 3.03, page 130
++ */
++static void switch_spd_mux(uint8_t channel)
++{
++      uint8_t byte;
++
++      byte = pci_read_config8(PCI_DEV(0, 0x14, 0), 0x54);
++      byte &= ~0xc;                   /* Clear SPD mux GPIOs */
++      byte &= ~0xc0;                  /* Enable SPD mux GPIO output drivers */
++      byte |= (channel << 2) & 0xc;   /* Set SPD mux GPIOs */
++      pci_write_config8(PCI_DEV(0, 0x14, 0), 0x54, byte);
++}
++
++static const uint8_t spd_addr[] = {
++      // Socket 0 Node 0 ("Node 0")
++      RC00, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
++      // Socket 0 Node 1 ("Node 1")
++      RC00, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
++      // Socket 1 Node 1 ("Node 2")
++      RC01, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
++      // Socket 1 Node 0 ("Node 3")
++      RC01, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
++};
++
++static void activate_spd_rom(const struct mem_controller *ctrl) {
++      struct sys_info *sysinfo = &sysinfo_car;
++
++      printk(BIOS_DEBUG, "activate_spd_rom() for node %02x\n", ctrl->node_id);
++      if (ctrl->node_id == 0) {
++              printk(BIOS_DEBUG, "enable_spd_node0()\n");
++              switch_spd_mux(0x2);
++      } else if (ctrl->node_id == 1) {
++              printk(BIOS_DEBUG, "enable_spd_node1()\n");
++              switch_spd_mux((sysinfo->nodes <= 2)?0x2:0x3);
++      } else if (ctrl->node_id == 2) {
++              printk(BIOS_DEBUG, "enable_spd_node2()\n");
++              switch_spd_mux((sysinfo->nodes <= 2)?0x3:0x2);
++      } else if (ctrl->node_id == 3) {
++              printk(BIOS_DEBUG, "enable_spd_node3()\n");
++              switch_spd_mux(0x3);
++      }
++}
++
++/* Voltages are specified by index
++ * Valid indicies for this platform are:
++ * 0: 1.5V
++ * 1: 1.35V
++ * 2: 1.25V
++ * 3: 1.15V
++ */
++static void set_ddr3_voltage(uint8_t node, uint8_t index) {
++      uint8_t byte;
++      uint8_t value;
++
++      if (index == 0)
++              value = 0x0;
++      else if (index == 1)
++              value = 0x1;
++      else if (index == 2)
++              value = 0x4;
++      else if (index == 3)
++              value = 0x5;
++      if (node == 1)
++              value <<= 1;
++
++      /* Set GPIOs */
++      byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0xd1);
++      if (node == 0)
++              byte &= ~0x5;
++      if (node == 1)
++              byte &= ~0xa;
++      byte |= value;
++      pci_write_config8(PCI_DEV(0, 0x14, 3), 0xd1, byte);
++
++      /* Enable GPIO output drivers */
++      byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0xd0);
++      byte &= 0x0f;
++      pci_write_config8(PCI_DEV(0, 0x14, 3), 0xd0, byte);
++}
++
++static void set_peripheral_control_lines(void) {
++      uint8_t byte;
++
++      /* Enable PCICLK5 (onboard FireWire device) */
++      outb(0x41, 0xcd6);
++      outb(0x02, 0xcd7);
++
++      /* Enable the RTC AltCentury register */
++      outb(0x41, 0xcd6);
++      byte = inb(0xcd7);
++      byte |= 0x10;
++      outb(byte, 0xcd7);
++}
++
++#ifdef TEST_MEMORY
++static void execute_memory_test(void)
++{
++      /* Test DRAM functionality */
++      uint32_t i;
++      uint32_t* dataptr;
++      printk(BIOS_DEBUG, "Writing test patterns to memory...\n");
++      for (i=0; i < 0x1000000; i = i + 8) {
++              dataptr = (void *)(0x300000 + i);
++              *dataptr = 0x55555555;
++              dataptr = (void *)(0x300000 + i + 4);
++              *dataptr = 0xaaaaaaaa;
++      }
++      printk(BIOS_DEBUG, "Done!\n");
++      printk(BIOS_DEBUG, "Testing memory...\n");
++      uint32_t readback;
++      for (i=0; i < 0x1000000; i = i + 8) {
++              dataptr = (void *)(0x300000 + i);
++              readback = *dataptr;
++              if (readback != 0x55555555)
++                      printk(BIOS_DEBUG, "%p: INCORRECT VALUE %08x (should 
have been %08x)\n", dataptr, readback, 0x55555555);
++              dataptr = (void *)(0x300000 + i + 4);
++              readback = *dataptr;
++              if (readback != 0xaaaaaaaa)
++                      printk(BIOS_DEBUG, "%p: INCORRECT VALUE %08x (should 
have been %08x)\n", dataptr, readback, 0xaaaaaaaa);
++      }
++      printk(BIOS_DEBUG, "Done!\n");
++}
++#endif
++
++void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
++{
++      struct sys_info *sysinfo = &sysinfo_car;
++
++      u32 bsp_apicid = 0, val;
++      msr_t msr;
++
++      timestamp_init(timestamp_get());
++      timestamp_add_now(TS_START_ROMSTAGE);
++
++      if (!cpu_init_detectedx && boot_cpu()) {
++              /* Nothing special needs to be done to find bus 0 */
++              /* Allow the HT devices to be found */
++              set_bsp_node_CHtExtNodeCfgEn();
++              enumerate_ht_chain();
++
++              /* SR56x0 pcie bridges block pci_locate_device() before pcie 
training.
++               * disable all pcie bridges on SR56x0 to work around it
++               */
++              sr5650_disable_pcie_bridge();
++
++              /* Initialize southbridge */
++              sb7xx_51xx_pci_port80();
++
++              /* Initialize early serial */
++              nuvoton_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
++              console_init();
++      }
++
++      post_code(0x30);
++
++      if (bist == 0)
++              bsp_apicid = init_cpus(cpu_init_detectedx, sysinfo);
++
++      post_code(0x32);
++
++      enable_sr5650_dev8();
++      sb7xx_51xx_lpc_init();
++
++      if (CONFIG_MAX_PHYSICAL_CPUS != 4)
++              printk(BIOS_WARNING, "CONFIG_MAX_PHYSICAL_CPUS is %d, but this 
is a dual socket AMD G34 board!\n", CONFIG_MAX_PHYSICAL_CPUS);
++
++      /* Halt if there was a built in self test failure */
++      report_bist_failure(bist);
++
++      val = cpuid_eax(1);
++      printk(BIOS_DEBUG, "BSP Family_Model: %08x\n", val);
++      printk(BIOS_DEBUG, "*sysinfo range: [%p,%p]\n",sysinfo,sysinfo+1);
++      printk(BIOS_DEBUG, "bsp_apicid = %02x\n", bsp_apicid);
++      printk(BIOS_DEBUG, "cpu_init_detectedx = %08lx\n", cpu_init_detectedx);
++
++      /* Setup sysinfo defaults */
++      set_sysinfo_in_ram(0);
++
++      update_microcode(val);
++
++      post_code(0x33);
++
++      cpuSetAMDMSR();
++      post_code(0x34);
++
++      amd_ht_init(sysinfo);
++      amd_ht_fixup(sysinfo);
++      post_code(0x35);
++
++      /* Set DDR memory voltage
++       * FIXME
++       * This should be set based on the output of the DIMM SPDs
++       * For now it is locked to 1.5V
++       */
++      set_ddr3_voltage(0, 0); /* Node 0 */
++      set_ddr3_voltage(1, 0); /* Node 1 */
++
++      /* Setup nodes PCI space and start core 0 AP init. */
++      finalize_node_setup(sysinfo);
++
++      /* Setup any mainboard PCI settings etc. */
++      setup_mb_resource_map();
++      post_code(0x36);
++
++      /* wait for all the APs core0 started by finalize_node_setup. */
++      /* FIXME: A bunch of cores are going to start output to serial at once.
++       * It would be nice to fix up prink spinlocks for ROM XIP mode.
++       * I think it could be done by putting the spinlock flag in the cache
++       * of the BSP located right after sysinfo.
++       */
++      wait_all_core0_started();
++
++      /* run _early_setup before soft-reset. */
++      sr5650_early_setup();
++      sb7xx_51xx_early_setup();
++
++      if (IS_ENABLED(CONFIG_SET_FIDVID)) {
++              msr = rdmsr(0xc0010071);
++              printk(BIOS_DEBUG, "\nBegin FIDVID MSR 0xc0010071 0x%08x 
0x%08x\n", msr.hi, msr.lo);
++
++              /* FIXME: The sb fid change may survive the warm reset and only 
need to be done once */
++              enable_fid_change_on_sb(sysinfo->sbbusn, sysinfo->sbdn);
++
++              post_code(0x39);
++
++              if (!warm_reset_detect(0)) {                    // BSP is node 0
++                      init_fidvid_bsp(bsp_apicid, sysinfo->nodes);
++              } else {
++                      init_fidvid_stage2(bsp_apicid, 0);      // BSP is node 0
++              }
++
++              post_code(0x3A);
++
++              /* show final fid and vid */
++              msr=rdmsr(0xc0010071);
++              printk(BIOS_DEBUG, "End FIDVIDMSR 0xc0010071 0x%08x 0x%08x\n", 
msr.hi, msr.lo);
++      }
++
++      if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
++              /* Core0 on each node is configured. Now setup any additional 
cores. */
++              printk(BIOS_DEBUG, "start_other_cores()\n");
++              start_other_cores();
++              post_code(0x37);
++              wait_all_other_cores_started(bsp_apicid);
++      }
++
++      post_code(0x38);
++
++      init_timer(); // Need to use TMICT to synconize FID/VID
++
++      sr5650_htinit();
++
++      /* Reset for HT, FIDVID, PLL and errata changes to take affect. */
++      if (!warm_reset_detect(0)) {
++              printk(BIOS_INFO, "...WARM RESET...\n\n\n");
++              soft_reset();
++              die("After soft_reset_x - shouldn't see this message!!!\n");
++      }
++
++      /* Set up peripheral control lines */
++      set_peripheral_control_lines();
++
++      post_code(0x3B);
++
++      /* It's the time to set ctrl in sysinfo now; */
++      printk(BIOS_DEBUG, "fill_mem_ctrl() detected %d nodes\n", 
sysinfo->nodes);
++      fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr);
++      post_code(0x3D);
++
++#if 0
++      /* FIXME
++       * After the AMD K10 code has been converted to use
++       * IS_ENABLED(CONFIG_DEBUG_SMBUS) uncomment this block
++       */
++      if (IS_ENABLED(CONFIG_DEBUG_SMBUS)) {
++              dump_spd_registers(&cpu[0]);
++              dump_smbus_registers();
++      }
++#endif
++
++      post_code(0x40);
++
++      timestamp_add_now(TS_BEFORE_INITRAM);
++      printk(BIOS_DEBUG, "raminit_amdmct()\n");
++      raminit_amdmct(sysinfo);
++      timestamp_add_now(TS_AFTER_INITRAM);
++
++#if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
++      cbmem_initialize_empty();
++      post_code(0x41);
++
++      amdmct_cbmem_store_info(sysinfo);
++#endif
++
++      printk(BIOS_DEBUG, "disable_spd()\n");
++      switch_spd_mux(0x1);
++
++      sr5650_before_pci_init();
++      sb7xx_51xx_before_pci_init();
++
++      /* Configure SP5100 GPIOs to match vendor settings */
++      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x50, 0x0170);
++      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x54, 0x0707);
++      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x56, 0x0bb0);
++      pci_write_config16(PCI_DEV(0, 0x14, 0), 0x5a, 0x0ff0);
++
++      timestamp_add_now(TS_END_ROMSTAGE);
++
++#ifdef TEST_MEMORY
++      execute_memory_test();
++#endif
++
++      post_cache_as_ram();    // BSP switch stack to ram, copy then execute 
LB.
++      post_code(0x43);        // Should never see this post code.
++}
++
++/**
++ * BOOL AMD_CB_ManualBUIDSwapList(u8 Node, u8 Link, u8 **List)
++ * Description:
++ *    This routine is called every time a non-coherent chain is processed.
++ *    BUID assignment may be controlled explicitly on a non-coherent chain. 
Provide a
++ *    swap list. The first part of the list controls the BUID assignment and 
the
++ *    second part of the list provides the device to device linking.  Device 
orientation
++ *    can be detected automatically, or explicitly.  See documentation for 
more details.
++ *
++ *    Automatic non-coherent init assigns BUIDs starting at 1 and 
incrementing sequentially
++ *    based on each device's unit count.
++ *
++ * Parameters:
++ *    @param[in]  node   = The node on which this chain is located
++ *    @param[in]  link   = The link on the host for this chain
++ *    @param[out] List   = supply a pointer to a list
++ */
++BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 **List)
++{
++      return 0;
++}
+\ No newline at end of file
+diff --git a/src/mainboard/asus/kgpe-d16/spd_notes.txt 
b/src/mainboard/asus/kgpe-d16/spd_notes.txt
+new file mode 100644
+index 0000000..623a88f
+--- /dev/null
++++ b/src/mainboard/asus/kgpe-d16/spd_notes.txt
+@@ -0,0 +1,30 @@
++====================================================================================================
++SPD mux
++====================================================================================================
++                      SP5100
++                  GPIO 60 GPIO 59
++Disabled             0       0
++Normal operation     0       1
++CPU 0 SPD            1       0
++CPU 1 SPD            1       1
++
++====================================================================================================
++W83795
++====================================================================================================
++
++Sensor mappings:
++CPU_FAN1:  FAN1
++CPU_FAN2:  FAN2
++FRNT_FAN1: FAN3
++FRNT_FAN2: FAN4
++FRNT_FAN3: FAN5
++FRNT_FAN4: FAN6
++FRNT_FAN5: FAN7
++REAR_FAN1: FAN8
++
++====================================================================================================
++Other hardware
++====================================================================================================
++
++RECOVERY1 middle pin is connected to southbridge (AMD SP5100) GPIO 61
++Normal is HIGH, recovery is LOW.
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
 
b/resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
deleted file mode 100644
index 073e2dc..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0014-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 7137414550b7ef1d1f1d90e31c73eda392ab663d Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 11 Aug 2015 18:38:06 -0500
-Subject: [PATCH 014/139] mainboard/asus/kgpe-d16: Add nvram option to
- enable/disable the IEEE1394 controller
-
-Change-Id: I4f0f6c1cb1fad5b65f196dc6b443252a0ecc70a1
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/cmos.default |  1 +
- src/mainboard/asus/kgpe-d16/cmos.layout  |  1 +
- src/mainboard/asus/kgpe-d16/romstage.c   | 21 +++++++++++++++++----
- 3 files changed, 19 insertions(+), 4 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index cffdd03..e920297 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -12,5 +12,6 @@ ecc_scrub_rate = 1.28us
- interleave_chip_selects = Enable
- interleave_nodes = Disable
- interleave_memory_channels = Enable
-+ieee1394 = Enable
- power_on_after_fail = On
- boot_option = Fallback
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index bcf9cd3..b9266dc 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -41,6 +41,7 @@ entries
- 456          1       e       1        ECC_memory
- 457          1       e       1        ECC_redirection
- 458          4       e       11       hypertransport_speed_limit
-+477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
- # Reserve the extended AMD configuration registers
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index 9964cfe..616fdfb 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -165,10 +165,23 @@ static void set_ddr3_voltage(uint8_t node, uint8_t 
index) {
- 
- static void set_peripheral_control_lines(void) {
-       uint8_t byte;
--
--      /* Enable PCICLK5 (onboard FireWire device) */
--      outb(0x41, 0xcd6);
--      outb(0x02, 0xcd7);
-+      uint8_t nvram;
-+      uint8_t enable_ieee1394;
-+
-+      enable_ieee1394 = 1;
-+
-+      if (get_option(&nvram, "ieee1394") == CB_SUCCESS)
-+              enable_ieee1394 = nvram & 0x1;
-+
-+      if (enable_ieee1394) {
-+              /* Enable PCICLK5 (onboard FireWire device) */
-+              outb(0x41, 0xcd6);
-+              outb(0x02, 0xcd7);
-+      } else {
-+              /* Disable PCICLK5 (onboard FireWire device) */
-+              outb(0x41, 0xcd6);
-+              outb(0x00, 0xcd7);
-+      }
- 
-       /* Enable the RTC AltCentury register */
-       outb(0x41, 0xcd6);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0015-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
 
b/resources/libreboot/patch/kgpe-d16/0015-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
deleted file mode 100644
index 1bf44c0..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0015-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
+++ /dev/null
@@ -1,116 +0,0 @@
-From 158141bedc473c21a11918605dc7e76eee0c43e5 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:46:54 -0500
-Subject: [PATCH 015/139] cpu/amd/model_10xxx: Clean up debugging statements
-
-Change-Id: I6dff74b3857e1fb384aefc87b44e7679bd4aab07
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/model_10xxx/fidvid.c | 43 ++++++++++++++++++++--------------------
- 1 file changed, 21 insertions(+), 22 deletions(-)
-
-diff --git a/src/cpu/amd/model_10xxx/fidvid.c 
b/src/cpu/amd/model_10xxx/fidvid.c
-index 36bdf36..99ffcc8 100644
---- a/src/cpu/amd/model_10xxx/fidvid.c
-+++ b/src/cpu/amd/model_10xxx/fidvid.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -460,35 +461,35 @@ static void config_clk_power_ctrl_reg0(int node, u32 
cpuRev, u8 procPkg) {
- 
- static void config_power_ctrl_misc_reg(device_t dev,u32 cpuRev, u8 procPkg) {
-       /* check PVI/SVI */
--      u32 dword = pci_read_config32(dev, 0xA0);
-+      u32 dword = pci_read_config32(dev, 0xa0);
- 
--        /* BKDG r31116 2010-04-22  2.4.1.7 step b F3xA0[VSSlamVidMod] */
--        /* PllLockTime and PsiVidEn set in ruleset in defaults.h */
-+      /* BKDG r31116 2010-04-22  2.4.1.7 step b F3xA0[VSSlamVidMod] */
-+      /* PllLockTime and PsiVidEn set in ruleset in defaults.h */
-       if (dword & PVI_MODE) { /* PVI */
-               /* set slamVidMode to 0 for PVI */
-               dword &= VID_SLAM_OFF ;
-       } else {        /* SVI */
-               /* set slamVidMode to 1 for SVI */
-               dword |= VID_SLAM_ON;
--        }
-+      }
-         /* set the rest of A0 since we're at it... */
- 
--        if (cpuRev & (AMD_DA_Cx | AMD_RB_C3 )) {
--           dword |= NB_PSTATE_FORCE_ON;
-+      if (cpuRev & (AMD_DA_Cx | AMD_RB_C3 )) {
-+              dword |= NB_PSTATE_FORCE_ON;
-       } // else should we clear it ?
- 
- 
-         if ((procPkg == AMD_PKGTYPE_G34) || (procPkg == AMD_PKGTYPE_C32) ) {
--        dword |= BP_INS_TRI_EN_ON ;
-+              dword |= BP_INS_TRI_EN_ON ;
-       }
- 
-          /* TODO: look into C1E state and F3xA0[IdleExitEn]*/
-         #if CONFIG_SVI_HIGH_FREQ
--         if (cpuRev & AMD_FAM10_C3) {
--           dword |= SVI_HIGH_FREQ_ON;
--           }
--        #endif
--      pci_write_config32(dev, 0xA0, dword);
-+      if (cpuRev & AMD_FAM10_C3) {
-+              dword |= SVI_HIGH_FREQ_ON;
-+      }
-+      #endif
-+      pci_write_config32(dev, 0xa0, dword);
- }
- 
- static void config_nb_syn_ptr_adj(device_t dev, u32 cpuRev) {
-@@ -581,7 +582,7 @@ static void prep_fid_change(void)
-       nodes = get_nodes();
- 
-       for (i = 0; i < nodes; i++) {
--              printk(BIOS_DEBUG, "Prep FID/VID Node:%02x \n", i);
-+              printk(BIOS_DEBUG, "Prep FID/VID Node:%02x\n", i);
-               dev = NODE_PCI(i, 3);
-                 u32 cpuRev = mctGetLogicalCPUID(0xFF) ;
-               u8 procPkg =  mctGetProcessorPackageType();
-@@ -591,25 +592,23 @@ static void prep_fid_change(void)
-               /* Figure out the value for VsSlamTime and program it */
-               recalculateVsSlamTimeSettingOnCorePre(dev);
- 
--                config_clk_power_ctrl_reg0(i,cpuRev,procPkg);
-+              config_clk_power_ctrl_reg0(i,cpuRev,procPkg);
- 
-                 config_power_ctrl_misc_reg(dev,cpuRev,procPkg);
-               config_nb_syn_ptr_adj(dev,cpuRev);
- 
--                config_acpi_pwr_state_ctrl_regs(dev,cpuRev,procPkg);
-+              config_acpi_pwr_state_ctrl_regs(dev,cpuRev,procPkg);
- 
-               dword = pci_read_config32(dev, 0x80);
--              printk(BIOS_DEBUG, "  F3x80: %08x \n", dword);
-+              printk(BIOS_DEBUG, "  F3x80: %08x\n", dword);
-               dword = pci_read_config32(dev, 0x84);
--              printk(BIOS_DEBUG, "  F3x84: %08x \n", dword);
-+              printk(BIOS_DEBUG, "  F3x84: %08x\n", dword);
-               dword = pci_read_config32(dev, 0xD4);
--              printk(BIOS_DEBUG, "  F3xD4: %08x \n", dword);
-+              printk(BIOS_DEBUG, "  F3xD4: %08x\n", dword);
-               dword = pci_read_config32(dev, 0xD8);
--              printk(BIOS_DEBUG, "  F3xD8: %08x \n", dword);
-+              printk(BIOS_DEBUG, "  F3xD8: %08x\n", dword);
-               dword = pci_read_config32(dev, 0xDC);
--              printk(BIOS_DEBUG, "  F3xDC: %08x \n", dword);
--
--
-+              printk(BIOS_DEBUG, "  F3xDC: %08x\n", dword);
-       }
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0015-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
 
b/resources/libreboot/patch/kgpe-d16/0015-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
new file mode 100644
index 0000000..7f431f5
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0015-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch
@@ -0,0 +1,72 @@
+From b6b068c466059602175a86a1fdbf3a0031c53387 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 11 Aug 2015 18:38:06 -0500
+Subject: [PATCH 015/143] mainboard/asus/kgpe-d16: Add nvram option to
+ enable/disable the IEEE1394 controller
+
+Change-Id: I4f0f6c1cb1fad5b65f196dc6b443252a0ecc70a1
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.default |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout  |    1 +
+ src/mainboard/asus/kgpe-d16/romstage.c   |   21 +++++++++++++++++----
+ 3 files changed, 19 insertions(+), 4 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index cffdd03..e920297 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -12,5 +12,6 @@ ecc_scrub_rate = 1.28us
+ interleave_chip_selects = Enable
+ interleave_nodes = Disable
+ interleave_memory_channels = Enable
++ieee1394 = Enable
+ power_on_after_fail = On
+ boot_option = Fallback
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index bcf9cd3..b9266dc 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -41,6 +41,7 @@ entries
+ 456          1       e       1        ECC_memory
+ 457          1       e       1        ECC_redirection
+ 458          4       e       11       hypertransport_speed_limit
++477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+ # Reserve the extended AMD configuration registers
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index 9964cfe..616fdfb 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -165,10 +165,23 @@ static void set_ddr3_voltage(uint8_t node, uint8_t 
index) {
+ 
+ static void set_peripheral_control_lines(void) {
+       uint8_t byte;
+-
+-      /* Enable PCICLK5 (onboard FireWire device) */
+-      outb(0x41, 0xcd6);
+-      outb(0x02, 0xcd7);
++      uint8_t nvram;
++      uint8_t enable_ieee1394;
++
++      enable_ieee1394 = 1;
++
++      if (get_option(&nvram, "ieee1394") == CB_SUCCESS)
++              enable_ieee1394 = nvram & 0x1;
++
++      if (enable_ieee1394) {
++              /* Enable PCICLK5 (onboard FireWire device) */
++              outb(0x41, 0xcd6);
++              outb(0x02, 0xcd7);
++      } else {
++              /* Disable PCICLK5 (onboard FireWire device) */
++              outb(0x41, 0xcd6);
++              outb(0x00, 0xcd7);
++      }
+ 
+       /* Enable the RTC AltCentury register */
+       outb(0x41, 0xcd6);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0016-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
 
b/resources/libreboot/patch/kgpe-d16/0016-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
new file mode 100644
index 0000000..bd6a820
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0016-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch
@@ -0,0 +1,108 @@
+From 51e23836f586c79d63ca402bad738bd7a4149572 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:46:54 -0500
+Subject: [PATCH 016/143] cpu/amd/model_10xxx: Clean up debugging statements
+
+Change-Id: I6dff74b3857e1fb384aefc87b44e7679bd4aab07
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/model_10xxx/fidvid.c |   42 ++++++++++++++++++--------------------
+ 1 file changed, 20 insertions(+), 22 deletions(-)
+
+diff --git a/src/cpu/amd/model_10xxx/fidvid.c 
b/src/cpu/amd/model_10xxx/fidvid.c
+index 36bdf36..5b1c581 100644
+--- a/src/cpu/amd/model_10xxx/fidvid.c
++++ b/src/cpu/amd/model_10xxx/fidvid.c
+@@ -460,35 +460,35 @@ static void config_clk_power_ctrl_reg0(int node, u32 
cpuRev, u8 procPkg) {
+ 
+ static void config_power_ctrl_misc_reg(device_t dev,u32 cpuRev, u8 procPkg) {
+       /* check PVI/SVI */
+-      u32 dword = pci_read_config32(dev, 0xA0);
++      u32 dword = pci_read_config32(dev, 0xa0);
+ 
+-        /* BKDG r31116 2010-04-22  2.4.1.7 step b F3xA0[VSSlamVidMod] */
+-        /* PllLockTime and PsiVidEn set in ruleset in defaults.h */
++      /* BKDG r31116 2010-04-22  2.4.1.7 step b F3xA0[VSSlamVidMod] */
++      /* PllLockTime and PsiVidEn set in ruleset in defaults.h */
+       if (dword & PVI_MODE) { /* PVI */
+               /* set slamVidMode to 0 for PVI */
+               dword &= VID_SLAM_OFF ;
+       } else {        /* SVI */
+               /* set slamVidMode to 1 for SVI */
+               dword |= VID_SLAM_ON;
+-        }
++      }
+         /* set the rest of A0 since we're at it... */
+ 
+-        if (cpuRev & (AMD_DA_Cx | AMD_RB_C3 )) {
+-           dword |= NB_PSTATE_FORCE_ON;
++      if (cpuRev & (AMD_DA_Cx | AMD_RB_C3 )) {
++              dword |= NB_PSTATE_FORCE_ON;
+       } // else should we clear it ?
+ 
+ 
+         if ((procPkg == AMD_PKGTYPE_G34) || (procPkg == AMD_PKGTYPE_C32) ) {
+-        dword |= BP_INS_TRI_EN_ON ;
++              dword |= BP_INS_TRI_EN_ON ;
+       }
+ 
+          /* TODO: look into C1E state and F3xA0[IdleExitEn]*/
+         #if CONFIG_SVI_HIGH_FREQ
+-         if (cpuRev & AMD_FAM10_C3) {
+-           dword |= SVI_HIGH_FREQ_ON;
+-           }
+-        #endif
+-      pci_write_config32(dev, 0xA0, dword);
++      if (cpuRev & AMD_FAM10_C3) {
++              dword |= SVI_HIGH_FREQ_ON;
++      }
++      #endif
++      pci_write_config32(dev, 0xa0, dword);
+ }
+ 
+ static void config_nb_syn_ptr_adj(device_t dev, u32 cpuRev) {
+@@ -581,7 +581,7 @@ static void prep_fid_change(void)
+       nodes = get_nodes();
+ 
+       for (i = 0; i < nodes; i++) {
+-              printk(BIOS_DEBUG, "Prep FID/VID Node:%02x \n", i);
++              printk(BIOS_DEBUG, "Prep FID/VID Node:%02x\n", i);
+               dev = NODE_PCI(i, 3);
+                 u32 cpuRev = mctGetLogicalCPUID(0xFF) ;
+               u8 procPkg =  mctGetProcessorPackageType();
+@@ -591,25 +591,23 @@ static void prep_fid_change(void)
+               /* Figure out the value for VsSlamTime and program it */
+               recalculateVsSlamTimeSettingOnCorePre(dev);
+ 
+-                config_clk_power_ctrl_reg0(i,cpuRev,procPkg);
++              config_clk_power_ctrl_reg0(i,cpuRev,procPkg);
+ 
+                 config_power_ctrl_misc_reg(dev,cpuRev,procPkg);
+               config_nb_syn_ptr_adj(dev,cpuRev);
+ 
+-                config_acpi_pwr_state_ctrl_regs(dev,cpuRev,procPkg);
++              config_acpi_pwr_state_ctrl_regs(dev,cpuRev,procPkg);
+ 
+               dword = pci_read_config32(dev, 0x80);
+-              printk(BIOS_DEBUG, "  F3x80: %08x \n", dword);
++              printk(BIOS_DEBUG, "  F3x80: %08x\n", dword);
+               dword = pci_read_config32(dev, 0x84);
+-              printk(BIOS_DEBUG, "  F3x84: %08x \n", dword);
++              printk(BIOS_DEBUG, "  F3x84: %08x\n", dword);
+               dword = pci_read_config32(dev, 0xD4);
+-              printk(BIOS_DEBUG, "  F3xD4: %08x \n", dword);
++              printk(BIOS_DEBUG, "  F3xD4: %08x\n", dword);
+               dword = pci_read_config32(dev, 0xD8);
+-              printk(BIOS_DEBUG, "  F3xD8: %08x \n", dword);
++              printk(BIOS_DEBUG, "  F3xD8: %08x\n", dword);
+               dword = pci_read_config32(dev, 0xDC);
+-              printk(BIOS_DEBUG, "  F3xDC: %08x \n", dword);
+-
+-
++              printk(BIOS_DEBUG, "  F3xDC: %08x\n", dword);
+       }
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0016-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0016-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
deleted file mode 100644
index 446d1e8..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0016-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
+++ /dev/null
@@ -1,367 +0,0 @@
-From 4e9327a08f16505bbcdeb49592ded51873a4d62f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:14:25 -0500
-Subject: [PATCH 016/139] southbridge/amd/sb700: Add Suspend to RAM (S3)
- support
-
-Change-Id: Ic643e31b721f11a90d8fb5f8c8f8a3b7892c0d73
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/Makefile.inc  |   1 +
- src/southbridge/amd/sb700/bootblock.c   |   4 +-
- src/southbridge/amd/sb700/early_setup.c |  39 +++++++--
- src/southbridge/amd/sb700/lpc.c         |  12 ++-
- src/southbridge/amd/sb700/sb700.h       |   3 +
- src/southbridge/amd/sb700/spi.c         | 148 ++++++++++++++++++++++++++++++++
- src/southbridge/amd/sb700/spi.h         |  21 +++++
- 7 files changed, 216 insertions(+), 12 deletions(-)
- create mode 100644 src/southbridge/amd/sb700/spi.c
- create mode 100644 src/southbridge/amd/sb700/spi.h
-
-diff --git a/src/southbridge/amd/sb700/Makefile.inc 
b/src/southbridge/amd/sb700/Makefile.inc
-index 5ec8431..538a7c1 100644
---- a/src/southbridge/amd/sb700/Makefile.inc
-+++ b/src/southbridge/amd/sb700/Makefile.inc
-@@ -12,6 +12,7 @@ ramstage-y += pci.c
- ramstage-$(CONFIG_HAVE_ACPI_TABLES) += fadt.c
- romstage-y += reset.c
- ramstage-y += reset.c
-+ramstage-y += spi.c
- romstage-$(CONFIG_USBDEBUG_IN_ROMSTAGE) += enable_usbdebug.c
- ramstage-$(CONFIG_USBDEBUG) += enable_usbdebug.c
- 
-diff --git a/src/southbridge/amd/sb700/bootblock.c 
b/src/southbridge/amd/sb700/bootblock.c
-index 8f722a8..46e5597 100644
---- a/src/southbridge/amd/sb700/bootblock.c
-+++ b/src/southbridge/amd/sb700/bootblock.c
-@@ -71,7 +71,7 @@ static void sb700_enable_rom(void)
-       /* Enable LPC ROM range end at 0xffff(ffff). */
-       pci_io_write_config16(dev, 0x6e, 0xffff);
- 
--      /* SB700 LPC Bridge 0x48h.
-+      /* SB700 LPC Bridge 0x48.
-        * Turn on all LPC IO Port decode enables
-        */
-       dword = pci_io_read_config32(dev, 0x44);
-@@ -89,7 +89,7 @@ static void sb700_enable_rom(void)
-       reg8 |= (1<<0) | (1<<1) | (1<<4) | (1<<6);
-       pci_io_write_config8(dev, 0x48, reg8);
- 
--      /* SB700 LPC Bridge 0x4ah.
-+      /* SB700 LPC Bridge 0x4a.
-        * BIT4: Port Enable for Port 0x80
-        */
-       reg8 = pci_io_read_config8(dev, 0x4a);
-diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
-index de3fa97..a6849b0 100644
---- a/src/southbridge/amd/sb700/early_setup.c
-+++ b/src/southbridge/amd/sb700/early_setup.c
-@@ -474,8 +474,10 @@ static void sb700_devices_por_init(void)
-       /* LPC Device, BDF:0-20-3 */
-       printk(BIOS_INFO, "sb700_devices_por_init(): LPC Device, BDF:0-20-3\n");
-       dev = pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
--      /* DMA enable */
--      pci_write_config8(dev, 0x40, 0x04);
-+      if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
-+              /* DMA enable */
-+              pci_write_config8(dev, 0x40, 0x04);
-+      }
- 
-       /* IO Port Decode Enable */
-       pci_write_config8(dev, 0x44, 0xFF);
-@@ -618,6 +620,17 @@ static void sb700_pmio_por_init(void)
-       byte = pmio_read(0xB2);
-       byte |= 1 << 0;
-       pmio_write(0xB2, byte);
-+
-+      // FIXME: Enabling this causes boot to hang while initializing 
processors.
-+//    /* Enable automatic C1e state switch */
-+//    byte = pmio_read(0xc9);
-+//    byte |= 0x11;
-+//    pmio_write(0xc9, byte);
-+
-+      /* Enable precision HPET clock and automatic C state switch */
-+      byte = pmio_read(0xbb);
-+      byte |= 0xc0;
-+      pmio_write(0xbb, byte);
- }
- 
- /*
-@@ -653,10 +666,12 @@ static void sb700_pci_cfg(void)
-        * mentioned in RPR. But I keep them. The registers and the
-        * comments are compatible. */
-       dev = pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
--      /* Enabling LPC DMA function. */
--      byte = pci_read_config8(dev, 0x40);
--      byte |= (1 << 2);
--      pci_write_config8(dev, 0x40, byte);
-+      if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
-+              /* Enabling LPC DMA function. */
-+              byte = pci_read_config8(dev, 0x40);
-+              byte |= (1 << 2);
-+              pci_write_config8(dev, 0x40, byte);
-+      }
-       /* Disabling LPC TimeOut. 0x48[7] clear. */
-       byte = pci_read_config8(dev, 0x48);
-       byte &= 0x7f;
-@@ -746,6 +761,18 @@ int acpi_get_sleep_type(void)
-       return ((tmp & (7 << 10)) >> 10);
- }
- 
-+void set_lpc_sticky_ctl(bool enable)
-+{
-+      uint8_t byte;
-+
-+      byte = pmio_read(0xbb);
-+      if (enable)
-+              byte |= 0x20;
-+      else
-+              byte &= ~0x20;
-+      pmio_write(0xbb, byte);
-+}
-+
- #if IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
- unsigned long get_top_of_ram(void)
- {
-diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c
-index 0cc1e8b..145a01f 100644
---- a/src/southbridge/amd/sb700/lpc.c
-+++ b/src/southbridge/amd/sb700/lpc.c
-@@ -61,10 +61,12 @@ static void lpc_init(device_t dev)
-       isa_dma_init();
- #endif
- 
--      /* Enable DMA transaction on the LPC bus */
--      byte = pci_read_config8(dev, 0x40);
--      byte |= (1 << 2);
--      pci_write_config8(dev, 0x40, byte);
-+      if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
-+              /* Enable DMA transaction on the LPC bus */
-+              byte = pci_read_config8(dev, 0x40);
-+              byte |= (1 << 2);
-+              pci_write_config8(dev, 0x40, byte);
-+      }
- 
-       /* Disable the timeout mechanism on LPC */
-       byte = pci_read_config8(dev, 0x48);
-@@ -85,11 +87,13 @@ static void lpc_init(device_t dev)
-       cmos_check_update_date();
- }
- 
-+#if (!IS_ENABLED(CONFIG_EARLY_CBMEM_INIT))
- int acpi_get_sleep_type(void)
- {
-       u16 tmp = inw(ACPI_PM1_CNT_BLK);
-       return ((tmp & (7 << 10)) >> 10);
- }
-+#endif
- 
- #if IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
- void backup_top_of_ram(uint64_t ramtop)
-diff --git a/src/southbridge/amd/sb700/sb700.h 
b/src/southbridge/amd/sb700/sb700.h
-index ca020a5..b477091 100644
---- a/src/southbridge/amd/sb700/sb700.h
-+++ b/src/southbridge/amd/sb700/sb700.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -75,6 +76,8 @@ void sb7xx_51xx_setup_sata_phys(struct device *dev);
- 
- #endif
- 
-+void set_lpc_sticky_ctl(bool enable);
-+
- int s3_save_nvram_early(u32 dword, int size, int  nvram_pos);
- int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos);
- 
-diff --git a/src/southbridge/amd/sb700/spi.c b/src/southbridge/amd/sb700/spi.c
-new file mode 100644
-index 0000000..a38ca2b
---- /dev/null
-+++ b/src/southbridge/amd/sb700/spi.c
-@@ -0,0 +1,148 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2012 Advanced Micro Devices, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include <stdint.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <arch/io.h>
-+#include <console/console.h>
-+#include <spi-generic.h>
-+#include <spi_flash.h>
-+#include <device/device.h>
-+#include <device/pci.h>
-+#include <device/pci_ops.h>
-+
-+#define AMD_SB_SPI_TX_LEN 8
-+
-+static uint32_t get_spi_bar(void)
-+{
-+      device_t dev;
-+
-+      dev = dev_find_slot(0, PCI_DEVFN(0x14, 3));
-+      return pci_read_config32(dev, 0xa0) & ~0x1f;
-+}
-+
-+void spi_init(void)
-+{
-+      /* Not needed */
-+}
-+
-+unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
-+{
-+      return min(AMD_SB_SPI_TX_LEN - cmd_len, buf_len);
-+}
-+
-+static void reset_internal_fifo_pointer(void)
-+{
-+      uint32_t spibar = get_spi_bar();
-+
-+      do {
-+              write8((void *)(spibar + 2),
-+              read8((void *)(spibar + 2)) | 0x10);
-+      } while (read8((void *)(spibar + 0xd)) & 0x7);
-+}
-+
-+static void execute_command(void)
-+{
-+      uint32_t spibar = get_spi_bar();
-+
-+      write8((void *)(spibar + 2), read8((void *)(spibar + 2)) | 1);
-+
-+      while ((read8((void *)(spibar + 2)) & 1) &&
-+              (read8((void *)(spibar+3)) & 0x80));
-+}
-+
-+int spi_claim_bus(struct spi_slave *slave)
-+{
-+      /* Handled internally by the SB700 */
-+      return 0;
-+}
-+
-+void spi_release_bus(struct spi_slave *slave)
-+{
-+      /* Handled internally by the SB700 */
-+}
-+
-+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
-+{
-+      struct spi_slave *slave = malloc(sizeof(*slave));
-+
-+      if (!slave) {
-+              return NULL;
-+      }
-+
-+      memset(slave, 0, sizeof(*slave));
-+
-+      return slave;
-+}
-+
-+int spi_xfer(struct spi_slave *slave, const void *dout,
-+              unsigned int bytesout, void *din, unsigned int bytesin)
-+{
-+      /* First byte is cmd which cannot be sent through the FIFO. */
-+      u8 cmd = *(u8 *)dout++;
-+      u8 readoffby1;
-+      u8 readwrite;
-+      u8 count;
-+
-+      uint32_t spibar = get_spi_bar();
-+
-+      bytesout--;
-+
-+      /*
-+       * Check if this is a write command attempting to transfer more bytes
-+       * than the controller can handle. Iterations for writes are not
-+       * supported here because each SPI write command needs to be preceded
-+       * and followed by other SPI commands, and this sequence is controlled
-+       * by the SPI chip driver.
-+       */
-+      if (bytesout > AMD_SB_SPI_TX_LEN) {
-+              printk(BIOS_DEBUG, "FCH SPI: Too much to write. Does your SPI 
chip driver use"
-+                   " spi_crop_chunk()?\n");
-+              return -1;
-+      }
-+
-+      readoffby1 = bytesout ? 0 : 1;
-+
-+      readwrite = (bytesin + readoffby1) << 4 | bytesout;
-+      write8((void *)(spibar + 1), readwrite);
-+      write8((void *)(spibar + 0), cmd);
-+
-+      reset_internal_fifo_pointer();
-+      for (count = 0; count < bytesout; count++, dout++) {
-+              write8((void *)(spibar + 0x0C), *(u8 *)dout);
-+      }
-+
-+      reset_internal_fifo_pointer();
-+      execute_command();
-+
-+      reset_internal_fifo_pointer();
-+      /* Skip the bytes we sent. */
-+      for (count = 0; count < bytesout; count++) {
-+              cmd = read8((void *)(spibar + 0x0C));
-+      }
-+
-+      reset_internal_fifo_pointer();
-+      for (count = 0; count < bytesin; count++, din++) {
-+              *(u8 *)din = read8((void *)(spibar + 0x0C));
-+      }
-+
-+      return 0;
-+}
-\ No newline at end of file
-diff --git a/src/southbridge/amd/sb700/spi.h b/src/southbridge/amd/sb700/spi.h
-new file mode 100644
-index 0000000..9b76b35
---- /dev/null
-+++ b/src/southbridge/amd/sb700/spi.h
-@@ -0,0 +1,21 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+int spi_claim_bus(struct spi_slave *slave);
-+void spi_release_bus(struct spi_slave *slave);
-\ No newline at end of file
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0017-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0017-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
new file mode 100644
index 0000000..1ebc523
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0017-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch
@@ -0,0 +1,367 @@
+From da02322d4086f1f391e2e4354b41c6b7056fc5d2 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:14:25 -0500
+Subject: [PATCH 017/143] southbridge/amd/sb700: Add Suspend to RAM (S3)
+ support
+
+Change-Id: Ic643e31b721f11a90d8fb5f8c8f8a3b7892c0d73
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/Makefile.inc  |    1 +
+ src/southbridge/amd/sb700/bootblock.c   |    4 +-
+ src/southbridge/amd/sb700/early_setup.c |   39 ++++++--
+ src/southbridge/amd/sb700/lpc.c         |   12 ++-
+ src/southbridge/amd/sb700/sb700.h       |    3 +
+ src/southbridge/amd/sb700/spi.c         |  148 +++++++++++++++++++++++++++++++
+ src/southbridge/amd/sb700/spi.h         |   21 +++++
+ 7 files changed, 216 insertions(+), 12 deletions(-)
+ create mode 100644 src/southbridge/amd/sb700/spi.c
+ create mode 100644 src/southbridge/amd/sb700/spi.h
+
+diff --git a/src/southbridge/amd/sb700/Makefile.inc 
b/src/southbridge/amd/sb700/Makefile.inc
+index 5ec8431..538a7c1 100644
+--- a/src/southbridge/amd/sb700/Makefile.inc
++++ b/src/southbridge/amd/sb700/Makefile.inc
+@@ -12,6 +12,7 @@ ramstage-y += pci.c
+ ramstage-$(CONFIG_HAVE_ACPI_TABLES) += fadt.c
+ romstage-y += reset.c
+ ramstage-y += reset.c
++ramstage-y += spi.c
+ romstage-$(CONFIG_USBDEBUG_IN_ROMSTAGE) += enable_usbdebug.c
+ ramstage-$(CONFIG_USBDEBUG) += enable_usbdebug.c
+ 
+diff --git a/src/southbridge/amd/sb700/bootblock.c 
b/src/southbridge/amd/sb700/bootblock.c
+index 8f722a8..46e5597 100644
+--- a/src/southbridge/amd/sb700/bootblock.c
++++ b/src/southbridge/amd/sb700/bootblock.c
+@@ -71,7 +71,7 @@ static void sb700_enable_rom(void)
+       /* Enable LPC ROM range end at 0xffff(ffff). */
+       pci_io_write_config16(dev, 0x6e, 0xffff);
+ 
+-      /* SB700 LPC Bridge 0x48h.
++      /* SB700 LPC Bridge 0x48.
+        * Turn on all LPC IO Port decode enables
+        */
+       dword = pci_io_read_config32(dev, 0x44);
+@@ -89,7 +89,7 @@ static void sb700_enable_rom(void)
+       reg8 |= (1<<0) | (1<<1) | (1<<4) | (1<<6);
+       pci_io_write_config8(dev, 0x48, reg8);
+ 
+-      /* SB700 LPC Bridge 0x4ah.
++      /* SB700 LPC Bridge 0x4a.
+        * BIT4: Port Enable for Port 0x80
+        */
+       reg8 = pci_io_read_config8(dev, 0x4a);
+diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
+index de3fa97..a6849b0 100644
+--- a/src/southbridge/amd/sb700/early_setup.c
++++ b/src/southbridge/amd/sb700/early_setup.c
+@@ -474,8 +474,10 @@ static void sb700_devices_por_init(void)
+       /* LPC Device, BDF:0-20-3 */
+       printk(BIOS_INFO, "sb700_devices_por_init(): LPC Device, BDF:0-20-3\n");
+       dev = pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
+-      /* DMA enable */
+-      pci_write_config8(dev, 0x40, 0x04);
++      if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
++              /* DMA enable */
++              pci_write_config8(dev, 0x40, 0x04);
++      }
+ 
+       /* IO Port Decode Enable */
+       pci_write_config8(dev, 0x44, 0xFF);
+@@ -618,6 +620,17 @@ static void sb700_pmio_por_init(void)
+       byte = pmio_read(0xB2);
+       byte |= 1 << 0;
+       pmio_write(0xB2, byte);
++
++      // FIXME: Enabling this causes boot to hang while initializing 
processors.
++//    /* Enable automatic C1e state switch */
++//    byte = pmio_read(0xc9);
++//    byte |= 0x11;
++//    pmio_write(0xc9, byte);
++
++      /* Enable precision HPET clock and automatic C state switch */
++      byte = pmio_read(0xbb);
++      byte |= 0xc0;
++      pmio_write(0xbb, byte);
+ }
+ 
+ /*
+@@ -653,10 +666,12 @@ static void sb700_pci_cfg(void)
+        * mentioned in RPR. But I keep them. The registers and the
+        * comments are compatible. */
+       dev = pci_locate_device(PCI_ID(0x1002, 0x439D), 0);
+-      /* Enabling LPC DMA function. */
+-      byte = pci_read_config8(dev, 0x40);
+-      byte |= (1 << 2);
+-      pci_write_config8(dev, 0x40, byte);
++      if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
++              /* Enabling LPC DMA function. */
++              byte = pci_read_config8(dev, 0x40);
++              byte |= (1 << 2);
++              pci_write_config8(dev, 0x40, byte);
++      }
+       /* Disabling LPC TimeOut. 0x48[7] clear. */
+       byte = pci_read_config8(dev, 0x48);
+       byte &= 0x7f;
+@@ -746,6 +761,18 @@ int acpi_get_sleep_type(void)
+       return ((tmp & (7 << 10)) >> 10);
+ }
+ 
++void set_lpc_sticky_ctl(bool enable)
++{
++      uint8_t byte;
++
++      byte = pmio_read(0xbb);
++      if (enable)
++              byte |= 0x20;
++      else
++              byte &= ~0x20;
++      pmio_write(0xbb, byte);
++}
++
+ #if IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
+ unsigned long get_top_of_ram(void)
+ {
+diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c
+index 0cc1e8b..145a01f 100644
+--- a/src/southbridge/amd/sb700/lpc.c
++++ b/src/southbridge/amd/sb700/lpc.c
+@@ -61,10 +61,12 @@ static void lpc_init(device_t dev)
+       isa_dma_init();
+ #endif
+ 
+-      /* Enable DMA transaction on the LPC bus */
+-      byte = pci_read_config8(dev, 0x40);
+-      byte |= (1 << 2);
+-      pci_write_config8(dev, 0x40, byte);
++      if (!IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA)) {
++              /* Enable DMA transaction on the LPC bus */
++              byte = pci_read_config8(dev, 0x40);
++              byte |= (1 << 2);
++              pci_write_config8(dev, 0x40, byte);
++      }
+ 
+       /* Disable the timeout mechanism on LPC */
+       byte = pci_read_config8(dev, 0x48);
+@@ -85,11 +87,13 @@ static void lpc_init(device_t dev)
+       cmos_check_update_date();
+ }
+ 
++#if (!IS_ENABLED(CONFIG_EARLY_CBMEM_INIT))
+ int acpi_get_sleep_type(void)
+ {
+       u16 tmp = inw(ACPI_PM1_CNT_BLK);
+       return ((tmp & (7 << 10)) >> 10);
+ }
++#endif
+ 
+ #if IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
+ void backup_top_of_ram(uint64_t ramtop)
+diff --git a/src/southbridge/amd/sb700/sb700.h 
b/src/southbridge/amd/sb700/sb700.h
+index ca020a5..b477091 100644
+--- a/src/southbridge/amd/sb700/sb700.h
++++ b/src/southbridge/amd/sb700/sb700.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -75,6 +76,8 @@ void sb7xx_51xx_setup_sata_phys(struct device *dev);
+ 
+ #endif
+ 
++void set_lpc_sticky_ctl(bool enable);
++
+ int s3_save_nvram_early(u32 dword, int size, int  nvram_pos);
+ int s3_load_nvram_early(int size, u32 *old_dword, int nvram_pos);
+ 
+diff --git a/src/southbridge/amd/sb700/spi.c b/src/southbridge/amd/sb700/spi.c
+new file mode 100644
+index 0000000..a38ca2b
+--- /dev/null
++++ b/src/southbridge/amd/sb700/spi.c
+@@ -0,0 +1,148 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2012 Advanced Micro Devices, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++#include <arch/io.h>
++#include <console/console.h>
++#include <spi-generic.h>
++#include <spi_flash.h>
++#include <device/device.h>
++#include <device/pci.h>
++#include <device/pci_ops.h>
++
++#define AMD_SB_SPI_TX_LEN 8
++
++static uint32_t get_spi_bar(void)
++{
++      device_t dev;
++
++      dev = dev_find_slot(0, PCI_DEVFN(0x14, 3));
++      return pci_read_config32(dev, 0xa0) & ~0x1f;
++}
++
++void spi_init(void)
++{
++      /* Not needed */
++}
++
++unsigned int spi_crop_chunk(unsigned int cmd_len, unsigned int buf_len)
++{
++      return min(AMD_SB_SPI_TX_LEN - cmd_len, buf_len);
++}
++
++static void reset_internal_fifo_pointer(void)
++{
++      uint32_t spibar = get_spi_bar();
++
++      do {
++              write8((void *)(spibar + 2),
++              read8((void *)(spibar + 2)) | 0x10);
++      } while (read8((void *)(spibar + 0xd)) & 0x7);
++}
++
++static void execute_command(void)
++{
++      uint32_t spibar = get_spi_bar();
++
++      write8((void *)(spibar + 2), read8((void *)(spibar + 2)) | 1);
++
++      while ((read8((void *)(spibar + 2)) & 1) &&
++              (read8((void *)(spibar+3)) & 0x80));
++}
++
++int spi_claim_bus(struct spi_slave *slave)
++{
++      /* Handled internally by the SB700 */
++      return 0;
++}
++
++void spi_release_bus(struct spi_slave *slave)
++{
++      /* Handled internally by the SB700 */
++}
++
++struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
++{
++      struct spi_slave *slave = malloc(sizeof(*slave));
++
++      if (!slave) {
++              return NULL;
++      }
++
++      memset(slave, 0, sizeof(*slave));
++
++      return slave;
++}
++
++int spi_xfer(struct spi_slave *slave, const void *dout,
++              unsigned int bytesout, void *din, unsigned int bytesin)
++{
++      /* First byte is cmd which cannot be sent through the FIFO. */
++      u8 cmd = *(u8 *)dout++;
++      u8 readoffby1;
++      u8 readwrite;
++      u8 count;
++
++      uint32_t spibar = get_spi_bar();
++
++      bytesout--;
++
++      /*
++       * Check if this is a write command attempting to transfer more bytes
++       * than the controller can handle. Iterations for writes are not
++       * supported here because each SPI write command needs to be preceded
++       * and followed by other SPI commands, and this sequence is controlled
++       * by the SPI chip driver.
++       */
++      if (bytesout > AMD_SB_SPI_TX_LEN) {
++              printk(BIOS_DEBUG, "FCH SPI: Too much to write. Does your SPI 
chip driver use"
++                   " spi_crop_chunk()?\n");
++              return -1;
++      }
++
++      readoffby1 = bytesout ? 0 : 1;
++
++      readwrite = (bytesin + readoffby1) << 4 | bytesout;
++      write8((void *)(spibar + 1), readwrite);
++      write8((void *)(spibar + 0), cmd);
++
++      reset_internal_fifo_pointer();
++      for (count = 0; count < bytesout; count++, dout++) {
++              write8((void *)(spibar + 0x0C), *(u8 *)dout);
++      }
++
++      reset_internal_fifo_pointer();
++      execute_command();
++
++      reset_internal_fifo_pointer();
++      /* Skip the bytes we sent. */
++      for (count = 0; count < bytesout; count++) {
++              cmd = read8((void *)(spibar + 0x0C));
++      }
++
++      reset_internal_fifo_pointer();
++      for (count = 0; count < bytesin; count++, din++) {
++              *(u8 *)din = read8((void *)(spibar + 0x0C));
++      }
++
++      return 0;
++}
+\ No newline at end of file
+diff --git a/src/southbridge/amd/sb700/spi.h b/src/southbridge/amd/sb700/spi.h
+new file mode 100644
+index 0000000..9b76b35
+--- /dev/null
++++ b/src/southbridge/amd/sb700/spi.h
+@@ -0,0 +1,21 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++int spi_claim_bus(struct spi_slave *slave);
++void spi_release_bus(struct spi_slave *slave);
+\ No newline at end of file
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0017-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
 
b/resources/libreboot/patch/kgpe-d16/0017-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
deleted file mode 100644
index e7ce695..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0017-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-From d09d475241b1017919ac2048177ce5ab60f7328f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:26:30 -0500
-Subject: [PATCH 017/139] superio/nuvoton/nct5572d: Enable power state after
- power failure support
-
-Change-Id: Ia0313b9ecd64c9e6f99a140772ebb35abe0175fd
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/superio/nuvoton/nct5572d/superio.c | 31 +++++++++++++++++++++++++++++++
- 1 file changed, 31 insertions(+)
-
-diff --git a/src/superio/nuvoton/nct5572d/superio.c 
b/src/superio/nuvoton/nct5572d/superio.c
-index c5278d6..ccf2416 100644
---- a/src/superio/nuvoton/nct5572d/superio.c
-+++ b/src/superio/nuvoton/nct5572d/superio.c
-@@ -3,6 +3,7 @@
-  *
-  * Copyright (C) 2014 Felix Held <address@hidden>
-  * Copyright (C) 2014 Edward O'Callaghan <address@hidden>
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -19,17 +20,29 @@
-  * Foundation, Inc.
-  */
- 
-+#include <console/console.h>
- #include <arch/io.h>
- #include <device/device.h>
- #include <device/pnp.h>
- #include <pc80/keyboard.h>
-+#include <pc80/mc146818rtc.h>
- #include <stdlib.h>
- #include <superio/conf_mode.h>
- 
- #include "nct5572d.h"
- 
-+#define MAINBOARD_POWER_OFF 0
-+#define MAINBOARD_POWER_ON 1
-+
-+#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
-+#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
-+#endif
-+
- static void nct5572d_init(struct device *dev)
- {
-+      uint8_t byte;
-+      uint32_t power_status;
-+
-       if (!dev->enabled)
-               return;
- 
-@@ -38,6 +51,24 @@ static void nct5572d_init(struct device *dev)
-       case NCT5572D_KBC:
-               pc_keyboard_init();
-               break;
-+      case NCT5572D_ACPI:
-+              /* Set power state after power fail */
-+              power_status = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
-+              get_option(&power_status, "power_on_after_fail");
-+              pnp_enter_conf_mode_8787(dev);
-+              outb(0x07, dev->path.pnp.port);
-+              outb(NCT5572D_ACPI, dev->path.pnp.port+1);      /* ACPI 
function */
-+              outb(0xe4, dev->path.pnp.port);                 /* CRE4 */
-+              byte = inb(dev->path.pnp.port+1);
-+              byte &= ~0x60;
-+              if (power_status == 1)
-+                      byte |= (0x1 << 5);    /* Force power on */
-+              else if (power_status == 2)
-+                      byte |= (0x2 << 5);    /* Use last power state */
-+              outb(byte, dev->path.pnp.port+1);
-+              pnp_exit_conf_mode_aa(dev);
-+              printk(BIOS_INFO, "set power %s after power fail\n", 
power_status ? "on" : "off");
-+              break;
-       }
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0018-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
 
b/resources/libreboot/patch/kgpe-d16/0018-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
deleted file mode 100644
index 0fac423..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0018-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
+++ /dev/null
@@ -1,135 +0,0 @@
-From 38e3b0862f6e914b010c004ff03cb9063452e26c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:39:34 -0500
-Subject: [PATCH 018/139] northbridge/amd/amdfam10: Add Suspend to RAM (S3)
- Flash data storage area
-
-Change-Id: I169fafc3a61e11c3e4781190053e57bf34502d7b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/Kconfig          |  6 ++++
- src/northbridge/amd/amdfam10/Makefile.inc     | 19 ++++++++++
- src/northbridge/amd/amdfam10/raminit_amdmct.c | 50 +++++++++++++++------------
- 3 files changed, 53 insertions(+), 22 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/Kconfig 
b/src/northbridge/amd/amdfam10/Kconfig
-index 4d7147d..ff92fca 100644
---- a/src/northbridge/amd/amdfam10/Kconfig
-+++ b/src/northbridge/amd/amdfam10/Kconfig
-@@ -89,6 +89,12 @@ if DIMM_FBDIMM
-               default 0x0110
- endif
- 
-+if HAVE_ACPI_RESUME
-+      config S3_DATA_SIZE
-+              int
-+              default 16384
-+endif
-+
- if DIMM_DDR2
-       if DIMM_REGISTERED
-       config DIMM_SUPPORT
-diff --git a/src/northbridge/amd/amdfam10/Makefile.inc 
b/src/northbridge/amd/amdfam10/Makefile.inc
-index 8a105fd..b4097b4 100644
---- a/src/northbridge/amd/amdfam10/Makefile.inc
-+++ b/src/northbridge/amd/amdfam10/Makefile.inc
-@@ -15,4 +15,23 @@ ramstage-y += get_pci1234.c
- # Call show_all_routes() anywhere amdfam10.h is included.
- #ramstage-y += util.c
- 
-+ifeq ($(CONFIG_HAVE_ACPI_RESUME), y)
-+
-+$(obj)/coreboot_s3nv.rom: $(obj)/config.h
-+      echo "    S3 NVRAM   $(CONFIG_S3_DATA_POS) (S3 storage area)"
-+      # force C locale, so cygwin awk doesn't try to interpret the 0xff below 
as UTF-8 (or worse)
-+      printf %d $(CONFIG_S3_DATA_SIZE) | LC_ALL=C awk '{for (i=0; i<$$1*2; 
i++) {printf "%c", 255}}' > address@hidden
-+      mv address@hidden $@
-+
-+cbfs-files-y += s3nv
-+s3nv-file := $(obj)/coreboot_s3nv.rom
-+s3nv-position := $(CONFIG_S3_DATA_POS)
-+s3nv-type := raw
-+
-+ifeq ($(CONFIG_DIMM_DDR3), y)
-+ramstage-y += ../amdmct/mct_ddr3/s3utils.c
-+endif
-+
-+endif
-+
- endif
-diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-index 3f33eba..5068e7a 100644
---- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
-+++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-@@ -110,6 +110,10 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t 
registered, uint16_t freq
- #include "../amdmct/mct_ddr3/mct_d.h"
- #include "../amdmct/mct_ddr3/mct_d_gcc.h"
- 
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-+#include "../amdmct/mct_ddr3/s3utils.c"
-+#endif
-+
- #include "../amdmct/wrappers/mcti_d.c"
- #include "../amdmct/mct_ddr3/mct_d.c"
- 
-@@ -249,33 +253,35 @@ static void amdmct_cbmem_store_info(struct sys_info 
*sysinfo)
-       size_t i;
-       struct DCTStatStruc *pDCTstatA = NULL;
- 
--      /* Allocate memory */
--      struct amdmct_memory_info* mem_info;
--      mem_info = cbmem_add(CBMEM_ID_AMDMCT_MEMINFO, sizeof(struct 
amdmct_memory_info));
--      if (!mem_info)
--              return;
-+      if (!acpi_is_wakeup_s3()) {
-+              /* Allocate memory */
-+              struct amdmct_memory_info* mem_info;
-+              mem_info = cbmem_add(CBMEM_ID_AMDMCT_MEMINFO, sizeof(struct 
amdmct_memory_info));
-+              if (!mem_info)
-+                      return;
- 
--      printk(BIOS_DEBUG, "%s: Storing AMDMCT configuration in CBMEM\n", 
__func__);
-+              printk(BIOS_DEBUG, "%s: Storing AMDMCT configuration in 
CBMEM\n", __func__);
- 
--      /* Initialize memory */
--      memset(mem_info, 0,  sizeof(struct amdmct_memory_info));
-+              /* Initialize memory */
-+              memset(mem_info, 0,  sizeof(struct amdmct_memory_info));
- 
--      /* Copy data */
--      memcpy(&mem_info->mct_stat, &(sysinfo->MCTstat), sizeof(struct 
MCTStatStruc));
--      for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
--              pDCTstatA = sysinfo->DCTstatA + i;
--              memcpy(&mem_info->dct_stat[i], pDCTstatA, sizeof(struct 
DCTStatStruc));
--      }
--      mem_info->ecc_enabled = mctGet_NVbits(NV_ECC_CAP);
--      mem_info->ecc_scrub_rate = mctGet_NVbits(NV_DramBKScrub);
-+              /* Copy data */
-+              memcpy(&mem_info->mct_stat, &(sysinfo->MCTstat), sizeof(struct 
MCTStatStruc));
-+              for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
-+                      pDCTstatA = sysinfo->DCTstatA + i;
-+                      memcpy(&mem_info->dct_stat[i], pDCTstatA, sizeof(struct 
DCTStatStruc));
-+              }
-+              mem_info->ecc_enabled = mctGet_NVbits(NV_ECC_CAP);
-+              mem_info->ecc_scrub_rate = mctGet_NVbits(NV_DramBKScrub);
- 
--      /* Zero out invalid/unused pointers */
-+              /* Zero out invalid/unused pointers */
- #if IS_ENABLED(CONFIG_DIMM_DDR3)
--      for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
--              mem_info->dct_stat[i].C_MCTPtr = NULL;
--              mem_info->dct_stat[i].C_DCTPtr[0] = NULL;
--              mem_info->dct_stat[i].C_DCTPtr[1] = NULL;
--      }
-+              for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
-+                      mem_info->dct_stat[i].C_MCTPtr = NULL;
-+                      mem_info->dct_stat[i].C_DCTPtr[0] = NULL;
-+                      mem_info->dct_stat[i].C_DCTPtr[1] = NULL;
-+              }
- #endif
-+      }
- }
- #endif
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0018-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
 
b/resources/libreboot/patch/kgpe-d16/0018-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
new file mode 100644
index 0000000..61abd52
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0018-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch
@@ -0,0 +1,80 @@
+From e2c23ef578b911c1fe91b582c5c26a2b1e6fcaca Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:26:30 -0500
+Subject: [PATCH 018/143] superio/nuvoton/nct5572d: Enable power state after
+ power failure support
+
+Change-Id: Ia0313b9ecd64c9e6f99a140772ebb35abe0175fd
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/superio/nuvoton/nct5572d/superio.c |   29 +++++++++++++++++++++++++++++
+ 1 file changed, 29 insertions(+)
+
+diff --git a/src/superio/nuvoton/nct5572d/superio.c 
b/src/superio/nuvoton/nct5572d/superio.c
+index c5278d6..3b71c6b 100644
+--- a/src/superio/nuvoton/nct5572d/superio.c
++++ b/src/superio/nuvoton/nct5572d/superio.c
+@@ -3,6 +3,7 @@
+  *
+  * Copyright (C) 2014 Felix Held <address@hidden>
+  * Copyright (C) 2014 Edward O'Callaghan <address@hidden>
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -19,17 +20,29 @@
+  * Foundation, Inc.
+  */
+ 
++#include <console/console.h>
+ #include <arch/io.h>
+ #include <device/device.h>
+ #include <device/pnp.h>
+ #include <pc80/keyboard.h>
++#include <pc80/mc146818rtc.h>
+ #include <stdlib.h>
+ #include <superio/conf_mode.h>
+ 
+ #include "nct5572d.h"
+ 
++#define MAINBOARD_POWER_OFF 0
++#define MAINBOARD_POWER_ON 1
++
++#ifndef CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL
++#define CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL MAINBOARD_POWER_ON
++#endif
++
+ static void nct5572d_init(struct device *dev)
+ {
++      uint8_t byte;
++      uint8_t power_status;
++
+       if (!dev->enabled)
+               return;
+ 
+@@ -38,6 +51,22 @@ static void nct5572d_init(struct device *dev)
+       case NCT5572D_KBC:
+               pc_keyboard_init();
+               break;
++      case NCT5572D_ACPI:
++              /* Set power state after power fail */
++              power_status = CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL;
++              get_option(&power_status, "power_on_after_fail");
++              pnp_enter_conf_mode_8787(dev);
++              pnp_set_logical_device(dev);
++              byte = pnp_read_config(dev, 0xe4);
++              byte &= ~0x60;
++              if (power_status == 1)
++                      byte |= (0x1 << 5);    /* Force power on */
++              else if (power_status == 2)
++                      byte |= (0x2 << 5);    /* Use last power state */
++              pnp_write_config(dev, 0xe4, byte);
++              pnp_exit_conf_mode_aa(dev);
++              printk(BIOS_INFO, "set power %s after power fail\n", 
power_status ? "on" : "off");
++              break;
+       }
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0019-mainboard-asrock-e350m1-Update-CMOS-layout-to-match-.patch
 
b/resources/libreboot/patch/kgpe-d16/0019-mainboard-asrock-e350m1-Update-CMOS-layout-to-match-.patch
new file mode 100644
index 0000000..d4b20fe
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0019-mainboard-asrock-e350m1-Update-CMOS-layout-to-match-.patch
@@ -0,0 +1,38 @@
+From 8249f770fd166cc1ce8d6c033c01103d36763977 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Wed, 21 Oct 2015 15:27:02 -0500
+Subject: [PATCH 019/143] mainboard/asrock/e350m1: Update CMOS layout to match
+ SIO changes
+
+Change-Id: I3f1f33b50f788b6d57f1a7986c4bdb912426e4f0
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asrock/e350m1/cmos.layout |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/mainboard/asrock/e350m1/cmos.layout 
b/src/mainboard/asrock/e350m1/cmos.layout
+index 996160e..bc8de75 100644
+--- a/src/mainboard/asrock/e350m1/cmos.layout
++++ b/src/mainboard/asrock/e350m1/cmos.layout
+@@ -29,7 +29,7 @@ entries
+ 396          1       e       1        interleave_chip_selects
+ 397          2       e       8        max_mem_clock
+ 399          1       e       2        multi_core
+-400          1       e       1        power_on_after_fail
++400          2       e       3        power_on_after_fail
+ 412          4       e       6        debug_level
+ 440          4       e       9        slow_cpu
+ 444          1       e       1        nmi
+@@ -49,6 +49,9 @@ enumerations
+ 1     1     Enable
+ 2     0     Enable
+ 2     1     Disable
++3     0     Off
++3     1     On
++3     2     Last
+ 4     0     Fallback
+ 4     1     Normal
+ 5     0     115200
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0019-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
 
b/resources/libreboot/patch/kgpe-d16/0019-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
deleted file mode 100644
index 482bedb..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0019-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
+++ /dev/null
@@ -1,1007 +0,0 @@
-From b1e36a17d254e15459729ebfc3a83df4a2b28468 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:40:31 -0500
-Subject: [PATCH 019/139] northbridge/amd/amdmct/mct_ddr3: Add initial Suspend
- to RAM (S3) support
-
-Change-Id: Ic97567851fa40295bc21cefd7537407b99d71709
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/northbridge.c    |   8 +
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   | 154 ++++---
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   | 112 +++++
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 610 ++++++++++++++++++++++++++
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.h |  28 ++
- 5 files changed, 840 insertions(+), 72 deletions(-)
- create mode 100644 src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
- create mode 100644 src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 74cecc8..9cc3d96 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -54,6 +54,10 @@
- #include <sb_cimx.h>
- #endif
- 
-+#if IS_ENABLED(CONFIG_DIMM_DDR3)
-+#include "../amdmct/mct_ddr3/s3utils.h"
-+#endif
-+
- struct amdfam10_sysconf_t sysconf;
- 
- #define FX_DEVS NODE_NUMS
-@@ -1413,6 +1417,10 @@ static void root_complex_enable_dev(struct device *dev)
-       /* Do not delay UMA setup, as a device on the PCI bus may evaluate
-          the global uma_memory variables already in its enable function. */
-       if (!done) {
-+#if IS_ENABLED(CONFIG_DIMM_DDR3)
-+              save_mct_information_to_nvram();
-+#endif
-+
-               setup_bsp_ramtop();
-               setup_uma_memory();
-               done = 1;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index fa59d71..a8212c5 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -272,91 +272,101 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
-       u8 Node, NodesWmem;
-       u32 node_sys_base;
- 
-+      uint8_t s3resume = acpi_is_wakeup_s3();
-+
- restartinit:
-       mctInitMemGPIOs_A_D();          /* Set any required GPIOs*/
--      NodesWmem = 0;
--      node_sys_base = 0;
--      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
--              struct DCTStatStruc *pDCTstat;
--              pDCTstat = pDCTstatA + Node;
-+      if (s3resume) {
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
-+              restore_mct_information_from_nvram();
-+#endif
-+      } else {
-+              NodesWmem = 0;
-+              node_sys_base = 0;
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
- 
--              /* Zero out data structures to avoid false detection of DIMMs */
--              memset(pDCTstat, 0, sizeof(struct DCTStatStruc));
--
--              /* Initialize data structures */
--              pDCTstat->Node_ID = Node;
--              pDCTstat->dev_host = PA_HOST(Node);
--              pDCTstat->dev_map = PA_MAP(Node);
--              pDCTstat->dev_dct = PA_DCT(Node);
--              pDCTstat->dev_nbmisc = PA_NBMISC(Node);
--              pDCTstat->NodeSysBase = node_sys_base;
--
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node %d\n", 
Node);
--              mct_init(pMCTstat, pDCTstat);
--              mctNodeIDDebugPort_D();
--              pDCTstat->NodePresent = NodePresent_D(Node);
--              if (pDCTstat->NodePresent) {            /* See if Node is 
there*/
--                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
--                      clear_legacy_Mode(pMCTstat, pDCTstat);
--                      pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
--
--                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
--                      mct_InitialMCT_D(pMCTstat, pDCTstat);
--
--                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
--                      mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
--
--                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_initDCT\n");
--                      mct_initDCT(pMCTstat, pDCTstat);
--                      if (pDCTstat->ErrCode == SC_FatalErr) {
--                              goto fatalexit;         /* any fatal errors?*/
--                      } else if (pDCTstat->ErrCode < SC_StopError) {
--                              NodesWmem++;
--                      }
--              }       /* if Node present */
--              node_sys_base = pDCTstat->NodeSysBase;
--              node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
--      }
--      if (NodesWmem == 0) {
--              printk(BIOS_DEBUG, "No Nodes?!\n");
--              goto fatalexit;
--      }
-+                      /* Zero out data structures to avoid false detection of 
DIMMs */
-+                      memset(pDCTstat, 0, sizeof(struct DCTStatStruc));
-+
-+                      /* Initialize data structures */
-+                      pDCTstat->Node_ID = Node;
-+                      pDCTstat->dev_host = PA_HOST(Node);
-+                      pDCTstat->dev_map = PA_MAP(Node);
-+                      pDCTstat->dev_dct = PA_DCT(Node);
-+                      pDCTstat->dev_nbmisc = PA_NBMISC(Node);
-+                      pDCTstat->NodeSysBase = node_sys_base;
-+
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node 
%d\n", Node);
-+                      mct_init(pMCTstat, pDCTstat);
-+                      mctNodeIDDebugPort_D();
-+                      pDCTstat->NodePresent = NodePresent_D(Node);
-+                      if (pDCTstat->NodePresent) {            /* See if Node 
is there*/
-+                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
-+                              clear_legacy_Mode(pMCTstat, pDCTstat);
-+                              pDCTstat->LogicalCPUID = 
mctGetLogicalCPUID_D(Node);
-+
-+                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
-+                              mct_InitialMCT_D(pMCTstat, pDCTstat);
-+
-+                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
-+                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
-+
-+                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_initDCT\n");
-+                              mct_initDCT(pMCTstat, pDCTstat);
-+                              if (pDCTstat->ErrCode == SC_FatalErr) {
-+                                      goto fatalexit;         /* any fatal 
errors?*/
-+                              } else if (pDCTstat->ErrCode < SC_StopError) {
-+                                      NodesWmem++;
-+                              }
-+                      }       /* if Node present */
-+                      node_sys_base = pDCTstat->NodeSysBase;
-+                      node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
-+              }
-+              if (NodesWmem == 0) {
-+                      printk(BIOS_DEBUG, "No Nodes?!\n");
-+                      goto fatalexit;
-+              }
- 
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
--      SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are ready for 
accesses.*/
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
-+              SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are 
ready for accesses.*/
- 
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D: HTMemMapInit_D\n");
--      HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory into system 
address space.*/
--      mctHookAfterHTMap();
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: HTMemMapInit_D\n");
-+              HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory 
into system address space.*/
-+              mctHookAfterHTMap();
- 
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
--      CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC CPU 
cacheability */
--      mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
-+              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
-+              mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
- 
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
--      DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable and DQS 
signal timing*/
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
-+              DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable 
and DQS signal timing*/
- 
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
--      UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA sizing */
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
-+              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
- 
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
--      mct_OtherTiming(pMCTstat, pDCTstatA);
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
-+              mct_OtherTiming(pMCTstat, pDCTstatA);
- 
--      if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st 
pass of DIMM spare enabled*/
--              goto restartinit;
--      }
- 
--      InterleaveNodes_D(pMCTstat, pDCTstatA);
--      InterleaveChannels_D(pMCTstat, pDCTstatA);
-+              if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 
1st pass of DIMM spare enabled*/
-+                      goto restartinit;
-+              }
- 
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
--      if (ECCInit_D(pMCTstat, pDCTstatA)) {           /* Setup ECC control 
and ECC check-bits*/
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
--              MCTMemClr_D(pMCTstat,pDCTstatA);
--      }
-+              InterleaveNodes_D(pMCTstat, pDCTstatA);
-+              InterleaveChannels_D(pMCTstat, pDCTstatA);
-+
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
-+              if (ECCInit_D(pMCTstat, pDCTstatA)) {           /* Setup ECC 
control and ECC check-bits*/
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
-+                      MCTMemClr_D(pMCTstat,pDCTstatA);
-+              }
- 
--      mct_FinalMCT_D(pMCTstat, pDCTstatA);
--      printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", 
pMCTstat->GStatus);
-+              mct_FinalMCT_D(pMCTstat, pDCTstatA);
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: 
%x\n", pMCTstat->GStatus);
-+      }
- 
-       return;
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 219aa42..c790d7e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -24,6 +24,8 @@
- #ifndef MCT_D_H
- #define MCT_D_H
- 
-+#include <cpu/x86/msr.h>
-+
- /*===========================================================================
-       CPU - K8/FAM10
- ===========================================================================*/
-@@ -596,6 +598,116 @@ struct DCTStatStruc {            /* A per Node 
structure*/
-       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
- } __attribute__((packed));
- 
-+struct amd_s3_persistent_mct_channel_data {
-+      /* Stage 1 (1 dword) */
-+      uint32_t f2x110;
-+
-+      /* Stage 2 (88 dwords) */
-+      uint32_t f1x40;
-+      uint32_t f1x44;
-+      uint32_t f1x48;
-+      uint32_t f1x4c;
-+      uint32_t f1x50;
-+      uint32_t f1x54;
-+      uint32_t f1x58;
-+      uint32_t f1x5c;
-+      uint32_t f1x60;
-+      uint32_t f1x64;
-+      uint32_t f1x68;
-+      uint32_t f1x6c;
-+      uint32_t f1x70;
-+      uint32_t f1x74;
-+      uint32_t f1x78;
-+      uint32_t f1x7c;
-+      uint32_t f1xf0;
-+      uint32_t f1x120;
-+      uint32_t f1x124;
-+      uint32_t f2x10c;
-+      uint32_t f2x114;
-+      uint32_t f2x118;
-+      uint32_t f2x11c;
-+      uint32_t f2x1b0;
-+      uint32_t f3x44;
-+      uint64_t msr0000020[16];
-+      uint64_t msr00000250;
-+      uint64_t msr00000258;
-+      uint64_t msr0000026[8];
-+      uint64_t msr000002ff;
-+      uint64_t msrc0010010;
-+      uint64_t msrc001001a;
-+      uint64_t msrc001001d;
-+      uint64_t msrc001001f;
-+
-+      /* Stage 3 (21 dwords) */
-+      uint32_t f2x40;
-+      uint32_t f2x44;
-+      uint32_t f2x48;
-+      uint32_t f2x4c;
-+      uint32_t f2x50;
-+      uint32_t f2x54;
-+      uint32_t f2x58;
-+      uint32_t f2x5c;
-+      uint32_t f2x60;
-+      uint32_t f2x64;
-+      uint32_t f2x68;
-+      uint32_t f2x6c;
-+      uint32_t f2x78;
-+      uint32_t f2x7c;
-+      uint32_t f2x80;
-+      uint32_t f2x84;
-+      uint32_t f2x88;
-+      uint32_t f2x8c;
-+      uint32_t f2x90;
-+      uint32_t f2xa4;
-+      uint32_t f2xa8;
-+
-+      /* Stage 4 (1 dword) */
-+      uint32_t f2x94;
-+
-+      /* Stage 6 (33 dwords) */
-+      uint32_t f2x9cx0d0f0_f_8_0_0_8_4_0[9][3];       /* [lane][setting] */
-+      uint32_t f2x9cx00;
-+      uint32_t f2x9cx0a;
-+      uint32_t f2x9cx0c;
-+
-+      /* Stage 7 (1 dword) */
-+      uint32_t f2x9cx04;
-+
-+      /* Stage 9 (2 dwords) */
-+      uint32_t f2x9cx0d0fe006;
-+      uint32_t f2x9cx0d0fe007;
-+
-+      /* Stage 10 (78 dwords) */
-+      uint32_t f2x9cx10[12];
-+      uint32_t f2x9cx20[12];
-+      uint32_t f2x9cx3_0_0_3_1[4][3];         /* [dimm][setting] */
-+      uint32_t f2x9cx3_0_0_7_5[4][3];         /* [dimm][setting] */
-+      uint32_t f2x9cx0d;
-+      uint32_t f2x9cx0d0f0_f_0_13[9];         /* [lane] */
-+      uint32_t f2x9cx0d0f0_f_0_30[9];         /* [lane] */
-+      uint32_t f2x9cx0d0f2_f_0_30[4];         /* [pad select] */
-+      uint32_t f2x9cx0d0f8_8_4_0[2][3];       /* [offset][pad select] */
-+      uint32_t f2x9cx0d0f812f;
-+
-+      /* Stage 11 (24 dwords) */
-+      uint32_t f2x9cx30[12];
-+      uint32_t f2x9cx40[12];
-+
-+      /* Other (1 dword) */
-+      uint32_t f3x58;
-+
-+      /* TOTAL: 250 dwords */
-+} __attribute__((packed));
-+
-+struct amd_s3_persistent_node_data {
-+      uint32_t node_present;
-+      struct amd_s3_persistent_mct_channel_data channel[2];
-+} __attribute__((packed));
-+
-+struct amd_s3_persistent_data {
-+      struct amd_s3_persistent_node_data node[MAX_NODES_SUPPORTED];
-+} __attribute__((packed));
-+
- 
/*===============================================================================
-       Local Error Status Codes (DCTStatStruc.ErrCode)
- 
===============================================================================*/
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-new file mode 100644
-index 0000000..78523e8
---- /dev/null
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -0,0 +1,610 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
-+ */
-+
-+#include <string.h>
-+#include <arch/acpi.h>
-+#include <cpu/x86/msr.h>
-+#include <device/device.h>
-+#include <device/pci_def.h>
-+#include <device/pci_ops.h>
-+#include <console/console.h>
-+#include <cbfs.h>
-+#include <spi-generic.h>
-+#include <spi_flash.h>
-+
-+#include "s3utils.h"
-+
-+#define S3NV_FILE_NAME "s3nv"
-+
-+static ssize_t get_s3nv_file_offset(void);
-+
-+ssize_t get_s3nv_file_offset(void)
-+{
-+      struct region_device s3nv_region;
-+      struct cbfsf s3nv_cbfs_file;
-+      if (cbfs_boot_locate(&s3nv_cbfs_file, S3NV_FILE_NAME, NULL)) {
-+              printk(BIOS_DEBUG, "S3 state file not found in CBFS: %s\n", 
S3NV_FILE_NAME);
-+              return -1;
-+      }
-+      cbfs_file_data(&s3nv_region, &s3nv_cbfs_file);
-+
-+      return s3nv_region.region.offset;
-+}
-+
-+static uint32_t read_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index)
-+{
-+      uint32_t dword;
-+
-+      index &= ~(1 << 30);
-+      pci_write_config32(dev, index_ctl_reg, index);
-+      do {
-+              dword = pci_read_config32(dev, index_ctl_reg);
-+      } while (!(dword & (1 << 31)));
-+      dword = pci_read_config32(dev, index_ctl_reg + 0x04);
-+
-+      return dword;
-+}
-+
-+#ifdef __RAMSTAGE__
-+static uint64_t rdmsr_uint64_t(unsigned long index) {
-+      msr_t msr = rdmsr(index);
-+      return (((uint64_t)msr.hi) << 32) | ((uint64_t)msr.lo);
-+}
-+
-+void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
-+{
-+      uint8_t i;
-+      uint8_t j;
-+      uint8_t node;
-+      uint8_t channel;
-+
-+      /* Zero out data structure */
-+      memset(persistent_data, 0, sizeof(struct amd_s3_persistent_data));
-+
-+      /* Load data from DCTs into data structure */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
-+              device_t dev_fn2 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 2));
-+              device_t dev_fn3 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 3));
-+              if ((!dev_fn1) || (!dev_fn2) || (!dev_fn3)) {
-+                      persistent_data->node[node].node_present = 0;
-+                      continue;
-+              }
-+              persistent_data->node[node].node_present = 1;
-+
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+
-+                      /* Stage 1 */
-+                      data->f2x110 = pci_read_config32(dev_fn2, 0x110);
-+
-+                      /* Stage 2 */
-+                      data->f1x40 = pci_read_config32(dev_fn1, 0x40 + (0x100 
* channel));
-+                      data->f1x44 = pci_read_config32(dev_fn1, 0x44 + (0x100 
* channel));
-+                      data->f1x48 = pci_read_config32(dev_fn1, 0x48 + (0x100 
* channel));
-+                      data->f1x4c = pci_read_config32(dev_fn1, 0x4c + (0x100 
* channel));
-+                      data->f1x50 = pci_read_config32(dev_fn1, 0x50 + (0x100 
* channel));
-+                      data->f1x54 = pci_read_config32(dev_fn1, 0x54 + (0x100 
* channel));
-+                      data->f1x58 = pci_read_config32(dev_fn1, 0x58 + (0x100 
* channel));
-+                      data->f1x5c = pci_read_config32(dev_fn1, 0x5c + (0x100 
* channel));
-+                      data->f1x60 = pci_read_config32(dev_fn1, 0x60 + (0x100 
* channel));
-+                      data->f1x64 = pci_read_config32(dev_fn1, 0x64 + (0x100 
* channel));
-+                      data->f1x68 = pci_read_config32(dev_fn1, 0x68 + (0x100 
* channel));
-+                      data->f1x6c = pci_read_config32(dev_fn1, 0x6c + (0x100 
* channel));
-+                      data->f1x70 = pci_read_config32(dev_fn1, 0x70 + (0x100 
* channel));
-+                      data->f1x74 = pci_read_config32(dev_fn1, 0x74 + (0x100 
* channel));
-+                      data->f1x78 = pci_read_config32(dev_fn1, 0x78 + (0x100 
* channel));
-+                      data->f1x7c = pci_read_config32(dev_fn1, 0x7c + (0x100 
* channel));
-+                      data->f1xf0 = pci_read_config32(dev_fn1, 0xf0);
-+                      data->f1x120 = pci_read_config32(dev_fn1, 0x120);
-+                      data->f1x124 = pci_read_config32(dev_fn1, 0x124);
-+                      data->f2x10c = pci_read_config32(dev_fn2, 0x10c);
-+                      data->f2x114 = pci_read_config32(dev_fn2, 0x114);
-+                      data->f2x118 = pci_read_config32(dev_fn2, 0x118);
-+                      data->f2x11c = pci_read_config32(dev_fn2, 0x11c);
-+                      data->f2x1b0 = pci_read_config32(dev_fn2, 0x1b0);
-+                      data->f3x44 = pci_read_config32(dev_fn3, 0x44);
-+                      for (i=0; i<16; i++) {
-+                              data->msr0000020[i] = rdmsr_uint64_t(0x00000200 
| i);
-+                      }
-+                      data->msr00000250 = rdmsr_uint64_t(0x00000250);
-+                      data->msr00000258 = rdmsr_uint64_t(0x00000258);
-+                      for (i=0; i<8; i++)
-+                              data->msr0000026[i] = rdmsr_uint64_t(0x00000260 
| (i + 8));
-+                      data->msr000002ff = rdmsr_uint64_t(0x000002ff);
-+                      data->msrc0010010 = rdmsr_uint64_t(0xc0010010);
-+                      data->msrc001001a = rdmsr_uint64_t(0xc001001a);
-+                      data->msrc001001d = rdmsr_uint64_t(0xc001001d);
-+                      data->msrc001001f = rdmsr_uint64_t(0xc001001f);
-+
-+                      /* Stage 3 */
-+                      data->f2x40 = pci_read_config32(dev_fn2, 0x40 + (0x100 
* channel));
-+                      data->f2x44 = pci_read_config32(dev_fn2, 0x44 + (0x100 
* channel));
-+                      data->f2x48 = pci_read_config32(dev_fn2, 0x48 + (0x100 
* channel));
-+                      data->f2x4c = pci_read_config32(dev_fn2, 0x4c + (0x100 
* channel));
-+                      data->f2x50 = pci_read_config32(dev_fn2, 0x50 + (0x100 
* channel));
-+                      data->f2x54 = pci_read_config32(dev_fn2, 0x54 + (0x100 
* channel));
-+                      data->f2x58 = pci_read_config32(dev_fn2, 0x58 + (0x100 
* channel));
-+                      data->f2x5c = pci_read_config32(dev_fn2, 0x5c + (0x100 
* channel));
-+                      data->f2x60 = pci_read_config32(dev_fn2, 0x60 + (0x100 
* channel));
-+                      data->f2x64 = pci_read_config32(dev_fn2, 0x64 + (0x100 
* channel));
-+                      data->f2x68 = pci_read_config32(dev_fn2, 0x68 + (0x100 
* channel));
-+                      data->f2x6c = pci_read_config32(dev_fn2, 0x6c + (0x100 
* channel));
-+                      data->f2x78 = pci_read_config32(dev_fn2, 0x78 + (0x100 
* channel));
-+                      data->f2x7c = pci_read_config32(dev_fn2, 0x7c + (0x100 
* channel));
-+                      data->f2x80 = pci_read_config32(dev_fn2, 0x80 + (0x100 
* channel));
-+                      data->f2x84 = pci_read_config32(dev_fn2, 0x84 + (0x100 
* channel));
-+                      data->f2x88 = pci_read_config32(dev_fn2, 0x88 + (0x100 
* channel));
-+                      data->f2x8c = pci_read_config32(dev_fn2, 0x8c + (0x100 
* channel));
-+                      data->f2x90 = pci_read_config32(dev_fn2, 0x90 + (0x100 
* channel));
-+                      data->f2xa4 = pci_read_config32(dev_fn2, 0xa4 + (0x100 
* channel));
-+                      data->f2xa8 = pci_read_config32(dev_fn2, 0xa8 + (0x100 
* channel));
-+
-+                      /* Stage 4 */
-+                      data->f2x94 = pci_read_config32(dev_fn2, 0x94 + (0x100 
* channel));
-+
-+                      /* Stage 6 */
-+                      for (i=0; i<9; i++)
-+                              for (j=0; j<3; j++)
-+                                      data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
-+                      data->f2x9cx00 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x00);
-+                      data->f2x9cx0a = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0a);
-+                      data->f2x9cx0c = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0c);
-+
-+                      /* Stage 7 */
-+                      data->f2x9cx04 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x04);
-+
-+                      /* Stage 9 */
-+                      data->f2x9cx0d0fe006 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe006);
-+                      data->f2x9cx0d0fe007 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe007);
-+
-+                      /* Stage 10 */
-+                      for (i=0; i<12; i++)
-+                              data->f2x9cx10[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x10 + i);
-+                      for (i=0; i<12; i++)
-+                              data->f2x9cx20[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x20 + i);
-+                      for (i=0; i<4; i++)
-+                              for (j=0; j<3; j++)
-+                                      data->f2x9cx3_0_0_3_1[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x01 + i) + 
(0x100 * j));
-+                      for (i=0; i<4; i++)
-+                              for (j=0; j<3; j++)
-+                                      data->f2x9cx3_0_0_7_5[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x05 + i) + 
(0x100 * j));
-+                      data->f2x9cx0d = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0d);
-+                      for (i=0; i<9; i++)
-+                              data->f2x9cx0d0f0_f_0_13[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0013 | (i 
<< 8));
-+                      for (i=0; i<9; i++)
-+                              data->f2x9cx0d0f0_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0030 | (i 
<< 8));
-+                      for (i=0; i<4; i++)
-+                              data->f2x9cx0d0f2_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f2030 | (i 
<< 8));
-+                      for (i=0; i<2; i++)
-+                              for (j=0; j<3; j++)
-+                                      data->f2x9cx0d0f8_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
-+                      data->f2x9cx0d0f812f = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f812f);
-+
-+                      /* Stage 11 */
-+                      if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+                              for (i=0; i<12; i++)
-+                                      data->f2x9cx30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x30 + i);
-+                              for (i=0; i<12; i++)
-+                                      data->f2x9cx40[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x40 + i);
-+                      }
-+
-+                      /* Other */
-+                      /* ECC scrub rate control */
-+                      data->f3x58 = pci_read_config32(dev_fn3, 0x58);
-+              }
-+      }
-+}
-+#else
-+static void write_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index, uint32_t value)
-+{
-+      uint32_t dword;
-+
-+      pci_write_config32(dev, index_ctl_reg + 0x04, value);
-+      index |= (1 << 30);
-+      pci_write_config32(dev, index_ctl_reg, index);
-+      do {
-+              dword = pci_read_config32(dev, index_ctl_reg);
-+      } while (!(dword & (1 << 31)));
-+}
-+#endif
-+
-+#ifdef __PRE_RAM__
-+static void wrmsr_uint64_t(unsigned long index, uint64_t value) {
-+      msr_t msr;
-+      msr.hi = (value & 0xffffffff00000000ULL) >> 32;
-+      msr.lo = (value & 0xffffffff);
-+      wrmsr(index, msr);
-+}
-+
-+void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data)
-+{
-+      uint8_t i;
-+      uint8_t j;
-+      uint8_t node;
-+      uint8_t channel;
-+      uint8_t ganged;
-+      uint8_t dct_enabled;
-+      uint32_t dword;
-+
-+      /* Load data from data structure into DCTs */
-+      /* Stage 1 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x110, 
data->f2x110);
-+              }
-+      }
-+
-+      /* Stage 2 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x40 + 
(0x100 * channel), data->f1x40);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x44 + 
(0x100 * channel), data->f1x44);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x48 + 
(0x100 * channel), data->f1x48);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x4c + 
(0x100 * channel), data->f1x4c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x50 + 
(0x100 * channel), data->f1x50);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x54 + 
(0x100 * channel), data->f1x54);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x58 + 
(0x100 * channel), data->f1x58);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x5c + 
(0x100 * channel), data->f1x5c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x60 + 
(0x100 * channel), data->f1x60);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x64 + 
(0x100 * channel), data->f1x64);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x68 + 
(0x100 * channel), data->f1x68);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x6c + 
(0x100 * channel), data->f1x6c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x70 + 
(0x100 * channel), data->f1x70);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x74 + 
(0x100 * channel), data->f1x74);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x78 + 
(0x100 * channel), data->f1x78);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x7c + 
(0x100 * channel), data->f1x7c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0xf0 + 
(0x100 * channel), data->f1xf0);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x120 + 
(0x100 * channel), data->f1x120);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x124 + 
(0x100 * channel), data->f1x124);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x10c + 
(0x100 * channel), data->f2x10c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x114 + 
(0x100 * channel), data->f2x114);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x118 + 
(0x100 * channel), data->f2x118);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x11c + 
(0x100 * channel), data->f2x11c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x1b0 + 
(0x100 * channel), data->f2x1b0);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x44 + 
(0x100 * channel), data->f3x44);
-+                      for (i=0; i<16; i++) {
-+                              wrmsr_uint64_t(0x00000200 | i, 
data->msr0000020[i]);
-+                      }
-+                      wrmsr_uint64_t(0x00000250, data->msr00000250);
-+                      wrmsr_uint64_t(0x00000258, data->msr00000258);
-+                      /* FIXME
-+                       * Restoring these MSRs causes a hang on resume
-+                       * For now, skip restoration...
-+                       */
-+                      // for (i=0; i<8; i++)
-+                      //      wrmsr_uint64_t(0x00000260 | (i + 8), 
data->msr0000026[i]);
-+                      wrmsr_uint64_t(0x000002ff, data->msr000002ff);
-+                      wrmsr_uint64_t(0xc0010010, data->msrc0010010);
-+                      wrmsr_uint64_t(0xc001001a, data->msrc001001a);
-+                      wrmsr_uint64_t(0xc001001d, data->msrc001001d);
-+                      wrmsr_uint64_t(0xc001001f, data->msrc001001f);
-+              }
-+      }
-+
-+      /* Stage 3 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      ganged = !!(data->f2x110 & 0x10);
-+                      if ((ganged == 1) && (channel > 0))
-+                              continue;
-+
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x40 + 
(0x100 * channel), data->f2x40);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x44 + 
(0x100 * channel), data->f2x44);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x48 + 
(0x100 * channel), data->f2x48);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x4c + 
(0x100 * channel), data->f2x4c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x50 + 
(0x100 * channel), data->f2x50);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x54 + 
(0x100 * channel), data->f2x54);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x58 + 
(0x100 * channel), data->f2x58);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x5c + 
(0x100 * channel), data->f2x5c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x60 + 
(0x100 * channel), data->f2x60);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x64 + 
(0x100 * channel), data->f2x64);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x68 + 
(0x100 * channel), data->f2x68);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x6c + 
(0x100 * channel), data->f2x6c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x78 + 
(0x100 * channel), data->f2x78);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x7c + 
(0x100 * channel), data->f2x7c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x80 + 
(0x100 * channel), data->f2x80);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x84 + 
(0x100 * channel), data->f2x84);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x88 + 
(0x100 * channel), data->f2x88);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x8c + 
(0x100 * channel), data->f2x8c);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), data->f2x90);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa4 + 
(0x100 * channel), data->f2xa4);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa8 + 
(0x100 * channel), data->f2xa8);
-+              }
-+      }
-+
-+      /* Stage 4 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      ganged = !!(data->f2x110 & 0x10);
-+                      if ((ganged == 1) && (channel > 0))
-+                              continue;
-+
-+                      /* Disable PHY auto-compensation engine */
-+                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
-+                      if (!(dword & (1 << 30))) {
-+                              dword |= (1 << 30);
-+                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08, dword);
-+
-+                              /* Wait for 5us */
-+                              mct_Wait(100);
-+                      }
-+
-+                      /* Restore DRAM Configuration High Register */
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x94 + 
(0x100 * channel), data->f2x94);
-+
-+                      /* Enable PHY auto-compensation engine */
-+                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
-+                      dword &= ~(1 << 30);
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x08, dword);
-+              }
-+      }
-+
-+      /* Wait for 750us */
-+      mct_Wait(15000);
-+
-+      /* Stage 5 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      ganged = !!(data->f2x110 & 0x10);
-+                      if ((ganged == 1) && (channel > 0))
-+                              continue;
-+
-+                      /* Wait for any pending PHY frequency changes to 
complete */
-+                      do {
-+                              dword = read_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x08);
-+                      } while (dword & (1 << 21));
-+              }
-+      }
-+
-+      /* Stage 6 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      for (i=0; i<9; i++)
-+                              for (j=0; j<3; j++)
-+                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x00, data->f2x9cx00);
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0a, data->f2x9cx0a);
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0c, data->f2x9cx0c);
-+              }
-+      }
-+
-+      /* Stage 7 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      ganged = !!(data->f2x110 & 0x10);
-+                      if ((ganged == 1) && (channel > 0))
-+                              continue;
-+
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x04, data->f2x9cx04);
-+              }
-+      }
-+
-+      /* Stage 8 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      dct_enabled = !(data->f2x94 & (1 << 14));
-+                      if (!dct_enabled)
-+                              continue;
-+
-+                      ganged = !!(data->f2x110 & 0x10);
-+                      if ((ganged == 1) && (channel > 0))
-+                              continue;
-+
-+                      printk(BIOS_SPEW, "Taking DIMMs out of self refresh 
node: %d channel: %d\n", node, channel);
-+
-+                      /* Exit self refresh mode */
-+                      dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 
0x90 + (0x100 * channel));
-+                      dword |= (1 << 1);
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), dword);
-+              }
-+      }
-+
-+      /* Stage 9 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      dct_enabled = !(data->f2x94 & (1 << 14));
-+                      if (!dct_enabled)
-+                              continue;
-+
-+                      printk(BIOS_SPEW, "Waiting for DIMMs to exit self 
refresh node: %d channel: %d\n", node, channel);
-+
-+                      /* Wait for transition from self refresh mode to 
complete */
-+                      do {
-+                              dword = pci_read_config32(PCI_DEV(0, 0x18 + 
node, 2), 0x90 + (0x100 * channel));
-+                      } while (dword & (1 << 1));
-+
-+                      /* Restore registers */
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe006, data->f2x9cx0d0fe006);
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe007, data->f2x9cx0d0fe007);
-+              }
-+      }
-+
-+      /* Stage 10 */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      for (i=0; i<12; i++)
-+                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x10 + i, data->f2x9cx10[i]);
-+                      for (i=0; i<12; i++)
-+                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x20 + i, data->f2x9cx20[i]);
-+                      for (i=0; i<4; i++)
-+                              for (j=0; j<3; j++)
-+                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j), 
data->f2x9cx3_0_0_3_1[i][j]);
-+                      for (i=0; i<4; i++)
-+                              for (j=0; j<3; j++)
-+                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j), 
data->f2x9cx3_0_0_7_5[i][j]);
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d, data->f2x9cx0d);
-+                      for (i=0; i<9; i++)
-+                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8), 
data->f2x9cx0d0f0_f_0_13[i]);
-+                      for (i=0; i<9; i++)
-+                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8), 
data->f2x9cx0d0f0_f_0_30[i]);
-+                      for (i=0; i<4; i++)
-+                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8), 
data->f2x9cx0d0f2_f_0_30[i]);
-+                      for (i=0; i<2; i++)
-+                              for (j=0; j<3; j++)
-+                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f8_8_4_0[i][j]);
-+                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0f812f, data->f2x9cx0d0f812f);
-+              }
-+      }
-+
-+      /* Stage 11 */
-+      if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+                      for (channel = 0; channel < 2; channel++) {
-+                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
-+                              if (!persistent_data->node[node].node_present)
-+                                      continue;
-+
-+                              for (i=0; i<12; i++)
-+                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x30 + i, data->f2x9cx30[i]);
-+                              for (i=0; i<12; i++)
-+                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x40 + i, data->f2x9cx40[i]);
-+                      }
-+              }
-+      }
-+
-+      /* Other */
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              for (channel = 0; channel < 2; channel++) {
-+                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
-+                      if (!persistent_data->node[node].node_present)
-+                              continue;
-+
-+                      /* ECC scrub rate control */
-+                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x58, 
data->f3x58);
-+              }
-+      }
-+}
-+#endif
-+
-+#ifdef __RAMSTAGE__
-+int8_t save_mct_information_to_nvram(void)
-+{
-+      if (acpi_is_wakeup_s3())
-+              return 0;
-+
-+      printk(BIOS_DEBUG, "Writing AMD DCT configuration to Flash\n");
-+
-+      struct spi_flash *flash;
-+      ssize_t s3nv_offset;
-+      struct amd_s3_persistent_data persistent_data;
-+
-+      /* Obtain MCT configuration data */
-+      copy_mct_data_to_save_variable(&persistent_data);
-+
-+      /* Obtain CBFS file offset */
-+      s3nv_offset = get_s3nv_file_offset();
-+      if (s3nv_offset == -1)
-+              return -1;
-+
-+      /* Align flash pointer to nearest boundary */
-+      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
-+      s3nv_offset += CONFIG_S3_DATA_SIZE;
-+
-+      /* Set temporary SPI MMIO address */
-+      device_t lpc_dev = dev_find_slot(0, PCI_DEVFN(0x14, 3));
-+      uint32_t spi_mmio_prev = pci_read_config32(lpc_dev, 0xa0);
-+      pci_write_config32(lpc_dev, 0xa0, (spi_mmio_prev & 0x1f) | 0xf0000000);
-+
-+      /* Initialize SPI and detect devices */
-+      spi_init();
-+      flash = spi_flash_probe(0, 0);
-+      if (!flash) {
-+              printk(BIOS_DEBUG, "Could not find SPI device\n");
-+              return -1;
-+      }
-+
-+      /* Set up SPI flash access */
-+      flash->spi->rw = SPI_WRITE_FLAG;
-+      spi_claim_bus(flash->spi);
-+
-+      /* Erase and write data structure */
-+      flash->erase(flash, s3nv_offset, CONFIG_S3_DATA_SIZE);
-+      flash->write(flash, s3nv_offset, sizeof(struct amd_s3_persistent_data), 
&persistent_data);
-+
-+      /* Tear down SPI flash access */
-+      flash->spi->rw = SPI_WRITE_FLAG;
-+      spi_release_bus(flash->spi);
-+
-+      /* Restore SPI MMIO address */
-+      pci_write_config32(lpc_dev, 0xa0, spi_mmio_prev);
-+
-+      return 0;
-+}
-+#endif
-+
-+int8_t restore_mct_information_from_nvram(void)
-+{
-+      ssize_t s3nv_offset;
-+      struct amd_s3_persistent_data persistent_data;
-+
-+      /* Obtain CBFS file offset */
-+      s3nv_offset = get_s3nv_file_offset();
-+      if (s3nv_offset == -1)
-+              return -1;
-+
-+      /* Align flash pointer to nearest boundary */
-+      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
-+      s3nv_offset += CONFIG_S3_DATA_SIZE;
-+
-+      cbfs_read(CBFS_DEFAULT_MEDIA, &persistent_data, s3nv_offset, 
sizeof(struct amd_s3_persistent_data));
-+      restore_mct_data_from_save_variable(&persistent_data);
-+
-+      return 0;
-+}
-\ No newline at end of file
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-new file mode 100644
-index 0000000..dcddcad
---- /dev/null
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-@@ -0,0 +1,28 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
-+ */
-+
-+#include "../wrappers/mcti.h"
-+#include "mct_d.h"
-+
-+#ifdef __RAMSTAGE__
-+int8_t save_mct_information_to_nvram(void);
-+#endif
-+int8_t restore_mct_information_from_nvram(void);
-+void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data);
-+void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data);
-\ No newline at end of file
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0020-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0020-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
deleted file mode 100644
index 672a21f..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0020-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 043f3abb58733fe14feb7cca5c2101f6a905aeb8 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:46:24 -0500
-Subject: [PATCH 020/139] cpu/amd/car: Add initial Suspend to RAM (S3) support
-
-Change-Id: I1e1a67fa3c2c13cebcf8f0af318055b9d97d0a59
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/car/post_cache_as_ram.c | 12 ++++++++++++
- 1 file changed, 12 insertions(+)
-
-diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
-index 230d1aa..e265de1 100644
---- a/src/cpu/amd/car/post_cache_as_ram.c
-+++ b/src/cpu/amd/car/post_cache_as_ram.c
-@@ -1,4 +1,5 @@
- /* Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2012 ChromeOS Authors
-  * 2005.6 by yhlu
-  * 2006.3 yhlu add copy data from CAR to ram
-  */
-@@ -9,6 +10,7 @@
- #include <cpu/amd/mtrr.h>
- #include <cpu/amd/car.h>
- #include <arch/acpi.h>
-+#include <romstage_handoff.h>
- #include "cbmem.h"
- #include "cpu/amd/car/disable_cache_as_ram.c"
- 
-@@ -103,6 +105,13 @@ void post_cache_as_ram(void)
- {
-       void *resume_backup_memory = NULL;
- 
-+      struct romstage_handoff *handoff;
-+      handoff = romstage_handoff_find_or_add();
-+      if (handoff != NULL)
-+              handoff->s3_resume = acpi_is_wakeup_s3();
-+      else
-+              printk(BIOS_DEBUG, "Romstage handoff structure not added!\n");
-+
-       int s3resume = acpi_is_wakeup_s3();
-       if (s3resume) {
-               cbmem_recovery(s3resume);
-@@ -150,6 +159,9 @@ void cache_as_ram_new_stack (void)
- 
-       if (acpi_is_wakeup_s3()) {
-               resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
-+#if PRINTK_IN_CAR
-+              printk(BIOS_DEBUG, "Resume backup memory location: %p\n", 
resume_backup_memory);
-+#endif
-       }
-       prepare_ramstage_region(resume_backup_memory);
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0020-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
 
b/resources/libreboot/patch/kgpe-d16/0020-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
new file mode 100644
index 0000000..31f37ec
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0020-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch
@@ -0,0 +1,135 @@
+From 41778c7eef84c582216fd517274b55637bb3bbc3 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:39:34 -0500
+Subject: [PATCH 020/143] northbridge/amd/amdfam10: Add Suspend to RAM (S3)
+ Flash data storage area
+
+Change-Id: I169fafc3a61e11c3e4781190053e57bf34502d7b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/Kconfig          |    6 +++
+ src/northbridge/amd/amdfam10/Makefile.inc     |   19 ++++++++++
+ src/northbridge/amd/amdfam10/raminit_amdmct.c |   50 ++++++++++++++-----------
+ 3 files changed, 53 insertions(+), 22 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/Kconfig 
b/src/northbridge/amd/amdfam10/Kconfig
+index 4d7147d..ff92fca 100644
+--- a/src/northbridge/amd/amdfam10/Kconfig
++++ b/src/northbridge/amd/amdfam10/Kconfig
+@@ -89,6 +89,12 @@ if DIMM_FBDIMM
+               default 0x0110
+ endif
+ 
++if HAVE_ACPI_RESUME
++      config S3_DATA_SIZE
++              int
++              default 16384
++endif
++
+ if DIMM_DDR2
+       if DIMM_REGISTERED
+       config DIMM_SUPPORT
+diff --git a/src/northbridge/amd/amdfam10/Makefile.inc 
b/src/northbridge/amd/amdfam10/Makefile.inc
+index 8a105fd..b4097b4 100644
+--- a/src/northbridge/amd/amdfam10/Makefile.inc
++++ b/src/northbridge/amd/amdfam10/Makefile.inc
+@@ -15,4 +15,23 @@ ramstage-y += get_pci1234.c
+ # Call show_all_routes() anywhere amdfam10.h is included.
+ #ramstage-y += util.c
+ 
++ifeq ($(CONFIG_HAVE_ACPI_RESUME), y)
++
++$(obj)/coreboot_s3nv.rom: $(obj)/config.h
++      echo "    S3 NVRAM   $(CONFIG_S3_DATA_POS) (S3 storage area)"
++      # force C locale, so cygwin awk doesn't try to interpret the 0xff below 
as UTF-8 (or worse)
++      printf %d $(CONFIG_S3_DATA_SIZE) | LC_ALL=C awk '{for (i=0; i<$$1*2; 
i++) {printf "%c", 255}}' > address@hidden
++      mv address@hidden $@
++
++cbfs-files-y += s3nv
++s3nv-file := $(obj)/coreboot_s3nv.rom
++s3nv-position := $(CONFIG_S3_DATA_POS)
++s3nv-type := raw
++
++ifeq ($(CONFIG_DIMM_DDR3), y)
++ramstage-y += ../amdmct/mct_ddr3/s3utils.c
++endif
++
++endif
++
+ endif
+diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+index 3f33eba..5068e7a 100644
+--- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
++++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+@@ -110,6 +110,10 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t 
registered, uint16_t freq
+ #include "../amdmct/mct_ddr3/mct_d.h"
+ #include "../amdmct/mct_ddr3/mct_d_gcc.h"
+ 
++#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
++#include "../amdmct/mct_ddr3/s3utils.c"
++#endif
++
+ #include "../amdmct/wrappers/mcti_d.c"
+ #include "../amdmct/mct_ddr3/mct_d.c"
+ 
+@@ -249,33 +253,35 @@ static void amdmct_cbmem_store_info(struct sys_info 
*sysinfo)
+       size_t i;
+       struct DCTStatStruc *pDCTstatA = NULL;
+ 
+-      /* Allocate memory */
+-      struct amdmct_memory_info* mem_info;
+-      mem_info = cbmem_add(CBMEM_ID_AMDMCT_MEMINFO, sizeof(struct 
amdmct_memory_info));
+-      if (!mem_info)
+-              return;
++      if (!acpi_is_wakeup_s3()) {
++              /* Allocate memory */
++              struct amdmct_memory_info* mem_info;
++              mem_info = cbmem_add(CBMEM_ID_AMDMCT_MEMINFO, sizeof(struct 
amdmct_memory_info));
++              if (!mem_info)
++                      return;
+ 
+-      printk(BIOS_DEBUG, "%s: Storing AMDMCT configuration in CBMEM\n", 
__func__);
++              printk(BIOS_DEBUG, "%s: Storing AMDMCT configuration in 
CBMEM\n", __func__);
+ 
+-      /* Initialize memory */
+-      memset(mem_info, 0,  sizeof(struct amdmct_memory_info));
++              /* Initialize memory */
++              memset(mem_info, 0,  sizeof(struct amdmct_memory_info));
+ 
+-      /* Copy data */
+-      memcpy(&mem_info->mct_stat, &(sysinfo->MCTstat), sizeof(struct 
MCTStatStruc));
+-      for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
+-              pDCTstatA = sysinfo->DCTstatA + i;
+-              memcpy(&mem_info->dct_stat[i], pDCTstatA, sizeof(struct 
DCTStatStruc));
+-      }
+-      mem_info->ecc_enabled = mctGet_NVbits(NV_ECC_CAP);
+-      mem_info->ecc_scrub_rate = mctGet_NVbits(NV_DramBKScrub);
++              /* Copy data */
++              memcpy(&mem_info->mct_stat, &(sysinfo->MCTstat), sizeof(struct 
MCTStatStruc));
++              for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
++                      pDCTstatA = sysinfo->DCTstatA + i;
++                      memcpy(&mem_info->dct_stat[i], pDCTstatA, sizeof(struct 
DCTStatStruc));
++              }
++              mem_info->ecc_enabled = mctGet_NVbits(NV_ECC_CAP);
++              mem_info->ecc_scrub_rate = mctGet_NVbits(NV_DramBKScrub);
+ 
+-      /* Zero out invalid/unused pointers */
++              /* Zero out invalid/unused pointers */
+ #if IS_ENABLED(CONFIG_DIMM_DDR3)
+-      for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
+-              mem_info->dct_stat[i].C_MCTPtr = NULL;
+-              mem_info->dct_stat[i].C_DCTPtr[0] = NULL;
+-              mem_info->dct_stat[i].C_DCTPtr[1] = NULL;
+-      }
++              for (i = 0; i < MAX_NODES_SUPPORTED; i++) {
++                      mem_info->dct_stat[i].C_MCTPtr = NULL;
++                      mem_info->dct_stat[i].C_DCTPtr[0] = NULL;
++                      mem_info->dct_stat[i].C_DCTPtr[1] = NULL;
++              }
+ #endif
++      }
+ }
+ #endif
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0021-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
 
b/resources/libreboot/patch/kgpe-d16/0021-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
deleted file mode 100644
index 83ee459..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0021-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
+++ /dev/null
@@ -1,832 +0,0 @@
-From 65fa0d700672fcc4556f0d3300912e336a727d87 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 7 May 2015 01:32:08 -0500
-Subject: [PATCH 021/139] mainboard/asus/kgpe-d16: Add initial Suspend to RAM
- (S3) support
-
-Change-Id: I7da84b064287a445fd75a947e2f96ce1ae30d3de
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/Kconfig          |   3 +
- src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl | 639 ++++++++++++++-------------
- src/mainboard/asus/kgpe-d16/dsdt.asl         |   5 +-
- src/mainboard/asus/kgpe-d16/romstage.c       |  34 +-
- src/mainboard/asus/kgpe-d16/spd_notes.txt    |  16 +
- 5 files changed, 369 insertions(+), 328 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-index 95b3b5b..f9556fc 100644
---- a/src/mainboard/asus/kgpe-d16/Kconfig
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -23,6 +23,9 @@ config BOARD_SPECIFIC_OPTIONS # dummy
-       select BOARD_ROMSIZE_KB_2048
-       select ENABLE_APIC_EXT_ID
-       select MMCONF_SUPPORT_DEFAULT
-+      select SPI_FLASH
-+      select SPI_FLASH_WINBOND
-+      select HAVE_ACPI_RESUME
-       select DRIVERS_I2C_W83795
-       select DRIVERS_ASPEED_AST2050
-       select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG
-diff --git a/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl 
b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
-index b3c65ca..737d8cd 100644
---- a/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
-+++ b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
-@@ -18,350 +18,359 @@
-  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-  */
- 
-+/* Port 80 POST card debug */
-+OperationRegion (DBG0, SystemIO, 0x80, One)
-+      Field (DBG0, ByteAcc, NoLock, Preserve) {
-+      DBG8, 8
-+}
-+
-+/* SuperIO control port */
-+Name (SPIO, 0x2E)
-+
-+/* SuperIO control map */
-+OperationRegion (SPIM, SystemIO, SPIO, 0x02)
-+      Field (SPIM, ByteAcc, NoLock, Preserve) {
-+      INDX, 8,
-+      DATA, 8
-+}
-+
-+/* SuperIO control registers */
-+IndexField (INDX, DATA, ByteAcc, NoLock, Preserve) {
-+      Offset (0x07),
-+      CR07, 8,                /* Logical device number */
-+      Offset (0x2C),
-+      CR2C, 8,                /* GPIO3 multiplexed pin selection */
-+      Offset (0x30),
-+      CR30, 8,                /* Logical device activation control register */
-+      Offset (0xE0),
-+      CRE0, 8,                /* Wake control register */
-+      Offset (0xE4),
-+      CRE4, 8,                /* Standby power control register */
-+      Offset (0xE6),
-+      CRE6, 8,                /* Mouse wake event configuration register */
-+      Offset (0xF1),
-+      CRF1, 8,                /* GPIO3 data register */
-+      Offset (0xF3),
-+      CRF3, 8,                /* SUSLED mode register */
-+      Offset (0xF6),
-+      CRF6, 8,                /* SMI/PME event generation control register */
-+      Offset (0xF9),
-+      CRF9, 8,                /* ACPI PME configuration register */
-+}
-+
-+/* Power Management I/O registers */
-+OperationRegion(PIOR, SystemIO, 0x00000CD6, 0x00000002)
-+      Field(PIOR, ByteAcc, NoLock, Preserve) {
-+      PIOI, 0x00000008,
-+      PIOD, 0x00000008,
-+}
-+IndexField (PIOI, PIOD, ByteAcc, NoLock, Preserve) {
-+      Offset(0x00),   /* MiscControl */
-+      , 1,
-+      T1EE, 1,
-+      T2EE, 1,
-+      Offset(0x01),   /* MiscStatus */
-+      , 1,
-+      T1E, 1,
-+      T2E, 1,
-+      Offset(0x04),   /* SmiWakeUpEventEnable3 */
-+      , 7,
-+      SSEN, 1,
-+      Offset(0x07),   /* SmiWakeUpEventStatus3 */
-+      , 7,
-+      CSSM, 1,
-+      Offset(0x10),   /* AcpiEnable */
-+      , 6,
-+      PWDE, 1,
-+      Offset(0x1C),   /* ProgramIoEnable */
-+      , 3,
-+      MKME, 1,
-+      IO3E, 1,
-+      IO2E, 1,
-+      IO1E, 1,
-+      IO0E, 1,
-+      Offset(0x1D),   /* IOMonitorStatus */
-+      , 3,
-+      MKMS, 1,
-+      IO3S, 1,
-+      IO2S, 1,
-+      IO1S, 1,
-+      IO0S,1,
-+      Offset(0x20),   /* AcpiPmEvtBlk */
-+      APEB, 16,
-+      Offset(0x36),   /* GEvtLevelConfig */
-+      , 6,
-+      ELC6, 1,
-+      ELC7, 1,
-+      Offset(0x37),   /* GPMLevelConfig0 */
-+      , 3,
-+      PLC0, 1,
-+      PLC1, 1,
-+      PLC2, 1,
-+      PLC3, 1,
-+      PLC8, 1,
-+      Offset(0x38),   /* GPMLevelConfig1 */
-+      , 1,
-+              PLC4, 1,
-+              PLC5, 1,
-+      , 1,
-+              PLC6, 1,
-+              PLC7, 1,
-+      Offset(0x3B),   /* PMEStatus1 */
-+      GP0S, 1,
-+      GM4S, 1,
-+      GM5S, 1,
-+      APS, 1,
-+      GM6S, 1,
-+      GM7S, 1,
-+      GP2S, 1,
-+      STSS, 1,
-+      Offset(0x55),   /* SoftPciRst */
-+      SPRE, 1,
-+      , 1,
-+      , 1,
-+      PNAT, 1,
-+      PWMK, 1,
-+      PWNS, 1,
-+
-+      /*      Offset(0x61), */        /*  Options_1 */
-+      /*              ,7,  */
-+      /*              R617,1, */
-+
-+      Offset(0x65),   /* UsbPMControl */
-+      , 4,
-+      URRE, 1,
-+      , 2,
-+      BCDL, 1,
-+      Offset(0x68),   /* MiscEnable68 */
-+      , 2,
-+      MAPC, 1,
-+      TMTE, 1,
-+      , 1,
-+      Offset(0x7C),   /* MiscEnable7C */
-+      , 2,
-+      BLNK, 2,
-+      Offset(0x92),   /* GEVENTIN */
-+      , 7,
-+      E7IS, 1,
-+      Offset(0x96),   /* GPM98IN */
-+      G8IS, 1,
-+      G9IS, 1,
-+      Offset(0x9A),   /* EnhanceControl */
-+      ,7,
-+      HPDE, 1,
-+      Offset(0xA8),   /* PIO7654Enable */
-+      IO4E, 1,
-+      IO5E, 1,
-+      IO6E, 1,
-+      IO7E, 1,
-+      Offset(0xA9),   /* PIO7654Status */
-+      IO4S, 1,
-+      IO5S, 1,
-+      IO6S, 1,
-+      IO7S, 1,
-+}
-+
-+/* PM1 Event Block
-+      * First word is PM1_Status, Second word is PM1_Enable
-+      */
-+OperationRegion(P1EB, SystemIO, APEB, 0x04)
-+      Field(P1EB, ByteAcc, NoLock, Preserve) {
-+      TMST, 1,
-+      ,    3,
-+      BMST,    1,
-+      GBST,   1,
-+      Offset(0x01),
-+      PBST, 1,
-+      , 1,
-+      RTST, 1,
-+      , 3,
-+      PWST, 1,
-+      SPWS, 1,
-+      Offset(0x02),
-+      TMEN, 1,
-+      , 4,
-+      GBEN, 1,
-+      Offset(0x03),
-+      PBEN, 1,
-+      , 1,
-+      RTEN, 1,
-+      , 3,
-+      PWDA, 1,
-+}
-+
-+/* Wake status package */
-+Name(WKST,Package() {Zero, Zero})
-+
- /*
-- * WARNING: Sleep/Wake is a work in progress and is still somewhat flaky!
-+ *  \_WAK System Wake method
-+ *
-+ *    Entry:
-+ *            Arg0=The value of the sleeping state S1=1, S2=2
-+ *
-+ *    Exit:
-+ *            Return package of 2 DWords
-+ *            Dword 1 - Status
-+ *                    0x00000000      wake succeeded
-+ *                    0x00000001      Wake was signaled but failed due to 
lack of power
-+ *                    0x00000002      Wake was signaled but failed due to 
thermal condition
-+ *            Dword 2 - Power Supply state
-+ *                    if non-zero the effective S-state the power supply 
entered
-  */
--
--      /* Port 80 POST card debug */
--      OperationRegion (DBG0, SystemIO, 0x80, One)
--              Field (DBG0, ByteAcc, NoLock, Preserve) {
--              DBG8, 8
--      }
--
--      /* SuperIO control port */
--      Name (SPIO, 0x2E)
--
--      /* SuperIO control map */
--      OperationRegion (SPIM, SystemIO, SPIO, 0x02)
--              Field (SPIM, ByteAcc, NoLock, Preserve) {
--              INDX, 8,
--              DATA, 8
--      }
--
--      /* SuperIO control registers */
--      IndexField (INDX, DATA, ByteAcc, NoLock, Preserve) {
--              Offset (0x07),
--              CR07, 8,                /* Logical device number */
--              Offset (0x2C),
--              CR2C, 8,                /* GPIO3 multiplexed pin selection */
--              Offset (0x30),
--              CR30, 8,                /* Logical device activation control 
register */
--              Offset (0xE0),
--              CRE0, 8,                /* Wake control register */
--              Offset (0xE6),
--              CRE6, 8,                /* Mouse wake event configuration 
register */
--              Offset (0xF1),
--              CRF1, 8,                /* GPIO3 data register */
--              Offset (0xF3),
--              CRF3, 8,                /* SUSLED mode register */
--              Offset (0xF6),
--              CRF6, 8,                /* SMI/PME event generation control 
register */
--              Offset (0xF9),
--              CRF9, 8,                /* ACPI PME configuration register */
-+Method(\_WAK, 1) {
-+      Store (0x20, DBG8)
-+
-+      /* Set up LEDs */
-+      /* Set power LED to steady on */
-+      Store(0x3, BLNK)
-+
-+      /* Configure SuperIO for wake */
-+      /* Access SuperIO ACPI device */
-+      Store(0x87, INDX)
-+      Store(0x87, INDX)
-+      Store(0x0A, CR07)
-+
-+      if (LEqual(Arg0, One))  /* Resuming from power state S1 */
-+      {
-+              /* Deactivate the ACPI device */
-+              Store(Zero, CR30)
-+
-+              /* Disable PS/2 SMI/PME events */
-+              And(CRF6, 0xCF, CRF6)
-       }
--
--      /* Power Management I/O registers */
--      OperationRegion(PIOR, SystemIO, 0x00000CD6, 0x00000002)
--              Field(PIOR, ByteAcc, NoLock, Preserve) {
--              PIOI, 0x00000008,
--              PIOD, 0x00000008,
--      }
--      IndexField (PIOI, PIOD, ByteAcc, NoLock, Preserve) {
--              Offset(0x00),   /* MiscControl */
--              , 1,
--              T1EE, 1,
--              T2EE, 1,
--              Offset(0x01),   /* MiscStatus */
--              , 1,
--              T1E, 1,
--              T2E, 1,
--              Offset(0x04),   /* SmiWakeUpEventEnable3 */
--              , 7,
--              SSEN, 1,
--              Offset(0x07),   /* SmiWakeUpEventStatus3 */
--              , 7,
--              CSSM, 1,
--              Offset(0x10),   /* AcpiEnable */
--              , 6,
--              PWDE, 1,
--              Offset(0x1C),   /* ProgramIoEnable */
--              , 3,
--              MKME, 1,
--              IO3E, 1,
--              IO2E, 1,
--              IO1E, 1,
--              IO0E, 1,
--              Offset(0x1D),   /* IOMonitorStatus */
--              , 3,
--              MKMS, 1,
--              IO3S, 1,
--              IO2S, 1,
--              IO1S, 1,
--              IO0S,1,
--              Offset(0x20),   /* AcpiPmEvtBlk */
--              APEB, 16,
--              Offset(0x36),   /* GEvtLevelConfig */
--              , 6,
--              ELC6, 1,
--              ELC7, 1,
--              Offset(0x37),   /* GPMLevelConfig0 */
--              , 3,
--              PLC0, 1,
--              PLC1, 1,
--              PLC2, 1,
--              PLC3, 1,
--              PLC8, 1,
--              Offset(0x38),   /* GPMLevelConfig1 */
--              , 1,
--               PLC4, 1,
--               PLC5, 1,
--              , 1,
--               PLC6, 1,
--               PLC7, 1,
--              Offset(0x3B),   /* PMEStatus1 */
--              GP0S, 1,
--              GM4S, 1,
--              GM5S, 1,
--              APS, 1,
--              GM6S, 1,
--              GM7S, 1,
--              GP2S, 1,
--              STSS, 1,
--              Offset(0x55),   /* SoftPciRst */
--              SPRE, 1,
--              , 1,
--              , 1,
--              PNAT, 1,
--              PWMK, 1,
--              PWNS, 1,
--
--              /*      Offset(0x61), */        /*  Options_1 */
--              /*              ,7,  */
--              /*              R617,1, */
--
--              Offset(0x65),   /* UsbPMControl */
--              , 4,
--              URRE, 1,
--              Offset(0x68),   /* MiscEnable68 */
--              , 3,
--              TMTE, 1,
--              , 1,
--              Offset(0x7C),   /* MiscEnable7C */
--              , 2,
--              BLNK, 2,
--              Offset(0x92),   /* GEVENTIN */
--              , 7,
--              E7IS, 1,
--              Offset(0x96),   /* GPM98IN */
--              G8IS, 1,
--              G9IS, 1,
--              Offset(0x9A),   /* EnhanceControl */
--              ,7,
--              HPDE, 1,
--              Offset(0xA8),   /* PIO7654Enable */
--              IO4E, 1,
--              IO5E, 1,
--              IO6E, 1,
--              IO7E, 1,
--              Offset(0xA9),   /* PIO7654Status */
--              IO4S, 1,
--              IO5S, 1,
--              IO6S, 1,
--              IO7S, 1,
-+      if (Lor(LEqual(Arg0, 0x03), LEqual(Arg0, 0x04)))        /* Resuming 
from power state S3 or S4 */
-+      {
-+              /* Disable PS/2 wake */
-+              And(CRE0, 0x1D, CRE0)
-+              And(CRE6, 0x7F, CRE6)
-       }
- 
--      /* PM1 Event Block
--       * First word is PM1_Status, Second word is PM1_Enable
--       */
--      OperationRegion(P1EB, SystemIO, APEB, 0x04)
--              Field(P1EB, ByteAcc, NoLock, Preserve) {
--              TMST, 1,
--              ,    3,
--              BMST,    1,
--              GBST,   1,
--              Offset(0x01),
--              PBST, 1,
--              , 1,
--              RTST, 1,
--              , 3,
--              PWST, 1,
--              SPWS, 1,
--              Offset(0x02),
--              TMEN, 1,
--              , 4,
--              GBEN, 1,
--              Offset(0x03),
--              PBEN, 1,
--              , 1,
--              RTEN, 1,
--              , 3,
--              PWDA, 1,
--      }
--
--      /* Wake status package */
--      Name(WKST,Package(){Zero, Zero})
--
--      /*
--       *  \_WAK System Wake method
--       *
--       *      Entry:
--       *              Arg0=The value of the sleeping state S1=1, S2=2
--       *
--       *      Exit:
--       *              Return package of 2 DWords
--       *              Dword 1 - Status
--       *                      0x00000000      wake succeeded
--       *                      0x00000001      Wake was signaled but failed 
due to lack of power
--       *                      0x00000002      Wake was signaled but failed 
due to thermal condition
--       *              Dword 2 - Power Supply state
--       *                      if non-zero the effective S-state the power 
supply entered
--       */
--      Method(\_WAK, 1) {
--              Store (0x20, DBG8)
--
--              /* Set up LEDs */
--              /* Set power LED to steady on */
--              Store(0x3, BLNK)
--
--              /* Configure SuperIO for wake */
--              /* Access SuperIO ACPI device */
--              Store(0x87, INDX)
--              Store(0x87, INDX)
--              Store(0x0A, CR07)
--
--              if (LEqual(Arg0, One))  /* Resuming from power state S1 */
--              {
--                      /* Deactivate the ACPI device */
--                      Store(Zero, CR30)
--
--                      /* Disable PS/2 SMI/PME events */
--                      And(CRF6, 0xCF, CRF6)
--              }
--              if (Lor(LEqual(Arg0, 0x03), LEqual(Arg0, 0x04)))        /* 
Resuming from power state S3 or S4 */
--              {
--                      /* Disable PS/2 wake */
--                      And(CRE0, 0x1D, CRE0)
--                      And(CRE6, 0x7F, CRE6)
--              }
-+      /* Restore default SuperIO access */
-+      Store(0xAA, INDX)
- 
--              /* Restore default SuperIO access */
--              Store(0xAA, INDX)
-+      Store (0x21, DBG8)
- 
--              Store (0x21, DBG8)
-+      /* Re-enable HPET */
-+      Store(1, HPDE)
- 
--              /* Re-enable HPET */
--              Store(1, HPDE)
-+      /* Restore PCIRST# so it resets USB */
-+      if (LEqual(Arg0, 3)){
-+              Store(1, URRE)
-+      }
- 
--              /* Restore PCIRST# so it resets USB */
--              if (LEqual(Arg0, 3)){
--                      Store(1, URRE)
--              }
-+      /* Configure southbridge for wake */
-+      /* Arbitrarily clear PciExpWakeStatus */
-+      Store(PWST, PWST)
- 
--              /* Configure southbridge for wake */
--              /* Arbitrarily clear PciExpWakeStatus */
--              Store(PWST, PWST)
-+      Store (0x22, DBG8)
- 
--              Store (0x22, DBG8)
-+      Notify(\_SB.PWRB, 0x02)                 /* NOTIFY_DEVICE_WAKE */
- 
--              Notify(\_SB.PWRB, 0x02)                 /* NOTIFY_DEVICE_WAKE */
-+      Return(WKST)
-+}
- 
--              Return(WKST)
-+/*
-+ * \_PTS - Prepare to Sleep method
-+ *
-+ *    Entry:
-+ *            Arg0=The value of the sleeping state S1=1, S2=2, etc
-+ *
-+ * Exit:
-+ *            -none-
-+ *
-+ * The _PTS control method is executed at the beginning of the sleep process
-+ * for S1-S5. The sleeping value is passed to the _PTS control method.        
This
-+ * control method may be executed a relatively long time before entering the
-+ * sleep state and the OS may abort the operation without notification to
-+ * the ACPI driver.  This method cannot modify the configuration or power
-+ * state of any device in the system.
-+ */
-+Method(\_PTS, 1) {
-+      Store (Arg0, DBG8)
-+
-+      /* Set up LEDs */
-+      if (LEqual(Arg0, One))  /* Power state S1 requested */
-+      {
-+              /* Set suspend LED to 0.25Hz toggle pulse with 50% duty cycle */
-+              Store(0x2, BLNK)
-+      }
-+      if (LEqual(Arg0, 0x3))  /* Power state S3 requested */
-+      {
-+              /* Set suspend LED to 0.25Hz toggle pulse with 25% duty cycle */
-+              Store(0x1, BLNK)
-       }
- 
--      /*
--       * \_PTS - Prepare to Sleep method
--       *
--       *      Entry:
--       *              Arg0=The value of the sleeping state S1=1, S2=2, etc
--       *
--       * Exit:
--       *              -none-
--       *
--       * The _PTS control method is executed at the beginning of the sleep 
process
--       * for S1-S5. The sleeping value is passed to the _PTS control method.  
This
--       * control method may be executed a relatively long time before 
entering the
--       * sleep state and the OS may abort the operation without notification 
to
--       * the ACPI driver.  This method cannot modify the configuration or 
power
--       * state of any device in the system.
--       */
--      Method(\_PTS, 1) {
--              Store (Arg0, DBG8)
--
--              /* Set up LEDs */
--              if (LEqual(Arg0, One))  /* Power state S1 requested */
--              {
--                      /* Set suspend LED to 0.25Hz toggle pulse with 50% duty 
cycle */
--                      Store(0x2, BLNK)
--              }
--              if (LEqual(Arg0, 0x3))  /* Power state S3 requested */
--              {
--                      /* Set suspend LED to 0.25Hz toggle pulse with 25% duty 
cycle */
--                      Store(0x1, BLNK)
--              }
-+      /* Configure SuperIO for sleep */
-+      /* Access SuperIO ACPI device */
-+      Store(0x87, INDX)
-+      Store(0x87, INDX)
-+      Store(0x0A, CR07)
- 
--              /* Configure SuperIO for sleep */
--              /* Access SuperIO ACPI device */
--              Store(0x87, INDX)
--              Store(0x87, INDX)
--              Store(0x0A, CR07)
-+      /* Disable PS/2 wakeup and connect PANSW_IN to PANSW_OUT */
-+      And(CRE0, 0x1F, CRE0)
- 
--              /* Disable PS/2 wakeup and connect PANSW_IN to PANSW_OUT */
--              And(CRE0, 0x1F, CRE0)
-+      if (LEqual(Arg0, One))  /* Power state S1 requested */
-+      {
-+              /* Activate the ACPI device */
-+              Store(One, CR30)
- 
--              if (LEqual(Arg0, One))  /* Power state S1 requested */
--              {
--                      /* Activate the ACPI device */
--                      Store(One, CR30)
-+              /* Disable SMI/PME events for:
-+                      * LPT
-+                      * FDC
-+                      * UART
-+                      */
-+              Store(0x00, CRF6)
- 
--                      /* Disable SMI/PME events for:
--                       * LPT
--                       * FDC
--                       * UART
--                      Store(0x00, CRF6)
-+              /* Enable PS/2 keyboard SMI/PME events */
-+              Or(CRF6, 0x10, CRF6)
- 
--                      /* Enable PS/2 keyboard SMI/PME events */
--                      Or(CRF6, 0x10, CRF6)
-+              /* Enable PS/2 keyboard wake */
-+              Or(CRE0, 0x40, CRE0)
- 
--                      /* Enable PS/2 keyboard wake */
--                      Or(CRE0, 0x40, CRE0)
-+              /* Enable PS/2 mouse SMI/PME events */
-+              Or(CRF6, 0x20, CRF6)
- 
--                      /* Enable PS/2 mouse SMI/PME events */
--                      Or(CRF6, 0x20, CRF6)
-+              /* Enable PS/2 mouse wake  */
-+              Or(CRE0, 0x20, CRE0)
-+      } else {
-+              /* Enable PS/2 keyboard wake on any keypress */
-+              Or(CRE0, 0x41, CRE0)
- 
--                      /* Enable PS/2 mouse wake  */
--                      Or(CRE0, 0x20, CRE0)
--              } else {
--                      /* Enable PS/2 keyboard wake on any keypress */
--                      Or(CRE0, 0x41, CRE0)
-+              /* Enable PS/2 mouse wake on any click  */
-+              Or(CRE0, 0x22, CRE0)
-+              Or(CRE6, 0x80, CRE6)
- 
--                      /* Enable PS/2 mouse wake on any click  */
--                      Or(CRE0, 0x22, CRE0)
--                      Or(CRE6, 0x80, CRE6)
-+              if (LEqual(Arg0, 0x03)) /* Power state S3 requested */
-+              {
-+                      /* Set VSBGATE# to provide standby power during S3 */
-+                      Or(CRE4, 0x10, CRE4)
-               }
-+      }
- 
--              /* Restore default SuperIO access */
--              Store(0xAA, INDX)
-+      /* Restore default SuperIO access */
-+      Store(0xAA, INDX)
- 
--              Store (0x10, DBG8)
-+      Store (0x10, DBG8)
- 
--              /* Don't allow PCIRST# to reset USB */
--              if (LEqual(Arg0, 3)){
--                      Store(0, URRE)
--              }
-+      /* Don't allow PCIRST# to reset USB */
-+      if (LEqual(Arg0, 3)){
-+              Store(0, URRE)
-+      }
- 
--              /* Configure southbridge for sleep */
--              /* Clear sleep SMI status flag and enable sleep SMI trap. */
--              // Store(One, CSSM)     /* Set ExtEvent0 as SMI# source */
--              // Store(One, SSEN)     /* Enable wake on external event 0 */
-+      /* Configure southbridge for sleep */
-+      /* Use bus clock for delay timebase */
-+      Store(0, BCDL)
-+      /* Defer APIC interrupts until first ACPI access */
-+      Store(One, MAPC)
- 
--              /* On older chips, clear PciExpWakeDisEn */
--              // if (LLessEqual(SBRI, 0x13)) {
--              //      Store(0, PWDE)
--              // }
-+      /* On older chips, clear PciExpWakeDisEn */
-+      // if (LLessEqual(SBRI, 0x13)) {
-+      //      Store(0, PWDE)
-+      // }
- 
--              Store (0x11, DBG8)
-+      Store (0x11, DBG8)
- 
--              /* Clear wake status structure. */
--              Store(0, Index(WKST,0))
--              Store(0, Index(WKST,1))
--      }
-\ No newline at end of file
-+      /* Clear wake status structure. */
-+      Store(0, Index(WKST,0))
-+      Store(0, Index(WKST,1))
-+}
-diff --git a/src/mainboard/asus/kgpe-d16/dsdt.asl 
b/src/mainboard/asus/kgpe-d16/dsdt.asl
-index bdd1d2d..b6f10d9 100644
---- a/src/mainboard/asus/kgpe-d16/dsdt.asl
-+++ b/src/mainboard/asus/kgpe-d16/dsdt.asl
-@@ -58,9 +58,8 @@ DefinitionBlock (
-       /* Define power states */
-       Name (\_S0, Package () { 0x00, 0x00, 0x00, 0x00 })      /* Normal 
operation */
-       Name (\_S1, Package () { 0x01, 0x01, 0x00, 0x00 })      /* Standby */
--      Name (\_S2, Package () { 0x02, 0x02, 0x00, 0x00 })      /* Standby w/ 
CPU shutdown */
--      Name (\_S3, Package () { 0x03, 0x00, 0x00, 0x00 })      /* Suspend */
--      /* Name (\_S4, Package () { 0x04, 0x04, 0x00, 0x00 }) */
-+      Name (\_S3, Package () { 0x03, 0x03, 0x00, 0x00 })      /* Suspend to 
RAM */
-+      Name (\_S4, Package () { 0x04, 0x04, 0x00, 0x00 })      /* Suspend to 
disk */
-       Name (\_S5, Package () { 0x05, 0x05, 0x00, 0x00 })      /* Hard power 
off */
- 
-       /* The _PIC method is called by the OS to choose between interrupt
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index 616fdfb..3431bab 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -224,12 +224,15 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- {
-       struct sys_info *sysinfo = &sysinfo_car;
- 
--      u32 bsp_apicid = 0, val;
-+      uint32_t bsp_apicid = 0, val;
-+      uint8_t byte;
-       msr_t msr;
- 
-       timestamp_init(timestamp_get());
-       timestamp_add_now(TS_START_ROMSTAGE);
- 
-+      int s3resume = acpi_is_wakeup_s3();
-+
-       if (!cpu_init_detectedx && boot_cpu()) {
-               /* Nothing special needs to be done to find bus 0 */
-               /* Allow the HT devices to be found */
-@@ -247,6 +250,11 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               /* Initialize early serial */
-               nuvoton_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
-               console_init();
-+
-+              /* Disable LPC legacy DMA support to prevent lockup */
-+              byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0x78);
-+              byte &= ~(1 << 0);
-+              pci_write_config8(PCI_DEV(0, 0x14, 3), 0x78, byte);
-       }
- 
-       post_code(0x30);
-@@ -285,14 +293,6 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       amd_ht_fixup(sysinfo);
-       post_code(0x35);
- 
--      /* Set DDR memory voltage
--       * FIXME
--       * This should be set based on the output of the DIMM SPDs
--       * For now it is locked to 1.5V
--       */
--      set_ddr3_voltage(0, 0); /* Node 0 */
--      set_ddr3_voltage(1, 0); /* Node 1 */
--
-       /* Setup nodes PCI space and start core 0 AP init. */
-       finalize_node_setup(sysinfo);
- 
-@@ -355,6 +355,17 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               die("After soft_reset_x - shouldn't see this message!!!\n");
-       }
- 
-+      /* Set DDR memory voltage
-+       * FIXME
-+       * This should be set based on the output of the DIMM SPDs
-+       * For now it is locked to 1.5V
-+       */
-+      set_lpc_sticky_ctl(1);  /* Retain LPC/IMC GPIO configuration during S3 
sleep */
-+      if (!s3resume) {        /* Avoid supply voltage glitches while the 
DIMMs are retaining data */
-+              set_ddr3_voltage(0, 0); /* Node 0 */
-+              set_ddr3_voltage(1, 0); /* Node 1 */
-+      }
-+
-       /* Set up peripheral control lines */
-       set_peripheral_control_lines();
- 
-@@ -384,7 +395,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       timestamp_add_now(TS_AFTER_INITRAM);
- 
- #if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
--      cbmem_initialize_empty();
-+      if (s3resume)
-+              cbmem_initialize();
-+      else
-+              cbmem_initialize_empty();
-       post_code(0x41);
- 
-       amdmct_cbmem_store_info(sysinfo);
-diff --git a/src/mainboard/asus/kgpe-d16/spd_notes.txt 
b/src/mainboard/asus/kgpe-d16/spd_notes.txt
-index 623a88f..ddd5cc8 100644
---- a/src/mainboard/asus/kgpe-d16/spd_notes.txt
-+++ b/src/mainboard/asus/kgpe-d16/spd_notes.txt
-@@ -28,3 +28,19 @@ Other hardware
- 
- RECOVERY1 middle pin is connected to southbridge (AMD SP5100) GPIO 61
- Normal is HIGH, recovery is LOW.
-+
-++12VSB is generated using a charge pump attached to pin 7 of PU24 (APW7145).
-+
-+The +12VSB standby voltage to each bank of DIMMs is switched by a bank of 
small FETs located close to each RAM power regulator control chip.
-+The +12V primary voltage (lower left pin of the FET placed on the upper left 
of the control chip of the second node) is also connected to the 232GE located 
near the PCI slot.
-+
-+The control line running to the gates of the +12VSB control FETs is connected 
to the +5VSB power for the USB ports.
-+That line in turn is connected to +5VSB via the lone P06P03G PMOS transistor 
on the reverse side of the board, near the center on the lower half.
-+The gate of that transistor is connected via a resistor to the source of the 
P06P03G PMOS transistor located adjacent to the unpopulated SMA clock header.
-+The gate of that transistor is connected directly to the drain of the small 
FET directly below it.
-+After that, there's a cascade of small FETs and resistors in that region, 
eventually leading to SuperIO pin 81.
-+
-+SuperIO pin 81 (VSBGATE#) enables the standby voltage rails when set LOW.
-+VSBGATE# is reset on every assertion of PWRGOOD.
-+
-+Setting SuperIO LDN 9 CRF4 bits 1 or 0 (or both) to 0 disables NICB.
-\ No newline at end of file
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0021-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
 
b/resources/libreboot/patch/kgpe-d16/0021-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
new file mode 100644
index 0000000..65315b4
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0021-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch
@@ -0,0 +1,1017 @@
+From e0f5bb37ad0aacb69044c70bb61483cb1df72d08 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:40:31 -0500
+Subject: [PATCH 021/143] northbridge/amd/amdmct/mct_ddr3: Add initial Suspend
+ to RAM (S3) support
+
+Change-Id: Ic97567851fa40295bc21cefd7537407b99d71709
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/northbridge.c    |    8 +
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |  154 +++---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |  112 +++++
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c |  620 +++++++++++++++++++++++++
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.h |   28 ++
+ 5 files changed, 850 insertions(+), 72 deletions(-)
+ create mode 100644 src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+ create mode 100644 src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 74cecc8..d4fe986 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -54,6 +54,10 @@
+ #include <sb_cimx.h>
+ #endif
+ 
++#if IS_ENABLED(CONFIG_DIMM_DDR3)
++#include "../amdmct/mct_ddr3/s3utils.h"
++#endif
++
+ struct amdfam10_sysconf_t sysconf;
+ 
+ #define FX_DEVS NODE_NUMS
+@@ -1413,6 +1417,10 @@ static void root_complex_enable_dev(struct device *dev)
+       /* Do not delay UMA setup, as a device on the PCI bus may evaluate
+          the global uma_memory variables already in its enable function. */
+       if (!done) {
++#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) && IS_ENABLED(CONFIG_DIMM_DDR3)
++              save_mct_information_to_nvram();
++#endif
++
+               setup_bsp_ramtop();
+               setup_uma_memory();
+               done = 1;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index fa59d71..a8212c5 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -272,91 +272,101 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
+       u8 Node, NodesWmem;
+       u32 node_sys_base;
+ 
++      uint8_t s3resume = acpi_is_wakeup_s3();
++
+ restartinit:
+       mctInitMemGPIOs_A_D();          /* Set any required GPIOs*/
+-      NodesWmem = 0;
+-      node_sys_base = 0;
+-      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+-              struct DCTStatStruc *pDCTstat;
+-              pDCTstat = pDCTstatA + Node;
++      if (s3resume) {
++#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
++              restore_mct_information_from_nvram();
++#endif
++      } else {
++              NodesWmem = 0;
++              node_sys_base = 0;
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
+ 
+-              /* Zero out data structures to avoid false detection of DIMMs */
+-              memset(pDCTstat, 0, sizeof(struct DCTStatStruc));
+-
+-              /* Initialize data structures */
+-              pDCTstat->Node_ID = Node;
+-              pDCTstat->dev_host = PA_HOST(Node);
+-              pDCTstat->dev_map = PA_MAP(Node);
+-              pDCTstat->dev_dct = PA_DCT(Node);
+-              pDCTstat->dev_nbmisc = PA_NBMISC(Node);
+-              pDCTstat->NodeSysBase = node_sys_base;
+-
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node %d\n", 
Node);
+-              mct_init(pMCTstat, pDCTstat);
+-              mctNodeIDDebugPort_D();
+-              pDCTstat->NodePresent = NodePresent_D(Node);
+-              if (pDCTstat->NodePresent) {            /* See if Node is 
there*/
+-                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
+-                      clear_legacy_Mode(pMCTstat, pDCTstat);
+-                      pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node);
+-
+-                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
+-                      mct_InitialMCT_D(pMCTstat, pDCTstat);
+-
+-                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
+-                      mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
+-
+-                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_initDCT\n");
+-                      mct_initDCT(pMCTstat, pDCTstat);
+-                      if (pDCTstat->ErrCode == SC_FatalErr) {
+-                              goto fatalexit;         /* any fatal errors?*/
+-                      } else if (pDCTstat->ErrCode < SC_StopError) {
+-                              NodesWmem++;
+-                      }
+-              }       /* if Node present */
+-              node_sys_base = pDCTstat->NodeSysBase;
+-              node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
+-      }
+-      if (NodesWmem == 0) {
+-              printk(BIOS_DEBUG, "No Nodes?!\n");
+-              goto fatalexit;
+-      }
++                      /* Zero out data structures to avoid false detection of 
DIMMs */
++                      memset(pDCTstat, 0, sizeof(struct DCTStatStruc));
++
++                      /* Initialize data structures */
++                      pDCTstat->Node_ID = Node;
++                      pDCTstat->dev_host = PA_HOST(Node);
++                      pDCTstat->dev_map = PA_MAP(Node);
++                      pDCTstat->dev_dct = PA_DCT(Node);
++                      pDCTstat->dev_nbmisc = PA_NBMISC(Node);
++                      pDCTstat->NodeSysBase = node_sys_base;
++
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node 
%d\n", Node);
++                      mct_init(pMCTstat, pDCTstat);
++                      mctNodeIDDebugPort_D();
++                      pDCTstat->NodePresent = NodePresent_D(Node);
++                      if (pDCTstat->NodePresent) {            /* See if Node 
is there*/
++                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
++                              clear_legacy_Mode(pMCTstat, pDCTstat);
++                              pDCTstat->LogicalCPUID = 
mctGetLogicalCPUID_D(Node);
++
++                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
++                              mct_InitialMCT_D(pMCTstat, pDCTstat);
++
++                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
++                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
++
++                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_initDCT\n");
++                              mct_initDCT(pMCTstat, pDCTstat);
++                              if (pDCTstat->ErrCode == SC_FatalErr) {
++                                      goto fatalexit;         /* any fatal 
errors?*/
++                              } else if (pDCTstat->ErrCode < SC_StopError) {
++                                      NodesWmem++;
++                              }
++                      }       /* if Node present */
++                      node_sys_base = pDCTstat->NodeSysBase;
++                      node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
++              }
++              if (NodesWmem == 0) {
++                      printk(BIOS_DEBUG, "No Nodes?!\n");
++                      goto fatalexit;
++              }
+ 
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
+-      SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are ready for 
accesses.*/
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
++              SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are 
ready for accesses.*/
+ 
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D: HTMemMapInit_D\n");
+-      HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory into system 
address space.*/
+-      mctHookAfterHTMap();
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: HTMemMapInit_D\n");
++              HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory 
into system address space.*/
++              mctHookAfterHTMap();
+ 
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
+-      CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC CPU 
cacheability */
+-      mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
++              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
++              mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
+ 
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
+-      DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable and DQS 
signal timing*/
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
++              DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable 
and DQS signal timing*/
+ 
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
+-      UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA sizing */
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
++              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
+ 
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+-      mct_OtherTiming(pMCTstat, pDCTstatA);
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
++              mct_OtherTiming(pMCTstat, pDCTstatA);
+ 
+-      if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st 
pass of DIMM spare enabled*/
+-              goto restartinit;
+-      }
+ 
+-      InterleaveNodes_D(pMCTstat, pDCTstatA);
+-      InterleaveChannels_D(pMCTstat, pDCTstatA);
++              if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 
1st pass of DIMM spare enabled*/
++                      goto restartinit;
++              }
+ 
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
+-      if (ECCInit_D(pMCTstat, pDCTstatA)) {           /* Setup ECC control 
and ECC check-bits*/
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
+-              MCTMemClr_D(pMCTstat,pDCTstatA);
+-      }
++              InterleaveNodes_D(pMCTstat, pDCTstatA);
++              InterleaveChannels_D(pMCTstat, pDCTstatA);
++
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
++              if (ECCInit_D(pMCTstat, pDCTstatA)) {           /* Setup ECC 
control and ECC check-bits*/
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
++                      MCTMemClr_D(pMCTstat,pDCTstatA);
++              }
+ 
+-      mct_FinalMCT_D(pMCTstat, pDCTstatA);
+-      printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", 
pMCTstat->GStatus);
++              mct_FinalMCT_D(pMCTstat, pDCTstatA);
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: 
%x\n", pMCTstat->GStatus);
++      }
+ 
+       return;
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 219aa42..c790d7e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -24,6 +24,8 @@
+ #ifndef MCT_D_H
+ #define MCT_D_H
+ 
++#include <cpu/x86/msr.h>
++
+ /*===========================================================================
+       CPU - K8/FAM10
+ ===========================================================================*/
+@@ -596,6 +598,116 @@ struct DCTStatStruc {            /* A per Node 
structure*/
+       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
+ } __attribute__((packed));
+ 
++struct amd_s3_persistent_mct_channel_data {
++      /* Stage 1 (1 dword) */
++      uint32_t f2x110;
++
++      /* Stage 2 (88 dwords) */
++      uint32_t f1x40;
++      uint32_t f1x44;
++      uint32_t f1x48;
++      uint32_t f1x4c;
++      uint32_t f1x50;
++      uint32_t f1x54;
++      uint32_t f1x58;
++      uint32_t f1x5c;
++      uint32_t f1x60;
++      uint32_t f1x64;
++      uint32_t f1x68;
++      uint32_t f1x6c;
++      uint32_t f1x70;
++      uint32_t f1x74;
++      uint32_t f1x78;
++      uint32_t f1x7c;
++      uint32_t f1xf0;
++      uint32_t f1x120;
++      uint32_t f1x124;
++      uint32_t f2x10c;
++      uint32_t f2x114;
++      uint32_t f2x118;
++      uint32_t f2x11c;
++      uint32_t f2x1b0;
++      uint32_t f3x44;
++      uint64_t msr0000020[16];
++      uint64_t msr00000250;
++      uint64_t msr00000258;
++      uint64_t msr0000026[8];
++      uint64_t msr000002ff;
++      uint64_t msrc0010010;
++      uint64_t msrc001001a;
++      uint64_t msrc001001d;
++      uint64_t msrc001001f;
++
++      /* Stage 3 (21 dwords) */
++      uint32_t f2x40;
++      uint32_t f2x44;
++      uint32_t f2x48;
++      uint32_t f2x4c;
++      uint32_t f2x50;
++      uint32_t f2x54;
++      uint32_t f2x58;
++      uint32_t f2x5c;
++      uint32_t f2x60;
++      uint32_t f2x64;
++      uint32_t f2x68;
++      uint32_t f2x6c;
++      uint32_t f2x78;
++      uint32_t f2x7c;
++      uint32_t f2x80;
++      uint32_t f2x84;
++      uint32_t f2x88;
++      uint32_t f2x8c;
++      uint32_t f2x90;
++      uint32_t f2xa4;
++      uint32_t f2xa8;
++
++      /* Stage 4 (1 dword) */
++      uint32_t f2x94;
++
++      /* Stage 6 (33 dwords) */
++      uint32_t f2x9cx0d0f0_f_8_0_0_8_4_0[9][3];       /* [lane][setting] */
++      uint32_t f2x9cx00;
++      uint32_t f2x9cx0a;
++      uint32_t f2x9cx0c;
++
++      /* Stage 7 (1 dword) */
++      uint32_t f2x9cx04;
++
++      /* Stage 9 (2 dwords) */
++      uint32_t f2x9cx0d0fe006;
++      uint32_t f2x9cx0d0fe007;
++
++      /* Stage 10 (78 dwords) */
++      uint32_t f2x9cx10[12];
++      uint32_t f2x9cx20[12];
++      uint32_t f2x9cx3_0_0_3_1[4][3];         /* [dimm][setting] */
++      uint32_t f2x9cx3_0_0_7_5[4][3];         /* [dimm][setting] */
++      uint32_t f2x9cx0d;
++      uint32_t f2x9cx0d0f0_f_0_13[9];         /* [lane] */
++      uint32_t f2x9cx0d0f0_f_0_30[9];         /* [lane] */
++      uint32_t f2x9cx0d0f2_f_0_30[4];         /* [pad select] */
++      uint32_t f2x9cx0d0f8_8_4_0[2][3];       /* [offset][pad select] */
++      uint32_t f2x9cx0d0f812f;
++
++      /* Stage 11 (24 dwords) */
++      uint32_t f2x9cx30[12];
++      uint32_t f2x9cx40[12];
++
++      /* Other (1 dword) */
++      uint32_t f3x58;
++
++      /* TOTAL: 250 dwords */
++} __attribute__((packed));
++
++struct amd_s3_persistent_node_data {
++      uint32_t node_present;
++      struct amd_s3_persistent_mct_channel_data channel[2];
++} __attribute__((packed));
++
++struct amd_s3_persistent_data {
++      struct amd_s3_persistent_node_data node[MAX_NODES_SUPPORTED];
++} __attribute__((packed));
++
+ 
/*===============================================================================
+       Local Error Status Codes (DCTStatStruc.ErrCode)
+ 
===============================================================================*/
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+new file mode 100644
+index 0000000..a49499f
+--- /dev/null
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -0,0 +1,620 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
++ */
++
++#include <string.h>
++#include <arch/acpi.h>
++#include <cpu/x86/msr.h>
++#include <device/device.h>
++#include <device/pci_def.h>
++#include <device/pci_ops.h>
++#include <console/console.h>
++#include <cbfs.h>
++#include <spi-generic.h>
++#include <spi_flash.h>
++
++#include "s3utils.h"
++
++#define S3NV_FILE_NAME "s3nv"
++
++static ssize_t get_s3nv_file_offset(void);
++
++ssize_t get_s3nv_file_offset(void)
++{
++      struct region_device s3nv_region;
++      struct cbfsf s3nv_cbfs_file;
++      if (cbfs_boot_locate(&s3nv_cbfs_file, S3NV_FILE_NAME, NULL)) {
++              printk(BIOS_DEBUG, "S3 state file not found in CBFS: %s\n", 
S3NV_FILE_NAME);
++              return -1;
++      }
++      cbfs_file_data(&s3nv_region, &s3nv_cbfs_file);
++
++      return s3nv_region.region.offset;
++}
++
++static uint32_t read_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index)
++{
++      uint32_t dword;
++
++      index &= ~(1 << 30);
++      pci_write_config32(dev, index_ctl_reg, index);
++      do {
++              dword = pci_read_config32(dev, index_ctl_reg);
++      } while (!(dword & (1 << 31)));
++      dword = pci_read_config32(dev, index_ctl_reg + 0x04);
++
++      return dword;
++}
++
++#ifdef __RAMSTAGE__
++static uint64_t rdmsr_uint64_t(unsigned long index) {
++      msr_t msr = rdmsr(index);
++      return (((uint64_t)msr.hi) << 32) | ((uint64_t)msr.lo);
++}
++
++void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
++{
++      uint8_t i;
++      uint8_t j;
++      uint8_t node;
++      uint8_t channel;
++
++      /* Zero out data structure */
++      memset(persistent_data, 0, sizeof(struct amd_s3_persistent_data));
++
++      /* Load data from DCTs into data structure */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
++              device_t dev_fn2 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 2));
++              device_t dev_fn3 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 3));
++              if ((!dev_fn1) || (!dev_fn2) || (!dev_fn3)) {
++                      persistent_data->node[node].node_present = 0;
++                      continue;
++              }
++              persistent_data->node[node].node_present = 1;
++
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++
++                      /* Stage 1 */
++                      data->f2x110 = pci_read_config32(dev_fn2, 0x110);
++
++                      /* Stage 2 */
++                      data->f1x40 = pci_read_config32(dev_fn1, 0x40 + (0x100 
* channel));
++                      data->f1x44 = pci_read_config32(dev_fn1, 0x44 + (0x100 
* channel));
++                      data->f1x48 = pci_read_config32(dev_fn1, 0x48 + (0x100 
* channel));
++                      data->f1x4c = pci_read_config32(dev_fn1, 0x4c + (0x100 
* channel));
++                      data->f1x50 = pci_read_config32(dev_fn1, 0x50 + (0x100 
* channel));
++                      data->f1x54 = pci_read_config32(dev_fn1, 0x54 + (0x100 
* channel));
++                      data->f1x58 = pci_read_config32(dev_fn1, 0x58 + (0x100 
* channel));
++                      data->f1x5c = pci_read_config32(dev_fn1, 0x5c + (0x100 
* channel));
++                      data->f1x60 = pci_read_config32(dev_fn1, 0x60 + (0x100 
* channel));
++                      data->f1x64 = pci_read_config32(dev_fn1, 0x64 + (0x100 
* channel));
++                      data->f1x68 = pci_read_config32(dev_fn1, 0x68 + (0x100 
* channel));
++                      data->f1x6c = pci_read_config32(dev_fn1, 0x6c + (0x100 
* channel));
++                      data->f1x70 = pci_read_config32(dev_fn1, 0x70 + (0x100 
* channel));
++                      data->f1x74 = pci_read_config32(dev_fn1, 0x74 + (0x100 
* channel));
++                      data->f1x78 = pci_read_config32(dev_fn1, 0x78 + (0x100 
* channel));
++                      data->f1x7c = pci_read_config32(dev_fn1, 0x7c + (0x100 
* channel));
++                      data->f1xf0 = pci_read_config32(dev_fn1, 0xf0);
++                      data->f1x120 = pci_read_config32(dev_fn1, 0x120);
++                      data->f1x124 = pci_read_config32(dev_fn1, 0x124);
++                      data->f2x10c = pci_read_config32(dev_fn2, 0x10c);
++                      data->f2x114 = pci_read_config32(dev_fn2, 0x114);
++                      data->f2x118 = pci_read_config32(dev_fn2, 0x118);
++                      data->f2x11c = pci_read_config32(dev_fn2, 0x11c);
++                      data->f2x1b0 = pci_read_config32(dev_fn2, 0x1b0);
++                      data->f3x44 = pci_read_config32(dev_fn3, 0x44);
++                      for (i=0; i<16; i++) {
++                              data->msr0000020[i] = rdmsr_uint64_t(0x00000200 
| i);
++                      }
++                      data->msr00000250 = rdmsr_uint64_t(0x00000250);
++                      data->msr00000258 = rdmsr_uint64_t(0x00000258);
++                      for (i=0; i<8; i++)
++                              data->msr0000026[i] = rdmsr_uint64_t(0x00000260 
| (i + 8));
++                      data->msr000002ff = rdmsr_uint64_t(0x000002ff);
++                      data->msrc0010010 = rdmsr_uint64_t(0xc0010010);
++                      data->msrc001001a = rdmsr_uint64_t(0xc001001a);
++                      data->msrc001001d = rdmsr_uint64_t(0xc001001d);
++                      data->msrc001001f = rdmsr_uint64_t(0xc001001f);
++
++                      /* Stage 3 */
++                      data->f2x40 = pci_read_config32(dev_fn2, 0x40 + (0x100 
* channel));
++                      data->f2x44 = pci_read_config32(dev_fn2, 0x44 + (0x100 
* channel));
++                      data->f2x48 = pci_read_config32(dev_fn2, 0x48 + (0x100 
* channel));
++                      data->f2x4c = pci_read_config32(dev_fn2, 0x4c + (0x100 
* channel));
++                      data->f2x50 = pci_read_config32(dev_fn2, 0x50 + (0x100 
* channel));
++                      data->f2x54 = pci_read_config32(dev_fn2, 0x54 + (0x100 
* channel));
++                      data->f2x58 = pci_read_config32(dev_fn2, 0x58 + (0x100 
* channel));
++                      data->f2x5c = pci_read_config32(dev_fn2, 0x5c + (0x100 
* channel));
++                      data->f2x60 = pci_read_config32(dev_fn2, 0x60 + (0x100 
* channel));
++                      data->f2x64 = pci_read_config32(dev_fn2, 0x64 + (0x100 
* channel));
++                      data->f2x68 = pci_read_config32(dev_fn2, 0x68 + (0x100 
* channel));
++                      data->f2x6c = pci_read_config32(dev_fn2, 0x6c + (0x100 
* channel));
++                      data->f2x78 = pci_read_config32(dev_fn2, 0x78 + (0x100 
* channel));
++                      data->f2x7c = pci_read_config32(dev_fn2, 0x7c + (0x100 
* channel));
++                      data->f2x80 = pci_read_config32(dev_fn2, 0x80 + (0x100 
* channel));
++                      data->f2x84 = pci_read_config32(dev_fn2, 0x84 + (0x100 
* channel));
++                      data->f2x88 = pci_read_config32(dev_fn2, 0x88 + (0x100 
* channel));
++                      data->f2x8c = pci_read_config32(dev_fn2, 0x8c + (0x100 
* channel));
++                      data->f2x90 = pci_read_config32(dev_fn2, 0x90 + (0x100 
* channel));
++                      data->f2xa4 = pci_read_config32(dev_fn2, 0xa4 + (0x100 
* channel));
++                      data->f2xa8 = pci_read_config32(dev_fn2, 0xa8 + (0x100 
* channel));
++
++                      /* Stage 4 */
++                      data->f2x94 = pci_read_config32(dev_fn2, 0x94 + (0x100 
* channel));
++
++                      /* Stage 6 */
++                      for (i=0; i<9; i++)
++                              for (j=0; j<3; j++)
++                                      data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
++                      data->f2x9cx00 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x00);
++                      data->f2x9cx0a = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0a);
++                      data->f2x9cx0c = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0c);
++
++                      /* Stage 7 */
++                      data->f2x9cx04 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x04);
++
++                      /* Stage 9 */
++                      data->f2x9cx0d0fe006 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe006);
++                      data->f2x9cx0d0fe007 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe007);
++
++                      /* Stage 10 */
++                      for (i=0; i<12; i++)
++                              data->f2x9cx10[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x10 + i);
++                      for (i=0; i<12; i++)
++                              data->f2x9cx20[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x20 + i);
++                      for (i=0; i<4; i++)
++                              for (j=0; j<3; j++)
++                                      data->f2x9cx3_0_0_3_1[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x01 + i) + 
(0x100 * j));
++                      for (i=0; i<4; i++)
++                              for (j=0; j<3; j++)
++                                      data->f2x9cx3_0_0_7_5[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x05 + i) + 
(0x100 * j));
++                      data->f2x9cx0d = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0d);
++                      for (i=0; i<9; i++)
++                              data->f2x9cx0d0f0_f_0_13[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0013 | (i 
<< 8));
++                      for (i=0; i<9; i++)
++                              data->f2x9cx0d0f0_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0030 | (i 
<< 8));
++                      for (i=0; i<4; i++)
++                              data->f2x9cx0d0f2_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f2030 | (i 
<< 8));
++                      for (i=0; i<2; i++)
++                              for (j=0; j<3; j++)
++                                      data->f2x9cx0d0f8_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
++                      data->f2x9cx0d0f812f = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f812f);
++
++                      /* Stage 11 */
++                      if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++                              for (i=0; i<12; i++)
++                                      data->f2x9cx30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x30 + i);
++                              for (i=0; i<12; i++)
++                                      data->f2x9cx40[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x40 + i);
++                      }
++
++                      /* Other */
++                      /* ECC scrub rate control */
++                      data->f3x58 = pci_read_config32(dev_fn3, 0x58);
++              }
++      }
++}
++#else
++static void write_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index, uint32_t value)
++{
++      uint32_t dword;
++
++      pci_write_config32(dev, index_ctl_reg + 0x04, value);
++      index |= (1 << 30);
++      pci_write_config32(dev, index_ctl_reg, index);
++      do {
++              dword = pci_read_config32(dev, index_ctl_reg);
++      } while (!(dword & (1 << 31)));
++}
++#endif
++
++#ifdef __PRE_RAM__
++static void wrmsr_uint64_t(unsigned long index, uint64_t value) {
++      msr_t msr;
++      msr.hi = (value & 0xffffffff00000000ULL) >> 32;
++      msr.lo = (value & 0xffffffff);
++      wrmsr(index, msr);
++}
++
++void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data)
++{
++      uint8_t i;
++      uint8_t j;
++      uint8_t node;
++      uint8_t channel;
++      uint8_t ganged;
++      uint8_t dct_enabled;
++      uint32_t dword;
++
++      /* Load data from data structure into DCTs */
++      /* Stage 1 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x110, 
data->f2x110);
++              }
++      }
++
++      /* Stage 2 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x40 + 
(0x100 * channel), data->f1x40);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x44 + 
(0x100 * channel), data->f1x44);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x48 + 
(0x100 * channel), data->f1x48);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x4c + 
(0x100 * channel), data->f1x4c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x50 + 
(0x100 * channel), data->f1x50);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x54 + 
(0x100 * channel), data->f1x54);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x58 + 
(0x100 * channel), data->f1x58);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x5c + 
(0x100 * channel), data->f1x5c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x60 + 
(0x100 * channel), data->f1x60);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x64 + 
(0x100 * channel), data->f1x64);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x68 + 
(0x100 * channel), data->f1x68);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x6c + 
(0x100 * channel), data->f1x6c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x70 + 
(0x100 * channel), data->f1x70);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x74 + 
(0x100 * channel), data->f1x74);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x78 + 
(0x100 * channel), data->f1x78);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x7c + 
(0x100 * channel), data->f1x7c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0xf0 + 
(0x100 * channel), data->f1xf0);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x120 + 
(0x100 * channel), data->f1x120);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x124 + 
(0x100 * channel), data->f1x124);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x10c + 
(0x100 * channel), data->f2x10c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x114 + 
(0x100 * channel), data->f2x114);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x118 + 
(0x100 * channel), data->f2x118);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x11c + 
(0x100 * channel), data->f2x11c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x1b0 + 
(0x100 * channel), data->f2x1b0);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x44 + 
(0x100 * channel), data->f3x44);
++                      for (i=0; i<16; i++) {
++                              wrmsr_uint64_t(0x00000200 | i, 
data->msr0000020[i]);
++                      }
++                      wrmsr_uint64_t(0x00000250, data->msr00000250);
++                      wrmsr_uint64_t(0x00000258, data->msr00000258);
++                      /* FIXME
++                       * Restoring these MSRs causes a hang on resume
++                       * For now, skip restoration...
++                       */
++                      // for (i=0; i<8; i++)
++                      //      wrmsr_uint64_t(0x00000260 | (i + 8), 
data->msr0000026[i]);
++                      wrmsr_uint64_t(0x000002ff, data->msr000002ff);
++                      wrmsr_uint64_t(0xc0010010, data->msrc0010010);
++                      wrmsr_uint64_t(0xc001001a, data->msrc001001a);
++                      wrmsr_uint64_t(0xc001001d, data->msrc001001d);
++                      wrmsr_uint64_t(0xc001001f, data->msrc001001f);
++              }
++      }
++
++      /* Stage 3 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      ganged = !!(data->f2x110 & 0x10);
++                      if ((ganged == 1) && (channel > 0))
++                              continue;
++
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x40 + 
(0x100 * channel), data->f2x40);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x44 + 
(0x100 * channel), data->f2x44);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x48 + 
(0x100 * channel), data->f2x48);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x4c + 
(0x100 * channel), data->f2x4c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x50 + 
(0x100 * channel), data->f2x50);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x54 + 
(0x100 * channel), data->f2x54);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x58 + 
(0x100 * channel), data->f2x58);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x5c + 
(0x100 * channel), data->f2x5c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x60 + 
(0x100 * channel), data->f2x60);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x64 + 
(0x100 * channel), data->f2x64);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x68 + 
(0x100 * channel), data->f2x68);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x6c + 
(0x100 * channel), data->f2x6c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x78 + 
(0x100 * channel), data->f2x78);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x7c + 
(0x100 * channel), data->f2x7c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x80 + 
(0x100 * channel), data->f2x80);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x84 + 
(0x100 * channel), data->f2x84);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x88 + 
(0x100 * channel), data->f2x88);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x8c + 
(0x100 * channel), data->f2x8c);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), data->f2x90);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa4 + 
(0x100 * channel), data->f2xa4);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa8 + 
(0x100 * channel), data->f2xa8);
++              }
++      }
++
++      /* Stage 4 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      ganged = !!(data->f2x110 & 0x10);
++                      if ((ganged == 1) && (channel > 0))
++                              continue;
++
++                      /* Disable PHY auto-compensation engine */
++                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
++                      if (!(dword & (1 << 30))) {
++                              dword |= (1 << 30);
++                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08, dword);
++
++                              /* Wait for 5us */
++                              mct_Wait(100);
++                      }
++
++                      /* Restore DRAM Configuration High Register */
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x94 + 
(0x100 * channel), data->f2x94);
++
++                      /* Enable PHY auto-compensation engine */
++                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
++                      dword &= ~(1 << 30);
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x08, dword);
++              }
++      }
++
++      /* Wait for 750us */
++      mct_Wait(15000);
++
++      /* Stage 5 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      ganged = !!(data->f2x110 & 0x10);
++                      if ((ganged == 1) && (channel > 0))
++                              continue;
++
++                      /* Wait for any pending PHY frequency changes to 
complete */
++                      do {
++                              dword = read_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x08);
++                      } while (dword & (1 << 21));
++              }
++      }
++
++      /* Stage 6 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      for (i=0; i<9; i++)
++                              for (j=0; j<3; j++)
++                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x00, data->f2x9cx00);
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0a, data->f2x9cx0a);
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0c, data->f2x9cx0c);
++              }
++      }
++
++      /* Stage 7 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      ganged = !!(data->f2x110 & 0x10);
++                      if ((ganged == 1) && (channel > 0))
++                              continue;
++
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x04, data->f2x9cx04);
++              }
++      }
++
++      /* Stage 8 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      dct_enabled = !(data->f2x94 & (1 << 14));
++                      if (!dct_enabled)
++                              continue;
++
++                      ganged = !!(data->f2x110 & 0x10);
++                      if ((ganged == 1) && (channel > 0))
++                              continue;
++
++                      printk(BIOS_SPEW, "Taking DIMMs out of self refresh 
node: %d channel: %d\n", node, channel);
++
++                      /* Exit self refresh mode */
++                      dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 
0x90 + (0x100 * channel));
++                      dword |= (1 << 1);
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), dword);
++              }
++      }
++
++      /* Stage 9 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      dct_enabled = !(data->f2x94 & (1 << 14));
++                      if (!dct_enabled)
++                              continue;
++
++                      printk(BIOS_SPEW, "Waiting for DIMMs to exit self 
refresh node: %d channel: %d\n", node, channel);
++
++                      /* Wait for transition from self refresh mode to 
complete */
++                      do {
++                              dword = pci_read_config32(PCI_DEV(0, 0x18 + 
node, 2), 0x90 + (0x100 * channel));
++                      } while (dword & (1 << 1));
++
++                      /* Restore registers */
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe006, data->f2x9cx0d0fe006);
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe007, data->f2x9cx0d0fe007);
++              }
++      }
++
++      /* Stage 10 */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      for (i=0; i<12; i++)
++                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x10 + i, data->f2x9cx10[i]);
++                      for (i=0; i<12; i++)
++                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x20 + i, data->f2x9cx20[i]);
++                      for (i=0; i<4; i++)
++                              for (j=0; j<3; j++)
++                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j), 
data->f2x9cx3_0_0_3_1[i][j]);
++                      for (i=0; i<4; i++)
++                              for (j=0; j<3; j++)
++                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j), 
data->f2x9cx3_0_0_7_5[i][j]);
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d, data->f2x9cx0d);
++                      for (i=0; i<9; i++)
++                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8), 
data->f2x9cx0d0f0_f_0_13[i]);
++                      for (i=0; i<9; i++)
++                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8), 
data->f2x9cx0d0f0_f_0_30[i]);
++                      for (i=0; i<4; i++)
++                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8), 
data->f2x9cx0d0f2_f_0_30[i]);
++                      for (i=0; i<2; i++)
++                              for (j=0; j<3; j++)
++                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f8_8_4_0[i][j]);
++                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0f812f, data->f2x9cx0d0f812f);
++              }
++      }
++
++      /* Stage 11 */
++      if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++                      for (channel = 0; channel < 2; channel++) {
++                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
++                              if (!persistent_data->node[node].node_present)
++                                      continue;
++
++                              for (i=0; i<12; i++)
++                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x30 + i, data->f2x9cx30[i]);
++                              for (i=0; i<12; i++)
++                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x40 + i, data->f2x9cx40[i]);
++                      }
++              }
++      }
++
++      /* Other */
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              for (channel = 0; channel < 2; channel++) {
++                      struct amd_s3_persistent_mct_channel_data* data = 
&persistent_data->node[node].channel[channel];
++                      if (!persistent_data->node[node].node_present)
++                              continue;
++
++                      /* ECC scrub rate control */
++                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x58, 
data->f3x58);
++              }
++      }
++}
++#endif
++
++#ifdef __RAMSTAGE__
++int8_t save_mct_information_to_nvram(void)
++{
++      if (acpi_is_wakeup_s3())
++              return 0;
++
++      printk(BIOS_DEBUG, "Writing AMD DCT configuration to Flash\n");
++
++      struct spi_flash *flash;
++      ssize_t s3nv_offset;
++      struct amd_s3_persistent_data persistent_data;
++
++      /* Obtain MCT configuration data */
++      copy_mct_data_to_save_variable(&persistent_data);
++
++      /* Obtain CBFS file offset */
++      s3nv_offset = get_s3nv_file_offset();
++      if (s3nv_offset == -1)
++              return -1;
++
++      /* Align flash pointer to nearest boundary */
++      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
++      s3nv_offset += CONFIG_S3_DATA_SIZE;
++
++      /* Set temporary SPI MMIO address */
++      device_t lpc_dev = dev_find_slot(0, PCI_DEVFN(0x14, 3));
++      uint32_t spi_mmio_prev = pci_read_config32(lpc_dev, 0xa0);
++      pci_write_config32(lpc_dev, 0xa0, (spi_mmio_prev & 0x1f) | 0xf0000000);
++
++      /* Initialize SPI and detect devices */
++      spi_init();
++      flash = spi_flash_probe(0, 0);
++      if (!flash) {
++              printk(BIOS_DEBUG, "Could not find SPI device\n");
++              return -1;
++      }
++
++      /* Set up SPI flash access */
++      flash->spi->rw = SPI_WRITE_FLAG;
++      spi_claim_bus(flash->spi);
++
++      /* Erase and write data structure */
++      flash->erase(flash, s3nv_offset, CONFIG_S3_DATA_SIZE);
++      flash->write(flash, s3nv_offset, sizeof(struct amd_s3_persistent_data), 
&persistent_data);
++
++      /* Tear down SPI flash access */
++      flash->spi->rw = SPI_WRITE_FLAG;
++      spi_release_bus(flash->spi);
++
++      /* Restore SPI MMIO address */
++      pci_write_config32(lpc_dev, 0xa0, spi_mmio_prev);
++
++      return 0;
++}
++#endif
++
++int8_t restore_mct_information_from_nvram(void)
++{
++      ssize_t s3nv_offset;
++      ssize_t s3nv_file_offset;
++      void * s3nv_cbfs_file_ptr;
++      struct amd_s3_persistent_data *persistent_data;
++
++      /* Obtain CBFS file offset */
++      s3nv_offset = get_s3nv_file_offset();
++      if (s3nv_offset == -1)
++              return -1;
++
++      /* Align flash pointer to nearest boundary */
++      s3nv_file_offset = s3nv_offset;
++      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
++      s3nv_offset += CONFIG_S3_DATA_SIZE;
++      s3nv_file_offset = s3nv_offset - s3nv_file_offset;
++
++      /* Map data structure in CBFS and restore settings */
++      s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, 
CBFS_TYPE_RAW, NULL);
++      if (!s3nv_cbfs_file_ptr) {
++              printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", 
S3NV_FILE_NAME);
++              return -1;
++      }
++      persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
++      restore_mct_data_from_save_variable(persistent_data);
++
++      return 0;
++}
+\ No newline at end of file
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+new file mode 100644
+index 0000000..dcddcad
+--- /dev/null
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+@@ -0,0 +1,28 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
++ */
++
++#include "../wrappers/mcti.h"
++#include "mct_d.h"
++
++#ifdef __RAMSTAGE__
++int8_t save_mct_information_to_nvram(void);
++#endif
++int8_t restore_mct_information_from_nvram(void);
++void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data);
++void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data);
+\ No newline at end of file
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0022-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0022-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
new file mode 100644
index 0000000..3afb5d5
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0022-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch
@@ -0,0 +1,56 @@
+From 9731b8e1e997c083bb2084085fb6d4c46d96910f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:46:24 -0500
+Subject: [PATCH 022/143] cpu/amd/car: Add initial Suspend to RAM (S3) support
+
+Change-Id: I1e1a67fa3c2c13cebcf8f0af318055b9d97d0a59
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/car/post_cache_as_ram.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
+index 230d1aa..e265de1 100644
+--- a/src/cpu/amd/car/post_cache_as_ram.c
++++ b/src/cpu/amd/car/post_cache_as_ram.c
+@@ -1,4 +1,5 @@
+ /* Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2012 ChromeOS Authors
+  * 2005.6 by yhlu
+  * 2006.3 yhlu add copy data from CAR to ram
+  */
+@@ -9,6 +10,7 @@
+ #include <cpu/amd/mtrr.h>
+ #include <cpu/amd/car.h>
+ #include <arch/acpi.h>
++#include <romstage_handoff.h>
+ #include "cbmem.h"
+ #include "cpu/amd/car/disable_cache_as_ram.c"
+ 
+@@ -103,6 +105,13 @@ void post_cache_as_ram(void)
+ {
+       void *resume_backup_memory = NULL;
+ 
++      struct romstage_handoff *handoff;
++      handoff = romstage_handoff_find_or_add();
++      if (handoff != NULL)
++              handoff->s3_resume = acpi_is_wakeup_s3();
++      else
++              printk(BIOS_DEBUG, "Romstage handoff structure not added!\n");
++
+       int s3resume = acpi_is_wakeup_s3();
+       if (s3resume) {
+               cbmem_recovery(s3resume);
+@@ -150,6 +159,9 @@ void cache_as_ram_new_stack (void)
+ 
+       if (acpi_is_wakeup_s3()) {
+               resume_backup_memory = cbmem_find(CBMEM_ID_RESUME);
++#if PRINTK_IN_CAR
++              printk(BIOS_DEBUG, "Resume backup memory location: %p\n", 
resume_backup_memory);
++#endif
+       }
+       prepare_ramstage_region(resume_backup_memory);
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0022-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
 
b/resources/libreboot/patch/kgpe-d16/0022-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
deleted file mode 100644
index debb88e..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0022-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From ec5844dce6ad1a2c1528ea7cb6f41f408fd48a4f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 19:00:34 -0500
-Subject: [PATCH 022/139] include/smbios: Update SMBIOS memory structures to
- version 2.8
-
-Change-Id: Icda915933c4ebf3a735d9e1d4e4dbb1138a06b39
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/include/smbios.h | 6 ++++--
- 1 file changed, 4 insertions(+), 2 deletions(-)
-
-diff --git a/src/include/smbios.h b/src/include/smbios.h
-index b654c23..fdb7bbd 100644
---- a/src/include/smbios.h
-+++ b/src/include/smbios.h
-@@ -409,9 +409,11 @@ struct smbios_type17 {
-       u8 asset_tag;
-       u8 part_number;
-       u8 attributes;
--      u16 extended_size;
-+      u32 extended_size;
-       u16 clock_speed;
--
-+      u16 minimum_voltage;
-+      u16 maximum_voltage;
-+      u16 configured_voltage;
-       char eos[2];
- } __attribute__((packed));
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0023-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
 
b/resources/libreboot/patch/kgpe-d16/0023-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
new file mode 100644
index 0000000..7aaeceb
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0023-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch
@@ -0,0 +1,832 @@
+From dbbc7efacaeec510163ef0f0f802ab75cca8d94e Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 7 May 2015 01:32:08 -0500
+Subject: [PATCH 023/143] mainboard/asus/kgpe-d16: Add initial Suspend to RAM
+ (S3) support
+
+Change-Id: I7da84b064287a445fd75a947e2f96ce1ae30d3de
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/Kconfig          |    3 +
+ src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl |  639 +++++++++++++-------------
+ src/mainboard/asus/kgpe-d16/dsdt.asl         |    5 +-
+ src/mainboard/asus/kgpe-d16/romstage.c       |   34 +-
+ src/mainboard/asus/kgpe-d16/spd_notes.txt    |   16 +
+ 5 files changed, 369 insertions(+), 328 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+index 95b3b5b..f9556fc 100644
+--- a/src/mainboard/asus/kgpe-d16/Kconfig
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -23,6 +23,9 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+       select BOARD_ROMSIZE_KB_2048
+       select ENABLE_APIC_EXT_ID
+       select MMCONF_SUPPORT_DEFAULT
++      select SPI_FLASH
++      select SPI_FLASH_WINBOND
++      select HAVE_ACPI_RESUME
+       select DRIVERS_I2C_W83795
+       select DRIVERS_ASPEED_AST2050
+       select MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG
+diff --git a/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl 
b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
+index b3c65ca..737d8cd 100644
+--- a/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
++++ b/src/mainboard/asus/kgpe-d16/acpi/pm_ctrl.asl
+@@ -18,350 +18,359 @@
+  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+  */
+ 
++/* Port 80 POST card debug */
++OperationRegion (DBG0, SystemIO, 0x80, One)
++      Field (DBG0, ByteAcc, NoLock, Preserve) {
++      DBG8, 8
++}
++
++/* SuperIO control port */
++Name (SPIO, 0x2E)
++
++/* SuperIO control map */
++OperationRegion (SPIM, SystemIO, SPIO, 0x02)
++      Field (SPIM, ByteAcc, NoLock, Preserve) {
++      INDX, 8,
++      DATA, 8
++}
++
++/* SuperIO control registers */
++IndexField (INDX, DATA, ByteAcc, NoLock, Preserve) {
++      Offset (0x07),
++      CR07, 8,                /* Logical device number */
++      Offset (0x2C),
++      CR2C, 8,                /* GPIO3 multiplexed pin selection */
++      Offset (0x30),
++      CR30, 8,                /* Logical device activation control register */
++      Offset (0xE0),
++      CRE0, 8,                /* Wake control register */
++      Offset (0xE4),
++      CRE4, 8,                /* Standby power control register */
++      Offset (0xE6),
++      CRE6, 8,                /* Mouse wake event configuration register */
++      Offset (0xF1),
++      CRF1, 8,                /* GPIO3 data register */
++      Offset (0xF3),
++      CRF3, 8,                /* SUSLED mode register */
++      Offset (0xF6),
++      CRF6, 8,                /* SMI/PME event generation control register */
++      Offset (0xF9),
++      CRF9, 8,                /* ACPI PME configuration register */
++}
++
++/* Power Management I/O registers */
++OperationRegion(PIOR, SystemIO, 0x00000CD6, 0x00000002)
++      Field(PIOR, ByteAcc, NoLock, Preserve) {
++      PIOI, 0x00000008,
++      PIOD, 0x00000008,
++}
++IndexField (PIOI, PIOD, ByteAcc, NoLock, Preserve) {
++      Offset(0x00),   /* MiscControl */
++      , 1,
++      T1EE, 1,
++      T2EE, 1,
++      Offset(0x01),   /* MiscStatus */
++      , 1,
++      T1E, 1,
++      T2E, 1,
++      Offset(0x04),   /* SmiWakeUpEventEnable3 */
++      , 7,
++      SSEN, 1,
++      Offset(0x07),   /* SmiWakeUpEventStatus3 */
++      , 7,
++      CSSM, 1,
++      Offset(0x10),   /* AcpiEnable */
++      , 6,
++      PWDE, 1,
++      Offset(0x1C),   /* ProgramIoEnable */
++      , 3,
++      MKME, 1,
++      IO3E, 1,
++      IO2E, 1,
++      IO1E, 1,
++      IO0E, 1,
++      Offset(0x1D),   /* IOMonitorStatus */
++      , 3,
++      MKMS, 1,
++      IO3S, 1,
++      IO2S, 1,
++      IO1S, 1,
++      IO0S,1,
++      Offset(0x20),   /* AcpiPmEvtBlk */
++      APEB, 16,
++      Offset(0x36),   /* GEvtLevelConfig */
++      , 6,
++      ELC6, 1,
++      ELC7, 1,
++      Offset(0x37),   /* GPMLevelConfig0 */
++      , 3,
++      PLC0, 1,
++      PLC1, 1,
++      PLC2, 1,
++      PLC3, 1,
++      PLC8, 1,
++      Offset(0x38),   /* GPMLevelConfig1 */
++      , 1,
++              PLC4, 1,
++              PLC5, 1,
++      , 1,
++              PLC6, 1,
++              PLC7, 1,
++      Offset(0x3B),   /* PMEStatus1 */
++      GP0S, 1,
++      GM4S, 1,
++      GM5S, 1,
++      APS, 1,
++      GM6S, 1,
++      GM7S, 1,
++      GP2S, 1,
++      STSS, 1,
++      Offset(0x55),   /* SoftPciRst */
++      SPRE, 1,
++      , 1,
++      , 1,
++      PNAT, 1,
++      PWMK, 1,
++      PWNS, 1,
++
++      /*      Offset(0x61), */        /*  Options_1 */
++      /*              ,7,  */
++      /*              R617,1, */
++
++      Offset(0x65),   /* UsbPMControl */
++      , 4,
++      URRE, 1,
++      , 2,
++      BCDL, 1,
++      Offset(0x68),   /* MiscEnable68 */
++      , 2,
++      MAPC, 1,
++      TMTE, 1,
++      , 1,
++      Offset(0x7C),   /* MiscEnable7C */
++      , 2,
++      BLNK, 2,
++      Offset(0x92),   /* GEVENTIN */
++      , 7,
++      E7IS, 1,
++      Offset(0x96),   /* GPM98IN */
++      G8IS, 1,
++      G9IS, 1,
++      Offset(0x9A),   /* EnhanceControl */
++      ,7,
++      HPDE, 1,
++      Offset(0xA8),   /* PIO7654Enable */
++      IO4E, 1,
++      IO5E, 1,
++      IO6E, 1,
++      IO7E, 1,
++      Offset(0xA9),   /* PIO7654Status */
++      IO4S, 1,
++      IO5S, 1,
++      IO6S, 1,
++      IO7S, 1,
++}
++
++/* PM1 Event Block
++      * First word is PM1_Status, Second word is PM1_Enable
++      */
++OperationRegion(P1EB, SystemIO, APEB, 0x04)
++      Field(P1EB, ByteAcc, NoLock, Preserve) {
++      TMST, 1,
++      ,    3,
++      BMST,    1,
++      GBST,   1,
++      Offset(0x01),
++      PBST, 1,
++      , 1,
++      RTST, 1,
++      , 3,
++      PWST, 1,
++      SPWS, 1,
++      Offset(0x02),
++      TMEN, 1,
++      , 4,
++      GBEN, 1,
++      Offset(0x03),
++      PBEN, 1,
++      , 1,
++      RTEN, 1,
++      , 3,
++      PWDA, 1,
++}
++
++/* Wake status package */
++Name(WKST,Package() {Zero, Zero})
++
+ /*
+- * WARNING: Sleep/Wake is a work in progress and is still somewhat flaky!
++ *  \_WAK System Wake method
++ *
++ *    Entry:
++ *            Arg0=The value of the sleeping state S1=1, S2=2
++ *
++ *    Exit:
++ *            Return package of 2 DWords
++ *            Dword 1 - Status
++ *                    0x00000000      wake succeeded
++ *                    0x00000001      Wake was signaled but failed due to 
lack of power
++ *                    0x00000002      Wake was signaled but failed due to 
thermal condition
++ *            Dword 2 - Power Supply state
++ *                    if non-zero the effective S-state the power supply 
entered
+  */
+-
+-      /* Port 80 POST card debug */
+-      OperationRegion (DBG0, SystemIO, 0x80, One)
+-              Field (DBG0, ByteAcc, NoLock, Preserve) {
+-              DBG8, 8
+-      }
+-
+-      /* SuperIO control port */
+-      Name (SPIO, 0x2E)
+-
+-      /* SuperIO control map */
+-      OperationRegion (SPIM, SystemIO, SPIO, 0x02)
+-              Field (SPIM, ByteAcc, NoLock, Preserve) {
+-              INDX, 8,
+-              DATA, 8
+-      }
+-
+-      /* SuperIO control registers */
+-      IndexField (INDX, DATA, ByteAcc, NoLock, Preserve) {
+-              Offset (0x07),
+-              CR07, 8,                /* Logical device number */
+-              Offset (0x2C),
+-              CR2C, 8,                /* GPIO3 multiplexed pin selection */
+-              Offset (0x30),
+-              CR30, 8,                /* Logical device activation control 
register */
+-              Offset (0xE0),
+-              CRE0, 8,                /* Wake control register */
+-              Offset (0xE6),
+-              CRE6, 8,                /* Mouse wake event configuration 
register */
+-              Offset (0xF1),
+-              CRF1, 8,                /* GPIO3 data register */
+-              Offset (0xF3),
+-              CRF3, 8,                /* SUSLED mode register */
+-              Offset (0xF6),
+-              CRF6, 8,                /* SMI/PME event generation control 
register */
+-              Offset (0xF9),
+-              CRF9, 8,                /* ACPI PME configuration register */
++Method(\_WAK, 1) {
++      Store (0x20, DBG8)
++
++      /* Set up LEDs */
++      /* Set power LED to steady on */
++      Store(0x3, BLNK)
++
++      /* Configure SuperIO for wake */
++      /* Access SuperIO ACPI device */
++      Store(0x87, INDX)
++      Store(0x87, INDX)
++      Store(0x0A, CR07)
++
++      if (LEqual(Arg0, One))  /* Resuming from power state S1 */
++      {
++              /* Deactivate the ACPI device */
++              Store(Zero, CR30)
++
++              /* Disable PS/2 SMI/PME events */
++              And(CRF6, 0xCF, CRF6)
+       }
+-
+-      /* Power Management I/O registers */
+-      OperationRegion(PIOR, SystemIO, 0x00000CD6, 0x00000002)
+-              Field(PIOR, ByteAcc, NoLock, Preserve) {
+-              PIOI, 0x00000008,
+-              PIOD, 0x00000008,
+-      }
+-      IndexField (PIOI, PIOD, ByteAcc, NoLock, Preserve) {
+-              Offset(0x00),   /* MiscControl */
+-              , 1,
+-              T1EE, 1,
+-              T2EE, 1,
+-              Offset(0x01),   /* MiscStatus */
+-              , 1,
+-              T1E, 1,
+-              T2E, 1,
+-              Offset(0x04),   /* SmiWakeUpEventEnable3 */
+-              , 7,
+-              SSEN, 1,
+-              Offset(0x07),   /* SmiWakeUpEventStatus3 */
+-              , 7,
+-              CSSM, 1,
+-              Offset(0x10),   /* AcpiEnable */
+-              , 6,
+-              PWDE, 1,
+-              Offset(0x1C),   /* ProgramIoEnable */
+-              , 3,
+-              MKME, 1,
+-              IO3E, 1,
+-              IO2E, 1,
+-              IO1E, 1,
+-              IO0E, 1,
+-              Offset(0x1D),   /* IOMonitorStatus */
+-              , 3,
+-              MKMS, 1,
+-              IO3S, 1,
+-              IO2S, 1,
+-              IO1S, 1,
+-              IO0S,1,
+-              Offset(0x20),   /* AcpiPmEvtBlk */
+-              APEB, 16,
+-              Offset(0x36),   /* GEvtLevelConfig */
+-              , 6,
+-              ELC6, 1,
+-              ELC7, 1,
+-              Offset(0x37),   /* GPMLevelConfig0 */
+-              , 3,
+-              PLC0, 1,
+-              PLC1, 1,
+-              PLC2, 1,
+-              PLC3, 1,
+-              PLC8, 1,
+-              Offset(0x38),   /* GPMLevelConfig1 */
+-              , 1,
+-               PLC4, 1,
+-               PLC5, 1,
+-              , 1,
+-               PLC6, 1,
+-               PLC7, 1,
+-              Offset(0x3B),   /* PMEStatus1 */
+-              GP0S, 1,
+-              GM4S, 1,
+-              GM5S, 1,
+-              APS, 1,
+-              GM6S, 1,
+-              GM7S, 1,
+-              GP2S, 1,
+-              STSS, 1,
+-              Offset(0x55),   /* SoftPciRst */
+-              SPRE, 1,
+-              , 1,
+-              , 1,
+-              PNAT, 1,
+-              PWMK, 1,
+-              PWNS, 1,
+-
+-              /*      Offset(0x61), */        /*  Options_1 */
+-              /*              ,7,  */
+-              /*              R617,1, */
+-
+-              Offset(0x65),   /* UsbPMControl */
+-              , 4,
+-              URRE, 1,
+-              Offset(0x68),   /* MiscEnable68 */
+-              , 3,
+-              TMTE, 1,
+-              , 1,
+-              Offset(0x7C),   /* MiscEnable7C */
+-              , 2,
+-              BLNK, 2,
+-              Offset(0x92),   /* GEVENTIN */
+-              , 7,
+-              E7IS, 1,
+-              Offset(0x96),   /* GPM98IN */
+-              G8IS, 1,
+-              G9IS, 1,
+-              Offset(0x9A),   /* EnhanceControl */
+-              ,7,
+-              HPDE, 1,
+-              Offset(0xA8),   /* PIO7654Enable */
+-              IO4E, 1,
+-              IO5E, 1,
+-              IO6E, 1,
+-              IO7E, 1,
+-              Offset(0xA9),   /* PIO7654Status */
+-              IO4S, 1,
+-              IO5S, 1,
+-              IO6S, 1,
+-              IO7S, 1,
++      if (Lor(LEqual(Arg0, 0x03), LEqual(Arg0, 0x04)))        /* Resuming 
from power state S3 or S4 */
++      {
++              /* Disable PS/2 wake */
++              And(CRE0, 0x1D, CRE0)
++              And(CRE6, 0x7F, CRE6)
+       }
+ 
+-      /* PM1 Event Block
+-       * First word is PM1_Status, Second word is PM1_Enable
+-       */
+-      OperationRegion(P1EB, SystemIO, APEB, 0x04)
+-              Field(P1EB, ByteAcc, NoLock, Preserve) {
+-              TMST, 1,
+-              ,    3,
+-              BMST,    1,
+-              GBST,   1,
+-              Offset(0x01),
+-              PBST, 1,
+-              , 1,
+-              RTST, 1,
+-              , 3,
+-              PWST, 1,
+-              SPWS, 1,
+-              Offset(0x02),
+-              TMEN, 1,
+-              , 4,
+-              GBEN, 1,
+-              Offset(0x03),
+-              PBEN, 1,
+-              , 1,
+-              RTEN, 1,
+-              , 3,
+-              PWDA, 1,
+-      }
+-
+-      /* Wake status package */
+-      Name(WKST,Package(){Zero, Zero})
+-
+-      /*
+-       *  \_WAK System Wake method
+-       *
+-       *      Entry:
+-       *              Arg0=The value of the sleeping state S1=1, S2=2
+-       *
+-       *      Exit:
+-       *              Return package of 2 DWords
+-       *              Dword 1 - Status
+-       *                      0x00000000      wake succeeded
+-       *                      0x00000001      Wake was signaled but failed 
due to lack of power
+-       *                      0x00000002      Wake was signaled but failed 
due to thermal condition
+-       *              Dword 2 - Power Supply state
+-       *                      if non-zero the effective S-state the power 
supply entered
+-       */
+-      Method(\_WAK, 1) {
+-              Store (0x20, DBG8)
+-
+-              /* Set up LEDs */
+-              /* Set power LED to steady on */
+-              Store(0x3, BLNK)
+-
+-              /* Configure SuperIO for wake */
+-              /* Access SuperIO ACPI device */
+-              Store(0x87, INDX)
+-              Store(0x87, INDX)
+-              Store(0x0A, CR07)
+-
+-              if (LEqual(Arg0, One))  /* Resuming from power state S1 */
+-              {
+-                      /* Deactivate the ACPI device */
+-                      Store(Zero, CR30)
+-
+-                      /* Disable PS/2 SMI/PME events */
+-                      And(CRF6, 0xCF, CRF6)
+-              }
+-              if (Lor(LEqual(Arg0, 0x03), LEqual(Arg0, 0x04)))        /* 
Resuming from power state S3 or S4 */
+-              {
+-                      /* Disable PS/2 wake */
+-                      And(CRE0, 0x1D, CRE0)
+-                      And(CRE6, 0x7F, CRE6)
+-              }
++      /* Restore default SuperIO access */
++      Store(0xAA, INDX)
+ 
+-              /* Restore default SuperIO access */
+-              Store(0xAA, INDX)
++      Store (0x21, DBG8)
+ 
+-              Store (0x21, DBG8)
++      /* Re-enable HPET */
++      Store(1, HPDE)
+ 
+-              /* Re-enable HPET */
+-              Store(1, HPDE)
++      /* Restore PCIRST# so it resets USB */
++      if (LEqual(Arg0, 3)){
++              Store(1, URRE)
++      }
+ 
+-              /* Restore PCIRST# so it resets USB */
+-              if (LEqual(Arg0, 3)){
+-                      Store(1, URRE)
+-              }
++      /* Configure southbridge for wake */
++      /* Arbitrarily clear PciExpWakeStatus */
++      Store(PWST, PWST)
+ 
+-              /* Configure southbridge for wake */
+-              /* Arbitrarily clear PciExpWakeStatus */
+-              Store(PWST, PWST)
++      Store (0x22, DBG8)
+ 
+-              Store (0x22, DBG8)
++      Notify(\_SB.PWRB, 0x02)                 /* NOTIFY_DEVICE_WAKE */
+ 
+-              Notify(\_SB.PWRB, 0x02)                 /* NOTIFY_DEVICE_WAKE */
++      Return(WKST)
++}
+ 
+-              Return(WKST)
++/*
++ * \_PTS - Prepare to Sleep method
++ *
++ *    Entry:
++ *            Arg0=The value of the sleeping state S1=1, S2=2, etc
++ *
++ * Exit:
++ *            -none-
++ *
++ * The _PTS control method is executed at the beginning of the sleep process
++ * for S1-S5. The sleeping value is passed to the _PTS control method.        
This
++ * control method may be executed a relatively long time before entering the
++ * sleep state and the OS may abort the operation without notification to
++ * the ACPI driver.  This method cannot modify the configuration or power
++ * state of any device in the system.
++ */
++Method(\_PTS, 1) {
++      Store (Arg0, DBG8)
++
++      /* Set up LEDs */
++      if (LEqual(Arg0, One))  /* Power state S1 requested */
++      {
++              /* Set suspend LED to 0.25Hz toggle pulse with 50% duty cycle */
++              Store(0x2, BLNK)
++      }
++      if (LEqual(Arg0, 0x3))  /* Power state S3 requested */
++      {
++              /* Set suspend LED to 0.25Hz toggle pulse with 25% duty cycle */
++              Store(0x1, BLNK)
+       }
+ 
+-      /*
+-       * \_PTS - Prepare to Sleep method
+-       *
+-       *      Entry:
+-       *              Arg0=The value of the sleeping state S1=1, S2=2, etc
+-       *
+-       * Exit:
+-       *              -none-
+-       *
+-       * The _PTS control method is executed at the beginning of the sleep 
process
+-       * for S1-S5. The sleeping value is passed to the _PTS control method.  
This
+-       * control method may be executed a relatively long time before 
entering the
+-       * sleep state and the OS may abort the operation without notification 
to
+-       * the ACPI driver.  This method cannot modify the configuration or 
power
+-       * state of any device in the system.
+-       */
+-      Method(\_PTS, 1) {
+-              Store (Arg0, DBG8)
+-
+-              /* Set up LEDs */
+-              if (LEqual(Arg0, One))  /* Power state S1 requested */
+-              {
+-                      /* Set suspend LED to 0.25Hz toggle pulse with 50% duty 
cycle */
+-                      Store(0x2, BLNK)
+-              }
+-              if (LEqual(Arg0, 0x3))  /* Power state S3 requested */
+-              {
+-                      /* Set suspend LED to 0.25Hz toggle pulse with 25% duty 
cycle */
+-                      Store(0x1, BLNK)
+-              }
++      /* Configure SuperIO for sleep */
++      /* Access SuperIO ACPI device */
++      Store(0x87, INDX)
++      Store(0x87, INDX)
++      Store(0x0A, CR07)
+ 
+-              /* Configure SuperIO for sleep */
+-              /* Access SuperIO ACPI device */
+-              Store(0x87, INDX)
+-              Store(0x87, INDX)
+-              Store(0x0A, CR07)
++      /* Disable PS/2 wakeup and connect PANSW_IN to PANSW_OUT */
++      And(CRE0, 0x1F, CRE0)
+ 
+-              /* Disable PS/2 wakeup and connect PANSW_IN to PANSW_OUT */
+-              And(CRE0, 0x1F, CRE0)
++      if (LEqual(Arg0, One))  /* Power state S1 requested */
++      {
++              /* Activate the ACPI device */
++              Store(One, CR30)
+ 
+-              if (LEqual(Arg0, One))  /* Power state S1 requested */
+-              {
+-                      /* Activate the ACPI device */
+-                      Store(One, CR30)
++              /* Disable SMI/PME events for:
++                      * LPT
++                      * FDC
++                      * UART
++                      */
++              Store(0x00, CRF6)
+ 
+-                      /* Disable SMI/PME events for:
+-                       * LPT
+-                       * FDC
+-                       * UART
+-                      Store(0x00, CRF6)
++              /* Enable PS/2 keyboard SMI/PME events */
++              Or(CRF6, 0x10, CRF6)
+ 
+-                      /* Enable PS/2 keyboard SMI/PME events */
+-                      Or(CRF6, 0x10, CRF6)
++              /* Enable PS/2 keyboard wake */
++              Or(CRE0, 0x40, CRE0)
+ 
+-                      /* Enable PS/2 keyboard wake */
+-                      Or(CRE0, 0x40, CRE0)
++              /* Enable PS/2 mouse SMI/PME events */
++              Or(CRF6, 0x20, CRF6)
+ 
+-                      /* Enable PS/2 mouse SMI/PME events */
+-                      Or(CRF6, 0x20, CRF6)
++              /* Enable PS/2 mouse wake  */
++              Or(CRE0, 0x20, CRE0)
++      } else {
++              /* Enable PS/2 keyboard wake on any keypress */
++              Or(CRE0, 0x41, CRE0)
+ 
+-                      /* Enable PS/2 mouse wake  */
+-                      Or(CRE0, 0x20, CRE0)
+-              } else {
+-                      /* Enable PS/2 keyboard wake on any keypress */
+-                      Or(CRE0, 0x41, CRE0)
++              /* Enable PS/2 mouse wake on any click  */
++              Or(CRE0, 0x22, CRE0)
++              Or(CRE6, 0x80, CRE6)
+ 
+-                      /* Enable PS/2 mouse wake on any click  */
+-                      Or(CRE0, 0x22, CRE0)
+-                      Or(CRE6, 0x80, CRE6)
++              if (LEqual(Arg0, 0x03)) /* Power state S3 requested */
++              {
++                      /* Set VSBGATE# to provide standby power during S3 */
++                      Or(CRE4, 0x10, CRE4)
+               }
++      }
+ 
+-              /* Restore default SuperIO access */
+-              Store(0xAA, INDX)
++      /* Restore default SuperIO access */
++      Store(0xAA, INDX)
+ 
+-              Store (0x10, DBG8)
++      Store (0x10, DBG8)
+ 
+-              /* Don't allow PCIRST# to reset USB */
+-              if (LEqual(Arg0, 3)){
+-                      Store(0, URRE)
+-              }
++      /* Don't allow PCIRST# to reset USB */
++      if (LEqual(Arg0, 3)){
++              Store(0, URRE)
++      }
+ 
+-              /* Configure southbridge for sleep */
+-              /* Clear sleep SMI status flag and enable sleep SMI trap. */
+-              // Store(One, CSSM)     /* Set ExtEvent0 as SMI# source */
+-              // Store(One, SSEN)     /* Enable wake on external event 0 */
++      /* Configure southbridge for sleep */
++      /* Use bus clock for delay timebase */
++      Store(0, BCDL)
++      /* Defer APIC interrupts until first ACPI access */
++      Store(One, MAPC)
+ 
+-              /* On older chips, clear PciExpWakeDisEn */
+-              // if (LLessEqual(SBRI, 0x13)) {
+-              //      Store(0, PWDE)
+-              // }
++      /* On older chips, clear PciExpWakeDisEn */
++      // if (LLessEqual(SBRI, 0x13)) {
++      //      Store(0, PWDE)
++      // }
+ 
+-              Store (0x11, DBG8)
++      Store (0x11, DBG8)
+ 
+-              /* Clear wake status structure. */
+-              Store(0, Index(WKST,0))
+-              Store(0, Index(WKST,1))
+-      }
+\ No newline at end of file
++      /* Clear wake status structure. */
++      Store(0, Index(WKST,0))
++      Store(0, Index(WKST,1))
++}
+diff --git a/src/mainboard/asus/kgpe-d16/dsdt.asl 
b/src/mainboard/asus/kgpe-d16/dsdt.asl
+index bdd1d2d..b6f10d9 100644
+--- a/src/mainboard/asus/kgpe-d16/dsdt.asl
++++ b/src/mainboard/asus/kgpe-d16/dsdt.asl
+@@ -58,9 +58,8 @@ DefinitionBlock (
+       /* Define power states */
+       Name (\_S0, Package () { 0x00, 0x00, 0x00, 0x00 })      /* Normal 
operation */
+       Name (\_S1, Package () { 0x01, 0x01, 0x00, 0x00 })      /* Standby */
+-      Name (\_S2, Package () { 0x02, 0x02, 0x00, 0x00 })      /* Standby w/ 
CPU shutdown */
+-      Name (\_S3, Package () { 0x03, 0x00, 0x00, 0x00 })      /* Suspend */
+-      /* Name (\_S4, Package () { 0x04, 0x04, 0x00, 0x00 }) */
++      Name (\_S3, Package () { 0x03, 0x03, 0x00, 0x00 })      /* Suspend to 
RAM */
++      Name (\_S4, Package () { 0x04, 0x04, 0x00, 0x00 })      /* Suspend to 
disk */
+       Name (\_S5, Package () { 0x05, 0x05, 0x00, 0x00 })      /* Hard power 
off */
+ 
+       /* The _PIC method is called by the OS to choose between interrupt
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index 616fdfb..3431bab 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -224,12 +224,15 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ {
+       struct sys_info *sysinfo = &sysinfo_car;
+ 
+-      u32 bsp_apicid = 0, val;
++      uint32_t bsp_apicid = 0, val;
++      uint8_t byte;
+       msr_t msr;
+ 
+       timestamp_init(timestamp_get());
+       timestamp_add_now(TS_START_ROMSTAGE);
+ 
++      int s3resume = acpi_is_wakeup_s3();
++
+       if (!cpu_init_detectedx && boot_cpu()) {
+               /* Nothing special needs to be done to find bus 0 */
+               /* Allow the HT devices to be found */
+@@ -247,6 +250,11 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               /* Initialize early serial */
+               nuvoton_enable_serial(SERIAL_DEV, CONFIG_TTYS0_BASE);
+               console_init();
++
++              /* Disable LPC legacy DMA support to prevent lockup */
++              byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0x78);
++              byte &= ~(1 << 0);
++              pci_write_config8(PCI_DEV(0, 0x14, 3), 0x78, byte);
+       }
+ 
+       post_code(0x30);
+@@ -285,14 +293,6 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+       amd_ht_fixup(sysinfo);
+       post_code(0x35);
+ 
+-      /* Set DDR memory voltage
+-       * FIXME
+-       * This should be set based on the output of the DIMM SPDs
+-       * For now it is locked to 1.5V
+-       */
+-      set_ddr3_voltage(0, 0); /* Node 0 */
+-      set_ddr3_voltage(1, 0); /* Node 1 */
+-
+       /* Setup nodes PCI space and start core 0 AP init. */
+       finalize_node_setup(sysinfo);
+ 
+@@ -355,6 +355,17 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               die("After soft_reset_x - shouldn't see this message!!!\n");
+       }
+ 
++      /* Set DDR memory voltage
++       * FIXME
++       * This should be set based on the output of the DIMM SPDs
++       * For now it is locked to 1.5V
++       */
++      set_lpc_sticky_ctl(1);  /* Retain LPC/IMC GPIO configuration during S3 
sleep */
++      if (!s3resume) {        /* Avoid supply voltage glitches while the 
DIMMs are retaining data */
++              set_ddr3_voltage(0, 0); /* Node 0 */
++              set_ddr3_voltage(1, 0); /* Node 1 */
++      }
++
+       /* Set up peripheral control lines */
+       set_peripheral_control_lines();
+ 
+@@ -384,7 +395,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+       timestamp_add_now(TS_AFTER_INITRAM);
+ 
+ #if !IS_ENABLED(CONFIG_LATE_CBMEM_INIT)
+-      cbmem_initialize_empty();
++      if (s3resume)
++              cbmem_initialize();
++      else
++              cbmem_initialize_empty();
+       post_code(0x41);
+ 
+       amdmct_cbmem_store_info(sysinfo);
+diff --git a/src/mainboard/asus/kgpe-d16/spd_notes.txt 
b/src/mainboard/asus/kgpe-d16/spd_notes.txt
+index 623a88f..ddd5cc8 100644
+--- a/src/mainboard/asus/kgpe-d16/spd_notes.txt
++++ b/src/mainboard/asus/kgpe-d16/spd_notes.txt
+@@ -28,3 +28,19 @@ Other hardware
+ 
+ RECOVERY1 middle pin is connected to southbridge (AMD SP5100) GPIO 61
+ Normal is HIGH, recovery is LOW.
++
+++12VSB is generated using a charge pump attached to pin 7 of PU24 (APW7145).
++
++The +12VSB standby voltage to each bank of DIMMs is switched by a bank of 
small FETs located close to each RAM power regulator control chip.
++The +12V primary voltage (lower left pin of the FET placed on the upper left 
of the control chip of the second node) is also connected to the 232GE located 
near the PCI slot.
++
++The control line running to the gates of the +12VSB control FETs is connected 
to the +5VSB power for the USB ports.
++That line in turn is connected to +5VSB via the lone P06P03G PMOS transistor 
on the reverse side of the board, near the center on the lower half.
++The gate of that transistor is connected via a resistor to the source of the 
P06P03G PMOS transistor located adjacent to the unpopulated SMA clock header.
++The gate of that transistor is connected directly to the drain of the small 
FET directly below it.
++After that, there's a cascade of small FETs and resistors in that region, 
eventually leading to SuperIO pin 81.
++
++SuperIO pin 81 (VSBGATE#) enables the standby voltage rails when set LOW.
++VSBGATE# is reset on every assertion of PWRGOOD.
++
++Setting SuperIO LDN 9 CRF4 bits 1 or 0 (or both) to 0 disables NICB.
+\ No newline at end of file
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0023-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
 
b/resources/libreboot/patch/kgpe-d16/0023-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
deleted file mode 100644
index 0867c83..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0023-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
+++ /dev/null
@@ -1,198 +0,0 @@
-From 4cc0cdf4b04ba705d302a60a7f5905c17fe9bffe Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 18:56:05 -0500
-Subject: [PATCH 023/139] northbridge/amd/amdfam10: Set DIMM voltage based on
- SPD data
-
-Change-Id: I67a76cf0e4ebc33fbd7dd151bb68dce1fc6ba680
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/Kconfig        |  4 ++
- src/northbridge/amd/amdfam10/acpi.c         |  3 +-
- src/northbridge/amd/amdfam10/northbridge.c  | 75 ++++++++++++++++++++++++-----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |  8 +++
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |  6 +++
- 5 files changed, 81 insertions(+), 15 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/Kconfig 
b/src/northbridge/amd/amdfam10/Kconfig
-index ff92fca..ada5b9f 100644
---- a/src/northbridge/amd/amdfam10/Kconfig
-+++ b/src/northbridge/amd/amdfam10/Kconfig
-@@ -83,6 +83,10 @@ config DIMM_REGISTERED
-       bool
-       default n
- 
-+config DIMM_VOLTAGE_SET_SUPPORT
-+      bool
-+      default n
-+
- if DIMM_FBDIMM
-       config DIMM_SUPPORT
-               hex
-diff --git a/src/northbridge/amd/amdfam10/acpi.c 
b/src/northbridge/amd/amdfam10/acpi.c
-index 4b86e96..92433bb 100644
---- a/src/northbridge/amd/amdfam10/acpi.c
-+++ b/src/northbridge/amd/amdfam10/acpi.c
-@@ -307,8 +307,7 @@ void northbridge_acpi_write_vars(device_t device)
-       } else {
-               if((sysconf.pci1234[0] >> 12) & 0xff) { //sb chain on  other 
than bus 0
-                       CBST = (u8) (0x0f);
--              }
--              else {
-+              } else {
-                       CBST = (u8) (0x00);
-               }
-       }
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 9cc3d96..3b302e8 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -950,19 +950,38 @@ static int amdfam10_get_smbios_data16(int* count, int 
handle, unsigned long *cur
- 
- static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
- {
--      switch (speed) {
--              case 1:
--                      return 200;
--              case 2:
--                      return 266;
--              case 3:
--                      return 333;
--              case 4:
--                      return 400;
--              case 5:
--                      return 533;
--              default:
--                      return 0;
-+      if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
-+              switch (speed) {
-+                      case 1:
-+                              return 200;
-+                      case 2:
-+                              return 266;
-+                      case 3:
-+                              return 333;
-+                      case 4:
-+                              return 400;
-+                      case 5:
-+                              return 533;
-+                      default:
-+                              return 0;
-+              }
-+      } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+              switch (speed) {
-+                      case 3:
-+                              return 333;
-+                      case 4:
-+                              return 400;
-+                      case 5:
-+                              return 533;
-+                      case 6:
-+                              return 667;
-+                      case 7:
-+                              return 800;
-+                      default:
-+                              return 0;
-+              }
-+      } else {
-+              return 0;
-       }
- }
- 
-@@ -1048,6 +1067,36 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
-                                       snprintf(string_buffer, sizeof 
(string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
-                                       t->serial_number = 
smbios_add_string(t->eos, string_buffer);
-                               }
-+                              if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
-+                                      /* JEDEC specifies 1.8V only, so assume 
that the memory is configured for 1.8V */
-+                                      t->minimum_voltage = 1800;
-+                                      t->maximum_voltage = 1800;
-+                                      t->configured_voltage = 1800;
-+                              } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+#if IS_ENABLED(CONFIG_DIMM_DDR3)
-+                                      /* Find the maximum and minimum 
supported voltages */
-+                                      uint8_t supported_voltages = 
mem_info->dct_stat[node].DimmSupportedVoltages[slot];
-+                                      if (supported_voltages & 0x8)
-+                                              t->minimum_voltage = 1150;
-+                                      else if (supported_voltages & 0x4)
-+                                              t->minimum_voltage = 1250;
-+                                      else if (supported_voltages & 0x2)
-+                                              t->minimum_voltage = 1350;
-+                                      else if (supported_voltages & 0x1)
-+                                              t->minimum_voltage = 1500;
-+
-+                                      if (supported_voltages & 0x1)
-+                                              t->maximum_voltage = 1500;
-+                                      else if (supported_voltages & 0x2)
-+                                              t->maximum_voltage = 1350;
-+                                      else if (supported_voltages & 0x4)
-+                                              t->maximum_voltage = 1250;
-+                                      else if (supported_voltages & 0x8)
-+                                              t->maximum_voltage = 1150;
-+
-+                                      t->configured_voltage = 
mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
-+#endif
-+                              }
-                               t->memory_error_information_handle = 0xFFFE;    
/* no error information handle available */
-                               single_len = t->length + 
smbios_string_table_len(t->eos);
-                               len += single_len;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index a8212c5..12dfff1 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -330,6 +330,11 @@ restartinit:
-                       goto fatalexit;
-               }
- 
-+#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
-+              DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
-+#endif
-+
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
-               SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are 
ready for accesses.*/
- 
-@@ -2122,6 +2127,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                       pDCTstat->DimmBanks[i] = 1ULL << 
(((mctRead_SPD(smbaddr, SPD_Density) & 0x70) >> 4) + 3);
-                                       pDCTstat->DimmWidth[i] = 1ULL << 
((mctRead_SPD(smbaddr, SPD_BusWidth) & 0x7) + 3);
-                               }
-+                              /* Check supported voltage(s) */
-+                              pDCTstat->DimmSupportedVoltages[i] = 
mctRead_SPD(smbaddr, SPD_Voltage) & 0x7;
-+                              pDCTstat->DimmSupportedVoltages[i] ^= 0x1;      
/* Invert LSB to convert from SPD format to internal bitmap format */
-                               /* Check module type */
-                               byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE) & 0x7;
-                               if (byte == JED_RDIMM || byte == JED_MiniRDIMM) 
{
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index c790d7e..a947c2d 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -206,6 +206,7 @@
-       #define JED_MiniRDIMM   0x5     /* Mini-RDIMM */
- #define SPD_Density   4               /* Bank address bits,SDRAM capacity */
- #define SPD_Addressing        5               /* Row/Column address bits */
-+#define SPD_Voltage   6               /* Supported voltage bitfield */
- #define SPD_Organization      7               /* rank#,Device width */
- #define SPD_BusWidth  8               /* ECC, Bus width */
-       #define JED_ECC         8       /* ECC capability */
-@@ -585,6 +586,10 @@ struct DCTStatStruc {             /* A per Node 
structure*/
-       struct _sDCTStruct s_C_DCTPtr[2];
-       /* struct _sDCTStruct s_C_DCT1Ptr[8]; */
- 
-+      /* DIMM supported voltage bitmap ([2:0]: 1.25V, 1.35V, 1.5V) */
-+      uint8_t DimmSupportedVoltages[MAX_DIMMS_SUPPORTED];
-+      uint32_t DimmConfiguredVoltage[MAX_DIMMS_SUPPORTED];    /* mV */
-+
-       uint8_t DimmRows[MAX_DIMMS_SUPPORTED];
-       uint8_t DimmCols[MAX_DIMMS_SUPPORTED];
-       uint8_t DimmRanks[MAX_DIMMS_SUPPORTED];
-@@ -905,6 +910,7 @@ u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 
dct, u32 val);
- void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct);
- void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 node);
- void mctSMBhub_Init(u32 node);
-+void DIMMSetVoltages(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- int mctRead_SPD(u32 smaddr, u32 reg);
- void InterleaveNodes_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0024-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
 
b/resources/libreboot/patch/kgpe-d16/0024-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
new file mode 100644
index 0000000..bdb2752
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0024-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch
@@ -0,0 +1,33 @@
+From aef05f58a4a6f2760a93cb645dbf7bc85225837a Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 19:00:34 -0500
+Subject: [PATCH 024/143] include/smbios: Update SMBIOS memory structures to
+ version 2.8
+
+Change-Id: Icda915933c4ebf3a735d9e1d4e4dbb1138a06b39
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/include/smbios.h |    6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/src/include/smbios.h b/src/include/smbios.h
+index b654c23..fdb7bbd 100644
+--- a/src/include/smbios.h
++++ b/src/include/smbios.h
+@@ -409,9 +409,11 @@ struct smbios_type17 {
+       u8 asset_tag;
+       u8 part_number;
+       u8 attributes;
+-      u16 extended_size;
++      u32 extended_size;
+       u16 clock_speed;
+-
++      u16 minimum_voltage;
++      u16 maximum_voltage;
++      u16 configured_voltage;
+       char eos[2];
+ } __attribute__((packed));
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0024-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
 
b/resources/libreboot/patch/kgpe-d16/0024-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
deleted file mode 100644
index 059aefc..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0024-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
+++ /dev/null
@@ -1,166 +0,0 @@
-From 7cc2167cf68f778b06a3defcb42b6b9ebdbce2e5 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 10 May 2015 04:37:56 -0500
-Subject: [PATCH 024/139] mainboard/asus/kgpe-d16: Set DDR3 memory voltage
- based on SPD data
-
-Change-Id: I21777283ce0fd3c607951204a63ff67dc656c8cc
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/Kconfig      |  1 +
- src/mainboard/asus/kgpe-d16/cmos.default |  1 +
- src/mainboard/asus/kgpe-d16/cmos.layout  |  5 +++
- src/mainboard/asus/kgpe-d16/romstage.c   | 76 +++++++++++++++++++++++++++++---
- 4 files changed, 78 insertions(+), 5 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-index f9556fc..9471692 100644
---- a/src/mainboard/asus/kgpe-d16/Kconfig
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -6,6 +6,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
-       select DIMM_DDR3
-       select DIMM_REGISTERED
-       # select QRANK_DIMM_SUPPORT
-+      select DIMM_VOLTAGE_SET_SUPPORT
-       select NORTHBRIDGE_AMD_AMDFAM10
-       select SOUTHBRIDGE_AMD_SR5650
-       select SOUTHBRIDGE_AMD_SB700
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index e920297..39a4778 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -6,6 +6,7 @@ iommu = Disable
- nmi = Disable
- hypertransport_speed_limit = Auto
- max_mem_clock = DDR3-1600
-+minimum_memory_voltage = 1.5V
- ECC_memory = Enable
- ECC_redirection = Disable
- ecc_scrub_rate = 1.28us
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index b9266dc..110e0bb 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -41,6 +41,7 @@ entries
- 456          1       e       1        ECC_memory
- 457          1       e       1        ECC_redirection
- 458          4       e       11       hypertransport_speed_limit
-+462          2       e       12       minimum_memory_voltage
- 477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
-@@ -129,6 +130,10 @@ enumerations
- 11    13    400MHz
- 11    14    300MHz
- 11    15    200MHz
-+12    0     1.5V
-+12    1     1.35V
-+12    2     1.25V
-+12    3     1.15V
- 
- checksums
- 
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index 3431bab..18e7c16 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -135,7 +135,7 @@ static void activate_spd_rom(const struct mem_controller 
*ctrl) {
-  */
- static void set_ddr3_voltage(uint8_t node, uint8_t index) {
-       uint8_t byte;
--      uint8_t value;
-+      uint8_t value = 0;
- 
-       if (index == 0)
-               value = 0x0;
-@@ -161,6 +161,74 @@ static void set_ddr3_voltage(uint8_t node, uint8_t index) 
{
-       byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0xd0);
-       byte &= 0x0f;
-       pci_write_config8(PCI_DEV(0, 0x14, 3), 0xd0, byte);
-+
-+      printk(BIOS_DEBUG, "Node %02d DIMM voltage set to index %02x\n", node, 
index);
-+}
-+
-+void DIMMSetVoltages(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstatA) {
-+      /* This mainboard allows the DIMM voltage to be set per-socket.
-+       * Therefore, for each socket, iterate over all DIMMs to find the
-+       * lowest supported voltage common to all DIMMs on that socket.
-+       */
-+      uint8_t nvram;
-+      uint8_t dimm;
-+      uint8_t node;
-+      uint8_t socket;
-+      uint8_t allowed_voltages = 0xf; /* The mainboard VRMs allow 1.15V, 
1.25V, 1.35V, and 1.5V */
-+      uint32_t set_voltage = 0;
-+
-+      if (get_option(&nvram, "minimum_memory_voltage") == CB_SUCCESS) {
-+              if (nvram == 2)
-+                      allowed_voltages = 0x7; /* Allow 1.25V, 1.35V, and 1.5V 
*/
-+              if (nvram == 1)
-+                      allowed_voltages = 0x3; /* Allow 1.35V and 1.5V */
-+              if (nvram == 0)
-+                      allowed_voltages = 0x1; /* Allow 1.5V only */
-+      }
-+
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              socket = node / 2;
-+              struct DCTStatStruc *pDCTstat;
-+              pDCTstat = pDCTstatA + node;
-+              if (pDCTstat->NodePresent) {
-+                      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
-+                              if (pDCTstat->DIMMValid & (1 << dimm)) {
-+                                      allowed_voltages &= 
pDCTstat->DimmSupportedVoltages[dimm];
-+                              }
-+                      }
-+              }
-+
-+              if (pDCTstat->NodePresent && (node & 0x1)) {
-+                      /* Set voltages */
-+                      if (allowed_voltages & 0x8) {
-+                              set_voltage = 1150;
-+                              set_ddr3_voltage(socket, 3);
-+                      } else if (allowed_voltages & 0x4) {
-+                              set_voltage = 1250;
-+                              set_ddr3_voltage(socket, 2);
-+                      } else if (allowed_voltages & 0x2) {
-+                              set_voltage = 1350;
-+                              set_ddr3_voltage(socket, 1);
-+                      } else {
-+                              set_voltage = 1500;
-+                              set_ddr3_voltage(socket, 0);
-+                      }
-+
-+                      /* Save final DIMM voltages for SMBIOS use */
-+                      if (pDCTstat->NodePresent) {
-+                              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; 
dimm++) {
-+                                      pDCTstat->DimmConfiguredVoltage[dimm] = 
set_voltage;
-+                              }
-+                      }
-+                      pDCTstat = pDCTstatA + (node - 1);
-+                      if (pDCTstat->NodePresent) {
-+                              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; 
dimm++) {
-+                                      pDCTstat->DimmConfiguredVoltage[dimm] = 
set_voltage;
-+                              }
-+                      }
-+              }
-+      }
- }
- 
- static void set_peripheral_control_lines(void) {
-@@ -355,10 +423,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               die("After soft_reset_x - shouldn't see this message!!!\n");
-       }
- 
--      /* Set DDR memory voltage
--       * FIXME
--       * This should be set based on the output of the DIMM SPDs
--       * For now it is locked to 1.5V
-+      /* Set default DDR memory voltage
-+       * This will be overridden later during RAM initialization
-        */
-       set_lpc_sticky_ctl(1);  /* Retain LPC/IMC GPIO configuration during S3 
sleep */
-       if (!s3resume) {        /* Avoid supply voltage glitches while the 
DIMMs are retaining data */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0025-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
 
b/resources/libreboot/patch/kgpe-d16/0025-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
new file mode 100644
index 0000000..917a36d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0025-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch
@@ -0,0 +1,198 @@
+From e6a4307e156538ca120f68d281f5237cb50f8456 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 18:56:05 -0500
+Subject: [PATCH 025/143] northbridge/amd/amdfam10: Set DIMM voltage based on
+ SPD data
+
+Change-Id: I67a76cf0e4ebc33fbd7dd151bb68dce1fc6ba680
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/Kconfig        |    4 ++
+ src/northbridge/amd/amdfam10/acpi.c         |    3 +-
+ src/northbridge/amd/amdfam10/northbridge.c  |   75 ++++++++++++++++++++++-----
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |    8 +++
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |    6 +++
+ 5 files changed, 81 insertions(+), 15 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/Kconfig 
b/src/northbridge/amd/amdfam10/Kconfig
+index ff92fca..ada5b9f 100644
+--- a/src/northbridge/amd/amdfam10/Kconfig
++++ b/src/northbridge/amd/amdfam10/Kconfig
+@@ -83,6 +83,10 @@ config DIMM_REGISTERED
+       bool
+       default n
+ 
++config DIMM_VOLTAGE_SET_SUPPORT
++      bool
++      default n
++
+ if DIMM_FBDIMM
+       config DIMM_SUPPORT
+               hex
+diff --git a/src/northbridge/amd/amdfam10/acpi.c 
b/src/northbridge/amd/amdfam10/acpi.c
+index 4b86e96..92433bb 100644
+--- a/src/northbridge/amd/amdfam10/acpi.c
++++ b/src/northbridge/amd/amdfam10/acpi.c
+@@ -307,8 +307,7 @@ void northbridge_acpi_write_vars(device_t device)
+       } else {
+               if((sysconf.pci1234[0] >> 12) & 0xff) { //sb chain on  other 
than bus 0
+                       CBST = (u8) (0x0f);
+-              }
+-              else {
++              } else {
+                       CBST = (u8) (0x00);
+               }
+       }
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index d4fe986..ff324cd 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -950,19 +950,38 @@ static int amdfam10_get_smbios_data16(int* count, int 
handle, unsigned long *cur
+ 
+ static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
+ {
+-      switch (speed) {
+-              case 1:
+-                      return 200;
+-              case 2:
+-                      return 266;
+-              case 3:
+-                      return 333;
+-              case 4:
+-                      return 400;
+-              case 5:
+-                      return 533;
+-              default:
+-                      return 0;
++      if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
++              switch (speed) {
++                      case 1:
++                              return 200;
++                      case 2:
++                              return 266;
++                      case 3:
++                              return 333;
++                      case 4:
++                              return 400;
++                      case 5:
++                              return 533;
++                      default:
++                              return 0;
++              }
++      } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++              switch (speed) {
++                      case 3:
++                              return 333;
++                      case 4:
++                              return 400;
++                      case 5:
++                              return 533;
++                      case 6:
++                              return 667;
++                      case 7:
++                              return 800;
++                      default:
++                              return 0;
++              }
++      } else {
++              return 0;
+       }
+ }
+ 
+@@ -1048,6 +1067,36 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
+                                       snprintf(string_buffer, sizeof 
(string_buffer), "%08X", mem_info->dct_stat[node].DimmSerialNumber[slot]);
+                                       t->serial_number = 
smbios_add_string(t->eos, string_buffer);
+                               }
++                              if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
++                                      /* JEDEC specifies 1.8V only, so assume 
that the memory is configured for 1.8V */
++                                      t->minimum_voltage = 1800;
++                                      t->maximum_voltage = 1800;
++                                      t->configured_voltage = 1800;
++                              } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++#if IS_ENABLED(CONFIG_DIMM_DDR3)
++                                      /* Find the maximum and minimum 
supported voltages */
++                                      uint8_t supported_voltages = 
mem_info->dct_stat[node].DimmSupportedVoltages[slot];
++                                      if (supported_voltages & 0x8)
++                                              t->minimum_voltage = 1150;
++                                      else if (supported_voltages & 0x4)
++                                              t->minimum_voltage = 1250;
++                                      else if (supported_voltages & 0x2)
++                                              t->minimum_voltage = 1350;
++                                      else if (supported_voltages & 0x1)
++                                              t->minimum_voltage = 1500;
++
++                                      if (supported_voltages & 0x1)
++                                              t->maximum_voltage = 1500;
++                                      else if (supported_voltages & 0x2)
++                                              t->maximum_voltage = 1350;
++                                      else if (supported_voltages & 0x4)
++                                              t->maximum_voltage = 1250;
++                                      else if (supported_voltages & 0x8)
++                                              t->maximum_voltage = 1150;
++
++                                      t->configured_voltage = 
mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
++#endif
++                              }
+                               t->memory_error_information_handle = 0xFFFE;    
/* no error information handle available */
+                               single_len = t->length + 
smbios_string_table_len(t->eos);
+                               len += single_len;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index a8212c5..12dfff1 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -330,6 +330,11 @@ restartinit:
+                       goto fatalexit;
+               }
+ 
++#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
++              DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
++#endif
++
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
+               SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are 
ready for accesses.*/
+ 
+@@ -2122,6 +2127,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                       pDCTstat->DimmBanks[i] = 1ULL << 
(((mctRead_SPD(smbaddr, SPD_Density) & 0x70) >> 4) + 3);
+                                       pDCTstat->DimmWidth[i] = 1ULL << 
((mctRead_SPD(smbaddr, SPD_BusWidth) & 0x7) + 3);
+                               }
++                              /* Check supported voltage(s) */
++                              pDCTstat->DimmSupportedVoltages[i] = 
mctRead_SPD(smbaddr, SPD_Voltage) & 0x7;
++                              pDCTstat->DimmSupportedVoltages[i] ^= 0x1;      
/* Invert LSB to convert from SPD format to internal bitmap format */
+                               /* Check module type */
+                               byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE) & 0x7;
+                               if (byte == JED_RDIMM || byte == JED_MiniRDIMM) 
{
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index c790d7e..a947c2d 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -206,6 +206,7 @@
+       #define JED_MiniRDIMM   0x5     /* Mini-RDIMM */
+ #define SPD_Density   4               /* Bank address bits,SDRAM capacity */
+ #define SPD_Addressing        5               /* Row/Column address bits */
++#define SPD_Voltage   6               /* Supported voltage bitfield */
+ #define SPD_Organization      7               /* rank#,Device width */
+ #define SPD_BusWidth  8               /* ECC, Bus width */
+       #define JED_ECC         8       /* ECC capability */
+@@ -585,6 +586,10 @@ struct DCTStatStruc {             /* A per Node 
structure*/
+       struct _sDCTStruct s_C_DCTPtr[2];
+       /* struct _sDCTStruct s_C_DCT1Ptr[8]; */
+ 
++      /* DIMM supported voltage bitmap ([2:0]: 1.25V, 1.35V, 1.5V) */
++      uint8_t DimmSupportedVoltages[MAX_DIMMS_SUPPORTED];
++      uint32_t DimmConfiguredVoltage[MAX_DIMMS_SUPPORTED];    /* mV */
++
+       uint8_t DimmRows[MAX_DIMMS_SUPPORTED];
+       uint8_t DimmCols[MAX_DIMMS_SUPPORTED];
+       uint8_t DimmRanks[MAX_DIMMS_SUPPORTED];
+@@ -905,6 +910,7 @@ u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 
dct, u32 val);
+ void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct);
+ void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 node);
+ void mctSMBhub_Init(u32 node);
++void DIMMSetVoltages(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ int mctRead_SPD(u32 smaddr, u32 reg);
+ void InterleaveNodes_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0025-src-console-Add-x86-romstage-spinlock-option.patch
 
b/resources/libreboot/patch/kgpe-d16/0025-src-console-Add-x86-romstage-spinlock-option.patch
deleted file mode 100644
index 2f8ef7f..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0025-src-console-Add-x86-romstage-spinlock-option.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From 2eced49516682afa1c56ac1e83a8f4260d4dec2a Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 18 May 2015 16:04:10 -0500
-Subject: [PATCH 025/139] src/console: Add x86 romstage spinlock option
-
-Change-Id: Ice42a0d3177736bf6e1bc601092e413601866f20
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/arch/x86/include/arch/smp/spinlock.h | 10 +++++++++-
- src/console/printk.c                     | 19 +++++++++++++++++++
- 2 files changed, 28 insertions(+), 1 deletion(-)
-
-diff --git a/src/arch/x86/include/arch/smp/spinlock.h 
b/src/arch/x86/include/arch/smp/spinlock.h
-index 32be2f2..a5904c7 100644
---- a/src/arch/x86/include/arch/smp/spinlock.h
-+++ b/src/arch/x86/include/arch/smp/spinlock.h
-@@ -1,7 +1,7 @@
- #ifndef ARCH_SMP_SPINLOCK_H
- #define ARCH_SMP_SPINLOCK_H
- 
--#ifndef __PRE_RAM__
-+#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
- 
- /*
-  * Your basic SMP spinlocks, allowing only a single CPU anywhere
-@@ -11,9 +11,17 @@ typedef struct {
-       volatile unsigned int lock;
- } spinlock_t;
- 
-+#ifdef __PRE_RAM__
-+spinlock_t* romstage_console_lock(void);
-+#endif
- 
- #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
-+
-+#ifndef __PRE_RAM__
- #define DECLARE_SPIN_LOCK(x) static spinlock_t x = SPIN_LOCK_UNLOCKED;
-+#else
-+#define DECLARE_SPIN_LOCK(x)
-+#endif
- 
- /*
-  * Simple spin lock operations.  There are two variants, one clears IRQ's
-diff --git a/src/console/printk.c b/src/console/printk.c
-index aab7ff5..2aae980 100644
---- a/src/console/printk.c
-+++ b/src/console/printk.c
-@@ -2,6 +2,7 @@
-  *  blatantly copied from linux/kernel/printk.c
-  *
-  *  Copyright (C) 1991, 1992  Linus Torvalds
-+ *  Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  */
- 
-@@ -13,7 +14,13 @@
- #include <stddef.h>
- #include <trace.h>
- 
-+#if defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
-+#ifndef __PRE_RAM__
- DECLARE_SPIN_LOCK(console_lock)
-+#endif
-+#else
-+DECLARE_SPIN_LOCK(console_lock)
-+#endif
- 
- void do_putchar(unsigned char byte)
- {
-@@ -39,7 +46,13 @@ int do_printk(int msg_level, const char *fmt, ...)
- #endif
- 
-       DISABLE_TRACE;
-+#ifdef __PRE_RAM__
-+#ifdef CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-+      spin_lock(romstage_console_lock());
-+#endif
-+#else
-       spin_lock(&console_lock);
-+#endif
- 
-       va_start(args, fmt);
-       i = vtxprintf(wrap_putchar, fmt, args, NULL);
-@@ -47,7 +60,13 @@ int do_printk(int msg_level, const char *fmt, ...)
- 
-       console_tx_flush();
- 
-+#ifdef __PRE_RAM__
-+#ifdef CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-+      spin_unlock(romstage_console_lock());
-+#endif
-+#else
-       spin_unlock(&console_lock);
-+#endif
-       ENABLE_TRACE;
- 
-       return i;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0026-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
 
b/resources/libreboot/patch/kgpe-d16/0026-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
new file mode 100644
index 0000000..9d6ebc8
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0026-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch
@@ -0,0 +1,166 @@
+From 7b1479a41c0fd5741f03fff5ce6ed3676f41b4dc Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 10 May 2015 04:37:56 -0500
+Subject: [PATCH 026/143] mainboard/asus/kgpe-d16: Set DDR3 memory voltage
+ based on SPD data
+
+Change-Id: I21777283ce0fd3c607951204a63ff67dc656c8cc
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/Kconfig      |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.default |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout  |    5 ++
+ src/mainboard/asus/kgpe-d16/romstage.c   |   76 ++++++++++++++++++++++++++++--
+ 4 files changed, 78 insertions(+), 5 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+index f9556fc..9471692 100644
+--- a/src/mainboard/asus/kgpe-d16/Kconfig
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -6,6 +6,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+       select DIMM_DDR3
+       select DIMM_REGISTERED
+       # select QRANK_DIMM_SUPPORT
++      select DIMM_VOLTAGE_SET_SUPPORT
+       select NORTHBRIDGE_AMD_AMDFAM10
+       select SOUTHBRIDGE_AMD_SR5650
+       select SOUTHBRIDGE_AMD_SB700
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index e920297..39a4778 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -6,6 +6,7 @@ iommu = Disable
+ nmi = Disable
+ hypertransport_speed_limit = Auto
+ max_mem_clock = DDR3-1600
++minimum_memory_voltage = 1.5V
+ ECC_memory = Enable
+ ECC_redirection = Disable
+ ecc_scrub_rate = 1.28us
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index b9266dc..110e0bb 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -41,6 +41,7 @@ entries
+ 456          1       e       1        ECC_memory
+ 457          1       e       1        ECC_redirection
+ 458          4       e       11       hypertransport_speed_limit
++462          2       e       12       minimum_memory_voltage
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+@@ -129,6 +130,10 @@ enumerations
+ 11    13    400MHz
+ 11    14    300MHz
+ 11    15    200MHz
++12    0     1.5V
++12    1     1.35V
++12    2     1.25V
++12    3     1.15V
+ 
+ checksums
+ 
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index 3431bab..18e7c16 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -135,7 +135,7 @@ static void activate_spd_rom(const struct mem_controller 
*ctrl) {
+  */
+ static void set_ddr3_voltage(uint8_t node, uint8_t index) {
+       uint8_t byte;
+-      uint8_t value;
++      uint8_t value = 0;
+ 
+       if (index == 0)
+               value = 0x0;
+@@ -161,6 +161,74 @@ static void set_ddr3_voltage(uint8_t node, uint8_t index) 
{
+       byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0xd0);
+       byte &= 0x0f;
+       pci_write_config8(PCI_DEV(0, 0x14, 3), 0xd0, byte);
++
++      printk(BIOS_DEBUG, "Node %02d DIMM voltage set to index %02x\n", node, 
index);
++}
++
++void DIMMSetVoltages(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstatA) {
++      /* This mainboard allows the DIMM voltage to be set per-socket.
++       * Therefore, for each socket, iterate over all DIMMs to find the
++       * lowest supported voltage common to all DIMMs on that socket.
++       */
++      uint8_t nvram;
++      uint8_t dimm;
++      uint8_t node;
++      uint8_t socket;
++      uint8_t allowed_voltages = 0xf; /* The mainboard VRMs allow 1.15V, 
1.25V, 1.35V, and 1.5V */
++      uint32_t set_voltage = 0;
++
++      if (get_option(&nvram, "minimum_memory_voltage") == CB_SUCCESS) {
++              if (nvram == 2)
++                      allowed_voltages = 0x7; /* Allow 1.25V, 1.35V, and 1.5V 
*/
++              if (nvram == 1)
++                      allowed_voltages = 0x3; /* Allow 1.35V and 1.5V */
++              if (nvram == 0)
++                      allowed_voltages = 0x1; /* Allow 1.5V only */
++      }
++
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              socket = node / 2;
++              struct DCTStatStruc *pDCTstat;
++              pDCTstat = pDCTstatA + node;
++              if (pDCTstat->NodePresent) {
++                      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
++                              if (pDCTstat->DIMMValid & (1 << dimm)) {
++                                      allowed_voltages &= 
pDCTstat->DimmSupportedVoltages[dimm];
++                              }
++                      }
++              }
++
++              if (pDCTstat->NodePresent && (node & 0x1)) {
++                      /* Set voltages */
++                      if (allowed_voltages & 0x8) {
++                              set_voltage = 1150;
++                              set_ddr3_voltage(socket, 3);
++                      } else if (allowed_voltages & 0x4) {
++                              set_voltage = 1250;
++                              set_ddr3_voltage(socket, 2);
++                      } else if (allowed_voltages & 0x2) {
++                              set_voltage = 1350;
++                              set_ddr3_voltage(socket, 1);
++                      } else {
++                              set_voltage = 1500;
++                              set_ddr3_voltage(socket, 0);
++                      }
++
++                      /* Save final DIMM voltages for SMBIOS use */
++                      if (pDCTstat->NodePresent) {
++                              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; 
dimm++) {
++                                      pDCTstat->DimmConfiguredVoltage[dimm] = 
set_voltage;
++                              }
++                      }
++                      pDCTstat = pDCTstatA + (node - 1);
++                      if (pDCTstat->NodePresent) {
++                              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; 
dimm++) {
++                                      pDCTstat->DimmConfiguredVoltage[dimm] = 
set_voltage;
++                              }
++                      }
++              }
++      }
+ }
+ 
+ static void set_peripheral_control_lines(void) {
+@@ -355,10 +423,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               die("After soft_reset_x - shouldn't see this message!!!\n");
+       }
+ 
+-      /* Set DDR memory voltage
+-       * FIXME
+-       * This should be set based on the output of the DIMM SPDs
+-       * For now it is locked to 1.5V
++      /* Set default DDR memory voltage
++       * This will be overridden later during RAM initialization
+        */
+       set_lpc_sticky_ctl(1);  /* Retain LPC/IMC GPIO configuration during S3 
sleep */
+       if (!s3resume) {        /* Avoid supply voltage glitches while the 
DIMMs are retaining data */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0026-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
 
b/resources/libreboot/patch/kgpe-d16/0026-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
deleted file mode 100644
index 638d21b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0026-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From ff54c12aa8d07a74ff4e84a5b020f64eb554ac4c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 31 May 2015 18:46:40 -0500
-Subject: [PATCH 026/139] northbridge/amd/amdmct/mct_ddr3: Fix S3 suspend
- overrunning the stack size limit
-
-Change-Id: Id7441dacef2e46e283d1fc99d5e5fa3f20e0d097
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 16 +++++++++++++---
- 1 file changed, 13 insertions(+), 3 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index 78523e8..1dcbea0 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -543,10 +543,17 @@ int8_t save_mct_information_to_nvram(void)
- 
-       struct spi_flash *flash;
-       ssize_t s3nv_offset;
--      struct amd_s3_persistent_data persistent_data;
-+      struct amd_s3_persistent_data *persistent_data;
-+
-+      /* Allocate temporary data structures */
-+      persistent_data = malloc(sizeof(struct amd_s3_persistent_data));
-+      if (!persistent_data) {
-+              printk(BIOS_DEBUG, "Could not allocate S3 data structure in 
RAM\n");
-+              return -1;
-+      }
- 
-       /* Obtain MCT configuration data */
--      copy_mct_data_to_save_variable(&persistent_data);
-+      copy_mct_data_to_save_variable(persistent_data);
- 
-       /* Obtain CBFS file offset */
-       s3nv_offset = get_s3nv_file_offset();
-@@ -576,7 +583,10 @@ int8_t save_mct_information_to_nvram(void)
- 
-       /* Erase and write data structure */
-       flash->erase(flash, s3nv_offset, CONFIG_S3_DATA_SIZE);
--      flash->write(flash, s3nv_offset, sizeof(struct amd_s3_persistent_data), 
&persistent_data);
-+      flash->write(flash, s3nv_offset, sizeof(struct amd_s3_persistent_data), 
persistent_data);
-+
-+      /* Deallocate temporary data structures */
-+      free(persistent_data);
- 
-       /* Tear down SPI flash access */
-       flash->spi->rw = SPI_WRITE_FLAG;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0027-northbridge-amd-amdmct-mct_ddr3-Fix-failing-S3-resum.patch
 
b/resources/libreboot/patch/kgpe-d16/0027-northbridge-amd-amdmct-mct_ddr3-Fix-failing-S3-resum.patch
deleted file mode 100644
index 852fc39..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0027-northbridge-amd-amdmct-mct_ddr3-Fix-failing-S3-resum.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From ade973158610c177dcdaa98cef1b44ebd6ad9255 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 1 Jun 2015 02:40:24 -0500
-Subject: [PATCH 027/139] northbridge/amd/amdmct/mct_ddr3: Fix failing S3
- resume
-
-Change-Id: I852a8132ff2f39f9297447455ad03d728ce9c5f6
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 16 +++++++++++++---
- 1 file changed, 13 insertions(+), 3 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index 1dcbea0..c9bcac1 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -602,7 +602,9 @@ int8_t save_mct_information_to_nvram(void)
- int8_t restore_mct_information_from_nvram(void)
- {
-       ssize_t s3nv_offset;
--      struct amd_s3_persistent_data persistent_data;
-+      ssize_t s3nv_file_offset;
-+      void * s3nv_cbfs_file_ptr;
-+      struct amd_s3_persistent_data *persistent_data;
- 
-       /* Obtain CBFS file offset */
-       s3nv_offset = get_s3nv_file_offset();
-@@ -610,11 +612,19 @@ int8_t restore_mct_information_from_nvram(void)
-               return -1;
- 
-       /* Align flash pointer to nearest boundary */
-+      s3nv_file_offset = s3nv_offset;
-       s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
-       s3nv_offset += CONFIG_S3_DATA_SIZE;
-+      s3nv_file_offset = s3nv_offset - s3nv_file_offset;
- 
--      cbfs_read(CBFS_DEFAULT_MEDIA, &persistent_data, s3nv_offset, 
sizeof(struct amd_s3_persistent_data));
--      restore_mct_data_from_save_variable(&persistent_data);
-+      /* Map data structure in CBFS and restore settings */
-+      s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, 
CBFS_TYPE_RAW, NULL);
-+      if (!s3nv_cbfs_file_ptr) {
-+              printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", 
S3NV_FILE_NAME);
-+              return -1;
-+      }
-+      persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
-+      restore_mct_data_from_save_variable(persistent_data);
- 
-       return 0;
- }
-\ No newline at end of file
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0027-src-console-Add-x86-romstage-spinlock-option-and-pri.patch
 
b/resources/libreboot/patch/kgpe-d16/0027-src-console-Add-x86-romstage-spinlock-option-and-pri.patch
new file mode 100644
index 0000000..a2aa438
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0027-src-console-Add-x86-romstage-spinlock-option-and-pri.patch
@@ -0,0 +1,193 @@
+From 27f6bb783ba638e6aa2539a6c51ec96386dbf28f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 18 May 2015 16:04:10 -0500
+Subject: [PATCH 027/143] src/console: Add x86 romstage spinlock option and
+ prink spinlock support
+
+Change-Id: Ice42a0d3177736bf6e1bc601092e413601866f20
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/Kconfig                              |    4 ++++
+ src/arch/x86/include/arch/smp/spinlock.h |   11 ++++++++++-
+ src/console/printk.c                     |   19 +++++++++++++++++++
+ src/cpu/amd/car/disable_cache_as_ram.c   |   10 ++++++++++
+ src/cpu/amd/car/post_cache_as_ram.c      |   20 ++++++++++++++------
+ 5 files changed, 57 insertions(+), 7 deletions(-)
+
+diff --git a/src/Kconfig b/src/Kconfig
+index 368384d..5aa33d00 100644
+--- a/src/Kconfig
++++ b/src/Kconfig
+@@ -446,6 +446,10 @@ config HAVE_HARD_RESET
+         This variable specifies whether a given board has a hard_reset
+         function, no matter if it's provided by board code or chipset code.
+ 
++config HAVE_ROMSTAGE_CONSOLE_SPINLOCK
++      bool
++      default n
++
+ config HAVE_MONOTONIC_TIMER
+       def_bool n
+       help
+diff --git a/src/arch/x86/include/arch/smp/spinlock.h 
b/src/arch/x86/include/arch/smp/spinlock.h
+index 32be2f2..3283540 100644
+--- a/src/arch/x86/include/arch/smp/spinlock.h
++++ b/src/arch/x86/include/arch/smp/spinlock.h
+@@ -1,7 +1,7 @@
+ #ifndef ARCH_SMP_SPINLOCK_H
+ #define ARCH_SMP_SPINLOCK_H
+ 
+-#ifndef __PRE_RAM__
++#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
+ 
+ /*
+  * Your basic SMP spinlocks, allowing only a single CPU anywhere
+@@ -11,9 +11,18 @@ typedef struct {
+       volatile unsigned int lock;
+ } spinlock_t;
+ 
++#ifdef __PRE_RAM__
++spinlock_t *romstage_console_lock(void);
++void initialize_romstage_console_lock(void);
++#endif
+ 
+ #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
++
++#ifndef __PRE_RAM__
+ #define DECLARE_SPIN_LOCK(x) static spinlock_t x = SPIN_LOCK_UNLOCKED;
++#else
++#define DECLARE_SPIN_LOCK(x)
++#endif
+ 
+ /*
+  * Simple spin lock operations.  There are two variants, one clears IRQ's
+diff --git a/src/console/printk.c b/src/console/printk.c
+index aab7ff5..5a23db0 100644
+--- a/src/console/printk.c
++++ b/src/console/printk.c
+@@ -2,6 +2,7 @@
+  *  blatantly copied from linux/kernel/printk.c
+  *
+  *  Copyright (C) 1991, 1992  Linus Torvalds
++ *  Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  */
+ 
+@@ -13,7 +14,13 @@
+ #include <stddef.h>
+ #include <trace.h>
+ 
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
++#ifndef __PRE_RAM__
+ DECLARE_SPIN_LOCK(console_lock)
++#endif
++#else
++DECLARE_SPIN_LOCK(console_lock)
++#endif
+ 
+ void do_putchar(unsigned char byte)
+ {
+@@ -39,7 +46,13 @@ int do_printk(int msg_level, const char *fmt, ...)
+ #endif
+ 
+       DISABLE_TRACE;
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
++      spin_lock(romstage_console_lock());
++#endif
++#else
+       spin_lock(&console_lock);
++#endif
+ 
+       va_start(args, fmt);
+       i = vtxprintf(wrap_putchar, fmt, args, NULL);
+@@ -47,7 +60,13 @@ int do_printk(int msg_level, const char *fmt, ...)
+ 
+       console_tx_flush();
+ 
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
++      spin_unlock(romstage_console_lock());
++#endif
++#else
+       spin_unlock(&console_lock);
++#endif
+       ENABLE_TRACE;
+ 
+       return i;
+diff --git a/src/cpu/amd/car/disable_cache_as_ram.c 
b/src/cpu/amd/car/disable_cache_as_ram.c
+index 3b464b8..5eccf79 100644
+--- a/src/cpu/amd/car/disable_cache_as_ram.c
++++ b/src/cpu/amd/car/disable_cache_as_ram.c
+@@ -24,6 +24,16 @@
+ 
+ #include <cpu/x86/cache.h>
+ 
++static inline __attribute__((always_inline)) uint32_t 
amd_fam1x_cpu_family(void)
++{
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      return family;
++}
++
+ static inline __attribute__((always_inline)) void disable_cache_as_ram(void)
+ {
+       msr_t msr;
+diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
+index e265de1..257b41a 100644
+--- a/src/cpu/amd/car/post_cache_as_ram.c
++++ b/src/cpu/amd/car/post_cache_as_ram.c
+@@ -84,6 +84,10 @@ static void prepare_ramstage_region(void 
*resume_backup_memory)
+               memset_((void*)0, 0, CONFIG_RAMTOP - backup_top);
+       }
+ 
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
++      initialize_romstage_console_lock();
++#endif
++
+       print_car_debug("Done\n");
+ }
+ 
+@@ -92,18 +96,19 @@ static void prepare_ramstage_region(void 
*resume_backup_memory)
+ static void vErrata343(void)
+ {
+ #ifdef BU_CFG2_MSR
+-    msr_t msr;
+-    unsigned int uiMask = 0xFFFFFFF7;
++      msr_t msr;
++      unsigned int uiMask = 0xFFFFFFF7;
+ 
+-    msr = rdmsr(BU_CFG2_MSR);
+-    msr.hi &= uiMask; // set bit 35 to 0
+-    wrmsr(BU_CFG2_MSR, msr);
++      msr = rdmsr(BU_CFG2_MSR);
++      msr.hi &= uiMask;       // IcDisSpecTlbWr (bit 35) = 0
++      wrmsr(BU_CFG2_MSR, msr);
+ #endif
+ }
+ 
+ void post_cache_as_ram(void)
+ {
+       void *resume_backup_memory = NULL;
++      uint32_t family = amd_fam1x_cpu_family();
+ 
+       struct romstage_handoff *handoff;
+       handoff = romstage_handoff_find_or_add();
+@@ -120,7 +125,10 @@ void post_cache_as_ram(void)
+       prepare_romstage_ramstack(resume_backup_memory);
+ 
+       /* from here don't store more data in CAR */
+-      vErrata343();
++      if (family < 0x6f) {
++              /* Family 10h or earlier */
++              vErrata343();
++      }
+ 
+       size_t car_size = car_data_size();
+       void *migrated_car = (void *)(CONFIG_RAMTOP - car_size);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0028-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
 
b/resources/libreboot/patch/kgpe-d16/0028-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
new file mode 100644
index 0000000..6616f45
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0028-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch
@@ -0,0 +1,51 @@
+From 7023056e63402e693489a04925f854e4217f9b50 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 31 May 2015 18:46:40 -0500
+Subject: [PATCH 028/143] northbridge/amd/amdmct/mct_ddr3: Fix S3 suspend
+ overrunning the stack size limit
+
+Change-Id: Id7441dacef2e46e283d1fc99d5e5fa3f20e0d097
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c |   16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+index a49499f..c9bcac1 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -543,10 +543,17 @@ int8_t save_mct_information_to_nvram(void)
+ 
+       struct spi_flash *flash;
+       ssize_t s3nv_offset;
+-      struct amd_s3_persistent_data persistent_data;
++      struct amd_s3_persistent_data *persistent_data;
++
++      /* Allocate temporary data structures */
++      persistent_data = malloc(sizeof(struct amd_s3_persistent_data));
++      if (!persistent_data) {
++              printk(BIOS_DEBUG, "Could not allocate S3 data structure in 
RAM\n");
++              return -1;
++      }
+ 
+       /* Obtain MCT configuration data */
+-      copy_mct_data_to_save_variable(&persistent_data);
++      copy_mct_data_to_save_variable(persistent_data);
+ 
+       /* Obtain CBFS file offset */
+       s3nv_offset = get_s3nv_file_offset();
+@@ -576,7 +583,10 @@ int8_t save_mct_information_to_nvram(void)
+ 
+       /* Erase and write data structure */
+       flash->erase(flash, s3nv_offset, CONFIG_S3_DATA_SIZE);
+-      flash->write(flash, s3nv_offset, sizeof(struct amd_s3_persistent_data), 
&persistent_data);
++      flash->write(flash, s3nv_offset, sizeof(struct amd_s3_persistent_data), 
persistent_data);
++
++      /* Deallocate temporary data structures */
++      free(persistent_data);
+ 
+       /* Tear down SPI flash access */
+       flash->spi->rw = SPI_WRITE_FLAG;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0028-src-console-Add-x86-printk-spinlock-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0028-src-console-Add-x86-printk-spinlock-support.patch
deleted file mode 100644
index 2baeb9c..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0028-src-console-Add-x86-printk-spinlock-support.patch
+++ /dev/null
@@ -1,149 +0,0 @@
-From 5748ef1b46c9625a81b63c9141dfe2bf55dccc20 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 19:23:49 -0500
-Subject: [PATCH 028/139] src/console: Add x86 printk spinlock support
-
-Change-Id: Ib189ab842ede603b8d5080012ceb92e6964d4fe0
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/Kconfig                              |  4 ++++
- src/arch/x86/include/arch/smp/spinlock.h |  1 +
- src/console/printk.c                     |  6 +++---
- src/cpu/amd/car/disable_cache_as_ram.c   | 10 ++++++++++
- src/cpu/amd/car/post_cache_as_ram.c      | 20 ++++++++++++++------
- 5 files changed, 32 insertions(+), 9 deletions(-)
-
-diff --git a/src/Kconfig b/src/Kconfig
-index 2822bfe..4e46364 100644
---- a/src/Kconfig
-+++ b/src/Kconfig
-@@ -447,6 +447,10 @@ config HAVE_HARD_RESET
-         This variable specifies whether a given board has a hard_reset
-         function, no matter if it's provided by board code or chipset code.
- 
-+config HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-+      bool
-+      default n
-+
- config HAVE_MONOTONIC_TIMER
-       def_bool n
-       help
-diff --git a/src/arch/x86/include/arch/smp/spinlock.h 
b/src/arch/x86/include/arch/smp/spinlock.h
-index a5904c7..5000779 100644
---- a/src/arch/x86/include/arch/smp/spinlock.h
-+++ b/src/arch/x86/include/arch/smp/spinlock.h
-@@ -13,6 +13,7 @@ typedef struct {
- 
- #ifdef __PRE_RAM__
- spinlock_t* romstage_console_lock(void);
-+void initialize_romstage_console_lock(void);
- #endif
- 
- #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
-diff --git a/src/console/printk.c b/src/console/printk.c
-index 2aae980..5a23db0 100644
---- a/src/console/printk.c
-+++ b/src/console/printk.c
-@@ -14,7 +14,7 @@
- #include <stddef.h>
- #include <trace.h>
- 
--#if defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
- #ifndef __PRE_RAM__
- DECLARE_SPIN_LOCK(console_lock)
- #endif
-@@ -47,7 +47,7 @@ int do_printk(int msg_level, const char *fmt, ...)
- 
-       DISABLE_TRACE;
- #ifdef __PRE_RAM__
--#ifdef CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
-       spin_lock(romstage_console_lock());
- #endif
- #else
-@@ -61,7 +61,7 @@ int do_printk(int msg_level, const char *fmt, ...)
-       console_tx_flush();
- 
- #ifdef __PRE_RAM__
--#ifdef CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
-       spin_unlock(romstage_console_lock());
- #endif
- #else
-diff --git a/src/cpu/amd/car/disable_cache_as_ram.c 
b/src/cpu/amd/car/disable_cache_as_ram.c
-index 3b464b8..5eccf79 100644
---- a/src/cpu/amd/car/disable_cache_as_ram.c
-+++ b/src/cpu/amd/car/disable_cache_as_ram.c
-@@ -24,6 +24,16 @@
- 
- #include <cpu/x86/cache.h>
- 
-+static inline __attribute__((always_inline)) uint32_t 
amd_fam1x_cpu_family(void)
-+{
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      return family;
-+}
-+
- static inline __attribute__((always_inline)) void disable_cache_as_ram(void)
- {
-       msr_t msr;
-diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
-index e265de1..257b41a 100644
---- a/src/cpu/amd/car/post_cache_as_ram.c
-+++ b/src/cpu/amd/car/post_cache_as_ram.c
-@@ -84,6 +84,10 @@ static void prepare_ramstage_region(void 
*resume_backup_memory)
-               memset_((void*)0, 0, CONFIG_RAMTOP - backup_top);
-       }
- 
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
-+      initialize_romstage_console_lock();
-+#endif
-+
-       print_car_debug("Done\n");
- }
- 
-@@ -92,18 +96,19 @@ static void prepare_ramstage_region(void 
*resume_backup_memory)
- static void vErrata343(void)
- {
- #ifdef BU_CFG2_MSR
--    msr_t msr;
--    unsigned int uiMask = 0xFFFFFFF7;
-+      msr_t msr;
-+      unsigned int uiMask = 0xFFFFFFF7;
- 
--    msr = rdmsr(BU_CFG2_MSR);
--    msr.hi &= uiMask; // set bit 35 to 0
--    wrmsr(BU_CFG2_MSR, msr);
-+      msr = rdmsr(BU_CFG2_MSR);
-+      msr.hi &= uiMask;       // IcDisSpecTlbWr (bit 35) = 0
-+      wrmsr(BU_CFG2_MSR, msr);
- #endif
- }
- 
- void post_cache_as_ram(void)
- {
-       void *resume_backup_memory = NULL;
-+      uint32_t family = amd_fam1x_cpu_family();
- 
-       struct romstage_handoff *handoff;
-       handoff = romstage_handoff_find_or_add();
-@@ -120,7 +125,10 @@ void post_cache_as_ram(void)
-       prepare_romstage_ramstack(resume_backup_memory);
- 
-       /* from here don't store more data in CAR */
--      vErrata343();
-+      if (family < 0x6f) {
-+              /* Family 10h or earlier */
-+              vErrata343();
-+      }
- 
-       size_t car_size = car_data_size();
-       void *migrated_car = (void *)(CONFIG_RAMTOP - car_size);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0029-lib-stack-Add-stack-overrun-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0029-lib-stack-Add-stack-overrun-detection.patch
index b0fc1e3..7a05905 100644
--- 
a/resources/libreboot/patch/kgpe-d16/0029-lib-stack-Add-stack-overrun-detection.patch
+++ 
b/resources/libreboot/patch/kgpe-d16/0029-lib-stack-Add-stack-overrun-detection.patch
@@ -1,12 +1,12 @@
-From aa92a6ff110c9fd77f6b157fa509988d597ad2e0 Mon Sep 17 00:00:00 2001
+From 1d4b434ed93ad03bd97152310fc24f60342e6b9b Mon Sep 17 00:00:00 2001
 From: Timothy Pearson <address@hidden>
 Date: Sat, 5 Sep 2015 19:31:03 -0500
-Subject: [PATCH 029/139] lib/stack: Add stack overrun detection
+Subject: [PATCH 029/143] lib/stack: Add stack overrun detection
 
 Change-Id: I9a59fcb7cf221ae590a047c520e7aff99e23ecf1
 Signed-off-by: Timothy Pearson <address@hidden>
 ---
- src/lib/stack.c | 5 +++--
+ src/lib/stack.c |    5 +++--
  1 file changed, 3 insertions(+), 2 deletions(-)
 
 diff --git a/src/lib/stack.c b/src/lib/stack.c
@@ -34,5 +34,5 @@ index 52dd723..bebeea2 100644
                return -1;
        }
 -- 
-1.9.1
+1.7.9.5
 
diff --git 
a/resources/libreboot/patch/kgpe-d16/0030-cpu-x86-lapic-Add-stack-overrun-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0030-cpu-x86-lapic-Add-stack-overrun-detection.patch
index 5defeab..10221c9 100644
--- 
a/resources/libreboot/patch/kgpe-d16/0030-cpu-x86-lapic-Add-stack-overrun-detection.patch
+++ 
b/resources/libreboot/patch/kgpe-d16/0030-cpu-x86-lapic-Add-stack-overrun-detection.patch
@@ -1,12 +1,12 @@
-From e30acf3fb35f09d788f29f9603124bcbc24723fb Mon Sep 17 00:00:00 2001
+From 626b7adfbc9c50a5e078075635efddf5707ef9a2 Mon Sep 17 00:00:00 2001
 From: Timothy Pearson <address@hidden>
 Date: Sat, 5 Sep 2015 19:31:20 -0500
-Subject: [PATCH 030/139] cpu/x86/lapic: Add stack overrun detection
+Subject: [PATCH 030/143] cpu/x86/lapic: Add stack overrun detection
 
 Change-Id: I03e43f38e0d2e51141208ebb169ad8deba77ab78
 Signed-off-by: Timothy Pearson <address@hidden>
 ---
- src/cpu/x86/lapic/lapic_cpu_init.c | 2 ++
+ src/cpu/x86/lapic/lapic_cpu_init.c |    2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/src/cpu/x86/lapic/lapic_cpu_init.c 
b/src/cpu/x86/lapic/lapic_cpu_init.c
@@ -30,5 +30,5 @@ index 7fedd00..faa1f1f 100644
                checkstack((void *)stacks[i] + CONFIG_STACK_SIZE, i);
  }
 -- 
-1.9.1
+1.7.9.5
 
diff --git 
a/resources/libreboot/patch/kgpe-d16/0031-southbridge-amd-sr5650-Add-AMD-Family-15h-CPU-suppor.patch
 
b/resources/libreboot/patch/kgpe-d16/0031-southbridge-amd-sr5650-Add-AMD-Family-15h-CPU-suppor.patch
index d43fab6..d99746e 100644
--- 
a/resources/libreboot/patch/kgpe-d16/0031-southbridge-amd-sr5650-Add-AMD-Family-15h-CPU-suppor.patch
+++ 
b/resources/libreboot/patch/kgpe-d16/0031-southbridge-amd-sr5650-Add-AMD-Family-15h-CPU-suppor.patch
@@ -1,13 +1,13 @@
-From 7102e3001406f8eedbfbbeefafb2f27b62b47d03 Mon Sep 17 00:00:00 2001
+From 89f0d8276a64d05d7cf091ac41402bdf7f71f4ba Mon Sep 17 00:00:00 2001
 From: Timothy Pearson <address@hidden>
 Date: Sat, 5 Sep 2015 19:30:38 -0500
-Subject: [PATCH 031/139] southbridge/amd/sr5650: Add AMD Family 15h CPU
+Subject: [PATCH 031/143] southbridge/amd/sr5650: Add AMD Family 15h CPU
  support
 
 Change-Id: I88203907270db1a268bd377151f15c24fca1efdc
 Signed-off-by: Timothy Pearson <address@hidden>
 ---
- src/southbridge/amd/sr5650/early_setup.c | 2 ++
+ src/southbridge/amd/sr5650/early_setup.c |    2 ++
  1 file changed, 2 insertions(+)
 
 diff --git a/src/southbridge/amd/sr5650/early_setup.c 
b/src/southbridge/amd/sr5650/early_setup.c
@@ -24,5 +24,5 @@ index 664f60a..62b0dab 100644
                printk(BIOS_INFO, "CPU Rev is not recognized.\n");
  }
 -- 
-1.9.1
+1.7.9.5
 
diff --git 
a/resources/libreboot/patch/kgpe-d16/0032-cpu-amd-Move-model_10xxx-to-family_10h-family_15h.patch
 
b/resources/libreboot/patch/kgpe-d16/0032-cpu-amd-Move-model_10xxx-to-family_10h-family_15h.patch
index a255f78..c70b089 100644
--- 
a/resources/libreboot/patch/kgpe-d16/0032-cpu-amd-Move-model_10xxx-to-family_10h-family_15h.patch
+++ 
b/resources/libreboot/patch/kgpe-d16/0032-cpu-amd-Move-model_10xxx-to-family_10h-family_15h.patch
@@ -1,7 +1,7 @@
-From 54b88ab6e8f0b5a48bf8b0df168a6d12d44b09df Mon Sep 17 00:00:00 2001
+From a9c46688fdefebdf70848b4aba0021d747baee16 Mon Sep 17 00:00:00 2001
 From: Timothy Pearson <address@hidden>
 Date: Fri, 16 Oct 2015 14:24:06 -0500
-Subject: [PATCH 032/139] cpu/amd: Move model_10xxx to family_10h-family_15h
+Subject: [PATCH 032/143] cpu/amd: Move model_10xxx to family_10h-family_15h
 
 Change-Id: I34501d3fc68b71db7781dad11d5b883868932a60
 Signed-off-by: Timothy Pearson <address@hidden>
@@ -10,7 +10,7 @@ Signed-off-by: Timothy Pearson <address@hidden>
  src/cpu/amd/family_10h-family_15h/Kconfig          |   88 ++
  src/cpu/amd/family_10h-family_15h/Makefile.inc     |   14 +
  src/cpu/amd/family_10h-family_15h/defaults.h       |  479 +++++++++
- src/cpu/amd/family_10h-family_15h/fidvid.c         | 1049 ++++++++++++++++++++
+ src/cpu/amd/family_10h-family_15h/fidvid.c         | 1048 ++++++++++++++++++++
  src/cpu/amd/family_10h-family_15h/init_cpus.c      |  968 ++++++++++++++++++
  .../amd/family_10h-family_15h/model_10xxx_init.c   |  165 +++
  .../amd/family_10h-family_15h/monotonic_timer.c    |   98 ++
@@ -22,7 +22,7 @@ Signed-off-by: Timothy Pearson <address@hidden>
  src/cpu/amd/model_10xxx/Kconfig                    |   88 --
  src/cpu/amd/model_10xxx/Makefile.inc               |   14 -
  src/cpu/amd/model_10xxx/defaults.h                 |  479 ---------
- src/cpu/amd/model_10xxx/fidvid.c                   | 1049 --------------------
+ src/cpu/amd/model_10xxx/fidvid.c                   | 1048 --------------------
  src/cpu/amd/model_10xxx/init_cpus.c                |  968 ------------------
  src/cpu/amd/model_10xxx/model_10xxx_init.c         |  165 ---
  src/cpu/amd/model_10xxx/monotonic_timer.c          |   98 --
@@ -60,7 +60,7 @@ Signed-off-by: Timothy Pearson <address@hidden>
  src/mainboard/supermicro/h8scm_fam10/romstage.c    |    2 +-
  src/mainboard/tyan/s2912_fam10/romstage.c          |    2 +-
  src/northbridge/amd/amdfam10/northbridge.c         |    2 +-
- 54 files changed, 3675 insertions(+), 3675 deletions(-)
+ 54 files changed, 3674 insertions(+), 3674 deletions(-)
  create mode 100644 src/cpu/amd/family_10h-family_15h/Kconfig
  create mode 100644 src/cpu/amd/family_10h-family_15h/Makefile.inc
  create mode 100644 src/cpu/amd/family_10h-family_15h/defaults.h
@@ -700,15 +700,14 @@ index 0000000..6fd1a7e
 +};
 diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
 new file mode 100644
-index 0000000..99ffcc8
+index 0000000..5b1c581
 --- /dev/null
 +++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
-@@ -0,0 +1,1049 @@
+@@ -0,0 +1,1048 @@
 +/*
 + * This file is part of the coreboot project.
 + *
 + * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
@@ -4417,15 +4416,14 @@ index 6fd1a7e..0000000
 -};
 diff --git a/src/cpu/amd/model_10xxx/fidvid.c 
b/src/cpu/amd/model_10xxx/fidvid.c
 deleted file mode 100644
-index 99ffcc8..0000000
+index 5b1c581..0000000
 --- a/src/cpu/amd/model_10xxx/fidvid.c
 +++ /dev/null
-@@ -1,1049 +0,0 @@
+@@ -1,1048 +0,0 @@
 -/*
 - * This file is part of the coreboot project.
 - *
 - * Copyright (C) 2007 Advanced Micro Devices, Inc.
-- * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
 - *
 - * This program is free software; you can redistribute it and/or modify
 - * it under the terms of the GNU General Public License as published by
@@ -7881,7 +7879,7 @@ index 1049014..0030619 100644
  
  static void sio_setup(void)
 diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 3b302e8..adcfdf0 100644
+index ff324cd..fb3b2f7 100644
 --- a/src/northbridge/amd/amdfam10/northbridge.c
 +++ b/src/northbridge/amd/amdfam10/northbridge.c
 @@ -34,7 +34,7 @@
@@ -7894,5 +7892,5 @@ index 3b302e8..adcfdf0 100644
  #if CONFIG_LOGICAL_CPUS
  #include <cpu/amd/multicore.h>
 -- 
-1.9.1
+1.7.9.5
 
diff --git 
a/resources/libreboot/patch/kgpe-d16/0033-cpu-amd-Add-initial-AMD-Family-15h-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0033-cpu-amd-Add-initial-AMD-Family-15h-support.patch
deleted file mode 100644
index 75aa195..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0033-cpu-amd-Add-initial-AMD-Family-15h-support.patch
+++ /dev/null
@@ -1,16206 +0,0 @@
-From db769f9a54ca4b8a1872c031f29aae31f412e2a2 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 16 Oct 2015 13:51:51 -0500
-Subject: [PATCH 033/139] cpu/amd: Add initial AMD Family 15h support
-
-TEST: Booted ASUS KGPE-D16 with single Opteron 6380
- * Unbuffered DDR3 DIMMs tested and working
- * Suspend to RAM (S3) tested and working
-
-Conflicts:
-
-       src/cpu/amd/car/disable_cache_as_ram.c
-
-Change-Id: Idffd2ce36ce183fbfa087e5ba69a9148f084b45e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/car/cache_as_ram.inc                   |  130 +-
- src/cpu/amd/car/disable_cache_as_ram.c             |   77 +-
- src/cpu/amd/family_10h-family_15h/defaults.h       |  266 +-
- src/cpu/amd/family_10h-family_15h/fidvid.c         |  235 +-
- src/cpu/amd/family_10h-family_15h/init_cpus.c      |  232 +-
- .../amd/family_10h-family_15h/model_10xxx_init.c   |   92 +-
- src/cpu/amd/family_10h-family_15h/powernow_acpi.c  |   50 +-
- src/cpu/amd/family_10h-family_15h/processor_name.c |  194 +-
- .../amd/family_10h-family_15h/update_microcode.c   |    6 +
- src/cpu/amd/quadcore/quadcore.c                    |  109 +-
- src/cpu/amd/quadcore/quadcore_id.c                 |   43 +-
- src/include/cpu/amd/model_10xxx_msr.h              |    7 +
- src/mainboard/advansus/a785e-i/romstage.c          |    2 +-
- src/mainboard/amd/bimini_fam10/romstage.c          |    2 +-
- src/mainboard/amd/mahogany_fam10/romstage.c        |    2 +-
- .../amd/serengeti_cheetah_fam10/romstage.c         |    2 +-
- src/mainboard/amd/tilapia_fam10/romstage.c         |    2 +-
- src/mainboard/asus/kfsn4-dre/romstage.c            |    2 +-
- src/mainboard/asus/m4a78-em/romstage.c             |    2 +-
- src/mainboard/asus/m4a785-m/romstage.c             |    2 +-
- src/mainboard/asus/m5a88-v/romstage.c              |    2 +-
- src/mainboard/avalue/eax-785e/romstage.c           |    2 +-
- src/mainboard/gigabyte/ma785gm/romstage.c          |    2 +-
- src/mainboard/gigabyte/ma785gmt/romstage.c         |    2 +-
- src/mainboard/gigabyte/ma78gm/romstage.c           |    2 +-
- src/mainboard/hp/dl165_g6_fam10/romstage.c         |    2 +-
- src/mainboard/iei/kino-780am2-fam10/romstage.c     |    2 +-
- src/mainboard/jetway/pa78vm5/romstage.c            |    2 +-
- src/mainboard/msi/ms9652_fam10/romstage.c          |    2 +-
- src/mainboard/supermicro/h8dmr_fam10/romstage.c    |    2 +-
- src/mainboard/supermicro/h8qme_fam10/romstage.c    |    2 +-
- src/mainboard/supermicro/h8scm_fam10/romstage.c    |    2 +-
- src/mainboard/tyan/s2912_fam10/romstage.c          |    2 +-
- src/northbridge/amd/amdfam10/Kconfig               |    2 +-
- src/northbridge/amd/amdfam10/Makefile.inc          |    2 +
- src/northbridge/amd/amdfam10/amdfam10.h            |    6 +-
- src/northbridge/amd/amdfam10/amdfam10_util.c       |   13 +-
- src/northbridge/amd/amdfam10/link_control.c        |   86 +
- src/northbridge/amd/amdfam10/misc_control.c        |    7 +
- src/northbridge/amd/amdfam10/nb_control.c          |   85 +
- src/northbridge/amd/amdfam10/northbridge.c         |  233 +-
- src/northbridge/amd/amdfam10/raminit_amdmct.c      |  304 +-
- src/northbridge/amd/amdht/h3ncmn.c                 |  171 +-
- src/northbridge/amd/amdht/ht_wrapper.c             |   43 +-
- src/northbridge/amd/amdmct/amddefs.h               |   78 +-
- src/northbridge/amd/amdmct/mct/mct_d.c             |    4 +-
- src/northbridge/amd/amdmct/mct/mct_d.h             |   20 +-
- src/northbridge/amd/amdmct/mct/mctpro_d.c          |   21 +-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c        | 3187 ++++++++++++++++----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h        |  124 +-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h    |    9 +
- src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c     |   21 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c     |   27 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c     | 1087 ++++++-
- src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c     |   55 +-
- src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c       |    7 +-
- src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c       |  105 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c      |    2 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctrci.c       |   24 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c       |  585 +++-
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c       | 1342 ++++++++-
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c     |   10 +-
- src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c      |   20 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctwl.c        |  255 +-
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c      | 1007 +++++--
- src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c     |   69 +-
- src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h       |   46 +-
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c      |  652 +++-
- src/northbridge/amd/amdmct/wrappers/mcti.h         |   14 +-
- src/northbridge/amd/amdmct/wrappers/mcti_d.c       |   42 +-
- 70 files changed, 9184 insertions(+), 2064 deletions(-)
- create mode 100644 src/northbridge/amd/amdfam10/link_control.c
- create mode 100644 src/northbridge/amd/amdfam10/nb_control.c
-
-diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
-index 0b2bc60..6542906 100644
---- a/src/cpu/amd/car/cache_as_ram.inc
-+++ b/src/cpu/amd/car/cache_as_ram.inc
-@@ -32,18 +32,23 @@
- #define CacheSizeAPStack      CONFIG_DCACHE_AP_STACK_SIZE
- 
- #define MSR_MCFG_BASE         0xC0010058
--#define MSR_FAM10             0xC001102A
-+#define MSR_BU_CFG2           0xC001102A
- 
- #define jmp_if_k8(x)          comisd  %xmm2, %xmm1; jb x
-+#define jmp_if_not_fam15h(x)  comisd  %xmm3, %xmm1; jb x
-+#define jmp_if_fam15h(x)      comisd  %xmm3, %xmm1; jae x
- 
- #define CPUID_MASK            0x0ff00f00
- #define CPUID_VAL_FAM10_ROTATED       0x0f000010
-+#define CPUID_VAL_FAM15_ROTATED       0x0f000060
- 
- /*
-  * XMM map:
-  *   xmm1: CPU family
-  *   xmm2: Fam10h comparison value
-- *   xmm3: Backup EBX
-+ *   xmm3: Fam15h comparison value
-+ *   xmm4: Backup EBX
-+ *   xmm5: Coreboot init detect
-  */
- 
-       /* Save the BIST result. */
-@@ -63,7 +68,7 @@ cache_as_ram_setup:
-       movl    %eax, %cr4
- 
-       /* Figure out the CPU family. */
--      cvtsi2sd %ebx, %xmm3
-+      cvtsi2sd %ebx, %xmm4
-       movl    $0x01, %eax
-       cpuid
-       /* Base family is bits 8..11, extended family is bits 20..27. */
-@@ -73,13 +78,16 @@ cache_as_ram_setup:
-       cvtsi2sd %eax, %xmm1
-       movl    $CPUID_VAL_FAM10_ROTATED, %eax
-       cvtsi2sd %eax, %xmm2
--      cvtsd2si %xmm3, %ebx
-+      movl    $CPUID_VAL_FAM15_ROTATED, %eax
-+      cvtsi2sd %eax, %xmm3
-+      cvtsd2si %xmm4, %ebx
- 
-       /* Check if cpu_init_detected. */
-       movl    $MTRR_DEF_TYPE_MSR, %ecx
-       rdmsr
-       andl    $MTRR_DEF_TYPE_EN, %eax
-       movl    %eax, %ebx      /* We store the status. */
-+      cvtsi2sd %ebx, %xmm5
- 
-       jmp_if_k8(CAR_FAM10_out_post_errata)
- 
-@@ -120,21 +128,24 @@ cache_as_ram_setup:
- 
- CAR_FAM10_out:
- 
-+      jmp_if_fam15h(CAR_FAM10_errata_applied)
-       /*
-        * Errata 193: Disable clean copybacks to L3 cache to allow cached ROM.
-        * Re-enable it in after RAM is initialized and before CAR is disabled.
-        */
--      movl    $MSR_FAM10, %ecx
-+      movl    $MSR_BU_CFG2, %ecx
-       rdmsr
--      bts     $15, %eax
-+      bts     $15, %eax       /* Set bit 15 in EDX:EAX (bit 15 in EAX). */
-       wrmsr
- 
-       /* Erratum 343, RevGuide for Fam10h, Pub#41322 Rev. 3.33 */
--      movl    $MSR_FAM10, %ecx
-+      movl    $MSR_BU_CFG2, %ecx
-       rdmsr
-       bts     $35-32, %edx    /* Set bit 35 in EDX:EAX (bit 3 in EDX). */
-       wrmsr
- 
-+CAR_FAM10_errata_applied:
-+
- #if CONFIG_MMCONF_SUPPORT
-    #if (CONFIG_MMCONF_BASE_ADDRESS > 0xFFFFFFFF)
-    #error "MMCONF_BASE_ADDRESS too big"
-@@ -169,6 +180,63 @@ CAR_FAM10_out:
- 
- CAR_FAM10_out_post_errata:
- 
-+      /* Fam15h APIC IDs do not depend on NB config bit 54 */
-+      jmp_if_not_fam15h(skip_nb54_set)
-+      movl    $0xc001001f, %ecx       /* NB_CFG_MSR */
-+      rdmsr
-+      bts     $(54 - 32), %edx        /* Set NB config bit 54 */
-+      wrmsr
-+
-+skip_nb54_set:
-+      /* On Fam15h CPUs each compute unit's MTRRs are shared between two 
cores */
-+      jmp_if_not_fam15h(skip_cu_check)
-+
-+      /* Get the initial APIC ID. */
-+      movl    $1, %eax
-+      cpuid
-+      movl    %ebx, %eax
-+
-+      /* Restore init detect */
-+      cvtsd2si %xmm5, %ebx
-+
-+      /* Determine if this is the second core to start in a compute unit; if 
so, wait for first core start, clear init detect and skip MTRR init */
-+      bt      $24, %eax
-+      jnc     skip_cu_check           /* First core in the compute unit jumps 
to skip_cu_check */
-+
-+      /* Determine if this is the second core to start in a compute unit; if 
so, clear init detect and skip MTRR init */
-+      /* Busywait until the first core sets up the MTRRs */
-+check_init_detect_1:
-+      /* Check if cpu_init_detected. */
-+      movl    $MTRR_DEF_TYPE_MSR, %ecx
-+      rdmsr
-+      andl    $MTRR_DEF_TYPE_EN, %eax
-+      cmp     $0x00000000, %eax
-+      je      check_init_detect_1     /* First core has not yet started */
-+
-+check_init_detect_2:
-+      movl    $SYSCFG_MSR, %ecx
-+      rdmsr
-+      andl    $(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrVarDramEn), %eax
-+      cmp     $0x00000000, %eax
-+      je      check_init_detect_2     /* First core has not yet started */
-+
-+      /* First core has now started */
-+      movl    $0x00000000, %ebx       /* Clear init detect flag */
-+      cvtsi2sd %ebx, %xmm5
-+      jmp     fam10_mtrr_setup_complete
-+
-+skip_cu_check:
-+
-+      jmp_if_not_fam15h(CAR_FAM15_errata_applied)
-+
-+      /* Erratum 714, RevGuide for Fam15h, Pub#48063 Rev. 3.24 */
-+      movl    $MSR_BU_CFG2, %ecx
-+      rdmsr
-+      bts     $8, %eax        /* Set bit 8 in EDX:EAX (bit 8 in EAX). */
-+      wrmsr
-+
-+CAR_FAM15_errata_applied:
-+
-       /* Set MtrrFixDramModEn for clear fixed MTRR. */
- enable_fixed_mtrr_dram_modify:
-       movl    $SYSCFG_MSR, %ecx
-@@ -337,8 +405,42 @@ wbcache_post_fam10_setup:
-       orl     $(SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn), %eax
-       wrmsr
- 
-+fam10_mtrr_setup_complete:
-       post_code(0xa1)
- 
-+      /* Disable conversion of INVD to WBINVD (INVDWBINVD = 0) */
-+      mov     $0xc0010015, %ecx
-+      rdmsr
-+      btr     $4, %eax
-+      wrmsr
-+
-+jmp_if_not_fam15h(fam15_car_msr_setup_complete)
-+      /* Disable streaming store (DisSS = 1) */
-+      mov     $0xc0011020, %ecx
-+      rdmsr
-+      bts     $28, %eax
-+      wrmsr
-+
-+      /* Disable speculative ITLB reloads (DisSpecTlbRld = 1) */
-+      mov     $0xc0011021, %ecx
-+      rdmsr
-+      bts     $9, %eax
-+      wrmsr
-+
-+      /* Disable speculative DTLB reloads (DisSpecTlbRld = 1) and set DisHwPf 
= 1 */
-+      mov     $0xc0011022, %ecx
-+      rdmsr
-+      bts     $4, %eax
-+      bts     $13, %eax
-+      wrmsr
-+
-+      /* Disable CR0 combining (CombineCr0Cd = 0) */
-+      mov     $0xc001102b, %ecx
-+      rdmsr
-+      btr     $49-32, %edx
-+      wrmsr
-+fam15_car_msr_setup_complete:
-+
-       /* Enable cache. */
-       movl    %cr0, %eax
-       andl    $(~(CR0_CacheDisable | CR0_NoWriteThrough)), %eax
-@@ -393,9 +495,6 @@ CAR_FAM10_ap:
-        * to reverse it.
-        */
- 
--      /* Store our init detected. */
--      movl    %ebx, %esi
--
-       /* Get the coreid bits at first. */
-       movl    $0x80000008, %eax
-       cpuid
-@@ -414,6 +513,8 @@ CAR_FAM10_ap:
-       movl    %edi, %ecx              /* CoreID bits */
-       bt      $(54 - 32), %edx
-       jc      roll_cfg
-+
-+      /* Fam10h NB config bit 54 was not set */
-       rolb    %cl, %bl
- roll_cfg:
- 
-@@ -423,8 +524,8 @@ roll_cfg:
-       movl    $(CacheBase + (CacheSize - (CacheSizeBSPStack + 
CacheSizeBSPSlush))), %esp
-       subl    %eax, %esp
- 
--      /* Retrive init detected. */
--      movl    %esi, %ebx
-+      /* Restore init detect */
-+      cvtsd2si %xmm5, %ebx
- 
-       post_code(0xa4)
- 
-@@ -437,6 +538,8 @@ CAR_FAM10_ap_out:
-       andl    $~(3 << 9), %eax
-       movl    %eax, %cr4
- 
-+      post_code(0xa6)
-+
-       /* Restore the BIST result. */
-       movl    %ebp, %eax
- 
-@@ -444,6 +547,9 @@ CAR_FAM10_ap_out:
-       movl    %esp, %ebp
-       pushl   %ebx            /* Init detected. */
-       pushl   %eax            /* BIST */
-+
-+      post_code(0xa7)
-+
-       call    cache_as_ram_main
- 
-       /* We will not go back. */
-diff --git a/src/cpu/amd/car/disable_cache_as_ram.c 
b/src/cpu/amd/car/disable_cache_as_ram.c
-index 5eccf79..5cab544 100644
---- a/src/cpu/amd/car/disable_cache_as_ram.c
-+++ b/src/cpu/amd/car/disable_cache_as_ram.c
-@@ -19,7 +19,7 @@
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc.
-  *
-- * be warned, this file will be used other cores and core 0 / node 0
-+ * WARNING: this file will be used by both any AP cores and core 0 / node 0
-  */
- 
- #include <cpu/x86/cache.h>
-@@ -34,41 +34,78 @@ static inline __attribute__((always_inline)) uint32_t 
amd_fam1x_cpu_family(void)
-       return family;
- }
- 
--static inline __attribute__((always_inline)) void disable_cache_as_ram(void)
-+static inline __attribute__((always_inline)) void 
disable_cache_as_ram(uint8_t skip_sharedc_config)
- {
-       msr_t msr;
-+      uint32_t family;
- 
--      /* disable cache */
--      write_cr0(read_cr0() | CR0_CacheDisable);
-+      if (!skip_sharedc_config) {
-+              /* disable cache */
-+              write_cr0(read_cr0() | CR0_CacheDisable);
- 
--      msr.lo = 0;
--      msr.hi = 0;
--      wrmsr(MTRR_FIX_4K_C8000, msr);
-+              msr.lo = 0;
-+              msr.hi = 0;
-+              wrmsr(MTRR_FIX_4K_C8000, msr);
- #if CONFIG_DCACHE_RAM_SIZE > 0x8000
--      wrmsr(MTRR_FIX_4K_C0000, msr);
-+              wrmsr(MTRR_FIX_4K_C0000, msr);
- #endif
- #if CONFIG_DCACHE_RAM_SIZE > 0x10000
--      wrmsr(MTRR_FIX_4K_D0000, msr);
-+              wrmsr(MTRR_FIX_4K_D0000, msr);
- #endif
- #if CONFIG_DCACHE_RAM_SIZE > 0x18000
--      wrmsr(MTRR_FIX_4K_D8000, msr);
-+              wrmsr(MTRR_FIX_4K_D8000, msr);
- #endif
--      /* disable fixed mtrr from now on, it will be enabled by ramstage 
again*/
-+              /* disable fixed mtrr from now on, it will be enabled by 
ramstage again */
-+              msr = rdmsr(SYSCFG_MSR);
-+              msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | 
SYSCFG_MSR_MtrrFixDramModEn);
-+              wrmsr(SYSCFG_MSR, msr);
-+
-+              /* Set the default memory type and disable fixed and enable 
variable MTRRs */
-+              msr.hi = 0;
-+              msr.lo = (1 << 11);
-+
-+              wrmsr(MTRR_DEF_TYPE_MSR, msr);
-+
-+              enable_cache();
-+      }
-+
-+      /* INVDWBINVD = 1 */
-+      msr = rdmsr(0xc0010015);
-+      msr.lo |= (0x1 << 4);
-+      wrmsr(0xc0010015, msr);
-+
-+      family = amd_fam1x_cpu_family();
-+
-+      if (family >= 0x6f) {
-+              /* Family 15h or later */
- 
--      msr = rdmsr(SYSCFG_MSR);
--      msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrFixDramModEn);
--      wrmsr(SYSCFG_MSR, msr);
-+              /* DisSS = 0 */
-+              msr = rdmsr(0xc0011020);
-+              msr.lo &= ~(0x1 << 28);
-+              wrmsr(0xc0011020, msr);
- 
--      /* Set the default memory type and disable fixed and enable variable 
MTRRs */
--      msr.hi = 0;
--      msr.lo = (1 << 11);
-+              if (!skip_sharedc_config) {
-+                      /* DisSpecTlbRld = 0 */
-+                      msr = rdmsr(0xc0011021);
-+                      msr.lo &= ~(0x1 << 9);
-+                      wrmsr(0xc0011021, msr);
- 
--      wrmsr(MTRR_DEF_TYPE_MSR, msr);
-+                      /* Erratum 714: SpecNbReqDis = 0 */
-+                      msr = rdmsr(BU_CFG2_MSR);
-+                      msr.lo &= ~(0x1 << 8);
-+                      wrmsr(BU_CFG2_MSR, msr);
-+              }
- 
--      enable_cache();
-+              /* DisSpecTlbRld = 0 */
-+              /* DisHwPf = 0 */
-+              msr = rdmsr(0xc0011022);
-+              msr.lo &= ~(0x1 << 4);
-+              msr.lo &= ~(0x1 << 13);
-+              wrmsr(0xc0011022, msr);
-+      }
- }
- 
- static void disable_cache_as_ram_bsp(void)
- {
--      disable_cache_as_ram();
-+      disable_cache_as_ram(0);
- }
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index 6fd1a7e..24f87ba 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2008 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -25,41 +26,65 @@
-  */
- static const struct {
-       u32 msr;
--      u32 revision;
-+      uint64_t revision;
-       u32 platform;
-       u32 data_lo;
-       u32 data_hi;
-       u32 mask_lo;
-       u32 mask_hi;
- } fam10_msr_default[] = {
--      { TOP_MEM2, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { TOP_MEM2, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00000000, 0x00000000,
-         0xFFFFFFFF, 0xFFFFFFFF },
- 
--      { SYSCFG, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { SYSCFG, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         3 << 21, 0x00000000,
-         3 << 21, 0x00000000 },        /* [MtrrTom2En]=1,[TOM2EnWB] = 1*/
- 
--      { HWCR, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        1 << 4, 0x00000000,
--        1 << 4, 0x00000000 },         /* [INVD_WBINVD]=1 */
-+      { MC1_CTL_MASK, AMD_OR_B2, AMD_PTYPE_ALL,
-+        1 << 18, 0x00000000,
-+        1 << 18, 0x00000000 },        /* Erratum 586: [DEIBP]=1 */
- 
--      { MC4_CTL_MASK, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { MC1_CTL_MASK, AMD_OR_B2, AMD_PTYPE_ALL,
-+        1 << 15, 0x00000000,
-+        1 << 15, 0x00000000 },        /* Erratum 593: [BSRP]=1 */
-+
-+      { MC1_CTL_MASK, AMD_OR_C0, AMD_PTYPE_ALL,
-+        1 << 15, 0x00000000,
-+        1 << 15, 0x00000000 },        /* Erratum 739: [BSRP]=1 */
-+
-+      { 0xc0011000, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        1 << 16, 0x00000000,
-+        1 << 16, 0x00000000 },        /* Erratum 608: [bit 16]=1 */
-+
-+      { 0xc0011000, AMD_OR_C0, AMD_PTYPE_ALL,
-+        1 << 15, 0x00000000,
-+        1 << 15, 0x00000000 },        /* Erratum 727: [bit 15]=1 */
-+
-+      { MC4_CTL_MASK, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0xF << 19, 0x00000000,
-         0xF << 19, 0x00000000 },      /* [RtryHt[0..3]]=1 */
- 
-+      { MC4_CTL_MASK, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+        1 << 10, 0x00000000,
-+        1 << 10, 0x00000000 },        /* [GartTblWkEn]=1 */
-+
-       { DC_CFG, AMD_FAM10_ALL, AMD_PTYPE_SVR,
-         0x00000000, 0x00000004,
--        0x00000000, 0x0000000C },     /* [REQ_CTR] = 1 for Server */
-+        0x00000000, 0x0000000C },     /* Family 10h: [REQ_CTR] = 1 for Server 
*/
- 
-       { DC_CFG, AMD_DR_Bx, AMD_PTYPE_SVR,
-         0x00000000, 0x00000000,
-         0x00000000, 0x00000C00 },     /* Erratum 326 */
- 
--      { NB_CFG, AMD_FAM10_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC,
-+      { NB_CFG, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC | AMD_PTYPE_MC,
-         0x00000000, 1 << 22,
-         0x00000000, 1 << 22 },        /* [ApicInitIDLo]=1 */
- 
-+      { NB_CFG, AMD_FAM15_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC,
-+        1 << 23, 0x00000000,
-+        1 << 23, 0x00000000 },        /* Erratum 663: [bit 23]=1 */
-+
-       { BU_CFG2, AMD_DR_Bx, AMD_PTYPE_ALL,
-         1 << 29, 0x00000000,
-         1 << 29, 0x00000000 },        /* For Bx Smash1GPages=1 */
-@@ -72,6 +97,14 @@ static const struct {
-         0 << 1, 0x00000000,
-         1 << 1, 0x00000000 },         /* IDX_MATCH_ALL=0 */
- 
-+      { IC_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
-+        0x00000000, 1 << (39-32),
-+        0x00000000, 1 << (39-32)},    /* C0 or above [DisLoopPredictor]=1 */
-+
-+      { IC_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
-+        0xf << 1, 0x00000000,
-+        0xf << 1, 0x00000000},        /* C0 or above [DisIcWayFilter]=0xf */
-+
-       { BU_CFG, AMD_DR_LT_B3, AMD_PTYPE_ALL,
-         1 << 21, 0x00000000,
-         1 << 21, 0x00000000 },        /* Erratum #254 DR B1 BU_CFG[21]=1 */
-@@ -80,19 +113,51 @@ static const struct {
-         1 << 23, 0x00000000,
-         1 << 23, 0x00000000 },        /* Erratum #309 BU_CFG[23]=1 */
- 
-+      { BU_CFG, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0 << 10, 0x00000000,
-+        1 << 10, 0x00000000 },        /* [DcacheAgressivePriority]=0 */
-+
-       /* CPUID_EXT_FEATURES */
--      { CPUIDFEATURES, AMD_FAM10_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC,
-+      { CPUIDFEATURES, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC | 
AMD_PTYPE_MC,
-         1 << 28, 0x00000000,
-         1 << 28, 0x00000000 },        /* [HyperThreadFeatEn]=1 */
- 
--      { CPUIDFEATURES, AMD_FAM10_ALL, AMD_PTYPE_DC,
-+      { CPUIDFEATURES, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC,
-         0x00000000, 1 << (33-32),
-         0x00000000, 1 << (33-32) },   /* [ExtendedFeatEn]=1 */
- 
-+      { DE_CFG, AMD_OR_B2, AMD_PTYPE_ALL,
-+        1 << 10, 0x00000000,
-+        1 << 10, 0x00000000 },        /* Bx [ResyncPredSingleDispDis]=1 */
-+
-       { BU_CFG2, AMD_DRBH_Cx, AMD_PTYPE_ALL,
-         0x00000000, 1 << (35-32),
-         0x00000000, 1 << (35-32) },   /* Erratum 343 (set to 0 after CAR, in 
post_cache_as_ram()/model_10xxx_init() )  */
- 
-+      { BU_CFG3, AMD_OR_B2, AMD_PTYPE_ALL,
-+        0x00000000, 1 << (42-32),
-+        0x00000000, 1 << (42-32)},    /* Bx [PwcDisableWalkerSharing]=1 */
-+
-+      { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL,
-+        1 << 22, 0x00000000,
-+        1 << 22, 0x00000000},         /* C0 or above [PfcDoubleStride]=1 */
-+
-+      { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
-+        0x00000000, 1 << (54-32),
-+        0x00000000, 1 << (54-32)},    /* C0 or above [LateSbzResync]=1 */
-+
-+      { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL,
-+        1 << 23, 0x00000000,
-+        1 << 23, 0x00000000},         /* C0 or above [DisScbThreshold]=1 */
-+
-+      { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL,
-+        1 << 14, 0x00000000,
-+        1 << 14, 0x00000000},         /* C0 or above 
[ForceSmcCheckFlowStDis]=1 */
-+
-+      { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL,
-+        1 << 12, 0x00000000,
-+        1 << 12, 0x00000000},         /* C0 or above [ForceBusLockDis]=1 */
-+
-       { OSVW_ID_Length, AMD_DR_Bx | AMD_DR_Cx | AMD_DR_Dx, AMD_PTYPE_ALL,
-         0x00000004, 0x00000000,
-         0x00000004, 0x00000000},      /* B0 or Above, OSVW_ID_Length is 0004h 
*/
-@@ -105,9 +170,45 @@ static const struct {
-         0x00000000, 1 << (50-32),
-         0x00000000, 1 << (50-32)},    /* D0 or Above, RdMmExtCfgQwEn*/
- 
-+      { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x0 << (36-32),
-+        0x00000000, 0x3 << (36-32)},  /* [ThrottleNbInterface]=0 */
-+
-+      { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        1 << 10, 0x00000000,
-+        1 << 10, 0x00000000},         /* [VicResyncChkEn]=1 */
-+
-+      { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        1 << 11, 0x00000000,
-+        1 << 11, 0x00000000},         /* Erratum 503: [bit 11]=1 */
-+
-       { CPU_ID_EXT_FEATURES_MSR, AMD_DR_Dx, AMD_PTYPE_ALL,
-         0x00000000, 1 << (51 - 32),
-         0x00000000, 1 << (51 - 32)},  /* G34_PKG | C32_PKG | S1G4_PKG | 
ASB2_PKG */
-+
-+      { CPU_ID_EXT_FEATURES_MSR, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 1 << (56 - 32),
-+        0x00000000, 1 << (56 - 32)},  /* [PerfCtrExtNB]=1 */
-+
-+      { CPU_ID_EXT_FEATURES_MSR, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 1 << (55 - 32),
-+        0x00000000, 1 << (55 - 32)},  /* [PerfCtrExtCore]=1 */
-+
-+      { IBS_OP_DATA3, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0 << 16, 0x00000000,
-+        1 << 16, 0x00000000},         /* [IbsDcMabHit]=0 */
-+
-+      { MC4_MISC0, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x1 << (52-32),
-+        0x00000000, 0xf << (52-32)},  /* [LvtOffset]=1 */
-+
-+      { MC4_MISC1, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x1 << (52-32),
-+        0x00000000, 0xf << (52-32)},  /* [LvtOffset]=1 */
-+
-+      { MC4_MISC2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x1 << (52-32),
-+        0x00000000, 0xf << (52-32)},  /* [LvtOffset]=1 */
- };
- 
- 
-@@ -117,37 +218,46 @@ static const struct {
- static const struct {
-       u8  function;
-       u16 offset;
--      u32 revision;
-+      uint64_t revision;
-       u32 platform;
-       u32 data;
-       u32 mask;
- } fam10_pci_default[] = {
- 
-       /* Function 0 - HT Config */
-+      { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+        0x000e0000, 0x000e0000 },             /* [19:17] for 8bit APIC config 
*/
-+
-+      { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+        0x00400000, 0x00600000 },             /* [22:21] DsNpReqLmt = 10b */
- 
--      { 0, 0x68, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        0x004E4800, 0x006E6800 },     /* [19:17] for 8bit APIC config,
--        [14:13] BufPriRel = 2h [11] RspPassPW set,
--        [22:21] DsNpReqLmt = 10b */
-+      { 0, 0x68, AMD_FAM10_LT_D, AMD_PTYPE_ALL,
-+        0x00004000, 0x00006000 },             /* [14:13] BufRelPri = 2h */
-+
-+      { 0, 0x68, (AMD_FAM10_REV_D | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+        0x00002000, 0x00006000 },             /* [14:13] BufRelPri = 1h */
-+
-+      { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+        0x00000800, 0x00000800 },             /* [11] RspPassPW = 1 */
- 
-       /* Errata 281 Workaround */
-       { 0, 0x68, (AMD_DR_B0 | AMD_DR_B1),
-         AMD_PTYPE_SVR, 0x00200000, 0x00600000 },      /* [22:21] DsNpReqLmt0 
= 01b */
- 
--      { 0, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 0, 0x84, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
--      { 0, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 0, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
--      { 0, 0xC4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 0, 0xC4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
--      { 0, 0xE4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 0, 0xE4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
-       /* Link Global Retry Control Register */
--      { 0, 0x150, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 0, 0x150, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00073900, 0x00073F00 },
- 
-       /*  Errata 351
-@@ -172,13 +282,39 @@ static const struct {
-         0x00000000, 0x00000100 },
-       { 0, 0x18C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00000000, 0x00000100 },
--      { 0, 0x170, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        0x00000000, 0x00000100 },
- 
-       /* Link Global Extended Control Register */
-       { 0, 0x16C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00000014, 0x0000003F },     /* [15:13] ForceFullT0 = 0b,
--                                                               * Set T0Time 
14h per BKDG */
-+                                       * Set T0Time 14h per BKDG */
-+
-+      { 0, 0x170, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+      { 0, 0x174, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+      { 0, 0x178, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+      { 0, 0x17C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+      { 0, 0x180, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+      { 0, 0x184, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+      { 0, 0x188, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+      { 0, 0x18C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000100, 0x00000100 },
-+
-+      /* Link Global Extended Control Register */
-+      { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000014, 0x0000003F },     /* [15:13] ForceFullT0 = 111b,
-+                                       * Set T0Time 26h per BKDG */
-+
-+      { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x7 << 13, 0x7 << 13 },       /* [15:13] ForceFullT0 = 7h */
-+
-+      { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x26, 0x3f }, /* [5:0] T0Time = 26h */
- 
- 
-       /* Function 1 - Map Init */
-@@ -205,10 +341,10 @@ static const struct {
-       /* Function 2 - DRAM Controller */
- 
-       /* Function 3 - Misc. Control */
--      { 3, 0x40, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0x40, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00000100, 0x00000100 },     /* [8] MstrAbrtEn */
- 
--      { 3, 0x44, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0x44, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x4A30005C, 0x4A30005C },     /* [30] SyncOnDramAdrParErrEn = 1,
-                                          [27] NbMcaToMstCpuEn = 1,
-                                          [25] DisPciCfgCpuErrRsp = 1,
-@@ -220,8 +356,12 @@ static const struct {
-                                          [2] SyncOnUcEccEn = 1 */
- 
-       /* XBAR buffer settings */
--      { 3, 0x6C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        0x00018052, 0x700780F7 },
-+      { 3, 0x6c, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+        0x00018052, 0x700780f7 },
-+
-+      /* XBAR buffer settings */
-+      { 3, 0x6c, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x10010052, 0x700700f7 },
- 
-       /* Errata 281 Workaround */
-       { 3, 0x6C, ( AMD_DR_B0 | AMD_DR_B1),
-@@ -233,12 +373,18 @@ static const struct {
-       { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00041153, 0x777777F7 },
- 
-+      { 3, 0x70, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x10171155, 0x777777f7 },
-+
-       { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x61221151, 0x777777F7 },
- 
-       { 3, 0x74, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x00080101, 0x000F7777 },
- 
-+      { 3, 0x74, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00172111, 0x77ff7777 },
-+
-       { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00090914, 0x707FFF1F },
- 
-@@ -246,12 +392,18 @@ static const struct {
-       { 3, 0x7C, ( AMD_DR_B0 | AMD_DR_B1),
-        AMD_PTYPE_SVR, 0x00144514, 0x707FFF1F },
- 
-+      { 3, 0x7C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x040d0f16, 0x07ffff1f },
-+
-       { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x00070814, 0x007FFF1F },
- 
-       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00800756, 0x00F3FFFF },
- 
-+      { 3, 0x140, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00a11755, 0x00f3ffff },
-+
-       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x00C37756, 0x00F3FFFF },
- 
-@@ -263,6 +415,9 @@ static const struct {
-        AMD_PTYPE_SVR, 0x00000001, 0x0000000F },
-               /* [3:0] RspTok = 0001b */
- 
-+      { 3, 0x144, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000028, 0x000000ff },
-+
-       { 3, 0x148, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x8000052A, 0xD5FFFFFF },
- 
-@@ -270,41 +425,53 @@ static const struct {
-       { 3, 0x80, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0xE6002200, 0xFFFFFFFF },
- 
-+      /* ACPI Power State Control Reg1 */
-+      { 3, 0x80, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0xe20be200, 0xefefef00 },
-+
-       /* ACPI Power State Control Reg2 */
-       { 3, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0xA0E641E6, 0xFFFFFFFF },
- 
-+      /* ACPI Power State Control Reg2 */
-+      { 3, 0x84, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x01e200e2, 0xefef00ef },
-+
-       { 3, 0xA0, AMD_FAM10_ALL, AMD_PTYPE_MOB | AMD_PTYPE_DSK,
-         0x00000080, 0x00000080 },     /* [7] PSIVidEnable */
- 
-       { 3, 0xA0, AMD_DR_Bx, AMD_PTYPE_ALL,
-         0x00002800, 0x000003800 },    /* [13:11] PllLockTime = 5 */
- 
--      { 3, 0xA0, (AMD_FAM10_ALL & ~(AMD_DR_Bx)), AMD_PTYPE_ALL,
-+      { 3, 0xA0, ((AMD_FAM10_ALL | AMD_FAM15_ALL) & ~(AMD_DR_Bx)), 
AMD_PTYPE_ALL,
-         0x00000800, 0x000003800 },    /* [13:11] PllLockTime = 1 */
- 
-       /* Reported Temp Control Register */
--      { 3, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00000080, 0x00000080 },     /* [7] TempSlewDnEn = 1 */
- 
-       /* Clock Power/Timing Control 0 Register */
--      { 3, 0xD4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0xD4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0xC0000F00, 0xF0000F00 },     /*  [31] NbClkDivApplyAll = 1,
-               [30:28] NbClkDiv = 100b,[11:8] ClkRampHystSel = 1111b */
- 
-       /* Clock Power/Timing Control 1 Register */
-+      { 3, 0xD8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+        0x03000010, 0x0F000070 },     /* [6:4] VSRampTime = 1,
-+                                       * [27:24] ReConDel = 3 */
-+
-+      /* Clock Power/Timing Control 1 Register */
-       { 3, 0xD8, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        0x03000016, 0x0F000077 },     /* [6:4] VSRampTime = 1,
--              [2:0] VSSlamTime = 6, [27:24] ReConDel = 3 */
-+        0x00000006, 0x00000007 },     /* [2:0] VSSlamTime = 6 */
- 
- 
-       /* Clock Power/Timing Control 2 Register */
--      { 3, 0xDC, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0xDC, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00005000, 0x00007000 },     /* [14:12] NbsynPtrAdj = 5 */
- 
- 
-       /* Extended NB MCA Config Register */
--      { 3, 0x180, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0x180, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x007003E2, 0x007003E2 },     /* [22:20] = SyncFloodOn_Err = 7,
-                                          [9] SyncOnUncNbAryEn = 1 ,
-                                          [8] SyncOnProtEn = 1,
-@@ -319,12 +486,17 @@ static const struct {
-         0x00400000, 0x00400000 },
- 
-       /* L3 Control Register */
--      { 3, 0x1B8, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0x1b8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00001000, 0x00001000 },     /* [12] = L3PrivReplEn */
- 
-       /* IBS Control Register */
--      { 3, 0x1CC, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-+      { 3, 0x1cc, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00000100, 0x00000100 },     /* [8] = LvtOffsetVal */
-+
-+      /* Erratum 619 - Family 15h Bx
-+       * System software should set F5x88[14] to 1b. */
-+      { 5, 0x88, AMD_OR_B2, AMD_PTYPE_ALL,
-+        1 << 14, 1 << 14 },
- };
- 
- 
-@@ -333,7 +505,7 @@ static const struct {
-  */
- static const struct {
-       u16 htreg;      /* HT Phy Register index */
--      u32 revision;
-+      uint64_t revision;
-       u32 platform;
-       u32 linktype;
-       u32 data;
-@@ -442,38 +614,38 @@ static const struct {
-       { 0x530A, AMD_DR_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
-         0x00004400, 0x00006400 },     /* HT_PHY_DLL_REG */
- 
--      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-         0x00000000, 0x000000FF },     /* Provide clear setting for logical
-                                          completeness */
- 
--      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-         0x00000000, 0x000000FF },     /* Provide clear setting for logical
-                                          completeness */
- 
--      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-+      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
-         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
- 
--      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
-+      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,  
HTPHY_LINKTYPE_HT1,
-         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
- 
-       /* Link Phy Receiver Loop Filter Registers */
--      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
-                                          [21:14] LfcMin = 10h */
- 
--      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
-                                          [21:14] LfcMin = 10h */
- 
--      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-+      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
-         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
-                                          [21:14] LfcMin = 08h */
- 
--      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-+      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
-         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
-                                          [21:14] LfcMin = 08h */
- 
--      { 0xC0, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
-+      { 0xC0, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_ALL,
-         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
-                                                                  [20:16] 
RttIndex = 04h */
- };
-diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
-index 99ffcc8..2e26645 100644
---- a/src/cpu/amd/family_10h-family_15h/fidvid.c
-+++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
-@@ -44,7 +44,7 @@ Fam10 Bios and Kernel Development Guide #31116, rev 3.48, 
April 22, 2010
- 
- 3.-  2.4.2.7 dualPlaneOnly(dev)
- 
--4.-  2.4.2.8 applyBoostFIDOffset(dev)
-+4.-  2.4.2.8 applyBoostFIDOffset(dev, nodeid)
- 
- 5.-  enableNbPState1(dev)
- 
-@@ -143,25 +143,33 @@ static void enable_fid_change(u8 fid)
-       }
- }
- 
--static void applyBoostFIDOffset(  device_t dev ) {
--  // BKDG 2.4.2.8
--  // revision E only, but E is apparently not supported yet, therefore 
untested
--  if ((cpuid_edx(0x80000007) & CPB_MASK)
--      &&  ((cpuid_ecx(0x80000008) & NC_MASK) ==5) ) {
--      u32 core =  get_node_core_id_x().coreid;
--      u32 asymetricBoostThisCore = ((pci_read_config32(dev, 0x10C) >> 
(core*2))) & 3;
--      msr_t msr =  rdmsr(PS_REG_BASE);
--      u32 cpuFid = msr.lo & PS_CPU_FID_MASK;
--      cpuFid = cpuFid + asymetricBoostThisCore;
--      msr.lo &=   ~PS_CPU_FID_MASK;
--      msr.lo |= cpuFid ;
--      wrmsr(PS_REG_BASE , msr);
--
--  }
-+static void applyBoostFIDOffset(device_t dev, uint32_t nodeid) {
-+      // BKDG 2.4.2.8
-+      // Fam10h revision E only, but E is apparently not supported yet, 
therefore untested
-+      if ((cpuid_edx(0x80000007) & CPB_MASK)
-+              &&  ((cpuid_ecx(0x80000008) & NC_MASK) == 5) ) {
-+              u32 core =  get_node_core_id_x().coreid;
-+              u32 asymetricBoostThisCore = ((pci_read_config32(dev, 0x10C) >> 
(core*2))) & 3;
-+              msr_t msr =  rdmsr(PS_REG_BASE);
-+              u32 cpuFid = msr.lo & PS_CPU_FID_MASK;
-+              cpuFid = cpuFid + asymetricBoostThisCore;
-+              msr.lo &=   ~PS_CPU_FID_MASK;
-+              msr.lo |= cpuFid ;
-+              wrmsr(PS_REG_BASE , msr);
-+      } else if (is_fam15h()) {
-+              uint32_t dword = pci_read_config32(NODE_PCI(nodeid, 4), 0x15c);
-+              uint8_t boost_count = (dword >> 2) & 0x7;
-+              if (boost_count > 0) {
-+                      /* Enable boost */
-+                      dword &= ~0x3;
-+                      dword |= 0x1;
-+                      pci_write_config32(NODE_PCI(nodeid, 4), 0x15c, dword);
-+              }
-+      }
- }
- 
- static void enableNbPState1( device_t dev ) {
--  u32 cpuRev =  mctGetLogicalCPUID(0xFF);
-+  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
-   if (cpuRev & AMD_FAM10_C3) {
-     u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
-     if ( nbPState){
-@@ -203,7 +211,7 @@ static u8 setPStateMaxVal( device_t dev ) {
- static void dualPlaneOnly(  device_t dev ) {
-   // BKDG 2.4.2.7
- 
--  u32 cpuRev =  mctGetLogicalCPUID(0xFF);
-+  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
-   if ((mctGetProcessorPackageType() ==  AMD_PKGTYPE_AM3_2r2)
-       && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no 
constant for E
-     if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
-@@ -283,12 +291,16 @@ static void 
recalculateVsSlamTimeSettingOnCorePre(device_t dev)
-        */
- 
-       /* Determine if this is a PVI or SVI system */
--      dtemp = pci_read_config32(dev, 0xA0);
--
--      if (dtemp & PVI_MODE)
--              pviModeFlag = 1;
--      else
-+      if (is_fam15h()) {
-               pviModeFlag = 0;
-+      } else {
-+              dtemp = pci_read_config32(dev, 0xa0);
-+
-+              if (dtemp & PVI_MODE)
-+                      pviModeFlag = 1;
-+              else
-+                      pviModeFlag = 0;
-+      }
- 
-       /* Get P0's voltage */
-         /* MSRC001_00[68:64] are not programmed yet when called from
-@@ -515,59 +527,67 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 
cpuRev) {
- }
- 
- static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 
procPkg) {
--                /* step 1, chapter 2.4.2.6 of AMD Fam 10 BKDG #31116 Rev 3.48 
22.4.2010 */
--        u32 dword;
--      u32 c1= 1;
--        if (cpuRev & (AMD_DR_Bx)) {
--            // will coreboot ever enable cache scrubbing ?
--            // if it does, will it be enough to check the current state
--            // or should we configure for what we'll set up later ?
--            dword = pci_read_config32(dev, 0x58);
--            u32 scrubbingCache = dword &
--                              ( (0x1F << 16) // DCacheScrub
--                                | (0x1F << 8) ); // L2Scrub
--          if (scrubbingCache) {
--              c1 = 0x80;
--          } else {
--              c1 = 0xA0;
--          }
--      } else { // rev C or later
--          // same doubt as cache scrubbing: ok to check current state ?
--            dword = pci_read_config32(dev, 0xDC);
--            u32 cacheFlushOnHalt = dword & (7 << 16);
--            if (!cacheFlushOnHalt) {
--                     c1 = 0x80;
--                  }
--              }
--              dword = (c1 << 24) | (0xE641E6);
--      pci_write_config32(dev, 0x84, dword);
--
--
--        /* FIXME: BKDG Table 100 says if the link is at a Gen1
--frequency and the chipset does not support a 10us minimum LDTSTOP
--assertion time, then { If ASB2 && SVI then smaf001 = F6h else
--smaf001=87h. } else ...  I hardly know what it means or how to check
--it from here, so I bluntly assume it is false and code here the else,
--which is easier  */
--
--        u32 smaf001 = 0xE6;
--        if (cpuRev & AMD_DR_Bx ) {
--          smaf001 = 0xA6;
--        } else {
--            #if CONFIG_SVI_HIGH_FREQ
--                if (cpuRev & (AMD_RB_C3 | AMD_DA_C3)) {
--                     smaf001 = 0xF6;
--                }
--            #endif
--        }
--        u32 fidvidChange = 0;
--        if (((cpuRev & AMD_DA_Cx) && (procPkg & AMD_PKGTYPE_S1gX))
--                  || (cpuRev & AMD_RB_C3) ) {
--                       fidvidChange=0x0B;
--        }
--      dword = (0xE6 << 24) | (fidvidChange << 16)
--                        | (smaf001 << 8) | 0x81;
--      pci_write_config32(dev, 0x80, dword);
-+      if (is_fam15h()) {
-+              /* Family 15h BKDG Rev. 3.14 D18F3x80 recommended settings */
-+              pci_write_config32(dev, 0x80, 0xe20be281);
-+
-+              /* Family 15h BKDG Rev. 3.14 D18F3x84 recommended settings */
-+              pci_write_config32(dev, 0x84, 0x01e200e2);
-+      } else {
-+              /* step 1, chapter 2.4.2.6 of AMD Fam 10 BKDG #31116 Rev 3.48 
22.4.2010 */
-+              u32 dword;
-+              u32 c1= 1;
-+              if (cpuRev & (AMD_DR_Bx)) {
-+                      // will coreboot ever enable cache scrubbing ?
-+                      // if it does, will it be enough to check the current 
state
-+                      // or should we configure for what we'll set up later ?
-+                      dword = pci_read_config32(dev, 0x58);
-+                      u32 scrubbingCache = dword &
-+                                              ( (0x1F << 16) // DCacheScrub
-+                                              | (0x1F << 8) ); // L2Scrub
-+                      if (scrubbingCache) {
-+                              c1 = 0x80;
-+                      } else {
-+                              c1 = 0xA0;
-+                      }
-+              } else { // rev C or later
-+                      // same doubt as cache scrubbing: ok to check current 
state ?
-+                      dword = pci_read_config32(dev, 0xDC);
-+                      u32 cacheFlushOnHalt = dword & (7 << 16);
-+                      if (!cacheFlushOnHalt) {
-+                              c1 = 0x80;
-+                      }
-+              }
-+              dword = (c1 << 24) | (0xE641E6);
-+              pci_write_config32(dev, 0x84, dword);
-+
-+              /* FIXME: BKDG Table 100 says if the link is at a Gen1
-+              * frequency and the chipset does not support a 10us minimum 
LDTSTOP
-+              * assertion time, then { If ASB2 && SVI then smaf001 = F6h else
-+              * smaf001=87h. } else ...  I hardly know what it means or how 
to check
-+              * it from here, so I bluntly assume it is false and code here 
the else,
-+              * which is easier
-+              */
-+
-+              u32 smaf001 = 0xE6;
-+              if (cpuRev & AMD_DR_Bx ) {
-+                      smaf001 = 0xA6;
-+              } else {
-+              #if CONFIG_SVI_HIGH_FREQ
-+                      if (cpuRev & (AMD_RB_C3 | AMD_DA_C3)) {
-+                              smaf001 = 0xF6;
-+                      }
-+              #endif
-+              }
-+              u32 fidvidChange = 0;
-+              if (((cpuRev & AMD_DA_Cx) && (procPkg & AMD_PKGTYPE_S1gX))
-+                      || (cpuRev & AMD_RB_C3) ) {
-+                              fidvidChange=0x0B;
-+              }
-+              dword = (0xE6 << 24) | (fidvidChange << 16)
-+                              | (smaf001 << 8) | 0x81;
-+              pci_write_config32(dev, 0x80, dword);
-+      }
- }
- 
- static void prep_fid_change(void)
-@@ -584,7 +604,7 @@ static void prep_fid_change(void)
-       for (i = 0; i < nodes; i++) {
-               printk(BIOS_DEBUG, "Prep FID/VID Node:%02x\n", i);
-               dev = NODE_PCI(i, 3);
--                u32 cpuRev = mctGetLogicalCPUID(0xFF) ;
-+                uint64_t cpuRev = mctGetLogicalCPUID(0xFF) ;
-               u8 procPkg =  mctGetProcessorPackageType();
- 
-               setVSRamp(dev);
-@@ -612,7 +632,7 @@ static void prep_fid_change(void)
-       }
- }
- 
--static void waitCurrentPstate(u32 target_pstate){
-+static void waitCurrentPstate(u32 target_pstate) {
-   msr_t initial_msr = rdmsr(TSC_MSR);
-   msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
-   msr_t tsc_msr;
-@@ -645,7 +665,7 @@ static void waitCurrentPstate(u32 target_pstate){
- 
-   if (pstate_msr.lo != target_pstate) {
-     msr_t limit_msr = rdmsr(0xc0010061);
--    printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state 
%01x P-state current limit MSRC001_0061=%02x\n", target_pstate, pstate_msr.lo, 
limit_msr.lo);
-+    printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state 
%01x P-state current limit MSRC001_0061=%08x %08x\n", target_pstate, 
pstate_msr.lo, limit_msr.hi, limit_msr.lo);
- 
-     do { // should we just go on instead ?
-       pstate_msr = rdmsr(CUR_PSTATE_MSR);
-@@ -655,6 +675,7 @@ static void waitCurrentPstate(u32 target_pstate){
- 
- static void set_pstate(u32 nonBoostedPState) {
-       msr_t msr;
-+      uint8_t skip_wait;
- 
-       // Transition P0 for calling core.
-       msr = rdmsr(0xC0010062);
-@@ -662,12 +683,21 @@ static void set_pstate(u32 nonBoostedPState) {
-       msr.lo = nonBoostedPState;
-       wrmsr(0xC0010062, msr);
- 
--      /* Wait for P0 to set. */
--        waitCurrentPstate(nonBoostedPState);
--}
--
--
-+      if (is_fam15h()) {
-+              /* Do not wait for the first (even) set of cores to transition 
on Family 15h systems */
-+              if ((cpuid_ebx(0x00000001) & 0x01000000))
-+                      skip_wait = 0;
-+              else
-+                      skip_wait = 1;
-+      } else {
-+              skip_wait = 0;
-+      }
- 
-+      if (!skip_wait) {
-+              /* Wait for core to transition to P0 */
-+              waitCurrentPstate(nonBoostedPState);
-+      }
-+}
- 
- static void UpdateSinglePlaneNbVid(void)
- {
-@@ -757,11 +787,14 @@ static u32 needs_NB_COF_VID_update(void)
-       u8 nodes;
-       u8 i;
- 
-+      if (is_fam15h())
-+              return 0;
-+
-       /* If any node has nb_cof_vid_update set all nodes need an update. */
-       nodes = get_nodes();
-       nb_cof_vid_update = 0;
-       for (i = 0; i < nodes; i++) {
--                u32 cpuRev = mctGetLogicalCPUID(i) ;
-+                uint64_t cpuRev = mctGetLogicalCPUID(i);
-                 u32 nbCofVidUpdateDefined = (cpuRev & (AMD_FAM10_LT_D));
-               if (nbCofVidUpdateDefined
-                     && (pci_read_config32(NODE_PCI(i, 3), 0x1FC)
-@@ -785,9 +818,11 @@ static u32 init_fidvid_core(u32 nodeid, u32 coreid)
-       /* Steps 1-6 of BIOS NB COF and VID Configuration
-        * for SVI and Single-Plane PVI Systems. BKDG 2.4.2.9 #31116 rev 3.48
-        */
--
-       dev = NODE_PCI(nodeid, 3);
--      pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE;
-+      if (is_fam15h())
-+              pvimode = 0;
-+      else
-+              pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE;
-       reg1fc = pci_read_config32(dev, 0x1FC);
- 
-       if (nb_cof_vid_update) {
-@@ -799,7 +834,7 @@ static u32 init_fidvid_core(u32 nodeid, u32 coreid)
-                       fid_max = fid_max +  ((reg1fc &  
DUAL_PLANE_NB_FID_OFF_MASK ) >>  DUAL_PLANE_NB_FID_SHIFT );
-               }
-               /* write newNbVid to P-state Reg's NbVid always if 
NbVidUpdatedAll=1 */
--              fixPsNbVidBeforeWR(vid_max, coreid,dev,pvimode);
-+              fixPsNbVidBeforeWR(vid_max, coreid, dev, pvimode);
- 
-               /* fid setup is handled by the BSP at the end. */
- 
-@@ -819,7 +854,7 @@ static void init_fidvid_ap(u32 apicid, u32 nodeid, u32 
coreid)
- 
-       printk(BIOS_DEBUG, "FIDVID on AP: %02x\n", apicid);
- 
--        send = init_fidvid_core(nodeid,coreid);
-+        send = init_fidvid_core(nodeid, coreid);
-       send |= (apicid << 24); // ap apicid
- 
-       // Send signal to BSP about this AP max fid
-@@ -861,7 +896,7 @@ static void init_fidvid_bsp_stage1(u32 ap_apicid, void *gp)
-       while (--loop > 0) {
-               if (lapic_remote_read(ap_apicid, LAPIC_MSG_REG, &readback) != 0)
-                       continue;
--              if ((readback & 0x3f) == 1) {
-+              if (((readback & 0x3f) == 1) || ((readback & 0x3f) == 
F10_APSTATE_ASLEEP)) {
-                       timeout = 0;
-                       break;  /* target ap is in stage 1 */
-               }
-@@ -949,7 +984,10 @@ static void init_fidvid_stage2(u32 apicid, u32 nodeid)
-       /* If any node has nb_cof_vid_update set all nodes need an update. */
- 
-       dev = NODE_PCI(nodeid, 3);
--      pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1;
-+      if (is_fam15h())
-+              pvimode = 0;
-+      else
-+              pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1;
-       reg1fc = pci_read_config32(dev, 0x1FC);
-       nbvid = (reg1fc >> 7) & 0x7F;
-       NbVidUpdateAll = (reg1fc >> 1) & 1;
-@@ -970,15 +1008,17 @@ static void init_fidvid_stage2(u32 apicid, u32 nodeid)
-       pci_write_config32(dev, 0xA0, dtemp);
- 
-         dualPlaneOnly(dev);
--        applyBoostFIDOffset(dev);
-+        applyBoostFIDOffset(dev, nodeid);
-         enableNbPState1(dev);
- 
-       finalPstateChange();
- 
--      /* Set TSC to tick at the P0 ndfid rate */
--      msr = rdmsr(HWCR);
--      msr.lo |= 1 << 24;
--      wrmsr(HWCR, msr);
-+      if (!is_fam15h()) {
-+              /* Set TSC to tick at the P0 ndfid rate */
-+              msr = rdmsr(HWCR);
-+              msr.lo |= 1 << 24;
-+              wrmsr(HWCR, msr);
-+      }
- }
- 
- 
-@@ -1012,8 +1052,7 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes)
-       /* Steps 1-6 of BIOS NB COF and VID Configuration
-        * for SVI and Single-Plane PVI Systems.
-        */
--
--      fv.common_fid = init_fidvid_core(0,0);
-+      fv.common_fid = init_fidvid_core(0, 0);
- 
-       print_debug_fv("BSP fid = ", fv.common_fid);
- 
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 8de6d25..aced850 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -30,9 +30,12 @@
- #include <northbridge/amd/amdfam10/raminit_amdmct.c>
- #include <reset.h>
- 
-+#if IS_ENABLED(CONFIG_SET_FIDVID)
- static void prep_fid_change(void);
- static void init_fidvid_stage2(u32 apicid, u32 nodeid);
--void cpuSetAMDMSR(void);
-+#endif
-+
-+void cpuSetAMDMSR(uint8_t node_id);
- 
- #if CONFIG_PCI_IO_CFG_EXT
- static void set_EnableCf8ExtCfg(void)
-@@ -51,43 +54,38 @@ static void set_EnableCf8ExtCfg(void) { }
- 
- typedef void (*process_ap_t) (u32 apicid, void *gp);
- 
--//core_range = 0 : all cores
--//core range = 1 : core 0 only
--//core range = 2 : cores other than core0
-+uint32_t get_boot_apic_id(uint8_t node, uint32_t core) {
-+      uint32_t ap_apicid;
- 
--static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t 
process_ap,
--                      void *gp)
--{
--      // here assume the OS don't change our apicid
--      u32 ap_apicid;
-+      uint32_t nb_cfg_54;
-+      uint32_t siblings;
-+      uint32_t cores_found;
- 
--      u32 nodes;
--      u32 siblings;
--      u32 disable_siblings;
--      u32 cores_found;
--      u32 nb_cfg_54;
--      int i, j;
--      u32 ApicIdCoreIdSize;
-+      uint8_t fam15h = 0;
-       uint8_t rev_gte_d = 0;
-       uint8_t dual_node = 0;
-       uint32_t f3xe8;
-+      uint32_t family;
-+      uint32_t model;
- 
--      /* get_nodes define in ht_wrapper.c */
--      nodes = get_nodes();
--
--      if (!CONFIG_LOGICAL_CPUS ||
--          read_option(multi_core, 0) != 0) {  // 0 means multi core
--              disable_siblings = 1;
--      } else {
--              disable_siblings = 0;
--      }
-+      uint32_t ApicIdCoreIdSize;
- 
-       /* Assume that all node are same stepping, otherwise we can use use
-          nb_cfg_54 from bsp for all nodes */
-       nb_cfg_54 = read_nb_cfg_54();
-       f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
- 
--      if (cpuid_eax(0x80000001) >= 0x8)
-+      family = model = cpuid_eax(0x80000001);
-+      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f) {
-+              /* Family 15h or later */
-+              fam15h = 1;
-+              nb_cfg_54 = 1;
-+      }
-+
-+      if ((model >= 0x8) || fam15h)
-               /* Revision D or later */
-               rev_gte_d = 1;
- 
-@@ -103,10 +101,63 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
-               siblings = 3;   //quad core
-       }
- 
-+      cores_found = get_core_num_in_bsp(node);
-+      if (siblings > cores_found)
-+              siblings = cores_found;
-+
-+      if (dual_node) {
-+              ap_apicid = 0;
-+              if (fam15h) {
-+                      ap_apicid |= ((node >> 1) & 0x3) << 5;                  
/* Node ID */
-+                      ap_apicid |= ((node & 0x1) * (siblings + 1)) + core;    
/* Core ID */
-+              } else {
-+                      if (nb_cfg_54) {
-+                              ap_apicid |= ((node >> 1) & 0x3) << 4;          
        /* Node ID */
-+                              ap_apicid |= ((node & 0x1) * (siblings + 1)) + 
core;    /* Core ID */
-+                      } else {
-+                              ap_apicid |= node & 0x3;                        
                /* Node ID */
-+                              ap_apicid |= (((node & 0x1) * (siblings + 1)) + 
core) << 4;     /* Core ID */
-+                      }
-+              }
-+      } else {
-+              if (fam15h) {
-+                      ap_apicid = (node * (siblings + 1)) + core;
-+              } else {
-+                      ap_apicid = node * (nb_cfg_54 ? (siblings + 1) : 1) +
-+                                      core * (nb_cfg_54 ? 1 : 64);
-+              }
-+      }
-+
-+      return ap_apicid;
-+}
-+
-+//core_range = 0 : all cores
-+//core range = 1 : core 0 only
-+//core range = 2 : cores other than core0
-+
-+static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t 
process_ap,
-+                      void *gp)
-+{
-+      // here assume the OS don't change our apicid
-+      u32 ap_apicid;
-+
-+      u32 nodes;
-+      u32 disable_siblings;
-+      u32 cores_found;
-+      int i, j;
-+
-+      /* get_nodes define in ht_wrapper.c */
-+      nodes = get_nodes();
-+
-+      if (!CONFIG_LOGICAL_CPUS ||
-+          read_option(multi_core, 0) != 0) {  // 0 means multi core
-+              disable_siblings = 1;
-+      } else {
-+              disable_siblings = 0;
-+      }
-+
-       for (i = 0; i < nodes; i++) {
-               cores_found = get_core_num_in_bsp(i);
--              if (siblings > cores_found)
--                      siblings = cores_found;
- 
-               u32 jstart, jend;
- 
-@@ -123,21 +174,7 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
-               }
- 
-               for (j = jstart; j <= jend; j++) {
--                      if (dual_node) {
--                              ap_apicid = 0;
--                              if (nb_cfg_54) {
--                                      ap_apicid |= ((i >> 1) & 0x3) << 4;     
                /* Node ID */
--                                      ap_apicid |= ((i & 0x1) * (siblings + 
1)) + j;          /* Core ID */
--                              } else {
--                                      ap_apicid |= i & 0x3;                   
                /* Node ID */
--                                      ap_apicid |= (((i & 0x1) * (siblings + 
1)) + j) << 4;   /* Core ID */
--                              }
--                      } else {
--                              ap_apicid =
--                              i * (nb_cfg_54 ? (siblings + 1) : 1) +
--                              j * (nb_cfg_54 ? 1 : 64);
--                      }
--
-+                      ap_apicid = get_boot_apic_id(i, j);
- 
- #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET > 0)
- #if !CONFIG_LIFT_BSP_APIC_ID
-@@ -197,7 +234,7 @@ void print_apicid_nodeid_coreid(u32 apicid, struct 
node_core_id id,
-              apicid, id.nodeid, id.coreid);
- }
- 
--static u32 wait_cpu_state(u32 apicid, u32 state)
-+uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2)
- {
-       u32 readback = 0;
-       u32 timeout = 1;
-@@ -205,7 +242,7 @@ static u32 wait_cpu_state(u32 apicid, u32 state)
-       while (--loop > 0) {
-               if (lapic_remote_read(apicid, LAPIC_MSG_REG, &readback) != 0)
-                       continue;
--              if ((readback & 0x3f) == state || (readback & 0x3f) == 
F10_APSTATE_RESET) {
-+              if ((readback & 0x3f) == state || (readback & 0x3f) == state2 
|| (readback & 0x3f) == F10_APSTATE_RESET) {
-                       timeout = 0;
-                       break;  //target cpu is in stage started
-               }
-@@ -222,7 +259,7 @@ static u32 wait_cpu_state(u32 apicid, u32 state)
- static void wait_ap_started(u32 ap_apicid, void *gp)
- {
-       u32 timeout;
--      timeout = wait_cpu_state(ap_apicid, F10_APSTATE_STARTED);
-+      timeout = wait_cpu_state(ap_apicid, F10_APSTATE_STARTED, 
F10_APSTATE_ASLEEP);
-       printk(BIOS_DEBUG, "* AP %02x", ap_apicid);
-       if (timeout) {
-               printk(BIOS_DEBUG, " timed out:%08x\n", timeout);
-@@ -258,16 +295,27 @@ static void enable_apic_ext_id(u32 node)
-       pci_write_config32(NODE_HT(node), 0x68, val);
- }
- 
--static void STOP_CAR_AND_CPU(void)
-+static void STOP_CAR_AND_CPU(uint8_t skip_sharedc_config, uint32_t apicid)
- {
-       msr_t msr;
-+      uint32_t family;
-+
-+      family = amd_fam1x_cpu_family();                // inline
-+
-+      if (family < 0x6f) {
-+              /* Family 10h or earlier */
-+
-+              /* Disable L2 IC to L3 connection (Only for CAR) */
-+              msr = rdmsr(BU_CFG2);
-+              msr.lo &= ~(1 << ClLinesToNbDis);
-+              wrmsr(BU_CFG2, msr);
-+      }
- 
--      /* Disable L2 IC to L3 connection (Only for CAR) */
--      msr = rdmsr(BU_CFG2);
--      msr.lo &= ~(1 << ClLinesToNbDis);
--      wrmsr(BU_CFG2, msr);
-+      disable_cache_as_ram(skip_sharedc_config);      // inline
-+
-+      /* Mark the core as sleeping */
-+      lapic_write(LAPIC_MSG_REG, (apicid << 24) | F10_APSTATE_ASLEEP);
- 
--      disable_cache_as_ram(); // inline
-       /* stop all cores except node0/core0 the bsp .... */
-       stop_this_cpu();
- }
-@@ -276,6 +324,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
- {
-       u32 bsp_apicid = 0;
-       u32 apicid;
-+      uint8_t set_mtrrs;
-       struct node_core_id id;
- 
-       /* Please refer to the calculations and explaination in 
cache_as_ram.inc before modifying these values */
-@@ -362,7 +411,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
-                */
-               update_microcode(cpuid_eax(1));
- 
--              cpuSetAMDMSR();
-+              cpuSetAMDMSR(id.nodeid);
- 
- #if CONFIG_SET_FIDVID
- #if CONFIG_LOGICAL_CPUS && CONFIG_SET_FIDVID_CORE0_ONLY
-@@ -385,10 +434,29 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
-               }
- #endif
- 
-+              if (is_fam15h()) {
-+                      /* core 1 on node 0 is special; to avoid corrupting the
-+                       * BSP do not alter MTRRs on that core */
-+                      if (apicid == 1)
-+                              set_mtrrs = 0;
-+                      else
-+                              set_mtrrs = !!(apicid & 0x1);
-+              } else {
-+                      set_mtrrs = 1;
-+              }
-+
-               /* AP is ready, configure MTRRs and go to sleep */
--              set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
-+              if (set_mtrrs)
-+                      set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, 
MTRR_TYPE_WRBACK);
- 
--              STOP_CAR_AND_CPU();
-+              printk(BIOS_DEBUG, "Disabling CAR on AP %02x\n", apicid);
-+              if (is_fam15h()) {
-+                      /* Only modify the MSRs on the odd cores (the last 
cores to finish booting) */
-+                      STOP_CAR_AND_CPU(!set_mtrrs, apicid);
-+              } else {
-+                      /* Modify MSRs on all cores */
-+                      STOP_CAR_AND_CPU(0, apicid);
-+              }
- 
-               printk(BIOS_DEBUG,
-                      "\nAP %02x should be halted but you are reading 
this....\n",
-@@ -496,7 +564,7 @@ static void setup_remote_node(u8 node)
- }
- #endif                                /* CONFIG_MAX_PHYSICAL_CPUS > 1 */
- 
--static void AMD_Errata281(u8 node, u32 revision, u32 platform)
-+static void AMD_Errata281(u8 node, uint64_t revision, u32 platform)
- {
-       /* Workaround for Transaction Scheduling Conflict in
-        * Northbridge Cross Bar.  Implement XCS Token adjustment
-@@ -794,7 +862,7 @@ static void AMD_SetHtPhyRegister(u8 node, u8 link, u8 
entry)
-       } while (!(val & HTPHY_IS_COMPLETE_MASK));
- }
- 
--void cpuSetAMDMSR(void)
-+void cpuSetAMDMSR(uint8_t node_id)
- {
-       /* This routine loads the CPU with default settings in fam10_msr_default
-        * table . It must be run after Cache-As-RAM has been enabled, and
-@@ -804,7 +872,8 @@ void cpuSetAMDMSR(void)
-        */
-       msr_t msr;
-       u8 i;
--      u32 revision, platform;
-+      u32 platform;
-+      uint64_t revision;
- 
-       printk(BIOS_DEBUG, "cpuSetAMDMSR ");
- 
-@@ -824,6 +893,49 @@ void cpuSetAMDMSR(void)
-       }
-       AMD_Errata298();
- 
-+      if (revision & AMD_FAM15_ALL) {
-+              uint32_t f5x80;
-+              uint8_t enabled;
-+              uint8_t compute_unit_count = 0;
-+              f5x80 = pci_read_config32(NODE_PCI(node_id, 5), 0x80);
-+              enabled = f5x80 & 0xf;
-+              if (enabled == 0x1)
-+                      compute_unit_count = 1;
-+              if (enabled == 0x3)
-+                      compute_unit_count = 2;
-+              if (enabled == 0x7)
-+                      compute_unit_count = 3;
-+              if (enabled == 0xf)
-+                      compute_unit_count = 4;
-+              msr = rdmsr(BU_CFG2);
-+              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
-+              msr.lo |= (((compute_unit_count - 1) & 0x3) << 6);
-+              wrmsr(BU_CFG2, msr);
-+      }
-+
-+      /* Revision C0 and above */
-+      if (revision & AMD_OR_C0) {
-+              uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 
0x1fc);
-+              msr = rdmsr(FP_CFG);
-+              msr.hi &= ~(0x7 << (42-32));                    /* DiDtCfg4 */
-+              msr.hi |= (((f3x1fc >> 17) & 0x7) << (42-32));
-+              msr.hi &= ~(0x1 << (41-32));                    /* DiDtCfg5 */
-+              msr.hi |= (((f3x1fc >> 22) & 0x1) << (41-32));
-+              msr.hi &= ~(0x1 << (40-32));                    /* DiDtCfg3 */
-+              msr.hi |= (((f3x1fc >> 16) & 0x1) << (40-32));
-+              msr.hi &= ~(0x7 << (32-32));                    /* DiDtCfg1 (1) 
*/
-+              msr.hi |= (((f3x1fc >> 11) & 0x7) << (32-32));
-+              msr.lo &= ~(0x1f << 27);                        /* DiDtCfg1 (2) 
*/
-+              msr.lo |= (((f3x1fc >> 6) & 0x1f) << 27);
-+              msr.lo &= ~(0x3 << 25);                         /* DiDtCfg2 */
-+              msr.lo |= (((f3x1fc >> 14) & 0x3) << 25);
-+              msr.lo &= ~(0x1f << 18);                        /* DiDtCfg0 */
-+              msr.lo |= (((f3x1fc >> 1) & 0x1f) << 18);
-+              msr.lo &= ~(0x1 << 16);                         /* DiDtMode */
-+              msr.lo |= ((f3x1fc & 0x1) << 16);
-+              wrmsr(FP_CFG, msr);
-+      }
-+
-       printk(BIOS_DEBUG, " done\n");
- }
- 
-@@ -835,9 +947,10 @@ static void cpuSetAMDPCI(u8 node)
-        * that it is run for the first core on each node
-        */
-       u8 i, j;
--      u32 revision, platform;
-+      u32 platform;
-       u32 val;
-       u8 offset;
-+      uint64_t revision;
- 
-       printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node);
- 
-@@ -899,6 +1012,7 @@ static void cpuSetAMDPCI(u8 node)
- }
- 
- #ifdef UNUSED_CODE
-+/* Clearing the MCA registers is apparently handled in the ramstage CPU 
Function 3 driver */
- static void cpuInitializeMCA(void)
- {
-       /* Clears Machine Check Architecture (MCA) registers, which power on
-diff --git a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c 
b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
-index b942c1a..8a61f13 100644
---- a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
-+++ b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
-@@ -39,6 +39,23 @@
- 
- #define MCI_STATUS 0x401
- 
-+static inline uint8_t is_fam15h(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      return fam15h;
-+}
-+
-+static volatile uint8_t 
fam15h_startup_flags[MAX_NODES_SUPPORTED][MAX_CORES_SUPPORTED] = {{ 0 }};
-+
- static void model_10xxx_init(device_t dev)
- {
-       u8 i;
-@@ -47,13 +64,44 @@ static void model_10xxx_init(device_t dev)
- #if CONFIG_LOGICAL_CPUS
-       u32 siblings;
- #endif
-+      uint8_t delay_start;
- 
-       id = get_node_core_id(read_nb_cfg_54());        /* nb_cfg_54 can not be 
set */
-       printk(BIOS_DEBUG, "nodeid = %02d, coreid = %02d\n", id.nodeid, 
id.coreid);
- 
-+      if (is_fam15h())
-+              delay_start = !!(id.coreid & 0x1);
-+      else
-+              delay_start = 0;
-+
-       /* Turn on caching if we haven't already */
-       x86_enable_cache();
--      amd_setup_mtrrs();
-+
-+      if (!delay_start) {
-+              /* Initialize all variable MTRRs except the first pair.
-+               * This prevents Linux from having to correct an inconsistent
-+               * MTRR setup, which would crash Family 15h CPUs due to the
-+               * compute unit structure sharing MTRR MSRs between AP cores.
-+               */
-+              msr.hi = 0x00000000;
-+              msr.lo = 0x00000000;
-+
-+              disable_cache();
-+
-+              for (i = 0x2; i < 0x10; i++) {
-+                      wrmsr(0x00000200 | i, msr);
-+              }
-+
-+              enable_cache();
-+
-+              /* Set up other MTRRs */
-+              amd_setup_mtrrs();
-+      } else {
-+              while (!fam15h_startup_flags[id.nodeid][id.coreid - 1]) {
-+                      /* Wait for CU first core startup */
-+              }
-+      }
-+
-       x86_mtrr_check();
- 
-       disable_cache();
-@@ -88,17 +136,24 @@ static void model_10xxx_init(device_t dev)
-       printk(BIOS_DEBUG, "siblings = %02d, ", siblings);
- #endif
- 
--      /* DisableCf8ExtCfg */
-+      /* Disable Cf8ExtCfg */
-       msr = rdmsr(NB_CFG_MSR);
-       msr.hi &= ~(1 << (46 - 32));
-       wrmsr(NB_CFG_MSR, msr);
- 
--      msr = rdmsr(BU_CFG2_MSR);
--      /* Clear ClLinesToNbDis */
--      msr.lo &= ~(1 << 15);
--      /* Clear bit 35 as per Erratum 343 */
--      msr.hi &= ~(1 << (35-32));
--      wrmsr(BU_CFG2_MSR, msr);
-+      if (is_fam15h()) {
-+              msr = rdmsr(BU_CFG3_MSR);
-+              /* Set CombineCr0Cd */
-+              msr.hi |= (1 << (49-32));
-+              wrmsr(BU_CFG3_MSR, msr);
-+      } else {
-+              msr = rdmsr(BU_CFG2_MSR);
-+              /* Clear ClLinesToNbDis */
-+              msr.lo &= ~(1 << 15);
-+              /* Clear bit 35 as per Erratum 343 */
-+              msr.hi &= ~(1 << (35-32));
-+              wrmsr(BU_CFG2_MSR, msr);
-+      }
- 
-       if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) {
-               printk(BIOS_DEBUG, "Initializing SMM ASeg memory\n");
-@@ -131,6 +186,7 @@ static void model_10xxx_init(device_t dev)
-       msr.lo |= (1 << 0);
-       wrmsr(HWCR_MSR, msr);
- 
-+      fam15h_startup_flags[id.nodeid][id.coreid] = 1;
- }
- 
- static struct device_operations cpu_dev_ops = {
-@@ -147,15 +203,17 @@ static struct cpu_device_id cpu_table[] = {
-       { X86_VENDOR_AMD, 0x100f22 },
-       { X86_VENDOR_AMD, 0x100f23 },
-       { X86_VENDOR_AMD, 0x100f40 },           /* RB-C0 */
--      { X86_VENDOR_AMD, 0x100F42 },           /* RB-C2 */
--      { X86_VENDOR_AMD, 0x100F43 },           /* RB-C3 */
--      { X86_VENDOR_AMD, 0x100F52 },           /* BL-C2 */
--      { X86_VENDOR_AMD, 0x100F62 },           /* DA-C2 */
--      { X86_VENDOR_AMD, 0x100F63 },           /* DA-C3 */
--      { X86_VENDOR_AMD, 0x100F80 },           /* HY-D0 */
--      { X86_VENDOR_AMD, 0x100F81 },           /* HY-D1 */
--      { X86_VENDOR_AMD, 0x100F91 },           /* HY-D1 */
--      { X86_VENDOR_AMD, 0x100FA0 },           /* PH-E0 */
-+      { X86_VENDOR_AMD, 0x100f42 },           /* RB-C2 */
-+      { X86_VENDOR_AMD, 0x100f43 },           /* RB-C3 */
-+      { X86_VENDOR_AMD, 0x100f52 },           /* BL-C2 */
-+      { X86_VENDOR_AMD, 0x100f62 },           /* DA-C2 */
-+      { X86_VENDOR_AMD, 0x100f63 },           /* DA-C3 */
-+      { X86_VENDOR_AMD, 0x100f80 },           /* HY-D0 */
-+      { X86_VENDOR_AMD, 0x100f81 },           /* HY-D1 */
-+      { X86_VENDOR_AMD, 0x100f91 },           /* HY-D1 */
-+      { X86_VENDOR_AMD, 0x100fa0 },           /* PH-E0 */
-+      { X86_VENDOR_AMD, 0x600f12 },           /* OR-B2 */
-+      { X86_VENDOR_AMD, 0x600f20 },           /* OR-C0 */
-       { 0, 0 },
- };
- 
-diff --git a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c 
b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
-index 98ef08a..84e5514 100644
---- a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
-+++ b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
-@@ -74,8 +74,7 @@ static void write_pstates_for_core(u8 pstate_num, u16 
*pstate_feq, u32 *pstate_p
-               /* Revision C or greater single-link processor */
-               cpuid1 = cpuid(0x80000008);
-               acpigen_write_PSD_package(0, (cpuid1.ecx & 0xff) + 1, SW_ALL);
--      }
--      else {
-+      } else {
-               /* Find the local APIC ID for the specified core ID */
-               struct device* cpu;
-               int cpu_index = 0;
-@@ -99,7 +98,9 @@ static void write_pstates_for_core(u8 pstate_num, u16 
*pstate_feq, u32 *pstate_p
- }
- 
- /*
--* For details of this algorithm, please refer to the BDKG 3.62 page 69
-+* For details of this algorithm, please refer to:
-+* Family 10h BDKG 3.62 page 69
-+* Family 15h BDKG 3.14 page 74
- *
- * WARNING: The core count algorithm below assumes that all processors
- * are identical, with the same number of active cores.  While the BKDG
-@@ -149,6 +150,13 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-       uint8_t node_count;
-       uint8_t cores_per_node;
-       uint8_t total_core_count;
-+      uint8_t fam15h;
-+      uint8_t fam10h_rev_e = 0;
-+
-+      /* Detect Revision E processors via method used in fidvid.c */
-+      if ((cpuid_edx(0x80000007) & CPB_MASK)
-+              &&  ((cpuid_ecx(0x80000008) & NC_MASK) == 5))
-+                      fam10h_rev_e = 1;
- 
-       /*
-        * Based on the CPU socket type,cmp_cap and pwr_lmt , get the power 
limit.
-@@ -156,11 +164,17 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-        * cmp_cap : 0x0 SingleCore ; 0x1 DualCore ; 0x2 TripleCore ; 0x3 
QuadCore ; 0x4 QuintupleCore ; 0x5 HexCore
-        */
-       printk(BIOS_INFO, "Pstates algorithm ...\n");
-+      fam15h = !!(mctGetLogicalCPUID(0) & AMD_FAM15_ALL);
-       /* Get number of cores */
--      dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xE8);
--      cmp_cap = (dtemp & 0x3000) >> 12;
--      if (mctGetLogicalCPUID(0) & AMD_FAM10_REV_D)    /* revision D */
--              cmp_cap |= (dtemp & 0x8000) >> 13;
-+      if (fam15h) {
-+              cmp_cap = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 
5)), 0x84) & 0xff;
-+      } else {
-+              dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 
0xe8);
-+              cmp_cap = (dtemp & 0x3000) >> 12;
-+              if (mctGetLogicalCPUID(0) & (AMD_FAM10_REV_D | AMD_FAM15_ALL))  
/* revision D or higher */
-+                      cmp_cap |= (dtemp & 0x8000) >> 13;
-+      }
-+
-       /* Get number of nodes */
-       dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 0)), 0x60);
-       node_count = ((dtemp & 0x70) >> 4) + 1;
-@@ -169,6 +183,14 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-       /* Compute total number of cores installed in system */
-       total_core_count = cores_per_node * node_count;
- 
-+      /* Get number of boost states */
-+      uint8_t boost_count = 0;
-+      dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 4)), 0x15c);
-+      if (fam10h_rev_e)
-+              boost_count = (dtemp >> 2) & 0x1;
-+      else if (mctGetLogicalCPUID(0) & AMD_FAM15_ALL)
-+              boost_count = (dtemp >> 2) & 0x7;
-+
-       Pstate_num = 0;
- 
-       /* See if the CPUID(0x80000007) returned EDX[7]==1b */
-@@ -205,7 +227,7 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
- 
-       /* Get PSmax's index */
-       msr = rdmsr(0xC0010061);
--      Pstate_max = (uint8_t) ((msr.lo >> PS_MAX_VAL_SHFT) & BIT_MASK_3);
-+      Pstate_max = (uint8_t) ((msr.lo >> PS_MAX_VAL_SHFT) & 
((fam15h)?BIT_MASK_7:BIT_MASK_3));
- 
-       /* Determine if all enabled Pstates have the same fidvid */
-       uint8_t i;
-@@ -219,10 +241,14 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-               }
-       }
- 
-+      /* Family 15h uses slightly different PSmax numbering */
-+      if (fam15h)
-+              Pstate_max++;
-+
-       /* Populate tables with all Pstate information */
-       for (Pstate_num = 0; Pstate_num < Pstate_max; Pstate_num++) {
-               /* Get power state information */
--              msr = rdmsr(0xC0010064 + Pstate_num);
-+              msr = rdmsr(0xC0010064 + Pstate_num + boost_count);
-               cpufid = (msr.lo & 0x3f);
-               cpudid = (msr.lo & 0x1c0) >> 6;
-               cpuvid = (msr.lo & 0xfe00) >> 9;
-@@ -232,12 +258,10 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-               if (pviModeFlag) {
-                       if (cpuvid >= 0x20) {
-                               core_voltage = 7625 - (((cpuvid - 0x20) * 
10000) / 80);
--                      }
--                      else {
-+                      } else {
-                               core_voltage = 15500 - ((cpuvid * 10000) / 40);
-                       }
--              }
--              else {
-+              } else {
-                       cpuvid = cpuvid & 0x7f;
-                       if (cpuvid >= 0x7c)
-                               core_voltage = 0;
-diff --git a/src/cpu/amd/family_10h-family_15h/processor_name.c 
b/src/cpu/amd/family_10h-family_15h/processor_name.c
-index 12c45c9..fbd0452 100644
---- a/src/cpu/amd/family_10h-family_15h/processor_name.c
-+++ b/src/cpu/amd/family_10h-family_15h/processor_name.c
-@@ -33,6 +33,10 @@
- #include <cpu/amd/mtrr.h>
- #include <cpu/cpu.h>
- #include <cpu/amd/model_10xxx_rev.h>
-+#include <device/device.h>
-+#include <device/pci.h>
-+#include <device/pnp.h>
-+#include <device/pci_ops.h>
- 
- /* The maximum length of CPU names is 48 bytes, including the final NULL byte.
-  * If you change these names your BIOS will _NOT_ pass the AMD validation and
-@@ -212,104 +216,138 @@ static int strcpymax(char *dst, const char *src, int 
buflen)
-       return i;
- }
- 
-+#define NAME_STRING_MAXLEN 48
- 
- int init_processor_name(void)
- {
--      /* variable names taken from fam10 revision guide for clarity */
--      u32 BrandId;    /* CPUID Fn8000_0001_EBX */
--      u8 String1;     /* BrandID[14:11] */
--      u8 String2;     /* BrandID[3:0] */
--      u8 Model;       /* BrandID[10:4] */
--      u8 Pg;          /* BrandID[15] */
--      u8 PkgTyp;      /* BrandID[31:28] */
--      u8 NC;          /* CPUID Fn8000_0008_ECX */
--      const char *processor_name_string = unknown;
--      char program_string[48];
--      u32 *p_program_string = (u32 *)program_string;
-       msr_t msr;
--      int i, j = 0, str2_checkNC = 1;
--      const struct str_s *str, *str2;
-+      ssize_t i;
-+      char program_string[NAME_STRING_MAXLEN];
-+      u32 *p_program_string = (u32 *)program_string;
-+      uint8_t fam15h = 0;
-+      uint32_t family;
- 
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
- 
--      /* Find out which CPU brand it is */
--      BrandId = cpuid_ebx(0x80000001);
--      String1 = (u8)((BrandId >> 11) & 0x0F);
--      String2 = (u8)((BrandId >> 0) & 0x0F);
--      Model = (u8)((BrandId >> 4) & 0x7F);
--      Pg = (u8)((BrandId >> 15) & 0x01);
--      PkgTyp = (u8)((BrandId >> 28) & 0x0F);
--      NC = (u8)(cpuid_ecx(0x80000008) & 0xFF);
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
- 
-       /* null the string */
-       memset(program_string, 0, sizeof(program_string));
- 
--      if (!Model) {
--              processor_name_string = Pg ? thermal : sample;
--              goto done;
--      }
--
--      switch (PkgTyp) {
--      case 0:         /* F1207 */
--              str = String1_socket_F;
--              str2 = String2_socket_F;
--              str2_checkNC = 0;
--              break;
--      case 1:         /* AM2 */
--              str = String1_socket_AM2;
--              str2 = String2_socket_AM2;
--              break;
--      case 3:         /* G34 */
--              str = String1_socket_G34;
--              str2 = String2_socket_G34;
--              str2_checkNC = 0;
--              break;
--      case 5:         /* C32 */
--              str = String1_socket_C32;
--              str2 = String2_socket_C32;
--              break;
--      default:
--              goto done;
--      }
-+      if (fam15h) {
-+              /* Family 15h or later */
-+              uint32_t dword;
-+              device_t cpu_fn5_dev = dev_find_slot(0, PCI_DEVFN(0x18, 5));
-+              pci_write_config32(cpu_fn5_dev, 0x194, 0);
-+              dword = pci_read_config32(cpu_fn5_dev, 0x198);
-+              if (dword == 0) {
-+                      strcpymax(program_string, sample, 
sizeof(program_string));
-+              } else {
-+                      /* Assemble the string from PCI configuration register 
contents */
-+                      for (i = 0; i < 12; i++) {
-+                              pci_write_config32(cpu_fn5_dev, 0x194, i);
-+                              p_program_string[i] = 
pci_read_config32(cpu_fn5_dev, 0x198);
-+                      }
-+
-+                      /* Correctly place the null terminator */
-+                      for (i = (NAME_STRING_MAXLEN - 2); i > 0; i--) {
-+                              if (program_string[i] != 0x20)
-+                                      break;
-+                      }
-+                      program_string[i + 1] = 0;
-+              }
-+      } else {
-+              /* variable names taken from fam10 revision guide for clarity */
-+              u32 BrandId;    /* CPUID Fn8000_0001_EBX */
-+              u8 String1;     /* BrandID[14:11] */
-+              u8 String2;     /* BrandID[3:0] */
-+              u8 Model;       /* BrandID[10:4] */
-+              u8 Pg;          /* BrandID[15] */
-+              u8 PkgTyp;      /* BrandID[31:28] */
-+              u8 NC;          /* CPUID Fn8000_0008_ECX */
-+              const char *processor_name_string = unknown;
-+              int j = 0, str2_checkNC = 1;
-+              const struct str_s *str, *str2;
-+
-+              /* Find out which CPU brand it is */
-+              BrandId = cpuid_ebx(0x80000001);
-+              String1 = (u8)((BrandId >> 11) & 0x0F);
-+              String2 = (u8)((BrandId >> 0) & 0x0F);
-+              Model = (u8)((BrandId >> 4) & 0x7F);
-+              Pg = (u8)((BrandId >> 15) & 0x01);
-+              PkgTyp = (u8)((BrandId >> 28) & 0x0F);
-+              NC = (u8)(cpuid_ecx(0x80000008) & 0xFF);
-+
-+              if (!Model) {
-+                      processor_name_string = Pg ? thermal : sample;
-+                      goto done;
-+              }
- 
--      /* String1 */
--      for (i = 0; str[i].value; i++) {
--              if ((str[i].Pg == Pg) &&
--                  (str[i].NC == NC) &&
--                  (str[i].String == String1)) {
--                      processor_name_string = str[i].value;
-+              switch (PkgTyp) {
-+              case 0:         /* F1207 */
-+                      str = String1_socket_F;
-+                      str2 = String2_socket_F;
-+                      str2_checkNC = 0;
-+                      break;
-+              case 1:         /* AM2 */
-+                      str = String1_socket_AM2;
-+                      str2 = String2_socket_AM2;
-+                      break;
-+              case 3:         /* G34 */
-+                      str = String1_socket_G34;
-+                      str2 = String2_socket_G34;
-+                      str2_checkNC = 0;
-+                      break;
-+              case 5:         /* C32 */
-+                      str = String1_socket_C32;
-+                      str2 = String2_socket_C32;
-                       break;
-+              default:
-+                      goto done;
-               }
--      }
- 
--      if (!str[i].value)
--              goto done;
-+              /* String1 */
-+              for (i = 0; str[i].value; i++) {
-+                      if ((str[i].Pg == Pg) &&
-+                      (str[i].NC == NC) &&
-+                      (str[i].String == String1)) {
-+                              processor_name_string = str[i].value;
-+                              break;
-+                      }
-+              }
- 
--      j = strcpymax(program_string, processor_name_string,
--                    sizeof(program_string));
-+              if (!str[i].value)
-+                      goto done;
- 
--      /* Translate Model from 01-99 to ASCII and put it on the end.
--       * Numbers less than 10 should include a leading zero, e.g., 09.*/
--      if (Model < 100 && j < sizeof(program_string) - 2) {
--              program_string[j++] = (Model / 10) + '0';
--              program_string[j++] = (Model % 10) + '0';
--      }
-+              j = strcpymax(program_string, processor_name_string,
-+                      sizeof(program_string));
- 
--      processor_name_string = unknown2;
--
--      /* String 2 */
--      for(i = 0; str2[i].value; i++) {
--              if ((str2[i].Pg == Pg) &&
--                  ((str2[i].NC == NC) || !str2_checkNC) &&
--                  (str2[i].String == String2)) {
--                      processor_name_string = str2[i].value;
--                      break;
-+              /* Translate Model from 01-99 to ASCII and put it on the end.
-+              * Numbers less than 10 should include a leading zero, e.g., 
09.*/
-+              if (Model < 100 && j < sizeof(program_string) - 2) {
-+                      program_string[j++] = (Model / 10) + '0';
-+                      program_string[j++] = (Model % 10) + '0';
-               }
--      }
- 
-+              processor_name_string = unknown2;
-+
-+              /* String 2 */
-+              for(i = 0; str2[i].value; i++) {
-+                      if ((str2[i].Pg == Pg) &&
-+                      ((str2[i].NC == NC) || !str2_checkNC) &&
-+                      (str2[i].String == String2)) {
-+                              processor_name_string = str2[i].value;
-+                              break;
-+                      }
-+              }
- 
--done:
--      strcpymax(&program_string[j], processor_name_string,
--                sizeof(program_string) - j);
-+      done:
-+              strcpymax(&program_string[j], processor_name_string,
-+                      sizeof(program_string) - j);
-+      }
- 
-       printk(BIOS_DEBUG, "CPU model: %s\n", program_string);
- 
-diff --git a/src/cpu/amd/family_10h-family_15h/update_microcode.c 
b/src/cpu/amd/family_10h-family_15h/update_microcode.c
-index 51aca35..3b2f5dd 100644
---- a/src/cpu/amd/family_10h-family_15h/update_microcode.c
-+++ b/src/cpu/amd/family_10h-family_15h/update_microcode.c
-@@ -28,6 +28,7 @@ struct id_mapping {
- 
- static u16 get_equivalent_processor_rev_id(u32 orig_id) {
-       static const struct id_mapping id_mapping_table[] = {
-+              /* Family 10h */
-               { 0x100f00, 0x1000 },
-               { 0x100f01, 0x1000 },
-               { 0x100f02, 0x1000 },
-@@ -42,8 +43,13 @@ static u16 get_equivalent_processor_rev_id(u32 orig_id) {
-               { 0x100f62, 0x1062 }, /* DA-C2 */
-               { 0x100f63, 0x1043 }, /* DA-C3 */
-               { 0x100f81, 0x1081 }, /* HY-D1 */
-+              { 0x100f91, 0x1081 }, /* HY-D1 */
-               { 0x100fa0, 0x10A0 }, /* PH-E0 */
- 
-+              /* Family 15h */
-+              { 0x600f12, 0x6012 }, /* OR-B2 */
-+              { 0x600f20, 0x6020 }, /* OR-C0 */
-+
-               /* Array terminator */
-               { 0xffffff, 0x0000 },
-       };
-diff --git a/src/cpu/amd/quadcore/quadcore.c b/src/cpu/amd/quadcore/quadcore.c
-index 9c21e94..8a9b5ed 100644
---- a/src/cpu/amd/quadcore/quadcore.c
-+++ b/src/cpu/amd/quadcore/quadcore.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -26,16 +27,41 @@
- 
- #include "cpu/amd/quadcore/quadcore_id.c"
- 
-+/* get_boot_apic_id and wait_cpu_state located in init_cpus.c */
-+uint32_t get_boot_apic_id(uint8_t node, uint32_t core);
-+uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2);
-+
-+static inline uint8_t is_fam15h(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      return fam15h;
-+}
-+
- static u32 get_core_num_in_bsp(u32 nodeid)
- {
-       u32 dword;
--      dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
--      dword >>= 12;
--      /* Bit 15 is CmpCap[2] since Revision D. */
--      if ((cpuid_ecx(0x80000008) & 0xff) > 3)
--          dword = ((dword & 8) >> 1) | (dword & 3);
--      else
--          dword &= 3;
-+      if (is_fam15h()) {
-+              /* Family 15h moved CmpCap to F5x84 [7:0] */
-+              dword = pci_read_config32(NODE_PCI(nodeid, 5), 0x84);
-+              dword &= 0xff;
-+      } else {
-+              dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
-+              dword >>= 12;
-+              /* Bit 15 is CmpCap[2] since Revision D. */
-+              if ((cpuid_ecx(0x80000008) & 0xff) > 3)
-+              dword = ((dword & 8) >> 1) | (dword & 3);
-+              else
-+              dword &= 3;
-+      }
-       return dword;
- }
- 
-@@ -50,28 +76,68 @@ static u8 set_apicid_cpuid_lo(void)
-       return 1;
- }
- 
--static void real_start_other_core(u32 nodeid, u32 cores)
-+static void real_start_other_core(uint32_t nodeid, uint32_t cores)
- {
--      u32 dword, i;
-+      ssize_t i;
-+      uint32_t dword;
- 
-       printk(BIOS_DEBUG, "Start other core - nodeid: %02x  cores: %02x\n", 
nodeid, cores);
- 
-       /* set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4
-          accesses and error logging to core0 */
-       dword = pci_read_config32(NODE_PCI(nodeid, 3), 0x44);
--      dword |= 1 << 27;       // NbMcaToMstCpuEn bit
-+      dword |= 1 << 30;       /* SyncFloodOnDramAdrParErr=1 */
-+      dword |= 1 << 27;       /* NbMcaToMstCpuEn=1 */
-+      dword |= 1 << 21;       /* SyncFloodOnAnyUcErr=1 */
-+      dword |= 1 << 20;       /* SyncFloodOnWDT=1 */
-+      dword |= 1 << 2;        /* SyncFloodOnDramUcEcc=1 */
-       pci_write_config32(NODE_PCI(nodeid, 3), 0x44, dword);
--      // set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
--      dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
--      dword |= 1 << 5;
--      pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);
--
--      if(cores > 1) {
--              dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
--              for (i = 0; i < cores - 1; i++) {
--                      dword |= 1 << i;
-+      if (is_fam15h()) {
-+              uint32_t core_activation_flags = 0;
-+              uint32_t active_cores = 0;
-+
-+              /* Set PCI_DEV(0, 0x18+nodeid, 0), 0x1dc bits 7:1 to start 
cores */
-+              dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x1dc);
-+              for (i = 1; i < cores + 1; i++) {
-+                      core_activation_flags |= 1 << i;
-+              }
-+
-+              /* Start the first core of each compute unit */
-+              active_cores |= core_activation_flags & 0x55;
-+              pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword | 
active_cores);
-+
-+              /* Each core shares a single set of MTRR registers with
-+               * another core in the same compute unit, therefore, it
-+               * is important that one core in each CU starts in advance
-+               * of the other in order to avoid one core stomping all over
-+               * the other core's settings.
-+               */
-+
-+              /* Wait for the first core of each compute unit to start... */
-+              uint32_t timeout;
-+              for (i = 1; i < cores + 1; i++) {
-+                      if (!(i & 0x1)) {
-+                              uint32_t ap_apicid = get_boot_apic_id(nodeid, 
i);
-+                              timeout = wait_cpu_state(ap_apicid, 
F10_APSTATE_ASLEEP, F10_APSTATE_ASLEEP);
-+                      }
-+              }
-+
-+              /* Start the second core of each compute unit */
-+              active_cores |= core_activation_flags & 0xaa;
-+              pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword | 
active_cores);
-+      } else {
-+              // set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
-+              dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
-+              dword |= 1 << 5;
-+              pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);
-+
-+              if (cores > 1) {
-+                      dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
-+                      for (i = 0; i < cores - 1; i++) {
-+                              dword |= 1 << i;
-+                      }
-+                      pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
-               }
--              pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
-       }
- }
- 
-@@ -91,10 +157,9 @@ static void start_other_cores(void)
- 
-       for (nodeid = 0; nodeid < nodes; nodeid++) {
-               u32 cores = get_core_num_in_bsp(nodeid);
--              printk(BIOS_DEBUG, "init node: %02x  cores: %02x \n", nodeid, 
cores);
-+              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1 \n", 
nodeid, cores);
-               if (cores > 0) {
-                       real_start_other_core(nodeid, cores);
-               }
-       }
--
- }
-diff --git a/src/cpu/amd/quadcore/quadcore_id.c 
b/src/cpu/amd/quadcore/quadcore_id.c
-index c5921de..c0537b3 100644
---- a/src/cpu/amd/quadcore/quadcore_id.c
-+++ b/src/cpu/amd/quadcore/quadcore_id.c
-@@ -43,9 +43,12 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
- {
-       struct node_core_id id;
-       uint8_t apicid;
-+      uint8_t fam15h = 0;
-       uint8_t rev_gte_d = 0;
-       uint8_t dual_node = 0;
-       uint32_t f3xe8;
-+      uint32_t family;
-+      uint32_t model;
- 
- #ifdef __PRE_RAM__
-       f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
-@@ -53,7 +56,17 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
-       f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
- #endif
- 
--      if (cpuid_eax(0x80000001) >= 0x8)
-+      family = model = cpuid_eax(0x80000001);
-+      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f) {
-+              /* Family 15h or later */
-+              fam15h = 1;
-+              nb_cfg_54 = 1;
-+      }
-+
-+      if ((model >= 0x8) || fam15h)
-               /* Revision D or later */
-               rev_gte_d = 1;
- 
-@@ -67,7 +80,13 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
-        */
-       apicid = (cpuid_ebx(1) >> 24) & 0xff;
-       if( nb_cfg_54) {
--              if (rev_gte_d && dual_node) {
-+              if (fam15h && dual_node) {
-+                      id.coreid = apicid & 0x1f;
-+                      id.nodeid = (apicid & 0x60) >> 5;
-+              } else if (fam15h && !dual_node) {
-+                      id.coreid = apicid & 0xf;
-+                      id.nodeid = (apicid & 0x70) >> 4;
-+              } else if (rev_gte_d && dual_node) {
-                       id.coreid = apicid & 0xf;
-                       id.nodeid = (apicid & 0x30) >> 4;
-               } else if (rev_gte_d && !dual_node) {
-@@ -90,7 +109,25 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
-               }
-       }
- 
--      if (rev_gte_d && dual_node) {
-+      if (fam15h && dual_node) {
-+              /* Coreboot expects each separate processor die to be on a 
different nodeid.
-+               * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
-+               */
-+              uint32_t f5x84;
-+              uint8_t core_count;
-+
-+#ifdef __PRE_RAM__
-+              f5x84 = pci_read_config32(NODE_PCI(0, 5), 0x84);
-+#else
-+              f5x84 = pci_read_config32(get_node_pci(0, 5), 0x84);
-+#endif
-+              core_count = (f5x84 & 0xff) + 1;
-+              id.nodeid = id.nodeid * 2;
-+              if (id.coreid >= core_count) {
-+                      id.nodeid += 1;
-+                      id.coreid = id.coreid - core_count;
-+              }
-+      } else if (rev_gte_d && dual_node) {
-               /* Coreboot expects each separate processor die to be on a 
different nodeid.
-                * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
-                */
-diff --git a/src/include/cpu/amd/model_10xxx_msr.h 
b/src/include/cpu/amd/model_10xxx_msr.h
-index 6c7dece..7d78e2d 100644
---- a/src/include/cpu/amd/model_10xxx_msr.h
-+++ b/src/include/cpu/amd/model_10xxx_msr.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -32,7 +33,13 @@
- #define IC_CFG_MSR                    0xC0011021
- #define DC_CFG_MSR                    0xC0011022
- #define BU_CFG_MSR                    0xC0011023
-+#define FP_CFG_MSR                    0xC0011028
-+#define DE_CFG_MSR                    0xC0011029
- #define BU_CFG2_MSR                   0xC001102A
-+#define BU_CFG3_MSR                   0xC001102B
-+#define EX_CFG_MSR                    0xC001102C
-+#define LS_CFG2_MSR                   0xC001102D
-+#define IBS_OP_DATA3_MSR              0xC0011037
- 
- #define CPU_ID_FEATURES_MSR           0xC0011004
- #define CPU_ID_HYPER_EXT_FEATURES     0xC001100d
-diff --git a/src/mainboard/advansus/a785e-i/romstage.c 
b/src/mainboard/advansus/a785e-i/romstage.c
-index 4c2b38a..ab717fd 100644
---- a/src/mainboard/advansus/a785e-i/romstage.c
-+++ b/src/mainboard/advansus/a785e-i/romstage.c
-@@ -131,7 +131,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/amd/bimini_fam10/romstage.c 
b/src/mainboard/amd/bimini_fam10/romstage.c
-index e2bd351..5e2cf82 100644
---- a/src/mainboard/amd/bimini_fam10/romstage.c
-+++ b/src/mainboard/amd/bimini_fam10/romstage.c
-@@ -123,7 +123,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/amd/mahogany_fam10/romstage.c 
b/src/mainboard/amd/mahogany_fam10/romstage.c
-index 74bc9d5..025a8bb 100644
---- a/src/mainboard/amd/mahogany_fam10/romstage.c
-+++ b/src/mainboard/amd/mahogany_fam10/romstage.c
-@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c 
b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
-index 20d46e6..5063439 100644
---- a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
-+++ b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
-@@ -231,7 +231,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/amd/tilapia_fam10/romstage.c 
b/src/mainboard/amd/tilapia_fam10/romstage.c
-index 89100b1..e37bc08 100644
---- a/src/mainboard/amd/tilapia_fam10/romstage.c
-+++ b/src/mainboard/amd/tilapia_fam10/romstage.c
-@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/asus/kfsn4-dre/romstage.c 
b/src/mainboard/asus/kfsn4-dre/romstage.c
-index 5d1f5a6..dd5c7dc 100644
---- a/src/mainboard/asus/kfsn4-dre/romstage.c
-+++ b/src/mainboard/asus/kfsn4-dre/romstage.c
-@@ -245,7 +245,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/asus/m4a78-em/romstage.c 
b/src/mainboard/asus/m4a78-em/romstage.c
-index 82f30d9..82b96bf 100644
---- a/src/mainboard/asus/m4a78-em/romstage.c
-+++ b/src/mainboard/asus/m4a78-em/romstage.c
-@@ -127,7 +127,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/asus/m4a785-m/romstage.c 
b/src/mainboard/asus/m4a785-m/romstage.c
-index 780bf81..30975fa 100644
---- a/src/mainboard/asus/m4a785-m/romstage.c
-+++ b/src/mainboard/asus/m4a785-m/romstage.c
-@@ -127,7 +127,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/asus/m5a88-v/romstage.c 
b/src/mainboard/asus/m5a88-v/romstage.c
-index 38761a6..4edaba2 100644
---- a/src/mainboard/asus/m5a88-v/romstage.c
-+++ b/src/mainboard/asus/m5a88-v/romstage.c
-@@ -128,7 +128,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/avalue/eax-785e/romstage.c 
b/src/mainboard/avalue/eax-785e/romstage.c
-index 764a5c6..447012b 100644
---- a/src/mainboard/avalue/eax-785e/romstage.c
-+++ b/src/mainboard/avalue/eax-785e/romstage.c
-@@ -132,7 +132,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/gigabyte/ma785gm/romstage.c 
b/src/mainboard/gigabyte/ma785gm/romstage.c
-index db4e449..444e59d 100644
---- a/src/mainboard/gigabyte/ma785gm/romstage.c
-+++ b/src/mainboard/gigabyte/ma785gm/romstage.c
-@@ -122,7 +122,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/gigabyte/ma785gmt/romstage.c 
b/src/mainboard/gigabyte/ma785gmt/romstage.c
-index 4ce7c58..705d7c5 100644
---- a/src/mainboard/gigabyte/ma785gmt/romstage.c
-+++ b/src/mainboard/gigabyte/ma785gmt/romstage.c
-@@ -122,7 +122,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/gigabyte/ma78gm/romstage.c 
b/src/mainboard/gigabyte/ma78gm/romstage.c
-index d2a0b95..5d21801 100644
---- a/src/mainboard/gigabyte/ma78gm/romstage.c
-+++ b/src/mainboard/gigabyte/ma78gm/romstage.c
-@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/hp/dl165_g6_fam10/romstage.c 
b/src/mainboard/hp/dl165_g6_fam10/romstage.c
-index 97e60d5..26c0bb9 100644
---- a/src/mainboard/hp/dl165_g6_fam10/romstage.c
-+++ b/src/mainboard/hp/dl165_g6_fam10/romstage.c
-@@ -137,7 +137,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/iei/kino-780am2-fam10/romstage.c 
b/src/mainboard/iei/kino-780am2-fam10/romstage.c
-index edbae3a..321eea6 100644
---- a/src/mainboard/iei/kino-780am2-fam10/romstage.c
-+++ b/src/mainboard/iei/kino-780am2-fam10/romstage.c
-@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/jetway/pa78vm5/romstage.c 
b/src/mainboard/jetway/pa78vm5/romstage.c
-index 16bb089..93dd2ce 100644
---- a/src/mainboard/jetway/pa78vm5/romstage.c
-+++ b/src/mainboard/jetway/pa78vm5/romstage.c
-@@ -130,7 +130,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/msi/ms9652_fam10/romstage.c 
b/src/mainboard/msi/ms9652_fam10/romstage.c
-index 4ea3306..5da971f 100644
---- a/src/mainboard/msi/ms9652_fam10/romstage.c
-+++ b/src/mainboard/msi/ms9652_fam10/romstage.c
-@@ -150,7 +150,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/supermicro/h8dmr_fam10/romstage.c 
b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
-index c224dbc..1425546 100644
---- a/src/mainboard/supermicro/h8dmr_fam10/romstage.c
-+++ b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
-@@ -146,7 +146,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/supermicro/h8qme_fam10/romstage.c 
b/src/mainboard/supermicro/h8qme_fam10/romstage.c
-index 0f9445b..4721eba 100644
---- a/src/mainboard/supermicro/h8qme_fam10/romstage.c
-+++ b/src/mainboard/supermicro/h8qme_fam10/romstage.c
-@@ -214,7 +214,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/mainboard/supermicro/h8scm_fam10/romstage.c 
b/src/mainboard/supermicro/h8scm_fam10/romstage.c
-index 4ea14fe..858aca0 100644
---- a/src/mainboard/supermicro/h8scm_fam10/romstage.c
-+++ b/src/mainboard/supermicro/h8scm_fam10/romstage.c
-@@ -136,7 +136,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       /* TODO: The Kernel must support 12 processor, otherwise the interrupt
-diff --git a/src/mainboard/tyan/s2912_fam10/romstage.c 
b/src/mainboard/tyan/s2912_fam10/romstage.c
-index 0030619..cdf51b1 100644
---- a/src/mainboard/tyan/s2912_fam10/romstage.c
-+++ b/src/mainboard/tyan/s2912_fam10/romstage.c
-@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-diff --git a/src/northbridge/amd/amdfam10/Kconfig 
b/src/northbridge/amd/amdfam10/Kconfig
-index ada5b9f..cb0d109 100644
---- a/src/northbridge/amd/amdfam10/Kconfig
-+++ b/src/northbridge/amd/amdfam10/Kconfig
-@@ -96,7 +96,7 @@ endif
- if HAVE_ACPI_RESUME
-       config S3_DATA_SIZE
-               int
--              default 16384
-+              default 32768
- endif
- 
- if DIMM_DDR2
-diff --git a/src/northbridge/amd/amdfam10/Makefile.inc 
b/src/northbridge/amd/amdfam10/Makefile.inc
-index b4097b4..4098dce 100644
---- a/src/northbridge/amd/amdfam10/Makefile.inc
-+++ b/src/northbridge/amd/amdfam10/Makefile.inc
-@@ -2,6 +2,8 @@ ifeq ($(CONFIG_NORTHBRIDGE_AMD_AMDFAM10),y)
- 
- ramstage-y += northbridge.c
- ramstage-y += misc_control.c
-+ramstage-y += link_control.c
-+ramstage-y += nb_control.c
- romstage-y += amdfam10_util.c
- ramstage-y += amdfam10_util.c
- 
-diff --git a/src/northbridge/amd/amdfam10/amdfam10.h 
b/src/northbridge/amd/amdfam10/amdfam10.h
-index a1e08a0..b724394 100644
---- a/src/northbridge/amd/amdfam10/amdfam10.h
-+++ b/src/northbridge/amd/amdfam10/amdfam10.h
-@@ -962,9 +962,12 @@ that are corresponding to 0x01, 0x02, 0x03, 0x05, 0x06, 
0x07
- 
- #define LAPIC_MSG_REG 0x380
- #define F10_APSTATE_STARTED 0x13  // start of AP execution
--#define F10_APSTATE_STOPPED 0x14  // allow AP to stop
-+#define F10_APSTATE_ASLEEP  0x14  // AP sleeping
-+#define F10_APSTATE_STOPPED 0x15  // allow AP to stop
- #define F10_APSTATE_RESET   0x01  // waiting for warm reset
- 
-+#define MAX_CORES_SUPPORTED 128
-+
- #include "nums.h"
- 
- #ifdef __PRE_RAM__
-@@ -1038,7 +1041,6 @@ struct sys_info {
- 
-       struct MCTStatStruc MCTstat;
-       struct DCTStatStruc DCTstatA[NODE_NUMS];
--
- } __attribute__((packed));
- 
- #ifdef __PRE_RAM__
-diff --git a/src/northbridge/amd/amdfam10/amdfam10_util.c 
b/src/northbridge/amd/amdfam10/amdfam10_util.c
-index 423bb73..a4045bd 100644
---- a/src/northbridge/amd/amdfam10/amdfam10_util.c
-+++ b/src/northbridge/amd/amdfam10/amdfam10_util.c
-@@ -34,14 +34,14 @@ u32 Get_NB32(u32 dev, u32 reg)
- }
- #endif
- 
--u32 mctGetLogicalCPUID(u32 Node)
-+uint64_t mctGetLogicalCPUID(u32 Node)
- {
-       /* Converts the CPUID to a logical ID MASK that is used to check
-        CPU version support versions */
-       u32 dev;
-       u32 val, valx;
-       u32 family, model, stepping;
--      u32 ret;
-+      uint64_t ret;
- 
-       if (Node == 0xFF) { /* current node */
-               val = cpuid_eax(0x80000001);
-@@ -100,9 +100,16 @@ u32 mctGetLogicalCPUID(u32 Node)
-       case 0x100a0:
-               ret = AMD_PH_E0;
-               break;
-+      case 0x15012:
-+      case 0x1501f:
-+              ret = AMD_OR_B2;
-+              break;
-+      case 0x15020:
-+              ret = AMD_OR_C0;
-+              break;
-       default:
-               /* FIXME: mabe we should die() here. */
--              printk(BIOS_ERR, "FIXME! CPU Version unknown or not supported! 
\n");
-+              printk(BIOS_ERR, "FIXME! CPU Version unknown or not supported! 
%08x\n", valx);
-               ret = 0;
-       }
- 
-diff --git a/src/northbridge/amd/amdfam10/link_control.c 
b/src/northbridge/amd/amdfam10/link_control.c
-new file mode 100644
-index 0000000..1091ef4
---- /dev/null
-+++ b/src/northbridge/amd/amdfam10/link_control.c
-@@ -0,0 +1,86 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
-+ */
-+
-+/* Configure various power control registers, including processor
-+ * boost support.
-+ */
-+
-+#include <console/console.h>
-+#include <device/device.h>
-+#include <device/pci.h>
-+#include <device/pci_ids.h>
-+#include <device/pci_ops.h>
-+#include <pc80/mc146818rtc.h>
-+#include <lib.h>
-+#include <cpu/amd/model_10xxx_rev.h>
-+
-+#include "amdfam10.h"
-+
-+static inline uint8_t is_fam15h(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      return fam15h;
-+}
-+
-+static void nb_control_init(struct device *dev)
-+{
-+      uint32_t dword;
-+
-+      printk(BIOS_DEBUG, "NB: Function 4 Link Control.. ");
-+
-+      if (is_fam15h()) {
-+              /* Enable APM */
-+              dword = pci_read_config32(dev, 0x15c);
-+              dword |= (0x1 << 7);                    /* ApmMasterEn = 1 */
-+              pci_write_config32(dev, 0x15c, dword);
-+      }
-+
-+      printk(BIOS_DEBUG, "done.\n");
-+}
-+
-+
-+static struct device_operations mcf4_ops  = {
-+      .read_resources   = pci_dev_read_resources,
-+      .set_resources    = pci_dev_set_resources,
-+      .enable_resources = pci_dev_enable_resources,
-+      .init             = nb_control_init,
-+      .scan_bus         = 0,
-+      .ops_pci          = 0,
-+};
-+
-+static const struct pci_driver mcf4_driver_fam10 __pci_driver = {
-+      .ops    = &mcf4_ops,
-+      .vendor = PCI_VENDOR_ID_AMD,
-+      .device = 0x1204,
-+};
-+
-+static const struct pci_driver mcf4_driver_fam15 __pci_driver = {
-+      .ops    = &mcf4_ops,
-+      .vendor = PCI_VENDOR_ID_AMD,
-+      .device = 0x1604,
-+};
-\ No newline at end of file
-diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
-index 90a4db1..8777e8f 100644
---- a/src/northbridge/amd/amdfam10/misc_control.c
-+++ b/src/northbridge/amd/amdfam10/misc_control.c
-@@ -4,6 +4,7 @@
-  * Copyright (C) 2003 by Eric Biederman
-  * Copyright (C) Stefan Reinauer
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -152,3 +153,9 @@ static const struct pci_driver mcf3_driver __pci_driver = {
-       .vendor = PCI_VENDOR_ID_AMD,
-       .device = 0x1203,
- };
-+
-+static const struct pci_driver mcf3_driver_fam15 __pci_driver = {
-+      .ops    = &mcf3_ops,
-+      .vendor = PCI_VENDOR_ID_AMD,
-+      .device = 0x1603,
-+};
-diff --git a/src/northbridge/amd/amdfam10/nb_control.c 
b/src/northbridge/amd/amdfam10/nb_control.c
-new file mode 100644
-index 0000000..f95b6f8
---- /dev/null
-+++ b/src/northbridge/amd/amdfam10/nb_control.c
-@@ -0,0 +1,85 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
-+ */
-+
-+/* Configure various power control registers, including processor boost
-+ * and TDP monitoring support.
-+ */
-+
-+#include <console/console.h>
-+#include <device/device.h>
-+#include <device/pci.h>
-+#include <device/pci_ids.h>
-+#include <device/pci_ops.h>
-+#include <pc80/mc146818rtc.h>
-+#include <lib.h>
-+#include <cpu/amd/model_10xxx_rev.h>
-+
-+#include "amdfam10.h"
-+
-+static void nb_control_init(struct device *dev)
-+{
-+      uint32_t dword;
-+      uint32_t f5x80;
-+      uint8_t cu_enabled;
-+      uint8_t compute_unit_count = 0;
-+
-+      printk(BIOS_DEBUG, "NB: Function 5 Northbridge Control.. ");
-+
-+      /* Determine the number of active compute units on this node */
-+      f5x80 = pci_read_config32(dev, 0x80);
-+      cu_enabled = f5x80 & 0xf;
-+      if (cu_enabled == 0x1)
-+              compute_unit_count = 1;
-+      if (cu_enabled == 0x3)
-+              compute_unit_count = 2;
-+      if (cu_enabled == 0x7)
-+              compute_unit_count = 3;
-+      if (cu_enabled == 0xf)
-+              compute_unit_count = 4;
-+
-+      /* Configure Processor TDP Running Average */
-+      dword = pci_read_config32(dev, 0xe0);
-+      dword &= ~0xf;                          /* RunAvgRange = 0x9 */
-+      dword |= 0x9;
-+      pci_write_config32(dev, 0xe0, dword);
-+
-+      /* Configure northbridge P-states */
-+      dword = pci_read_config32(dev, 0xe0);
-+      dword &= ~(0x7 << 9);                   /* NbPstateThreshold = 
compute_unit_count */
-+      dword |= (compute_unit_count & 0x7) << 9;
-+      pci_write_config32(dev, 0xe0, dword);
-+
-+      printk(BIOS_DEBUG, "done.\n");
-+}
-+
-+
-+static struct device_operations mcf5_ops  = {
-+      .read_resources   = pci_dev_read_resources,
-+      .set_resources    = pci_dev_set_resources,
-+      .enable_resources = pci_dev_enable_resources,
-+      .init             = nb_control_init,
-+      .scan_bus         = 0,
-+      .ops_pci          = 0,
-+};
-+
-+static const struct pci_driver mcf5_driver_fam15 __pci_driver = {
-+      .ops    = &mcf5_ops,
-+      .vendor = PCI_VENDOR_ID_AMD,
-+      .device = 0x1605,
-+};
-\ No newline at end of file
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index adcfdf0..baf77d6 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -81,6 +81,21 @@ device_t get_node_pci(u32 nodeid, u32 fn)
- #endif
- }
- 
-+static inline uint8_t is_fam15h(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      return fam15h;
-+}
-+
- static void get_fx_devs(void)
- {
-       int i;
-@@ -202,7 +217,7 @@ static void amd_g34_fixup(struct bus *link, device_t dev)
-               /* Revision D or later */
-               rev_gte_d = 1;
- 
--      if (rev_gte_d) {
-+      if (rev_gte_d || is_fam15h()) {
-               f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
- 
-               /* Check for dual node capability */
-@@ -215,6 +230,15 @@ static void amd_g34_fixup(struct bus *link, device_t dev)
-                       */
-                       f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 
0xe8);
-                       uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 
30);
-+                      uint8_t defective_link_number_1;
-+                      uint8_t defective_link_number_2;
-+                      if (is_fam15h()) {
-+                              defective_link_number_1 = 4;    /* Link 0 
Sublink 1 */
-+                              defective_link_number_2 = 7;    /* Link 3 
Sublink 1 */
-+                      } else {
-+                              defective_link_number_1 = 6;    /* Link 2 
Sublink 1 */
-+                              defective_link_number_2 = 5;    /* Link 1 
Sublink 1 */
-+                      }
-                       if (internal_node_number == 0) {
-                               /* Node 0 */
-                               if (link->link_num == 6)        /* Link 2 
Sublink 1 */
-@@ -314,6 +338,46 @@ static void amdfam10_scan_chains(device_t dev)
- {
-       struct bus *link;
- 
-+#if CONFIG_CPU_AMD_SOCKET_G34_NON_AGESA
-+      if (is_fam15h()) {
-+              uint8_t current_link_number = 0;
-+
-+              for (link = dev->link_list; link; link = link->next) {
-+                      /* The following links have changed position in Fam15h 
G34 processors:
-+                       * Fam10  Fam15
-+                       * Node 0
-+                       * L3 --> L1
-+                       * L0 --> L3
-+                       * L1 --> L2
-+                       * L2 --> L0
-+                       * Node 1
-+                       * L0 --> L0
-+                       * L1 --> L3
-+                       * L2 --> L1
-+                       * L3 --> L2
-+                       */
-+                      if (link->link_num == 0)
-+                              link->link_num = 3;
-+                      else if (link->link_num == 1)
-+                              link->link_num = 2;
-+                      else if (link->link_num == 2)
-+                              link->link_num = 0;
-+                      else if (link->link_num == 3)
-+                              link->link_num = 1;
-+                      else if (link->link_num == 5)
-+                              link->link_num = 7;
-+                      else if (link->link_num == 6)
-+                              link->link_num = 5;
-+                      else if (link->link_num == 7)
-+                              link->link_num = 6;
-+
-+                      current_link_number++;
-+                      if (current_link_number > 3)
-+                              current_link_number = 0;
-+              }
-+      }
-+#endif
-+
-       /* Do sb ht chain at first, in case s2885 put sb chain (8131/8111) on 
link2, but put 8151 on link0 */
-       trim_ht_chain(dev);
- 
-@@ -620,13 +684,21 @@ static const struct pci_driver mcf0_driver __pci_driver 
= {
-       .device = 0x1200,
- };
- 
-+
- static void amdfam10_nb_init(void *chip_info)
- {
-       relocate_sb_ht_chain();
- }
- 
-+static const struct pci_driver mcf0_driver_fam15 __pci_driver = {
-+      .ops    = &northbridge_operations,
-+      .vendor = PCI_VENDOR_ID_AMD,
-+      .device = 0x1600,
-+};
-+
-+
- struct chip_operations northbridge_amd_amdfam10_ops = {
--      CHIP_NAME("AMD FAM10 Northbridge")
-+      CHIP_NAME("AMD Family 10h/15h Northbridge")
-       .enable_dev = 0,
-       .init = amdfam10_nb_init,
- };
-@@ -950,38 +1022,61 @@ static int amdfam10_get_smbios_data16(int* count, int 
handle, unsigned long *cur
- 
- static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
- {
--      if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
--              switch (speed) {
--                      case 1:
--                              return 200;
--                      case 2:
--                              return 266;
--                      case 3:
--                              return 333;
--                      case 4:
--                              return 400;
--                      case 5:
--                              return 533;
--                      default:
--                              return 0;
--              }
--      } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
--              switch (speed) {
--                      case 3:
--                              return 333;
--                      case 4:
--                              return 400;
--                      case 5:
--                              return 533;
--                      case 6:
--                              return 667;
--                      case 7:
--                              return 800;
--                      default:
--                              return 0;
-+      if (is_fam15h()) {
-+              if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+                      switch (speed) {
-+                              case 0x4:
-+                                      return 333;
-+                              case 0x6:
-+                                      return 400;
-+                              case 0xa:
-+                                      return 533;
-+                              case 0xe:
-+                                      return 667;
-+                              case 0x12:
-+                                      return 800;
-+                              case 0x16:
-+                                      return 933;
-+                              default:
-+                                      return 0;
-+                      }
-+              } else {
-+                      return 0;
-               }
-       } else {
--              return 0;
-+              if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
-+                      switch (speed) {
-+                              case 1:
-+                                      return 200;
-+                              case 2:
-+                                      return 266;
-+                              case 3:
-+                                      return 333;
-+                              case 4:
-+                                      return 400;
-+                              case 5:
-+                                      return 533;
-+                              default:
-+                                      return 0;
-+                      }
-+              } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+                      switch (speed) {
-+                              case 3:
-+                                      return 333;
-+                              case 4:
-+                                      return 400;
-+                              case 5:
-+                                      return 533;
-+                              case 6:
-+                                      return 667;
-+                              case 7:
-+                                      return 800;
-+                              default:
-+                                      return 0;
-+                      }
-+              } else {
-+                      return 0;
-+              }
-       }
- }
- 
-@@ -1076,6 +1171,8 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
- #if IS_ENABLED(CONFIG_DIMM_DDR3)
-                                       /* Find the maximum and minimum 
supported voltages */
-                                       uint8_t supported_voltages = 
mem_info->dct_stat[node].DimmSupportedVoltages[slot];
-+                                      uint8_t configured_voltage = 
mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
-+
-                                       if (supported_voltages & 0x8)
-                                               t->minimum_voltage = 1150;
-                                       else if (supported_voltages & 0x4)
-@@ -1094,7 +1191,14 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
-                                       else if (supported_voltages & 0x8)
-                                               t->maximum_voltage = 1150;
- 
--                                      t->configured_voltage = 
mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
-+                                      if (configured_voltage & 0x8)
-+                                              t->configured_voltage = 1150;
-+                                      else if (configured_voltage & 0x4)
-+                                              t->configured_voltage = 1250;
-+                                      else if (configured_voltage & 0x2)
-+                                              t->configured_voltage = 1350;
-+                                      else if (configured_voltage & 0x1)
-+                                              t->configured_voltage = 1500;
- #endif
-                               }
-                               t->memory_error_information_handle = 0xFFFE;    
/* no error information handle available */
-@@ -1233,12 +1337,14 @@ static void cpu_bus_scan(device_t dev)
- #if CONFIG_CBB
-       device_t pci_domain;
- #endif
-+      int nvram = 0;
-       int i,j;
-       int nodes;
-       unsigned nb_cfg_54;
-       unsigned siblings;
-       int cores_found;
-       int disable_siblings;
-+      uint8_t disable_cu_siblings = 0;
-       unsigned ApicIdCoreIdSize;
- 
-       nb_cfg_54 = 0;
-@@ -1325,14 +1431,23 @@ static void cpu_bus_scan(device_t dev)
-       /* Always use the devicetree node with lapic_id 0 for BSP. */
-       remap_bsp_lapic(cpu_bus);
- 
-+      if (get_option(&nvram, "compute_unit_siblings") == CB_SUCCESS)
-+              disable_cu_siblings = !!nvram;
-+
-+      if (disable_cu_siblings)
-+              printk(BIOS_DEBUG, "Disabling siblings on each compute unit as 
requested\n");
-+
-       for(i = 0; i < nodes; i++) {
-               device_t cdb_dev;
-               unsigned busn, devn;
-               struct bus *pbus;
- 
-+              uint8_t fam15h = 0;
-               uint8_t rev_gte_d = 0;
-               uint8_t dual_node = 0;
-               uint32_t f3xe8;
-+              uint32_t family;
-+              uint32_t model;
- 
-               busn = CONFIG_CBB;
-               devn = CONFIG_CDB+i;
-@@ -1372,7 +1487,16 @@ static void cpu_bus_scan(device_t dev)
- 
-               f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
- 
--              if (cpuid_eax(0x80000001) >= 0x8)
-+              family = model = cpuid_eax(0x80000001);
-+              model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+
-+              if (is_fam15h()) {
-+                      /* Family 15h or later */
-+                      fam15h = 1;
-+                      nb_cfg_54 = 1;
-+              }
-+
-+              if ((model >= 0x8) || fam15h)
-                       /* Revision D or later */
-                       rev_gte_d = 1;
- 
-@@ -1382,13 +1506,20 @@ static void cpu_bus_scan(device_t dev)
-                               dual_node = 1;
- 
-               cores_found = 0; // one core
--              cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
-+              if (fam15h)
-+                      cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 5));
-+              else
-+                      cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
-               int enable_node = cdb_dev && cdb_dev->enabled;
-               if (enable_node) {
--                      j = pci_read_config32(cdb_dev, 0xe8);
--                      cores_found = (j >> 12) & 3; // dev is func 3
--                      if (siblings > 3)
--                              cores_found |= (j >> 13) & 4;
-+                      if (fam15h) {
-+                              cores_found = pci_read_config32(cdb_dev, 0x84) 
& 0xff;
-+                      } else {
-+                              j = pci_read_config32(cdb_dev, 0xe8);
-+                              cores_found = (j >> 12) & 3; // dev is func 3
-+                              if (siblings > 3)
-+                                      cores_found |= (j >> 13) & 4;
-+                      }
-                       printk(BIOS_DEBUG, "  %s siblings=%d\n", 
dev_path(cdb_dev), cores_found);
-               }
- 
-@@ -1408,15 +1539,24 @@ static void cpu_bus_scan(device_t dev)
- 
-                       if (dual_node) {
-                               apic_id = 0;
--                              if (nb_cfg_54) {
--                                      apic_id |= ((i >> 1) & 0x3) << 4;       
                /* Node ID */
-+                              if (fam15h) {
-+                                      apic_id |= ((i >> 1) & 0x3) << 5;       
                /* Node ID */
-                                       apic_id |= ((i & 0x1) * (siblings + 1)) 
+ j;            /* Core ID */
-                               } else {
--                                      apic_id |= i & 0x3;                     
                /* Node ID */
--                                      apic_id |= (((i & 0x1) * (siblings + 
1)) + j) << 4;     /* Core ID */
-+                                      if (nb_cfg_54) {
-+                                              apic_id |= ((i >> 1) & 0x3) << 
4;                       /* Node ID */
-+                                              apic_id |= ((i & 0x1) * 
(siblings + 1)) + j;            /* Core ID */
-+                                      } else {
-+                                              apic_id |= i & 0x3;             
                        /* Node ID */
-+                                              apic_id |= (((i & 0x1) * 
(siblings + 1)) + j) << 4;     /* Core ID */
-+                                      }
-                               }
-                       } else {
--                              apic_id = i * (nb_cfg_54?(siblings+1):1) + j * 
(nb_cfg_54?1:64); // ?
-+                              if (fam15h) {
-+                                      apic_id = (i * (siblings + 1)) + j;
-+                              } else {
-+                                      apic_id = i * 
(nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
-+                              }
-                       }
- 
- #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
-@@ -1426,6 +1566,9 @@ static void cpu_bus_scan(device_t dev)
-                               }
-                       }
- #endif
-+                      if (disable_cu_siblings && (j & 0x1))
-+                              continue;
-+
-                       device_t cpu = add_cpu_device(cpu_bus, apic_id, 
enable_node);
-                       if (cpu)
-                               amd_cpu_topology(cpu, i, j);
-@@ -1484,6 +1627,6 @@ static void root_complex_enable_dev(struct device *dev)
- }
- 
- struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
--      CHIP_NAME("AMD FAM10 Root Complex")
-+      CHIP_NAME("AMD Family 10h/15h Root Complex")
-       .enable_dev = root_complex_enable_dev,
- };
-diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-index 5068e7a..cae228f 100644
---- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
-+++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-@@ -44,8 +44,120 @@ static  void print_tf(const char *func, const char *strval)
- #endif
- }
- 
--static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t 
freq)
-+static inline void fam15h_switch_dct(uint32_t dev, uint8_t dct)
- {
-+      uint32_t dword;
-+
-+      dword = Get_NB32(dev, 0x10c);
-+      dword &= ~0x1;
-+      dword |= (dct & 0x1);
-+      Set_NB32(dev, 0x10c, dword);
-+}
-+
-+static inline void fam15h_switch_nb_pstate_config_reg(uint32_t dev, uint8_t 
nb_pstate)
-+{
-+      uint32_t dword;
-+
-+      dword = Get_NB32(dev, 0x10c);
-+      dword &= ~(0x3 << 4);
-+      dword |= (nb_pstate & 0x3) << 4;
-+      Set_NB32(dev, 0x10c, dword);
-+}
-+
-+static inline uint32_t Get_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg)
-+{
-+      if (is_fam15h()) {
-+              /* Obtain address of function 0x1 */
-+              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
-+              fam15h_switch_dct(dev_map, dct);
-+              return Get_NB32(dev, reg);
-+      } else {
-+              return Get_NB32(dev, (0x100 * dct) + reg);
-+      }
-+}
-+
-+static inline void Set_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg, 
uint32_t val)
-+{
-+      if (is_fam15h()) {
-+              /* Obtain address of function 0x1 */
-+              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
-+              fam15h_switch_dct(dev_map, dct);
-+              Set_NB32(dev, reg, val);
-+      } else {
-+              Set_NB32(dev, (0x100 * dct) + reg, val);
-+      }
-+}
-+
-+static inline uint32_t Get_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, 
uint8_t nb_pstate, uint32_t reg)
-+{
-+      if (is_fam15h()) {
-+              /* Obtain address of function 0x1 */
-+              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
-+              fam15h_switch_dct(dev_map, dct);
-+              fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate);
-+              return Get_NB32(dev, reg);
-+      } else {
-+              return Get_NB32(dev, (0x100 * dct) + reg);
-+      }
-+}
-+
-+static inline void Set_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, uint8_t 
nb_pstate, uint32_t reg, uint32_t val)
-+{
-+      if (is_fam15h()) {
-+              /* Obtain address of function 0x1 */
-+              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
-+              fam15h_switch_dct(dev_map, dct);
-+              fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate);
-+              Set_NB32(dev, reg, val);
-+      } else {
-+              Set_NB32(dev, (0x100 * dct) + reg, val);
-+      }
-+}
-+
-+static inline uint32_t Get_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, 
uint32_t index_reg, uint32_t index)
-+{
-+      if (is_fam15h()) {
-+              /* Obtain address of function 0x1 */
-+              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
-+              fam15h_switch_dct(dev_map, dct);
-+              return Get_NB32_index_wait(dev, index_reg, index);
-+      } else {
-+              return Get_NB32_index_wait(dev, (0x100 * dct) + index_reg, 
index);
-+      }
-+}
-+
-+static inline void Set_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, 
uint32_t index_reg, uint32_t index, uint32_t data)
-+{
-+      if (is_fam15h()) {
-+              /* Obtain address of function 0x1 */
-+              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
-+              fam15h_switch_dct(dev_map, dct);
-+              Set_NB32_index_wait(dev, index_reg, index, data);
-+      } else {
-+              Set_NB32_index_wait(dev, (0x100 * dct) + index_reg, index, 
data);
-+      }
-+}
-+
-+static uint16_t voltage_index_to_mv(uint8_t index)
-+{
-+      if (index & 0x8)
-+              return 1150;
-+      if (index & 0x4)
-+              return 1250;
-+      else if (index & 0x2)
-+              return 1350;
-+      else
-+              return 1500;
-+}
-+
-+static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t highest_rank_count, 
uint8_t registered, uint8_t voltage, uint16_t freq)
-+{
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-       /* Return limited maximum RAM frequency */
-       if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
-               if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
-@@ -68,34 +180,178 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t 
registered, uint16_t freq
-                       }
-               }
-       } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
--              if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
--                      /* K10 BKDG Rev. 3.62 Table 34 */
--                      if (count > 2) {
--                              /* Limit to DDR3-800 */
--                              if (freq > 400) {
--                                      freq = 400;
--                                      print_tf(__func__, ": More than 2 
registered DIMMs on channel; limiting to DDR3-800\n");
-+              if (voltage == 0) {
-+                      printk(BIOS_DEBUG, "%s: WARNING: Mainboard DDR3 voltage 
unknown, assuming 1.5V!\n", __func__);
-+                      voltage = 0x1;
-+              }
-+
-+              if (is_fam15h()) {
-+                      if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
-+                              /* Fam15h BKDG Rev. 3.14 Table 27 */
-+                              if (voltage & 0x4) {
-+                                      /* 1.25V */
-+                                      if (count > 1) {
-+                                              if (highest_rank_count > 1) {
-+                                                      /* Limit to DDR3-1066 */
-+                                                      if (freq > 533) {
-+                                                              freq = 533;
-+                                                              
printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting 
to DDR3-1066\n", __func__, voltage_index_to_mv(voltage));
-+                                                      }
-+                                              } else {
-+                                                      /* Limit to DDR3-1333 */
-+                                                      if (freq > 666) {
-+                                                              freq = 666;
-+                                                              
printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting 
to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
-+                                                      }
-+                                              }
-+                                      } else {
-+                                              /* Limit to DDR3-1333 */
-+                                              if (freq > 666) {
-+                                                      freq = 666;
-+                                                      printk(BIOS_DEBUG, "%s: 
1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
-+                                              }
-+                                      }
-+                              } else if (voltage & 0x2) {
-+                                      /* 1.35V */
-+                                      if (count > 1) {
-+                                              /* Limit to DDR3-1333 */
-+                                              if (freq > 666) {
-+                                                      freq = 666;
-+                                                      printk(BIOS_DEBUG, "%s: 
More than 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", 
__func__, voltage_index_to_mv(voltage));
-+                                              }
-+                                      } else {
-+                                              /* Limit to DDR3-1600 */
-+                                              if (freq > 800) {
-+                                                      freq = 800;
-+                                                      printk(BIOS_DEBUG, "%s: 
1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, 
voltage_index_to_mv(voltage));
-+                                              }
-+                                      }
-+                              } else if (voltage & 0x1) {
-+                                      /* 1.50V */
-+                                      if (count > 1) {
-+                                              /* Limit to DDR3-1600 */
-+                                              if (freq > 800) {
-+                                                      freq = 800;
-+                                                      printk(BIOS_DEBUG, "%s: 
More than 1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", 
__func__, voltage_index_to_mv(voltage));
-+                                              }
-+                                      } else {
-+                                              /* Limit to DDR3-1866 */
-+                                              if (freq > 933) {
-+                                                      freq = 933;
-+                                                      printk(BIOS_DEBUG, "%s: 
1 registered DIMM on %dmV channel; limiting to DDR3-1866\n", __func__, 
voltage_index_to_mv(voltage));
-+                                              }
-+                                      }
-+                              }
-+                      } else {
-+                              /* Fam15h BKDG Rev. 3.14 Table 26 */
-+                              if (voltage & 0x4) {
-+                                      /* 1.25V */
-+                                      if (count > 1) {
-+                                              if (highest_rank_count > 1) {
-+                                                      /* Limit to DDR3-1066 */
-+                                                      if (freq > 533) {
-+                                                              freq = 533;
-+                                                              
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1066\n", __func__, voltage_index_to_mv(voltage));
-+                                                      }
-+                                              } else {
-+                                                      /* Limit to DDR3-1333 */
-+                                                      if (freq > 666) {
-+                                                              freq = 666;
-+                                                              
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
-+                                                      }
-+                                              }
-+                                      } else {
-+                                              /* Limit to DDR3-1333 */
-+                                              if (freq > 666) {
-+                                                      freq = 666;
-+                                                      printk(BIOS_DEBUG, "%s: 
1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
-+                                              }
-+                                      }
-+                              } else if (voltage & 0x2) {
-+                                      /* 1.35V */
-+                                      if (MaxDimmsInstallable > 1) {
-+                                              /* Limit to DDR3-1333 */
-+                                              if (freq > 666) {
-+                                                      freq = 666;
-+                                                      printk(BIOS_DEBUG, "%s: 
More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", 
__func__, voltage_index_to_mv(voltage));
-+                                              }
-+                                      } else {
-+                                              /* Limit to DDR3-1600 */
-+                                              if (freq > 800) {
-+                                                      freq = 800;
-+                                                      printk(BIOS_DEBUG, "%s: 
1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, 
voltage_index_to_mv(voltage));
-+                                              }
-+                                      }
-+                              } else if (voltage & 0x1) {
-+                                      if (MaxDimmsInstallable == 1) {
-+                                              if (count > 1) {
-+                                                      /* Limit to DDR3-1600 */
-+                                                      if (freq > 800) {
-+                                                              freq = 800;
-+                                                              
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
-+                                                      }
-+                                              } else {
-+                                                      /* Limit to DDR3-1866 */
-+                                                      if (freq > 933) {
-+                                                              freq = 933;
-+                                                              
printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to 
DDR3-1866\n", __func__, voltage_index_to_mv(voltage));
-+                                                      }
-+                                              }
-+                                      } else {
-+                                              if (count > 1) {
-+                                                      if (highest_rank_count 
> 1) {
-+                                                              /* Limit to 
DDR3-1333 */
-+                                                              if (freq > 666) 
{
-+                                                                      freq = 
666;
-+                                                                      
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
-+                                                              }
-+                                                      } else {
-+                                                              /* Limit to 
DDR3-1600 */
-+                                                              if (freq > 800) 
{
-+                                                                      freq = 
800;
-+                                                                      
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
-+                                                              }
-+                                                      }
-+                                              } else {
-+                                                      /* Limit to DDR3-1600 */
-+                                                      if (freq > 800) {
-+                                                              freq = 800;
-+                                                              
printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to 
DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
-+                                                      }
-+                                              }
-+                                      }
-                               }
--                      } else if (count == 2) {
--                              /* Limit to DDR3-1066 */
--                              if (freq > 533) {
--                                      freq = 533;
--                                      print_tf(__func__, ": 2 registered 
DIMMs on channel; limiting to DDR3-1066\n");
-+                      }
-+              } else {
-+                      if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
-+                              /* K10 BKDG Rev. 3.62 Table 34 */
-+                              if (count > 2) {
-+                                      /* Limit to DDR3-800 */
-+                                      if (freq > 400) {
-+                                              freq = 400;
-+                                              printk(BIOS_DEBUG, "%s: More 
than 2 registered DIMMs on %dmV channel; limiting to DDR3-800\n", __func__, 
voltage_index_to_mv(voltage));
-+                                      }
-+                              } else if (count == 2) {
-+                                      /* Limit to DDR3-1066 */
-+                                      if (freq > 533) {
-+                                              freq = 533;
-+                                              printk(BIOS_DEBUG, "%s: 2 
registered DIMMs on %dmV channel; limiting to DDR3-1066\n", __func__, 
voltage_index_to_mv(voltage));
-+                                      }
-+                              } else {
-+                                      /* Limit to DDR3-1333 */
-+                                      if (freq > 666) {
-+                                              freq = 666;
-+                                              printk(BIOS_DEBUG, "%s: 1 
registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
-+                                      }
-                               }
-                       } else {
-+                              /* K10 BKDG Rev. 3.62 Table 33 */
-                               /* Limit to DDR3-1333 */
-                               if (freq > 666) {
-                                       freq = 666;
--                                      print_tf(__func__, ": 1 registered DIMM 
on channel; limiting to DDR3-1333\n");
-+                                      printk(BIOS_DEBUG, "%s: unbuffered 
DIMMs on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
-                               }
-                       }
--              } else {
--                      /* K10 BKDG Rev. 3.62 Table 33 */
--                      /* Limit to DDR3-1333 */
--                      if (freq > 666) {
--                              freq = 666;
--                              print_tf(__func__, ": unbuffered DIMMs on 
channel; limiting to DDR3-1333\n");
--                      }
-               }
-       }
- 
-@@ -225,11 +481,13 @@ void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 
node)
- 
- }
- 
-+#if IS_ENABLED(CONFIG_SET_FIDVID)
- static u8 mctGetProcessorPackageType(void) {
-       /* FIXME: I guess this belongs wherever mctGetLogicalCPUID ends up ? */
--     u32 BrandId = cpuid_ebx(0x80000001);
--     return (u8)((BrandId >> 28) & 0x0F);
-+      u32 BrandId = cpuid_ebx(0x80000001);
-+      return (u8)((BrandId >> 28) & 0x0F);
- }
-+#endif
- 
- static void raminit_amdmct(struct sys_info *sysinfo)
- {
-diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
-index 97f9db8..8f9177f 100644
---- a/src/northbridge/amd/amdht/h3ncmn.c
-+++ b/src/northbridge/amd/amdht/h3ncmn.c
-@@ -43,6 +43,7 @@
- #define CPU_HTNB_FUNC_04              4
- #define CPU_ADDR_FUNC_01              1
- #define CPU_NB_FUNC_03                        3
-+#define CPU_NB_FUNC_05                        5
- 
- /* Function 0 registers */
- #define REG_ROUTE0_0X40               0x40
-@@ -70,6 +71,7 @@
- #define REG_NB_CPUID_3XFC             0xFC
- #define REG_NB_LINK_XCS_TOKEN0_3X148  0x148
- #define REG_NB_DOWNCORE_3X190         0x190
-+#define REG_NB_CAPABILITY_5X84                0x84
- 
- /* Function 4 registers */
- 
-@@ -555,9 +557,10 @@ static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge 
*nb)
-                               15, 12, &temp);
- 
-       /* bits[15,13,12] specify the cores */
--      /* Support Downcoring */
-       temp = ((temp & 8) >> 1) + (temp & 3);
-       cores = temp + 1;
-+
-+      /* Support Downcoring */
-       AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
-                                       makePCIBusFromNode(node),
-                                       makePCIDeviceFromNode(node),
-@@ -576,6 +579,56 @@ static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge 
*nb)
- 
- 
/***************************************************************************//**
-  *
-+ * static u8
-+ * fam15GetNumCoresOnNode(u8 node, cNorthBridge *nb)
-+ *
-+ *  Description:
-+ *    Return the number of cores (1 based count) on node.
-+ *
-+ *  Parameters:
-+ *    @param[in]  node      = the node that will be examined
-+ *    @param[in] *nb = this northbridge
-+ *    @return    = the number of cores
-+ *
-+ *
-+ */
-+static u8 fam15GetNumCoresOnNode(u8 node, cNorthBridge *nb)
-+{
-+      u32 temp, leveling, cores;
-+      u8 i;
-+
-+      ASSERT((node < nb->maxNodes));
-+      /* Read CmpCap [7:0] */
-+      AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
-+                              makePCIBusFromNode(node),
-+                              makePCIDeviceFromNode(node),
-+                              CPU_NB_FUNC_05,
-+                              REG_NB_CAPABILITY_5X84),
-+                              7, 0, &temp);
-+
-+      /* bits[7:0] specify the cores */
-+      temp = temp & 0xff;
-+      cores = temp + 1;
-+
-+      /* Support Downcoring */
-+      AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
-+                                      makePCIBusFromNode(node),
-+                                      makePCIDeviceFromNode(node),
-+                                      CPU_NB_FUNC_03,
-+                                      REG_NB_DOWNCORE_3X190),
-+                                      31, 0, &leveling);
-+      for (i=0; i<cores; i++)
-+      {
-+              if (leveling & ((u32) 1 << i))
-+              {
-+                      temp--;
-+              }
-+      }
-+      return (u8)(temp+1);
-+}
-+
-+/***************************************************************************//**
-+ *
-  * static void
-  * setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge 
*nb)
-  *
-@@ -854,6 +907,69 @@ static BOOL fam10IsCapable(u8 node, sMainData *pDat, 
cNorthBridge *nb)
- 
- 
/***************************************************************************//**
-  *
-+ * static BOOL
-+ * fam15IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
-+ *
-+ *  Description:
-+ *    Get node capability and update the minimum supported system capability.
-+ *    Return whether the current configuration exceeds the capability.
-+ *
-+ *  Parameters:
-+ *    @param[in]  node   = the node
-+ *    @param[in,out] *pDat = sysMpCap (updated) and NodesDiscovered
-+ *    @param[in] *nb   = this northbridge
-+ *    @return             true: system is capable of current config.
-+ *                       false: system is not capable of current config.
-+ *
-+ * 
---------------------------------------------------------------------------------------
-+ */
-+static BOOL fam15IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
-+{
-+#ifndef HT_BUILD_NC_ONLY
-+      u32 temp;
-+      u8 maxNodes;
-+
-+      ASSERT(node < nb->maxNodes);
-+
-+      AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
-+                              makePCIBusFromNode(node),
-+                              makePCIDeviceFromNode(node),
-+                              CPU_NB_FUNC_03,
-+                              REG_NB_CAPABILITY_3XE8),
-+                              18, 16, &temp);
-+
-+      if (temp != 0)
-+      {
-+              maxNodes = (1 << (~temp & 0x3));  /* That is, 1, 2, 4, or 8 */
-+      }
-+      else
-+      {
-+              /* Check if CPU package is dual node */
-+              AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
-+                                      makePCIBusFromNode(node),
-+                                      makePCIDeviceFromNode(node),
-+                                      CPU_NB_FUNC_03,
-+                                      REG_NB_CAPABILITY_3XE8),
-+                                      29, 29, &temp);
-+              if (temp)
-+                      maxNodes = 4;
-+              else
-+                      maxNodes = 8;
-+      }
-+
-+      if (pDat->sysMpCap > maxNodes)
-+      {
-+              pDat->sysMpCap = maxNodes;
-+      }
-+      /* Note since sysMpCap is one based and NodesDiscovered is zero based, 
equal is false */
-+      return (pDat->sysMpCap > pDat->NodesDiscovered);
-+#else
-+      return 1;
-+#endif
-+}
-+
-+/***************************************************************************//**
-+ *
-  * static void
-  * fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb)
-  *
-@@ -2068,6 +2184,49 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
-       u32 match;
-       u32 extFam, baseFam, model;
- 
-+      cNorthBridge fam15 =
-+      {
-+#ifdef HT_BUILD_NC_ONLY
-+              8,
-+              1,
-+              12,
-+#else
-+              8,
-+              8,
-+              64,
-+#endif /* HT_BUILD_NC_ONLY*/
-+              writeRoutingTable,
-+              writeNodeID,
-+              readDefLnk,
-+              enableRoutingTables,
-+              verifyLinkIsCoherent,
-+              readTrueLinkFailStatus,
-+              readToken,
-+              writeToken,
-+              fam15GetNumCoresOnNode,
-+              setTotalNodesAndCores,
-+              limitNodes,
-+              writeFullRoutingTable,
-+              isCompatible,
-+              fam15IsCapable,
-+              (void (*)(u8, u8, cNorthBridge*))commonVoid,
-+              (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
-+              readSbLink,
-+              verifyLinkIsNonCoherent,
-+              ht3SetCFGAddrMap,
-+              convertBitsToWidth,
-+              convertWidthToBits,
-+              fam10NorthBridgeFreqMask,
-+              gatherLinkData,
-+              setLinkData,
-+              ht3WriteTrafficDistribution,
-+              fam10BufferOptimizations,
-+              0x00000001,
-+              0x00000200,
-+              18,
-+              0x00000f06
-+      };
-+
-       cNorthBridge fam10 =
-       {
- #ifdef HT_BUILD_NC_ONLY
-@@ -2175,8 +2334,14 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
-                       7, 4, &model);
-       match = (u32)((baseFam << 8) | extFam);
- 
--      /* Test each in turn looking for a match.       Init the struct if 
found */
--      if (match == fam10.compatibleKey)
-+      /* Test each in turn looking for a match.
-+       * Initialize the struct if found.
-+       */
-+      if (match == fam15.compatibleKey)
-+      {
-+              Amdmemcpy((void *)nb, (const void *)&fam15, (u32) 
sizeof(cNorthBridge));
-+      }
-+      else if (match == fam10.compatibleKey)
-       {
-               Amdmemcpy((void *)nb, (const void *)&fam10, (u32) 
sizeof(cNorthBridge));
-       }
-diff --git a/src/northbridge/amd/amdht/ht_wrapper.c 
b/src/northbridge/amd/amdht/ht_wrapper.c
-index 389b1b1..c0ccc69 100644
---- a/src/northbridge/amd/amdht/ht_wrapper.c
-+++ b/src/northbridge/amd/amdht/ht_wrapper.c
-@@ -174,16 +174,22 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
-       printk(BIOS_DEBUG, "amd_ht_fixup()\n");
-       if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX)) {
-               uint8_t rev_gte_d = 0;
-+              uint8_t fam15h = 0;
-               uint8_t dual_node = 0;
-               uint32_t f3xe8;
-               uint32_t family;
-               uint32_t model;
- 
-               family = model = cpuid_eax(0x80000001);
--              model = ((model & 0xf0000) >> 16) | ((model & 0xf0) >> 4);
-+              model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+              family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
- 
--              if (model >= 0x8)
--                      /* Revision D or later */
-+              if (family >= 0x6f)
-+                      /* Family 15h or later */
-+                      fam15h = 1;
-+
-+              if ((model >= 0x8) || fam15h)
-+                      /* Family 10h Revision D or later */
-                       rev_gte_d = 1;
- 
-               if (rev_gte_d) {
-@@ -195,7 +201,8 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
- 
-                       if (dual_node) {
-                               /* Each G34 processor contains a defective HT 
link.
--                              * See the BKDG Rev 3.62 section 2.7.1.5 for 
details.
-+                              * See the Family 10h BKDG Rev 3.62 section 
2.7.1.5 for details
-+                              * For Family 15h see the BKDG Rev. 3.14 section 
2.12.1.5 for details.
-                               */
-                               uint8_t node;
-                               uint8_t node_count = get_nodes();
-@@ -205,46 +212,46 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
-                                       uint8_t internal_node_number = ((f3xe8 
& 0xc0000000) >> 30);
-                                       printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link\n", node, 
internal_node_number);
-                                       if (internal_node_number == 0) {
--                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xd8) & 0x1;
-+                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0x98:0xd8) & 0x1;
-                                               if (package_link_3_connected) {
-                                                       /* Set WidthIn and 
WidthOut to 0 */
--                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xc4);
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4);
-                                                       dword &= ~0x77000000;
--                                                      
pci_write_config32(NODE_PCI(node, 0), 0xc4, dword);
-+                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4, dword);
-                                                       /* Set Ganged to 1 */
--                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x178);
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178);
-                                                       dword |= 0x00000001;
--                                                      
pci_write_config32(NODE_PCI(node, 0), 0x178, dword);
-+                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178, dword);
-                                               } else {
-                                                       /* Set ConnDly to 1 */
-                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
-                                                       dword |= 0x00000100;
-                                                       
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
-                                                       /* Set TransOff and 
EndOfChain to 1 */
--                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xc4);
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4);
-                                                       dword |= 0x000000c0;
--                                                      
pci_write_config32(NODE_PCI(node, 4), 0xc4, dword);
-+                                                      
pci_write_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4, dword);
-                                               }
-                                       } else if (internal_node_number == 1) {
--                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xb8) & 0x1;
-+                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0xf8:0xb8) & 0x1;
-                                               if (package_link_3_connected) {
-                                                       /* Set WidthIn and 
WidthOut to 0 */
--                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xa4);
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4);
-                                                       dword &= ~0x77000000;
--                                                      
pci_write_config32(NODE_PCI(node, 0), 0xa4, dword);
-+                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4, dword);
-                                                       /* Set Ganged to 1 */
--                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x174);
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174);
-                                                       dword |= 0x00000001;
--                                                      
pci_write_config32(NODE_PCI(node, 0), 0x174, dword);
-+                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174, dword);
-                                               } else {
-                                                       /* Set ConnDly to 1 */
-                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
-                                                       dword |= 0x00000100;
-                                                       
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
-                                                       /* Set TransOff and 
EndOfChain to 1 */
--                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xa4);
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4);
-                                                       dword |= 0x000000c0;
--                                                      
pci_write_config32(NODE_PCI(node, 4), 0xa4, dword);
-+                                                      
pci_write_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4, dword);
-                                               }
-                                       }
-                               }
-diff --git a/src/northbridge/amd/amdmct/amddefs.h 
b/src/northbridge/amd/amdmct/amddefs.h
-index 117fea5..20a77d3 100644
---- a/src/northbridge/amd/amdmct/amddefs.h
-+++ b/src/northbridge/amd/amdmct/amddefs.h
-@@ -20,33 +20,35 @@
- /* FIXME: this file should be moved to include/cpu/amd/amddefs.h */
- 
- /* Public Revisions - USE THESE VERSIONS TO MAKE COMPARE WITH CPULOGICALID 
RETURN VALUE*/
--#define       AMD_SAFEMODE    0x80000000      /* Unknown future revision - 
SAFE MODE */
--#define       AMD_NPT_F0      0x00000001      /* F0 stepping */
--#define       AMD_NPT_F1      0x00000002      /* F1 stepping */
--#define       AMD_NPT_F2C     0x00000004
--#define       AMD_NPT_F2D     0x00000008
--#define       AMD_NPT_F2E     0x00000010      /* F2 stepping E */
--#define       AMD_NPT_F2G     0x00000020      /* F2 stepping G */
--#define       AMD_NPT_F2J     0x00000040
--#define       AMD_NPT_F2K     0x00000080
--#define       AMD_NPT_F3L     0x00000100      /* F3 Stepping */
--#define       AMD_NPT_G0A     0x00000200      /* G0 stepping */
--#define       AMD_NPT_G1B     0x00000400      /* G1 stepping */
--#define       AMD_DR_A0A      0x00010000      /* Barcelona A0 */
--#define       AMD_DR_A1B      0x00020000      /* Barcelona A1 */
--#define       AMD_DR_A2       0x00040000      /* Barcelona A2 */
--#define       AMD_DR_B0       0x00080000      /* Barcelona B0 */
--#define       AMD_DR_B1       0x00100000      /* Barcelona B1 */
--#define       AMD_DR_B2       0x00200000      /* Barcelona B2 */
--#define       AMD_DR_BA       0x00400000      /* Barcelona BA */
--#define       AMD_DR_B3       0x00800000      /* Barcelona B3 */
--#define       AMD_RB_C2       0x01000000      /* Shanghai C2 */
--#define       AMD_DA_C2       0x02000000      /* XXXX C2 */
--#define       AMD_HY_D0       0x04000000      /* Istanbul D0 */
--#define       AMD_RB_C3       0x08000000      /* ??? C3 */
--#define       AMD_DA_C3       0x10000000      /* XXXX C3 */
--#define       AMD_HY_D1       0x20000000      /* Istanbul D1 */
--#define       AMD_PH_E0       0x40000000      /* Phenom II X4 X6 */
-+#define       AMD_SAFEMODE    0x8000000000000000      /* Unknown future 
revision - SAFE MODE */
-+#define       AMD_NPT_F0      0x0000000000000001      /* F0 stepping */
-+#define       AMD_NPT_F1      0x0000000000000002      /* F1 stepping */
-+#define       AMD_NPT_F2C     0x0000000000000004
-+#define       AMD_NPT_F2D     0x0000000000000008
-+#define       AMD_NPT_F2E     0x0000000000000010      /* F2 stepping E */
-+#define       AMD_NPT_F2G     0x0000000000000020      /* F2 stepping G */
-+#define       AMD_NPT_F2J     0x0000000000000040
-+#define       AMD_NPT_F2K     0x0000000000000080
-+#define       AMD_NPT_F3L     0x0000000000000100      /* F3 Stepping */
-+#define       AMD_NPT_G0A     0x0000000000000200      /* G0 stepping */
-+#define       AMD_NPT_G1B     0x0000000000000400      /* G1 stepping */
-+#define       AMD_DR_A0A      0x0000000000010000      /* Barcelona A0 */
-+#define       AMD_DR_A1B      0x0000000000020000      /* Barcelona A1 */
-+#define       AMD_DR_A2       0x0000000000040000      /* Barcelona A2 */
-+#define       AMD_DR_B0       0x0000000000080000      /* Barcelona B0 */
-+#define       AMD_DR_B1       0x0000000000100000      /* Barcelona B1 */
-+#define       AMD_DR_B2       0x0000000000200000      /* Barcelona B2 */
-+#define       AMD_DR_BA       0x0000000000400000      /* Barcelona BA */
-+#define       AMD_DR_B3       0x0000000000800000      /* Barcelona B3 */
-+#define       AMD_RB_C2       0x0000000001000000      /* Shanghai C2 */
-+#define       AMD_DA_C2       0x0000000002000000      /* XXXX C2 */
-+#define       AMD_HY_D0       0x0000000004000000      /* Istanbul D0 */
-+#define       AMD_RB_C3       0x0000000008000000      /* ??? C3 */
-+#define       AMD_DA_C3       0x0000000010000000      /* XXXX C3 */
-+#define       AMD_HY_D1       0x0000000020000000      /* Istanbul D1 */
-+#define       AMD_PH_E0       0x0000000040000000      /* Phenom II X4 X6 */
-+#define       AMD_OR_B2       0x0000000080000000      /* Interlagos */
-+#define       AMD_OR_C0       0x0000000100000000      /* Abu Dhabi */
- 
- /*
-  * Groups - Create as many as you wish, from the above public values
-@@ -76,6 +78,7 @@
- #define       AMD_DRBH_Cx     (AMD_DR_Cx | AMD_HY_D0 )
- #define       AMD_DRBA23_RBC2 (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 )
- #define       AMD_DR_DAC2_OR_C3       (AMD_DA_C2 | AMD_DA_C3 | AMD_RB_C3)
-+#define       AMD_FAM15_ALL   (AMD_OR_B2 | AMD_OR_C0)
- 
- /*
-  *  Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH 
CPUPLATFORMTYPE RETURN VALUE
-@@ -122,23 +125,34 @@
-  */
- #define CPUID_EXT_PM          0x80000007
- #define CPUID_MODEL           1
--#define MCG_CAP               0x00000179
-+#define MCG_CAP                       0x00000179
-       #define MCG_CTL_P       8
--#define MC0_CTL               0x00000400
--#define MC0_STA               MC0_CTL + 1
--#define FS_Base               0xC0000100
-+#define MC0_CTL                       0x00000400
-+#define MC0_STA                       (MC0_CTL + 1)
-+#define MC4_MISC0             0x00000413
-+#define MC4_MISC1             0xC0000408
-+#define MC4_MISC2             0xC0000409
-+#define FS_Base                       0xC0000100
- #define SYSCFG                        0xC0010010
- #define HWCR                  0xC0010015
- #define NB_CFG                        0xC001001F
- #define FidVidStatus          0xC0010042
-+#define MC1_CTL_MASK          0xC0010045
- #define MC4_CTL_MASK          0xC0010048
- #define OSVW_ID_Length                0xC0010140
- #define OSVW_Status           0xC0010141
- #define CPUIDFEATURES         0xC0011004
- #define LS_CFG                        0xC0011020
-+#define IC_CFG                        0xC0011021
- #define DC_CFG                        0xC0011022
- #define BU_CFG                        0xC0011023
--#define BU_CFG2               0xC001102A
-+#define FP_CFG                        0xC0011028
-+#define DE_CFG                        0xC0011029
-+#define BU_CFG2                       0xC001102A
-+#define BU_CFG3                       0xC001102B
-+#define EX_CFG                        0xC001102C
-+#define LS_CFG2                       0xC001102D
-+#define IBS_OP_DATA3          0xC0011037
- 
- /*
-  * Processor package types
-diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c 
b/src/northbridge/amd/amdmct/mct/mct_d.c
-index 88910e2..be0af65 100644
---- a/src/northbridge/amd/amdmct/mct/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct/mct_d.c
-@@ -2189,6 +2189,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                                       
pDCTstat->DimmManufacturerID[i] |= ((uint64_t)mctRead_SPD(smbaddr, 
SPD_MANID_START + k)) << (k * 8);
-                                               for (k = 0; k < 
SPD_PARTN_LENGTH; k++)
-                                                       
pDCTstat->DimmPartNumber[i][k] = mctRead_SPD(smbaddr, SPD_PARTN_START + k);
-+                                              
pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
-                                               pDCTstat->DimmRevisionNumber[i] 
= 0;
-                                               for (k = 0; k < 2; k++)
-                                                       
pDCTstat->DimmRevisionNumber[i] |= ((uint16_t)mctRead_SPD(smbaddr, 
SPD_REVNO_START + k)) << (k * 8);
-@@ -2206,8 +2207,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                       if (byte & JED_REGADCMSK) {
-                                               RegDIMMPresent |= 1 << i;
-                                               pDCTstat->DimmRegistered[i] = 1;
--                                      }
--                                      else {
-+                                      } else {
-                                               pDCTstat->DimmRegistered[i] = 0;
-                                       }
-                                       /* Check ECC capable */
-diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h 
b/src/northbridge/amd/amdmct/mct/mct_d.h
-index 132bdc9..6b6194d 100644
---- a/src/northbridge/amd/amdmct/mct/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct/mct_d.h
-@@ -434,7 +434,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-               /* CH A byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
-               /* CH B byte lane 0 - 7 minimum filtered window  passing DQS 
delay value*/
-               /* CH B byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
--      u32 LogicalCPUID;       /* The logical CPUID of the node*/
-+      uint64_t LogicalCPUID;  /* The logical CPUID of the node*/
-       u16 HostBiosSrvc1;      /* Word sized general purpose field for use by 
host BIOS.  Scratch space.*/
-       u32 HostBiosSrvc2;      /* Dword sized general purpose field for use by 
host BIOS.  Scratch space.*/
-       u16 DimmQRPresent;      /* QuadRank DIMM present?*/
-@@ -529,7 +529,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-       uint8_t DimmRegistered[MAX_DIMMS_SUPPORTED];
- 
-       uint64_t DimmManufacturerID[MAX_DIMMS_SUPPORTED];
--      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH];
-+      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
-       uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
-       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
- } __attribute__((packed));
-@@ -598,17 +598,18 @@ struct DCTStatStruc {            /* A per Node 
structure*/
-                                           266=266MHz (DDR533)
-                                           333=333MHz (DDR667)
-                                           400=400MHz (DDR800)*/
--#define NV_ECC_CAP            4       /* Bus ECC capable (1-bits)
-+#define NV_MIN_MEMCLK         4       /* Minimum platform demonstrated 
Memclock (10-bits) */
-+#define NV_ECC_CAP            5       /* Bus ECC capable (1-bits)
-                                           0=Platform not capable
-                                           1=Platform is capable*/
--#define NV_4RANKType          5       /* Quad Rank DIMM slot type (2-bits)
-+#define NV_4RANKType          6       /* Quad Rank DIMM slot type (2-bits)
-                                           0=Normal
-                                           1=R4 (4-Rank Registered DIMMs in 
AMD server configuration)
-                                           2=S4 (Unbuffered SO-DIMMs)*/
--#define NV_BYPMAX             6       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
-+#define NV_BYPMAX             7       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
-                                           4=4 times bypass (normal for 
non-UMA systems)
-                                           7=7 times bypass (normal for UMA 
systems)*/
--#define NV_RDWRQBYP           7       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
-+#define NV_RDWRQBYP           8       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
-                                           2=8 times (normal for non-UMA 
systems)
-                                           3=16 times (normal for UMA 
systems)*/
- 
-@@ -671,8 +672,9 @@ struct DCTStatStruc {              /* A per Node 
structure*/
- #define NV_ECCRedir           54      /* Dram ECC Redirection enable*/
- #define NV_DramBKScrub                55      /* Dram ECC Background Scrubber 
CTL*/
- #define NV_L2BKScrub          56      /* L2 ECC Background Scrubber CTL*/
--#define NV_DCBKScrub          57      /* DCache ECC Background Scrubber CTL*/
--#define NV_CS_SpareCTL                58      /* Chip Select Spare Control 
bit 0:
-+#define NV_L3BKScrub          57      /* L3 ECC Background Scrubber CTL*/
-+#define NV_DCBKScrub          58      /* DCache ECC Background Scrubber CTL*/
-+#define NV_CS_SpareCTL                59      /* Chip Select Spare Control 
bit 0:
-                                              0=disable Spare
-                                              1=enable Spare */
-                                       /* Chip Select Spare Control bit 1-4:
-@@ -712,7 +714,7 @@ u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
- u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 
RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
- void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
--u32 mctGetLogicalCPUID(u32 Node);
-+uint64_t mctGetLogicalCPUID(u32 Node);
- u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
- void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA, u8 Pass);
- void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
-diff --git a/src/northbridge/amd/amdmct/mct/mctpro_d.c 
b/src/northbridge/amd/amdmct/mct/mctpro_d.c
-index c332357..fe56201 100644
---- a/src/northbridge/amd/amdmct/mct/mctpro_d.c
-+++ b/src/northbridge/amd/amdmct/mct/mctpro_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -23,7 +24,7 @@ void EarlySampleSupport_D(void)
- 
- u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val)
- {
--      u32 tmp;
-+      uint64_t tmp;
-       tmp = pDCTstat->LogicalCPUID;
-       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
-               val &= 0x0FFFFFFF;
-@@ -42,7 +43,7 @@ u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val)
-        * ( F2x[1, 0]8C[1:0] > 00b).  Silicon Status: Fixed in Rev B
-        * FIXME: check if this is still required.
-        */
--      u32 tmp;
-+      uint64_t tmp;
-       tmp = pDCTstat->LogicalCPUID;
-       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
-               if(!(val & (3<<12) ))
-@@ -54,7 +55,7 @@ u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val)
- 
- void mct_ForceAutoPrecharge_D(struct DCTStatStruc *pDCTstat, u32 dct)
- {
--      u32 tmp;
-+      uint64_t tmp;
-       u32 reg;
-       u32 reg_off;
-       u32 dev;
-@@ -96,7 +97,7 @@ void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,
-        * FIXME: check this.
-        */
- 
--      u32 tmp;
-+      uint64_t tmp;
-       u32 dev;
-       u32 reg;
-       u32 val;
-@@ -143,10 +144,9 @@ void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc 
*pMCTstat,
-       u32 index;
-       u32 reg;
-       u32 val;
--      u32 tmp;
-+      uint64_t tmp;
-       u32 Channel;
- 
--
-       tmp = pDCTstat->LogicalCPUID;
-       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
- 
-@@ -206,7 +206,7 @@ u32 Modify_D3CMP(struct DCTStatStruc *pDCTstat, u32 dct, 
u32 value)
-       u32 index_reg;
-       u32 index;
-       u32 val;
--      u32 tmp;
-+      uint64_t tmp;
- 
-       tmp = pDCTstat->LogicalCPUID;
-       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
-@@ -237,7 +237,7 @@ void SyncSetting(struct DCTStatStruc *pDCTstat)
-        * Silicon Status: Fix TBD
-        */
- 
--      u32 tmp;
-+      uint64_t tmp;
-       tmp = pDCTstat->LogicalCPUID;
-       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
-               pDCTstat->CH_ODC_CTL[1] = pDCTstat->CH_ODC_CTL[0];
-@@ -278,7 +278,7 @@ u32 CheckNBCOFAutoPrechg(struct DCTStatStruc *pDCTstat, 
u32 dct)
- 
- void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct)
- {
--      u32 tmp;
-+      uint64_t tmp;
-       u32 Speed;
-       u32 ch, ch_start, ch_end;
-       u32 index_reg;
-@@ -286,7 +286,6 @@ void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, 
u32 dct)
-       u32 dev;
-       u32 val;
- 
--
-       tmp = pDCTstat->LogicalCPUID;
-       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
-               Speed = pDCTstat->Speed;
-@@ -331,7 +330,7 @@ static u8 mct_checkFenceHoleAdjust_D(struct MCTStatStruc 
*pMCTstat,
-                               u8 ChipSel,  u8 *result)
- {
-       u8 ByteLane;
--      u32 tmp;
-+      uint64_t tmp;
- 
-       tmp = pDCTstat->LogicalCPUID;
-       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 12dfff1..74066b1 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -75,6 +75,8 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct);
- static u16 Get_Fk_D(u8 k);
- static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i);
-+static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat);
- static void mct_initDCT(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat);
- static void mct_DramInit(struct MCTStatStruc *pMCTstat,
-@@ -105,11 +107,11 @@ static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
- static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat);
- static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
--                                      u32 dev, u32 index_reg);
-+                                      u32 dev, uint8_t dct, u32 index_reg);
- static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat, u8 dct,
-                                       u32 dev, u32 index_reg);
- static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
--                              u32 dev, u32 index_reg, u32 index);
-+                              u32 dev, uint8_t dct, u32 index_reg, u32 index);
- static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat);
- static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat, u8 dct,
-@@ -128,6 +130,8 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct);
- static void SetODTTriState(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct);
-+static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat, u8 dct);
- static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct);
- static u32 mct_NodePresent_D(void);
-@@ -138,7 +142,9 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc 
*pMCTstat,
- static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct);
- static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat);
-+                                      struct DCTStatStruc *pDCTstat, u8 dct);
-+static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat, u8 dct);
- void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat);
- static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
-@@ -158,6 +164,10 @@ static u32 mct_DisDllShutdownSR(struct MCTStatStruc 
*pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u32 
DramConfigLo, u8 dct);
- static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct);
-+static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat);
-+void SetTargetFreq(struct MCTStatStruc *pMCTstat,
-+                                        struct DCTStatStruc *pDCTstat);
- 
- static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u32 MrsChipSel);
-@@ -165,7 +175,8 @@ static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc 
*pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dimm);
- static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 
misc2);
- static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat);
--static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA);
-+static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Pass);
- static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct);
- static void SyncSetting(struct DCTStatStruc *pDCTstat);
-@@ -173,6 +184,12 @@ static u8 crcCheck(u8 smbaddr);
- static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
- static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
- 
-+static void read_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay,
-+                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
-+
-+static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay,
-+                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
-+
- /*See mctAutoInitMCT header for index relationships to CL and T*/
- static const u16 Table_F_k[]  = {00,200,266,333,400,533 };
- static const u8 Tab_BankAddr[]        = 
{0x3F,0x01,0x09,0x3F,0x3F,0x11,0x0A,0x19,0x12,0x1A,0x21,0x22,0x23};
-@@ -223,6 +240,936 @@ static const u8 Table_Comp_Rise_Slew_15x[] = {7, 7, 3, 
2, 0xFF};
- static const u8 Table_Comp_Fall_Slew_20x[] = {7, 5, 3, 2, 0xFF};
- static const u8 Table_Comp_Fall_Slew_15x[] = {7, 7, 5, 3, 0xFF};
- 
-+static uint8_t dct_ddr_voltage_index(struct DCTStatStruc *pDCTstat, uint8_t 
dct)
-+{
-+      uint8_t dimm;
-+      uint8_t ddr_voltage_index = 0;
-+
-+      /* Find current DDR supply voltage for this DCT */
-+      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
-+              if (pDCTstat->DIMMValidDCT[dct] & (1 << dimm))
-+                      ddr_voltage_index |= 
pDCTstat->DimmConfiguredVoltage[dimm];
-+      }
-+      if (ddr_voltage_index > 0x7) {
-+              printk(BIOS_DEBUG, "%s: Insufficient DDR supply voltage 
indicated!  Configuring processor for 1.25V operation, but this attempt may 
fail...\n", __func__);
-+              ddr_voltage_index = 0x4;
-+      }
-+      if (ddr_voltage_index == 0x0) {
-+              printk(BIOS_DEBUG, "%s: No DDR supply voltage indicated!  
Configuring processor for 1.5V operation, but this attempt may fail...\n", 
__func__);
-+              ddr_voltage_index = 0x1;
-+      }
-+
-+      return ddr_voltage_index;
-+}
-+
-+static uint16_t fam15h_mhz_to_memclk_config(uint16_t freq)
-+{
-+      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
-+      uint16_t iter;
-+
-+      /* Compute the index value for the given frequency */
-+      for (iter = 0; iter <= 0x16; iter++) {
-+              if (fam15h_freq_tab[iter] == freq)
-+                      break;
-+      }
-+      if (fam15h_freq_tab[iter] == freq)
-+              freq = iter;
-+      if (freq == 0)
-+              freq = 0x4;
-+
-+      return freq;
-+}
-+
-+static uint16_t fam10h_mhz_to_memclk_config(uint16_t freq)
-+{
-+      uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
-+      uint16_t iter;
-+
-+      /* Compute the index value for the given frequency */
-+      for (iter = 0; iter <= 0x6; iter++) {
-+              if (fam10h_freq_tab[iter] == freq)
-+                      break;
-+      }
-+      if (fam10h_freq_tab[iter] == freq)
-+              freq = iter;
-+      if (freq == 0)
-+              freq = 0x3;
-+
-+      return freq;
-+}
-+
-+static uint16_t mhz_to_memclk_config(uint16_t freq)
-+{
-+      if (is_fam15h())
-+              return fam15h_mhz_to_memclk_config(freq);
-+      else
-+              return fam10h_mhz_to_memclk_config(freq) + 1;
-+}
-+
-+static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t drive_strength)
-+{
-+      uint8_t lrdimm = 0;
-+      uint8_t package_type;
-+      uint8_t ddr_voltage_index;
-+      uint32_t calibration_code = 0;
-+      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+
-+      if (!lrdimm) {
-+              /* Not an LRDIMM */
-+              if ((package_type == PT_M2) || (package_type == PT_GR)) {
-+                      /* Socket AM3 or G34 */
-+                      if (ddr_voltage_index & 0x4) {
-+                              /* 1.25V */
-+                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 43 */
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xb6d;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x924;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x6db;
-+                              } else if ((MemClkFreq == 0xa) || (MemClkFreq 
== 0xe)) {
-+                                      /* DDR3-1066 - DDR3-1333 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xdb6;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x924;
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0xfff;
-+                              }
-+                      }
-+                      else if (ddr_voltage_index & 0x2) {
-+                              /* 1.35V */
-+                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 42 */
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x924;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x492;
-+                              } else if ((MemClkFreq == 0xa) || (MemClkFreq 
== 0xe)) {
-+                                      /* DDR3-1066 - DDR3-1333 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xdb6;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xbd6;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x6db;
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0xdb6;
-+                              }
-+                      }
-+                      else if (ddr_voltage_index & 0x1) {
-+                              /* 1.5V */
-+                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 41 */
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xb6d;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x492;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x492;
-+                              } else if ((MemClkFreq == 0xa) || (MemClkFreq 
== 0xe)) {
-+                                      /* DDR3-1066 - DDR3-1333 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x924;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x6db;
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0xb6d;
-+                              }
-+                      }
-+              }
-+              else if (package_type == PT_C3) {
-+                      /* Socket C32 */
-+                      if (ddr_voltage_index & 0x4) {
-+                              /* 1.25V */
-+                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 46 */
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xb6d;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x924;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x6db;
-+                              } else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xdb6;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x924;
-+                              } else if (MemClkFreq == 0xe) {
-+                                      /* DDR3-1333 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xb6d;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x492;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x492;
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0xfff;
-+                              }
-+                      }
-+                      else if (ddr_voltage_index & 0x2) {
-+                              /* 1.35V */
-+                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 45 */
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x924;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x492;
-+                              } else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xdb6;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xb6d;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x6db;
-+                              } else if (MemClkFreq == 0xe) {
-+                                      /* DDR3-1333 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x924;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x492;
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0xdb6;
-+                              }
-+                      }
-+                      else if (ddr_voltage_index & 0x1) {
-+                              /* 1.5V */
-+                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 44 */
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xb6d;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x492;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x492;
-+                              } else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x924;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x6db;
-+                              } else if (MemClkFreq == 0xe) {
-+                                      /* DDR3-1333 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xb6d;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0x6db;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0x492;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0x492;
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-+                                      if (drive_strength == 0x0)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x1)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x2)
-+                                              calibration_code = 0xfff;
-+                                      else if (drive_strength == 0x3)
-+                                              calibration_code = 0xb6d;
-+                              }
-+                      }
-+              }
-+      } else {
-+              /* LRDIMM */
-+
-+              /* TODO
-+               * Implement LRDIMM support
-+               * See Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Tables 47 - 49
-+               */
-+      }
-+
-+      return calibration_code;
-+}
-+
-+static uint32_t fam15h_phy_predriver_cmd_addr_calibration_code(struct 
DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength)
-+{
-+      uint8_t ddr_voltage_index;
-+      uint32_t calibration_code = 0;
-+      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
-+
-+      if (ddr_voltage_index & 0x4) {
-+              /* 1.25V */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 52 */
-+              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-+                      /* DDR3-667 - DDR3-800 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x492;
-+              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
-+                      /* DDR3-1066 - DDR3-1333 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xdad;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x6db;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x492;
-+              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
-+                      /* DDR3-1600 - DDR3-1866 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xdad;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xb64;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xb64;
-+              }
-+      }
-+      else if (ddr_voltage_index & 0x2) {
-+              /* 1.35V */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 51 */
-+              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-+                      /* DDR3-667 - DDR3-800 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x492;
-+              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
-+                      /* DDR3-1066 - DDR3-1333 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0x6db;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x6db;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x6db;
-+              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
-+                      /* DDR3-1600 - DDR3-1866 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xb6d;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xb6d;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x924;
-+              }
-+      }
-+      else if (ddr_voltage_index & 0x1) {
-+              /* 1.5V */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 50 */
-+              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-+                      /* DDR3-667 - DDR3-800 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x492;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x492;
-+              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
-+                      /* DDR3-1066 - DDR3-1333 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0x6db;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0x6db;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x6db;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x6db;
-+              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
-+                      /* DDR3-1600 - DDR3-1866 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xb6d;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xb6d;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xb6d;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xb6d;
-+              }
-+      }
-+
-+      return calibration_code;
-+}
-+
-+static uint32_t fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t drive_strength)
-+{
-+      uint8_t ddr_voltage_index;
-+      uint32_t calibration_code = 0;
-+      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
-+
-+      if (ddr_voltage_index & 0x4) {
-+              /* 1.25V */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 55 */
-+              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-+                      /* DDR3-667 - DDR3-800 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xdad;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xdad;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x924;
-+              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
-+                      /* DDR3-1066 - DDR3-1333 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xff6;
-+              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
-+                      /* DDR3-1600 - DDR3-1866 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xff6;
-+              }
-+      }
-+      else if (ddr_voltage_index & 0x2) {
-+              /* 1.35V */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 54 */
-+              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-+                      /* DDR3-667 - DDR3-800 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xdad;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xdad;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x924;
-+              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
-+                      /* DDR3-1066 - DDR3-1333 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xdad;
-+              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
-+                      /* DDR3-1600 - DDR3-1866 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xdad;
-+              }
-+      }
-+      else if (ddr_voltage_index & 0x1) {
-+              /* 1.5V */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 53 */
-+              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-+                      /* DDR3-667 - DDR3-800 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0x924;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0x924;
-+              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
-+                      /* DDR3-1066 - DDR3-1333 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xb6d;
-+              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
-+                      /* DDR3-1600 - DDR3-1866 */
-+                      if (drive_strength == 0x0)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x1)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x2)
-+                              calibration_code = 0xff6;
-+                      else if (drive_strength == 0x3)
-+                              calibration_code = 0xff6;
-+              }
-+      }
-+
-+      return calibration_code;
-+}
-+
-+static uint32_t fam15h_output_driver_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
-+{
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      uint8_t package_type;
-+      uint32_t calibration_code = 0;
-+
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      /* Obtain number of DIMMs on channel */
-+      uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+
-+      if (package_type == PT_GR) {
-+              /* Socket G34 */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-+              if (MaxDimmsInstallable == 1) {
-+                      if (MemClkFreq == 0x4) {
-+                              /* DDR3-667 */
-+                              calibration_code = 0x00112222;
-+                      }
-+                      else if (MemClkFreq == 0x6) {
-+                              /* DDR3-800 */
-+                              calibration_code = 0x10112222;
-+                      }
-+                      else if (MemClkFreq == 0xa) {
-+                              /* DDR3-1066 */
-+                              calibration_code = 0x20112222;
-+                      }
-+                      else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) {
-+                              /* DDR3-1333 - DDR3-1600 */
-+                              calibration_code = 0x30112222;
-+                      }
-+                      else if (MemClkFreq == 0x16) {
-+                              /* DDR3-1866 */
-+                              calibration_code = 0x30332222;
-+                      }
-+              } else if (MaxDimmsInstallable == 2) {
-+                      if (dimm_count == 1) {
-+                              /* 1 DIMM detected */
-+                              if (MemClkFreq == 0x4) {
-+                                      /* DDR3-667 */
-+                                      calibration_code = 0x00112222;
-+                              }
-+                              else if (MemClkFreq == 0x6) {
-+                                      /* DDR3-800 */
-+                                      calibration_code = 0x10112222;
-+                              }
-+                              else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      calibration_code = 0x20112222;
-+                              }
-+                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
-+                                      /* DDR3-1333 - DDR3-1600 */
-+                                      calibration_code = 0x30112222;
-+                              }
-+                      } else if (dimm_count == 2) {
-+                              /* 2 DIMMs detected */
-+                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                              if (MemClkFreq == 0x4) {
-+                                      /* DDR3-667 */
-+                                      calibration_code = 0x10222222;
-+                              }
-+                              else if (MemClkFreq == 0x6) {
-+                                      /* DDR3-800 */
-+                                      calibration_code = 0x20222222;
-+                              }
-+                              else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      calibration_code = 0x30222222;
-+                              }
-+                              else if (MemClkFreq == 0xe) {
-+                                      /* DDR3-1333 */
-+                                      calibration_code = 0x30222222;
-+                              }
-+                              else if (MemClkFreq == 0x12) {
-+                                      /* DDR3-1600 */
-+                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-+                                              calibration_code = 0x30222222;
-+                                      else
-+                                              calibration_code = 0x30112222;
-+                              }
-+                      }
-+              } else if (MaxDimmsInstallable == 3) {
-+                      /* TODO
-+                       * 3 DIMM/channel support unimplemented
-+                       */
-+              }
-+      } else {
-+              /* TODO
-+               * Other socket support unimplemented
-+               */
-+      }
-+
-+      return calibration_code;
-+}
-+
-+static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
-+{
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      uint8_t package_type;
-+      uint32_t calibration_code = 0;
-+
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      /* Obtain number of DIMMs on channel */
-+      uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+
-+      if (package_type == PT_GR) {
-+              /* Socket G34 */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-+              if (MaxDimmsInstallable == 1) {
-+                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                      if (MemClkFreq == 0x4) {
-+                              /* DDR3-667 */
-+                              if (rank_count_dimm0 == 1)
-+                                      calibration_code = 0x00000000;
-+                              else
-+                                      calibration_code = 0x003b0000;
-+                      } else if (MemClkFreq == 0x6) {
-+                              /* DDR3-800 */
-+                              if (rank_count_dimm0 == 1)
-+                                      calibration_code = 0x00000000;
-+                              else
-+                                      calibration_code = 0x003b0000;
-+                      } else if (MemClkFreq == 0xa) {
-+                              /* DDR3-1066 */
-+                              calibration_code = 0x00383837;
-+                      } else if (MemClkFreq == 0xe) {
-+                              /* DDR3-1333 */
-+                              calibration_code = 0x00363635;
-+                      } else if (MemClkFreq == 0x12) {
-+                              /* DDR3-1600 */
-+                              if (rank_count_dimm0 == 1)
-+                                      calibration_code = 0x00353533;
-+                              else
-+                                      calibration_code = 0x00003533;
-+                      } else if (MemClkFreq == 0x16) {
-+                              /* DDR3-1866 */
-+                              calibration_code = 0x00333330;
-+                      }
-+              } else if (MaxDimmsInstallable == 2) {
-+                      if (dimm_count == 1) {
-+                              /* 1 DIMM detected */
-+                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                              if (MemClkFreq == 0x4) {
-+                                      /* DDR3-667 */
-+                                      if (rank_count_dimm0 == 1)
-+                                              calibration_code = 0x00000000;
-+                                      else
-+                                              calibration_code = 0x003b0000;
-+                              } else if (MemClkFreq == 0x6) {
-+                                      /* DDR3-800 */
-+                                      if (rank_count_dimm0 == 1)
-+                                              calibration_code = 0x00000000;
-+                                      else
-+                                              calibration_code = 0x003b0000;
-+                              } else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      calibration_code = 0x00383837;
-+                              } else if (MemClkFreq == 0xe) {
-+                                      /* DDR3-1333 */
-+                                      calibration_code = 0x00363635;
-+                              } else if (MemClkFreq == 0x12) {
-+                                      /* DDR3-1600 */
-+                                      if (rank_count_dimm0 == 1)
-+                                              calibration_code = 0x00353533;
-+                                      else
-+                                              calibration_code = 0x00003533;
-+                              }
-+                      } else if (dimm_count == 2) {
-+                              /* 2 DIMMs detected */
-+                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                              if (MemClkFreq == 0x4) {
-+                                      /* DDR3-667 */
-+                                      calibration_code = 0x00390039;
-+                              } else if (MemClkFreq == 0x6) {
-+                                      /* DDR3-800 */
-+                                      calibration_code = 0x00390039;
-+                              } else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      calibration_code = 0x003a3a3a;
-+                              } else if (MemClkFreq == 0xe) {
-+                                      /* DDR3-1333 */
-+                                      calibration_code = 0x00003939;
-+                              } else if (MemClkFreq == 0x12) {
-+                                      /* DDR3-1600 */
-+                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-+                                              calibration_code = 0x00003738;
-+                              }
-+                      }
-+              } else if (MaxDimmsInstallable == 3) {
-+                      /* TODO
-+                       * 3 DIMM/channel support unimplemented
-+                       */
-+              }
-+      } else {
-+              /* TODO
-+               * Other socket support unimplemented
-+               */
-+      }
-+
-+      return calibration_code;
-+}
-+
-+static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t 
dct)
-+{
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      uint8_t package_type;
-+      uint32_t slow_access = 0;
-+
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      /* Obtain number of DIMMs on channel */
-+      uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+
-+      if (package_type == PT_GR) {
-+              /* Socket G34 */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-+              if (MaxDimmsInstallable == 1) {
-+                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                      if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
-+                              || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) {
-+                              /* DDR3-667 - DDR3-1333 */
-+                              slow_access = 0;
-+                      } else if ((MemClkFreq == 0x12) || (MemClkFreq == 
0x16)) {
-+                              /* DDR3-1600 - DDR3-1866 */
-+                              if (rank_count_dimm0 == 1)
-+                                      slow_access = 0;
-+                              else
-+                                      slow_access = 1;
-+                      }
-+              } else if (MaxDimmsInstallable == 2) {
-+                      if (dimm_count == 1) {
-+                              /* 1 DIMM detected */
-+                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
-+                                      || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
-+                                      /* DDR3-667 - DDR3-1333 */
-+                                      slow_access = 0;
-+                              }
-+                              else if (MemClkFreq == 0x12) {
-+                                      /* DDR3-1600 */
-+                                      if (rank_count_dimm0 == 1)
-+                                              slow_access = 0;
-+                                      else
-+                                              slow_access = 1;
-+                              }
-+                      } else if (dimm_count == 2) {
-+                              /* 2 DIMMs detected */
-+                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
-+                                      || (MemClkFreq == 0xa)) {
-+                                      /* DDR3-667 - DDR3-1066 */
-+                                      slow_access = 0;
-+                              }
-+                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
-+                                      /* DDR3-1333 - DDR3-1600 */
-+                                      slow_access = 1;
-+                              }
-+                      }
-+              } else if (MaxDimmsInstallable == 3) {
-+                      /* TODO
-+                       * 3 DIMM/channel support unimplemented
-+                       */
-+              }
-+      } else {
-+              /* TODO
-+               * Other socket support unimplemented
-+               */
-+      }
-+
-+      return slow_access;
-+}
-+
-+static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, u8 dct)
-+{
-+      uint32_t dev;
-+      uint32_t reg;
-+      uint32_t dword;
-+
-+      uint8_t enable_slow_access_mode = 0;
-+      dev = pDCTstat->dev_dct;
-+
-+      if (is_fam15h()) {
-+              if (pDCTstat->_2Tmode)
-+                      enable_slow_access_mode = 1;
-+      } else {
-+              if (pDCTstat->_2Tmode == 2)
-+                      enable_slow_access_mode = 1;
-+      }
-+
-+      reg = 0x94;                             /* DRAM Configuration High */
-+      dword = Get_NB32_DCT(dev, dct, reg);
-+      if (enable_slow_access_mode)
-+              dword |= (0x1 << 20);           /* Set 2T CMD mode */
-+      else
-+              dword &= ~(0x1 << 20);          /* Clear 2T CMD mode */
-+      Set_NB32_DCT(dev, dct, reg, dword);
-+}
-+
-+static void precise_ndelay_fam15(struct MCTStatStruc *pMCTstat, uint32_t 
nanoseconds) {
-+      msr_t tsc_msr;
-+      uint64_t cycle_count = (((uint64_t)pMCTstat->TSCFreq) * nanoseconds) / 
1000;
-+      uint64_t start_timestamp;
-+      uint64_t current_timestamp;
-+
-+      tsc_msr = rdmsr(0x00000010);
-+      start_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo;
-+        do {
-+              tsc_msr = rdmsr(0x00000010);
-+              current_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo;
-+        } while ((current_timestamp - start_timestamp) < cycle_count);
-+}
-+
-+static void precise_memclk_delay_fam15(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, uint8_t dct, uint32_t clocks) {
-+      uint16_t memclk_freq;
-+      uint32_t delay_ns;
-+      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
-+
-+      memclk_freq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      delay_ns = (((uint64_t)clocks * 1000) / fam15h_freq_tab[memclk_freq]);
-+      precise_ndelay_fam15(pMCTstat, delay_ns);
-+}
-+
- static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstatA)
- {
-@@ -277,10 +1224,26 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
- restartinit:
-       mctInitMemGPIOs_A_D();          /* Set any required GPIOs*/
-       if (s3resume) {
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_En_Fam15\n");
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
-+
-+                      mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
-+              }
-+
- #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
-               restore_mct_information_from_nvram();
- #endif
-+
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
-+
-+                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
-+              }
-       } else {
-               NodesWmem = 0;
-               node_sys_base = 0;
-@@ -297,15 +1260,15 @@ restartinit:
-                       pDCTstat->dev_map = PA_MAP(Node);
-                       pDCTstat->dev_dct = PA_DCT(Node);
-                       pDCTstat->dev_nbmisc = PA_NBMISC(Node);
-+                      pDCTstat->dev_link = PA_LINK(Node);
-+                      pDCTstat->dev_nbctl = PA_NBCTL(Node);
-                       pDCTstat->NodeSysBase = node_sys_base;
- 
-                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node 
%d\n", Node);
-                       mct_init(pMCTstat, pDCTstat);
-                       mctNodeIDDebugPort_D();
-                       pDCTstat->NodePresent = NodePresent_D(Node);
--                      if (pDCTstat->NodePresent) {            /* See if Node 
is there*/
--                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
--                              clear_legacy_Mode(pMCTstat, pDCTstat);
-+                      if (pDCTstat->NodePresent) {
-                               pDCTstat->LogicalCPUID = 
mctGetLogicalCPUID_D(Node);
- 
-                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
-@@ -314,6 +1277,26 @@ restartinit:
-                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
-                               mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
- 
-+                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_preInitDCT\n");
-+                              mct_preInitDCT(pMCTstat, pDCTstat);
-+                      }
-+                      node_sys_base = pDCTstat->NodeSysBase;
-+                      node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
-+              }
-+
-+#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
-+              DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
-+#endif
-+
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
-+
-+                      if (pDCTstat->NodePresent) {
-+                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
-+                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
-+
-                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_initDCT\n");
-                               mct_initDCT(pMCTstat, pDCTstat);
-                               if (pDCTstat->ErrCode == SC_FatalErr) {
-@@ -321,20 +1304,13 @@ restartinit:
-                               } else if (pDCTstat->ErrCode < SC_StopError) {
-                                       NodesWmem++;
-                               }
--                      }       /* if Node present */
--                      node_sys_base = pDCTstat->NodeSysBase;
--                      node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
-+                      }
-               }
-               if (NodesWmem == 0) {
-                       printk(BIOS_DEBUG, "No Nodes?!\n");
-                       goto fatalexit;
-               }
- 
--#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
--              DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
--#endif
--
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
-               SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are 
ready for accesses.*/
- 
-@@ -355,7 +1331,6 @@ restartinit:
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
-               mct_OtherTiming(pMCTstat, pDCTstatA);
- 
--
-               if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 
1st pass of DIMM spare enabled*/
-                       goto restartinit;
-               }
-@@ -369,6 +1344,14 @@ restartinit:
-                       MCTMemClr_D(pMCTstat,pDCTstatA);
-               }
- 
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
-+
-+                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
-+              }
-+
-               mct_FinalMCT_D(pMCTstat, pDCTstatA);
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: 
%x\n", pMCTstat->GStatus);
-       }
-@@ -408,6 +1391,425 @@ static u8 ReconfigureDIMMspare_D(struct MCTStatStruc 
*pMCTstat,
-       return ret;
- }
- 
-+/* Enable or disable phy-assisted training mode
-+ * Phy-assisted training mode applies to the follow DRAM training procedures:
-+ * Write Levelization Training (2.10.5.8.1)
-+ * DQS Receiver Enable Training (2.10.5.8.2)
-+ */
-+static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
-+                      struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t 
enable)
-+{
-+      uint8_t index;
-+      uint32_t dword;
-+      uint32_t index_reg = 0x98;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      if (enable) {
-+              /* Enable training mode */
-+              dword = Get_NB32_DCT(dev, dct, 0x78);                   /* DRAM 
Control */
-+              dword &= ~(0x1 << 17);                                  /* 
AddrCmdTriEn = 0 */
-+              Set_NB32_DCT(dev, dct, 0x78, dword);                    /* DRAM 
Control */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x8c);                   /* DRAM 
Timing High */
-+              dword |= (0x1 << 18);                                   /* 
DisAutoRefresh = 1 */
-+              Set_NB32_DCT(dev, dct, 0x8c, dword);                    /* DRAM 
Timing High */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x94);                   /* DRAM 
Configuration High */
-+              dword &= ~(0xf << 24);                                  /* 
DcqBypassMax = 0 */
-+              dword &= ~(0x1 << 22);                                  /* 
BankSwizzleMode = 0 */
-+              dword &= ~(0x1 << 15);                                  /* 
PowerDownEn = 0 */
-+              dword &= ~(0x3 << 10);                                  /* 
ZqcsInterval = 0 */
-+              Set_NB32_DCT(dev, dct, 0x94, dword);                    /* DRAM 
Configuration High */
-+
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d);
-+              dword &= ~(0xf << 16);                                  /* 
RxMaxDurDllNoLock = 0 */
-+              dword &= ~(0xf);                                        /* 
TxMaxDurDllNoLock = 0 */
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword);
-+
-+              for (index = 0; index < 0x9; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0010 | (index << 8));
-+                      dword &= ~(0x1 << 12);                          /* 
EnRxPadStandby = 0 */
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 
| (index << 8), dword);
-+              }
-+
-+              dword = Get_NB32_DCT(dev, dct, 0xa4);                   /* DRAM 
Controller Temperature Throttle */
-+              dword &= ~(0x1 << 11);                                  /* 
BwCapEn = 0 */
-+              dword &= ~(0x1 << 8);                                   /* 
ODTSEn = 0 */
-+              Set_NB32_DCT(dev, dct, 0xa4, dword);                    /* DRAM 
Controller Temperature Throttle */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* DRAM 
Controller Select Low */
-+              dword &= ~(0x1 << 2);                                   /* 
DctSelIntLvEn = 0 */
-+              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
-+
-+              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58);  /* 
Scrub Rate Control */
-+              dword &= ~(0x1f << 24);                                 /* 
L3Scrub = 0 */
-+              dword &= ~(0x1f);                                       /* 
DramScrub = 0 */
-+              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* 
Scrub Rate Control */
-+
-+              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM 
Scrub Address Low */
-+              dword &= ~(0x1);                                        /* 
ScrubReDirEn = 0 */
-+              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM 
Scrub Address Low */
-+
-+              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 
Control 1 */
-+              dword |= (0x1 << 4);                                    /* 
L3ScrbRedirDis = 1 */
-+              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 
Control 1 */
-+
-+              /* Fam15h BKDG section 2.10.5.5.1 */
-+              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
-+              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0xb */
-+              dword |= (0xb << 24);
-+              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = 0xb */
-+              dword |= (0xb << 16);
-+              dword &= ~(0xf);                                        /* 
TrdrdDd = 0xb */
-+              dword |= 0xb;
-+              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
-+
-+              /* Fam15h BKDG section 2.10.5.5.2 */
-+              dword = Get_NB32_DCT(dev, dct, 0x214);                  /* DRAM 
Timing 4 */
-+              dword &= ~(0xf << 16);                                  /* 
TwrwrSdSc = 0xb */
-+              dword |= (0xb << 16);
-+              dword &= ~(0xf << 8);                                   /* 
TwrwrSdDc = 0xb */
-+              dword |= (0xb << 8);
-+              dword &= ~(0xf);                                        /* 
TwrwrDd = 0xb */
-+              dword |= 0xb;
-+              Set_NB32_DCT(dev, dct, 0x214, dword);                   /* DRAM 
Timing 4 */
-+
-+              /* Fam15h BKDG section 2.10.5.5.3 */
-+              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
-+              dword &= ~(0xf << 8);                                   /* 
Twrrd = 0xb */
-+              dword |= (0xb << 8);
-+              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
-+
-+              /* Fam15h BKDG section 2.10.5.5.4 */
-+              dword = Get_NB32_DCT(dev, dct, 0x21c);                  /* DRAM 
Timing 6 */
-+              dword &= ~(0x1f << 8);                                  /* 
TrwtTO = 0x16 */
-+              dword |= (0x16 << 8);
-+              dword &= ~(0x1f << 16);                                 /* 
TrwtWB = TrwtTO + 1 */
-+              dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
-+              Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
-+      } else {
-+              /* Disable training mode */
-+              uint8_t lane;
-+              uint8_t dimm;
-+              uint8_t receiver;
-+              uint8_t max_lane;
-+              uint8_t ecc_enabled;
-+              uint8_t x4_present = 0;
-+              uint8_t x8_present = 0;
-+              uint8_t memclk_index;
-+              uint8_t interleave_channels = 0;
-+              uint8_t redirect_ecc_scrub = 0;
-+              uint16_t trdrdsddc;
-+              uint16_t trdrddd;
-+              uint16_t cdd_trdrddd;
-+              uint16_t twrwrsddc;
-+              uint16_t twrwrdd;
-+              uint16_t cdd_twrwrdd;
-+              uint16_t twrrd;
-+              uint16_t trwtto;
-+              uint8_t first_dimm;
-+              uint16_t delay;
-+              uint16_t delay2;
-+              uint8_t read_odt_delay;
-+              uint8_t write_odt_delay;
-+              uint16_t difference;
-+              uint16_t current_total_delay_1[MAX_BYTE_LANES];
-+              uint16_t current_total_delay_2[MAX_BYTE_LANES];
-+
-+              /* FIXME
-+               * This should be platform configurable
-+               */
-+              uint8_t dimm_event_l_pin_support = 0;
-+
-+              ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs);
-+              if (ecc_enabled)
-+                      max_lane = 9;
-+              else
-+                      max_lane = 8;
-+
-+              if (pDCTstat->Dimmx4Present & ((dct)?0xaa:0x55))
-+                      x4_present = 1;
-+              if (pDCTstat->Dimmx8Present & ((dct)?0xaa:0x55))
-+                      x8_present = 1;
-+              memclk_index = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
-+
-+              if (pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1] && 
mctGet_NVbits(NV_Unganged))
-+                      interleave_channels = 1;
-+
-+              if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
-+                      redirect_ecc_scrub = 1;
-+
-+              dword = (Get_NB32_DCT(dev, dct, 0x240) >> 4) & 0xf;
-+              if (dword > 6)
-+                      read_odt_delay = dword - 6;
-+              else
-+                      read_odt_delay = 0;
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x240);
-+              delay = (dword >> 4) & 0xf;
-+              if (delay > 6)
-+                      read_odt_delay = delay - 6;
-+              else
-+                      read_odt_delay = 0;
-+              delay = (dword >> 12) & 0x7;
-+              if (delay > 6)
-+                      write_odt_delay = delay - 6;
-+              else
-+                      write_odt_delay = 0;
-+
-+              /* TODO:
-+               * Adjust trdrdsddc if four-rank DIMMs are installed per
-+               * section 2.10.5.5.1 of the Family 15h BKDG.
-+               * cdd_trdrdsddc will also need to be calculated in that 
process.
-+               */
-+              trdrdsddc = 3;
-+
-+              /* Calculate the Critical Delay Difference for TrdrdDd */
-+              cdd_trdrddd = 0;
-+              first_dimm = 1;
-+              for (receiver = 0; receiver < 8; receiver += 2) {
-+                      dimm = (receiver >> 1);
-+
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
-+                              continue;
-+
-+                      
read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, 
dimm, index_reg);
-+
-+                      if (first_dimm) {
-+                              memcpy(current_total_delay_1, 
current_total_delay_2, sizeof(current_total_delay_1));
-+                              first_dimm = 0;
-+                      }
-+
-+                      for (lane = 0; lane < max_lane; lane++) {
-+                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
-+                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
-+                              else
-+                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
-+
-+                              if (difference > cdd_trdrddd)
-+                                      cdd_trdrddd = difference;
-+                      }
-+              }
-+
-+              /* Convert the difference to MEMCLKs */
-+              cdd_trdrddd = (((cdd_trdrddd >> 5) & 0x1f) + 1) / 2;
-+
-+              /* Calculate Trdrddd */
-+              delay = (read_odt_delay + 3) * 2;
-+              delay2 = cdd_trdrddd + 7;
-+              if (delay2 > delay)
-+                      delay = delay2;
-+              trdrddd = (delay + 1) / 2;      /* + 1 is equivalent to ceiling 
function here */
-+              if (trdrdsddc > trdrddd)
-+                      trdrddd = trdrdsddc;
-+
-+              /* TODO:
-+               * Adjust twrwrsddc if four-rank DIMMs are installed per
-+               * section 2.10.5.5.1 of the Family 15h BKDG.
-+               * cdd_twrwrsddc will also need to be calculated in that 
process.
-+               */
-+              twrwrsddc = 4;
-+
-+              /* Calculate the Critical Delay Difference for TwrwrDd */
-+              cdd_twrwrdd = 0;
-+              first_dimm = 1;
-+              for (receiver = 0; receiver < 8; receiver += 2) {
-+                      dimm = (receiver >> 1);
-+
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
-+                              continue;
-+
-+                      
read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, 
index_reg);
-+
-+                      if (first_dimm) {
-+                              memcpy(current_total_delay_1, 
current_total_delay_2, sizeof(current_total_delay_1));
-+                              first_dimm = 0;
-+                      }
-+
-+                      for (lane = 0; lane < max_lane; lane++) {
-+                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
-+                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
-+                              else
-+                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
-+
-+                              if (difference > cdd_twrwrdd)
-+                                      cdd_twrwrdd = difference;
-+                      }
-+              }
-+
-+              /* Convert the difference to MEMCLKs */
-+              cdd_twrwrdd = (((cdd_twrwrdd >> 5) & 0x1f) + 1) / 2;
-+
-+              /* Calculate Twrwrdd */
-+              delay = (write_odt_delay + 3) * 2;
-+              delay2 = cdd_twrwrdd + 7;
-+              if (delay2 > delay)
-+                      delay = delay2;
-+              twrwrdd = (delay + 1) / 2;      /* + 1 is equivalent to ceiling 
function here */
-+              if (twrwrsddc > twrwrdd)
-+                      twrwrdd = twrwrsddc;
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x78);                   /* DRAM 
Control */
-+              dword |= (0x1 << 17);                                   /* 
AddrCmdTriEn = 1 */
-+              Set_NB32_DCT(dev, dct, 0x78, dword);                    /* DRAM 
Control */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x8c);                   /* DRAM 
Timing High */
-+              dword &= ~(0x1 << 18);                                  /* 
DisAutoRefresh = 0 */
-+              Set_NB32_DCT(dev, dct, 0x8c, dword);                    /* DRAM 
Timing High */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x94);                   /* DRAM 
Configuration High */
-+              dword |= (0xf << 24);                                   /* 
DcqBypassMax = 0xf */
-+              dword |= (0x1 << 22);                                   /* 
BankSwizzleMode = 1 */
-+              dword |= (0x1 << 15);                                   /* 
PowerDownEn = 1 */
-+              dword &= ~(0x3 << 10);                                  /* 
ZqcsInterval = 0x2 */
-+              dword |= (0x2 << 10);
-+              Set_NB32_DCT(dev, dct, 0x94, dword);                    /* DRAM 
Configuration High */
-+
-+              if (x4_present && x8_present) {
-+                      /* Mixed channel of 4x and 8x DIMMs */
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d);
-+                      dword &= ~(0x3 << 24);                                  
/* RxDLLWakeupTime = 0 */
-+                      dword &= ~(0x7 << 20);                                  
/* RxCPUpdPeriod = 0 */
-+                      dword &= ~(0xf << 16);                                  
/* RxMaxDurDllNoLock = 0 */
-+                      dword &= ~(0x3 << 8);                                   
/* TxDLLWakeupTime = 0 */
-+                      dword &= ~(0x7 << 4);                                   
/* TxCPUpdPeriod = 0 */
-+                      dword &= ~(0xf);                                        
/* TxMaxDurDllNoLock = 0 */
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d, dword);
-+              } else {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d);
-+                      dword &= ~(0x3 << 24);                                  
/* RxDLLWakeupTime = 3 */
-+                      dword |= (0x3 << 24);
-+                      dword &= ~(0x7 << 20);                                  
/* RxCPUpdPeriod = 3 */
-+                      dword |= (0x3 << 20);
-+                      dword &= ~(0xf << 16);                                  
/* RxMaxDurDllNoLock = 7 */
-+                      dword |= (0x7 << 16);
-+                      dword &= ~(0x3 << 8);                                   
/* TxDLLWakeupTime = 3 */
-+                      dword |= (0x3 << 8);
-+                      dword &= ~(0x7 << 4);                                   
/* TxCPUpdPeriod = 3 */
-+                      dword |= (0x3 << 4);
-+                      dword &= ~(0xf);                                        
/* TxMaxDurDllNoLock = 7 */
-+                      dword |= 0x7;
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d, dword);
-+              }
-+
-+              if ((memclk_index <= 0x12) && (x4_present != x8_present)) {
-+                      /* MemClkFreq <= 800MHz
-+                       * Not a mixed channel of x4 and x8 DIMMs
-+                       */
-+                      for (index = 0; index < 0x9; index++) {
-+                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0010 | (index << 8));
-+                              dword |= (0x1 << 12);                           
/* EnRxPadStandby = 1 */
-+                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0010 | (index << 8), dword);
-+                      }
-+              } else {
-+                      for (index = 0; index < 0x9; index++) {
-+                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0010 | (index << 8));
-+                              dword &= ~(0x1 << 12);                          
/* EnRxPadStandby = 0 */
-+                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0010 | (index << 8), dword);
-+                      }
-+              }
-+
-+              /* TODO
-+               * Calculate Twrrd per section 2.10.5.5.3 of the Family 15h BKDG
-+               */
-+              twrrd = 0xb;
-+
-+              /* TODO
-+               * Calculate TrwtTO per section 2.10.5.5.4 of the Family 15h 
BKDG
-+               */
-+              trwtto = 0x16;
-+
-+              dword = Get_NB32_DCT(dev, dct, 0xa4);                   /* DRAM 
Controller Temperature Throttle */
-+              dword &= ~(0x1 << 11);                                  /* 
BwCapEn = 0 */
-+              dword &= ~(0x1 << 8);                                   /* 
ODTSEn = dimm_event_l_pin_support */
-+              dword |= (dimm_event_l_pin_support & 0x1) << 8;
-+              Set_NB32_DCT(dev, dct, 0xa4, dword);                    /* DRAM 
Controller Temperature Throttle */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* DRAM 
Controller Select Low */
-+              dword &= ~(0x1 << 2);                                   /* 
DctSelIntLvEn = interleave_channels */
-+              dword |= (interleave_channels & 0x1) << 2;
-+              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
-+
-+              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58);  /* 
Scrub Rate Control */
-+              dword &= ~(0x1f << 24);                                 /* 
L3Scrub = NV_L3BKScrub */
-+              dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
-+              dword &= ~(0x1f);                                       /* 
DramScrub = NV_DramBKScrub */
-+              dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f;
-+              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* 
Scrub Rate Control */
-+
-+              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM 
Scrub Address Low */
-+              dword &= ~(0x1);                                        /* 
ScrubReDirEn = redirect_ecc_scrub */
-+              dword |= redirect_ecc_scrub & 0x1;
-+              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM 
Scrub Address Low */
-+
-+              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 
Control 1 */
-+              dword &= ~(0x1 << 4);                                   /* 
L3ScrbRedirDis = 0 */
-+              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 
Control 1 */
-+
-+              /* FIXME
-+               * The BKDG-recommended settings cause memory corruption on the 
ASUS KGPE-D16.
-+               * Investigate and fix...
-+               */
-+#if 0
-+              /* Fam15h BKDG section 2.10.5.5.1 */
-+              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
-+              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0x1 */
-+              dword |= (0x1 << 24);
-+              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = trdrdsddc */
-+              dword |= ((trdrdsddc & 0xf) << 16);
-+              dword &= ~(0xf);                                        /* 
TrdrdDd = trdrddd */
-+              dword |= (trdrddd & 0xf);
-+              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
-+#endif
-+
-+              /* Fam15h BKDG section 2.10.5.5.2 */
-+              dword = Get_NB32_DCT(dev, dct, 0x214);                  /* DRAM 
Timing 4 */
-+              dword &= ~(0xf << 16);                                  /* 
TwrwrSdSc = 0x1 */
-+              dword |= (0x1 << 16);
-+              dword &= ~(0xf << 8);                                   /* 
TwrwrSdDc = twrwrsddc */
-+              dword |= ((twrwrsddc & 0xf) << 8);
-+              dword &= ~(0xf);                                        /* 
TwrwrDd = twrwrdd */
-+              dword |= (twrwrdd & 0xf);
-+              Set_NB32_DCT(dev, dct, 0x214, dword);                   /* DRAM 
Timing 4 */
-+
-+              /* Fam15h BKDG section 2.10.5.5.3 */
-+              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
-+              dword &= ~(0xf << 8);                                   /* 
Twrrd = twrrd */
-+              dword |= ((twrrd & 0xf) << 8);
-+              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
-+
-+              /* Fam15h BKDG section 2.10.5.5.4 */
-+              dword = Get_NB32_DCT(dev, dct, 0x21c);                  /* DRAM 
Timing 6 */
-+              dword &= ~(0x1f << 8);                                  /* 
TrwtTO = trwtto */
-+              dword |= ((trwtto & 0x1f) << 8);
-+              dword &= ~(0x1f << 16);                                 /* 
TrwtWB = TrwtTO + 1 */
-+              dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
-+              Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
-+
-+              /* Enable prefetchers */
-+              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* 
Memory Controller Configuration High */
-+              dword &= ~(0x1 << 13);                                  /* 
PrefIoDis = 0 */
-+              dword &= ~(0x1 << 12);                                  /* 
PrefCpuDis = 0 */
-+              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* 
Memory Controller Configuration High */
-+      }
-+}
-+
-+static void exit_training_mode_fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstatA)
-+{
-+      uint8_t node;
-+      uint8_t dct;
-+
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              struct DCTStatStruc *pDCTstat;
-+              pDCTstat = pDCTstatA + node;
-+
-+              if (pDCTstat->NodePresent)
-+                      for (dct = 0; dct < 2; dct++)
-+                              fam15EnableTrainingMode(pMCTstat, pDCTstat, 
dct, 0);
-+      }
-+}
-+
- static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstatA)
- {
-@@ -424,6 +1826,20 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
-       phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
- 
-+      if (is_fam15h()) {
-+              uint8_t Node;
-+              struct DCTStatStruc *pDCTstat;
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      pDCTstat = pDCTstatA + Node;
-+                      if (pDCTstat->NodePresent) {
-+                              if (pDCTstat->DIMMValidDCT[0])
-+                                      InitPhyCompensation(pMCTstat, pDCTstat, 
0);
-+                              if (pDCTstat->DIMMValidDCT[1])
-+                                      InitPhyCompensation(pMCTstat, pDCTstat, 
1);
-+                      }
-+              }
-+      }
-+
-       if (nv_DQSTrainCTL) {
-               mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
-               /* TODO: should be in mctHookBeforeAnyTraining */
-@@ -431,16 +1847,35 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-               _WRMSR(0x26D, 0x04040404, 0x04040404);
-               _WRMSR(0x26E, 0x04040404, 0x04040404);
-               _WRMSR(0x26F, 0x04040404, 0x04040404);
--              mct_WriteLevelization_HW(pMCTstat, pDCTstatA);
-+              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
- 
--              TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
-+              if (is_fam15h()) {
-+                      /* Receiver Enable Training Pass 1 */
-+                      TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
-+              }
- 
--              mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
-+              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass);
-+
-+              if (is_fam15h()) {
-+                      /* Receiver Enable Training Pass 2 */
-+                      // TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass);
-+
-+                      /* TODO:
-+                       * Determine why running TrainReceiverEn_D in SecondPass
-+                       * mode yields less stable training values than when run
-+                       * in FirstPass mode as in the HACK below.
-+                       */
-+                      TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
-+              } else {
-+                      TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
-+              }
- 
--              /* Second Pass never used for Barcelona! */
--              /* TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass); */
-+              mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
- 
--              mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
-+              if (is_fam15h())
-+                      exit_training_mode_fam15(pMCTstat, pDCTstatA);
-+              else
-+                      mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
- 
-               /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
-               mctHookAfterAnyTraining();
-@@ -476,7 +1911,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
-                       for (Channel = 0;Channel < 2; Channel++) {
-                               /* there are four receiver pairs,
-                                  loosely associated with chipselects.*/
--                              index_reg = 0x98 + Channel * 0x100;
-+                              index_reg = 0x98;
-                               for (Receiver = 0; Receiver < 8; Receiver += 2) 
{
-                                       /* Set Receiver Enable Values */
-                                       mct_SetRcvrEnDly_D(pDCTstat,
-@@ -492,7 +1927,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
-                                               txdqs = 
pDCTstat->CH_D_B_TxDqs[Channel][Receiver >> 1][ByteLane];
-                                               index = 
Table_DQSRcvEn_Offset[ByteLane >> 1];
-                                               index += (Receiver >> 1) * 3 + 
0x10 + 0x20; /* Addl_Index */
--                                              val = Get_NB32_index_wait(dev, 
0x98 + 0x100*Channel, index);
-+                                              val = 
Get_NB32_index_wait_DCT(dev, Channel, 0x98, index);
-                                               if (ByteLane & 1) { /* odd byte 
lane */
-                                                       val &= ~(0xFF << 16);
-                                                       val |= txdqs << 16;
-@@ -500,7 +1935,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
-                                                       val &= ~0xFF;
-                                                       val |= txdqs;
-                                               }
--                                              Set_NB32_index_wait(dev, 0x98 + 
0x100*Channel, index, val);
-+                                              Set_NB32_index_wait_DCT(dev, 
Channel, 0x98, index, val);
-                                       }
-                               }
-                       }
-@@ -510,7 +1945,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
- 
-                       for (Channel = 0; Channel < 2; Channel++) {
-                               u8 *p;
--                              index_reg = 0x98 + Channel * 0x100;
-+                              index_reg = 0x98;
- 
-                               /* NOTE:
-                                * when 400, 533, 667, it will support 
dimm0/1/2/3,
-@@ -525,7 +1960,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
-                                       if (DIMM == 0) {
-                                               index = 0;      /* CHA Write 
Data Timing Low */
-                                       } else {
--                                              if (pDCTstat->Speed >= 4) {
-+                                              if (pDCTstat->Speed >= 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-                                                       index = 0x100 * DIMM;
-                                               } else {
-                                                       break;
-@@ -534,23 +1969,23 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
-                                       for (Dir = 0; Dir < 2; Dir++) {/* RD/WR 
*/
-                                               p = 
pDCTstat->CH_D_DIR_B_DQS[Channel][DIMM][Dir];
-                                               val = stream_to_int(p); /* CHA 
Read Data Timing High */
--                                              Set_NB32_index_wait(dev, 
index_reg, index+1, val);
-+                                              Set_NB32_index_wait_DCT(dev, 
Channel, index_reg, index+1, val);
-                                               val = stream_to_int(p+4); /* 
CHA Write Data Timing High */
--                                              Set_NB32_index_wait(dev, 
index_reg, index+2, val);
-+                                              Set_NB32_index_wait_DCT(dev, 
Channel, index_reg, index+2, val);
-                                               val = *(p+8); /* CHA Write ECC 
Timing */
--                                              Set_NB32_index_wait(dev, 
index_reg, index+3, val);
-+                                              Set_NB32_index_wait_DCT(dev, 
Channel, index_reg, index+3, val);
-                                               index += 4;
-                                       }
-                               }
-                       }
- 
-                       for (Channel = 0; Channel<2; Channel++) {
--                              reg = 0x78 + Channel * 0x100;
--                              val = Get_NB32(dev, reg);
-+                              reg = 0x78;
-+                              val = Get_NB32_DCT(dev, Channel, reg);
-                               val &= ~(0x3ff<<22);
-                               val |= ((u32) pDCTstat->CH_MaxRdLat[Channel] << 
22);
-                               val &= ~(1<<DqsRcvEnTrain);
--                              Set_NB32(dev, reg, val);        /* program 
MaxRdLatency to correspond with current delay*/
-+                              Set_NB32_DCT(dev, Channel, reg, val);   /* 
program MaxRdLatency to correspond with current delay*/
-                       }
-               }
-       }
-@@ -812,49 +2247,70 @@ finish:
-       return ret;
- }
- 
--static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
-+static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
- {
-       /*
--       * Initialize DRAM on single Athlon 64/Opteron Node.
-+       * Run DCT pre-initialization tasks
-        */
--      u8 stopDCTflag;
--      u32 val;
-+      uint32_t dword;
- 
-+      /* Reset DCT registers */
-       ClearDCT_D(pMCTstat, pDCTstat, dct);
--      stopDCTflag = 1;                /*preload flag with 'disable' */
--      /* enable DDR3 support */
--      val = Get_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100);
--      val |= 1 << Ddr3Mode;
--      Set_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100, val);
-+      pDCTstat->stopDCT = 1;          /*preload flag with 'disable' */
-+
-+      if (!is_fam15h()) {
-+              /* Enable DDR3 support */
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
-+              dword |= 1 << Ddr3Mode;
-+              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
-+      }
-+
-+      /* Read the SPD information into the data structures */
-       if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
-               printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_DIMMPresence Done\n");
--              if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
--                      printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth 
Done\n");
--                      if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
--                              printk(BIOS_DEBUG, "\t\tDCTInit_D: 
AutoCycTiming_D Done\n");
--                              if (AutoConfig_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
--                                      printk(BIOS_DEBUG, "\t\tDCTInit_D: 
AutoConfig_D Done\n");
--                                      if (PlatformSpec_D(pMCTstat, pDCTstat, 
dct) < SC_StopError) {
--                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: PlatformSpec_D Done\n");
--                                              stopDCTflag = 0;
--                                              if (!(pMCTstat->GStatus & (1 << 
GSB_EnDIMMSpareNW))) {
--                                                      printk(BIOS_DEBUG, 
"\t\tDCTInit_D: StartupDCT_D\n");
--                                                      StartupDCT_D(pMCTstat, 
pDCTstat, dct);   /*yeaahhh! */
--                                              }
-+      }
-+}
-+
-+static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
-+{
-+      /*
-+       * Initialize DRAM on single Athlon 64/Opteron Node.
-+       */
-+      uint32_t dword;
-+
-+      if (!is_fam15h()) {
-+              /* (Re)-enable DDR3 support */
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
-+              dword |= 1 << Ddr3Mode;
-+              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
-+      }
-+
-+      if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
-+              printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
-+              if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
-+                      printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D 
Done\n");
-+                      if (AutoConfig_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
-+                              printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D 
Done\n");
-+                              if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
-+                                      printk(BIOS_DEBUG, "\t\tDCTInit_D: 
PlatformSpec_D Done\n");
-+                                      pDCTstat->stopDCT = 0;
-+                                      if (!(pMCTstat->GStatus & (1 << 
GSB_EnDIMMSpareNW))) {
-+                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: StartupDCT_D\n");
-+                                              StartupDCT_D(pMCTstat, 
pDCTstat, dct);   /*yeaahhh! */
-                                       }
-                               }
-                       }
-               }
-       }
- 
--      if (stopDCTflag) {
--              u32 reg_off = dct * 0x100;
--              val = 1<<DisDramInterface;
--              Set_NB32(pDCTstat->dev_dct, reg_off+0x94, val);
--              /*To maximize power savings when DisDramInterface=1b,
--                all of the MemClkDis bits should also be set.*/
--              val = 0xFF000000;
--              Set_NB32(pDCTstat->dev_dct, reg_off+0x88, val);
-+      if (pDCTstat->stopDCT) {
-+              dword = 1 << DisDramInterface;
-+              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
-+
-+              /* To maximize power savings when DisDramInterface=1b,
-+               * all of the MemClkDis bits should also be set.
-+               */
-+              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x88, 0xff000000);
-       } else {
-               mct_EnDllShutdownSR(pMCTstat, pDCTstat, dct);
-       }
-@@ -876,20 +2332,24 @@ static void SyncDCTsReady_D(struct MCTStatStruc 
*pMCTstat,
-               pDCTstat = pDCTstatA + Node;
-               mct_SyncDCTsReady(pDCTstat);
-       }
--      /* v6.1.3 */
--      /* re-enable phy compensation engine when dram init is completed on all 
nodes. */
--      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
--              struct DCTStatStruc *pDCTstat;
--              pDCTstat = pDCTstatA + Node;
--              if (pDCTstat->NodePresent) {
--                      if (pDCTstat->DIMMValidDCT[0] > 0 || 
pDCTstat->DIMMValidDCT[1] > 0) {
--                              /* re-enable phy compensation engine when dram 
init on both DCTs is completed. */
--                              val = Get_NB32_index_wait(pDCTstat->dev_dct, 
0x98, 0x8);
--                              val &= ~(1 << DisAutoComp);
--                              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 
0x8, val);
-+
-+      if (!is_fam15h()) {
-+              /* v6.1.3 */
-+              /* re-enable phy compensation engine when dram init is 
completed on all nodes. */
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
-+                      if (pDCTstat->NodePresent) {
-+                              if (pDCTstat->DIMMValidDCT[0] > 0 || 
pDCTstat->DIMMValidDCT[1] > 0) {
-+                                      /* re-enable phy compensation engine 
when dram init on both DCTs is completed. */
-+                                      val = 
Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8);
-+                                      val &= ~(1 << DisAutoComp);
-+                                      Set_NB32_index_wait(pDCTstat->dev_dct, 
0x98, 0x8, val);
-+                              }
-                       }
-               }
-       }
-+
-       /* wait 750us before any memory access can be made. */
-       mct_Wait(15000);
- }
-@@ -911,10 +2371,9 @@ static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
-        */
-       u32 val;
-       u32 dev;
--      u32 reg_off = dct * 0x100;
- 
-       dev = pDCTstat->dev_dct;
--      val = Get_NB32(dev, 0x94 + reg_off);
-+      val = Get_NB32_DCT(dev, dct, 0x94);
-       if (val & (1<<MemClkFreqVal)) {
-               mctHookBeforeDramInit();        /* generalized Hook */
-               if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)))
-@@ -929,23 +2388,23 @@ static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
- {
-       u32 reg_end;
-       u32 dev = pDCTstat->dev_dct;
--      u32 reg = 0x40 + 0x100 * dct;
-+      u32 reg = 0x40;
-       u32 val = 0;
- 
-       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
--              reg_end = 0x78 + 0x100 * dct;
-+              reg_end = 0x78;
-       } else {
--              reg_end = 0xA4 + 0x100 * dct;
-+              reg_end = 0xA4;
-       }
- 
-       while(reg < reg_end) {
-               if ((reg & 0xFF) == 0x90) {
-                       if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
--                              val = Get_NB32(dev, reg); /* get DRAMConfigLow 
*/
-+                              val = Get_NB32_DCT(dev, dct, reg); /* get 
DRAMConfigLow */
-                               val |= 0x08000000; /* preserve value of 
DisDllShutdownSR for only Rev.D */
-                       }
-               }
--              Set_NB32(dev, reg, val);
-+              Set_NB32_DCT(dev, dct, reg, val);
-               val = 0;
-               reg += 4;
-       }
-@@ -964,6 +2423,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-       u16 Trp, Trrd, Trcd, Tras, Trc;
-       u8 Trfc[4];
-       u16 Tfaw;
-+      u16 Tcwl;       /* Fam15h only */
-       u32 DramTimingLo, DramTimingHi;
-       u8 tCK16x;
-       u16 Twtr;
-@@ -972,10 +2432,11 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-       u8 byte;
-       u32 dword;
-       u32 dev;
--      u32 reg_off;
-       u32 val;
-       u16 smbaddr;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       /* Gather all DIMM mini-max values for cycle timing data */
-       Trp = 0;
-       Trrd = 0;
-@@ -1188,88 +2649,164 @@ static void SPD2ndTiming(struct MCTStatStruc 
*pMCTstat,
- 
-       mctAdjustAutoCycTmg_D();
- 
-+      if (is_fam15h()) {
-+              /* Compute Tcwl (Fam15h BKDG v3.14 Table 203) */
-+              if (pDCTstat->Speed <= 0x6)
-+                      Tcwl = 0x5;
-+              else if (pDCTstat->Speed == 0xa)
-+                      Tcwl = 0x6;
-+              else if (pDCTstat->Speed == 0xe)
-+                      Tcwl = 0x7;
-+              else if (pDCTstat->Speed == 0x12)
-+                      Tcwl = 0x8;
-+              else if (pDCTstat->Speed == 0x16)
-+                      Tcwl = 0x9;
-+              else
-+                      Tcwl = 0x5;     /* Power-on default */
-+      }
-+
-       /* Program DRAM Timing values */
--      DramTimingLo = 0;       /* Dram Timing Low init */
--      val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
--      DramTimingLo |= val;
-+      if (is_fam15h()) {
-+              dev = pDCTstat->dev_dct;
- 
--      val = pDCTstat->Trcd - Bias_TrcdT;
--      DramTimingLo |= val<<4;
-+              dword = Get_NB32_DCT(dev, dct, 0x8c);                           
/* DRAM Timing High */
-+              val = 2;                                                        
/* Tref = 7.8us */
-+              dword &= ~(0x3 << 16);
-+              dword |= (val & 0x3) << 16;
-+              Set_NB32_DCT(dev, dct, 0x8c, dword);                            
/* DRAM Timing High */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x200);                          
/* DRAM Timing 0 */
-+              dword &= ~(0x3f1f1f1f);
-+              dword |= ((pDCTstat->Tras + 0xf) & 0x3f) << 24;                 
/* Tras */
-+              dword |= ((pDCTstat->Trp + 0x5) & 0x1f) << 16;                  
/* Trp */
-+              dword |= ((pDCTstat->Trcd + 0x5) & 0x1f) << 8;                  
/* Trcd */
-+              dword |= (pDCTstat->CASL & 0x1f);                               
/* Tcl */
-+              Set_NB32_DCT(dev, dct, 0x200, dword);                           
/* DRAM Timing 0 */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x204);                          
/* DRAM Timing 1 */
-+              dword &= ~(0x0f3f0f3f);
-+              dword |= ((pDCTstat->Trtp + 0x4) & 0xf) << 24;                  
/* Trtp */
-+              if (pDCTstat->Tfaw != 0)
-+                      dword |= ((((pDCTstat->Tfaw - 0x1) * 2) + 0x10) & 0x3f) 
<< 16;  /* FourActWindow */
-+              dword |= ((pDCTstat->Trrd + 0x4) & 0xf) << 8;                   
/* Trrd */
-+              dword |= ((pDCTstat->Trc + 0xb) & 0x3f);                        
/* Trc */
-+              Set_NB32_DCT(dev, dct, 0x204, dword);                           
/* DRAM Timing 1 */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x208);                          
/* DRAM Timing 2 */
-+              dword &= ~(0x07070707);
-+              dword |= (pDCTstat->Trfc[3] & 0x7) << 24;                       
/* Trfc3 */
-+              dword |= (pDCTstat->Trfc[2] & 0x7) << 16;                       
/* Trfc2 */
-+              dword |= (pDCTstat->Trfc[1] & 0x7) << 8;                        
/* Trfc1 */
-+              dword |= (pDCTstat->Trfc[0] & 0x7);                             
/* Trfc0 */
-+              Set_NB32_DCT(dev, dct, 0x208, dword);                           
/* DRAM Timing 2 */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x20c);                          
/* DRAM Timing 3 */
-+              dword &= ~(0x00000f00);
-+              dword |= ((pDCTstat->Twtr + 0x4) & 0xf) << 8;                   
/* Twtr */
-+              dword &= ~(0x0000001f);
-+              dword |= (Tcwl & 0x1f);                                         
/* Tcwl */
-+              Set_NB32_DCT(dev, dct, 0x20c, dword);                           
/* DRAM Timing 3 */
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x22c);                          
/* DRAM Timing 10 */
-+              dword &= ~(0x0000001f);
-+              dword |= ((pDCTstat->Twr + 0x4) & 0x1f);                        
/* Twr */
-+              Set_NB32_DCT(dev, dct, 0x22c, dword);                           
/* DRAM Timing 10 */
-+
-+              if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-+                      /* Enable phy-assisted training mode */
-+                      fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 1);
-+              }
- 
--      val = pDCTstat->Trp - Bias_TrpT;
--      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
--      DramTimingLo |= val<<7;
-+              /* Other setup (not training specific) */
-+              dword = Get_NB32_DCT(dev, dct, 0x90);                           
/* DRAM Configuration Low */
-+              dword &= ~(0x1 << 23);                                          
/* ForceAutoPchg = 0 */
-+              dword &= ~(0x1 << 20);                                          
/* DynPageCloseEn = 0 */
-+              Set_NB32_DCT(dev, dct, 0x90, dword);                            
/* DRAM Configuration Low */
- 
--      val = pDCTstat->Trtp - Bias_TrtpT;
--      DramTimingLo |= val<<10;
-+              Set_NB32_DCT(dev, dct, 0x228, 0x14141414);                      
/* DRAM Timing 9 */
-+      } else {
-+              DramTimingLo = 0;       /* Dram Timing Low init */
-+              val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
-+              DramTimingLo |= val;
- 
--      val = pDCTstat->Tras - Bias_TrasT;
--      DramTimingLo |= val<<12;
-+              val = pDCTstat->Trcd - Bias_TrcdT;
-+              DramTimingLo |= val<<4;
- 
--      val = pDCTstat->Trc - Bias_TrcT;
--      DramTimingLo |= val<<16;
-+              val = pDCTstat->Trp - Bias_TrpT;
-+              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
-+              DramTimingLo |= val<<7;
- 
--      val = pDCTstat->Trrd - Bias_TrrdT;
--      DramTimingLo |= val<<22;
-+              val = pDCTstat->Trtp - Bias_TrtpT;
-+              DramTimingLo |= val<<10;
- 
--      DramTimingHi = 0;       /* Dram Timing High init */
--      val = pDCTstat->Twtr - Bias_TwtrT;
--      DramTimingHi |= val<<8;
-+              val = pDCTstat->Tras - Bias_TrasT;
-+              DramTimingLo |= val<<12;
- 
--      val = 2;
--      DramTimingHi |= val<<16;
-+              val = pDCTstat->Trc - Bias_TrcT;
-+              DramTimingLo |= val<<16;
- 
--      val = 0;
--      for (i=4;i>0;i--) {
--              val <<= 3;
--              val |= Trfc[i-1];
--      }
--      DramTimingHi |= val << 20;
-+              val = pDCTstat->Trrd - Bias_TrrdT;
-+              DramTimingLo |= val<<22;
- 
--      dev = pDCTstat->dev_dct;
--      reg_off = 0x100 * dct;
--      /* Twr */
--      val = pDCTstat->Twr;
--      if (val == 10)
--              val = 9;
--      else if (val == 12)
--              val = 10;
--      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
--      val -= Bias_TwrT;
--      val <<= 4;
--      dword = Get_NB32(dev, 0x84 + reg_off);
--      dword &= ~0x70;
--      dword |= val;
--      Set_NB32(dev, 0x84 + reg_off, dword);
-+              DramTimingHi = 0;       /* Dram Timing High init */
-+              val = pDCTstat->Twtr - Bias_TwtrT;
-+              DramTimingHi |= val<<8;
- 
--      /* Tfaw */
--      val = pDCTstat->Tfaw;
--      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
--      val -= Bias_TfawT;
--      val >>= 1;
--      val <<= 28;
--      dword = Get_NB32(dev, 0x94 + reg_off);
--      dword &= ~0xf0000000;
--      dword |= val;
--      Set_NB32(dev, 0x94 + reg_off, dword);
--
--      /* dev = pDCTstat->dev_dct; */
--      /* reg_off = 0x100 * dct; */
--
--      if (pDCTstat->Speed > 4) {
--              val = Get_NB32(dev, 0x88 + reg_off);
--              val &= 0xFF000000;
--              DramTimingLo |= val;
--      }
--      Set_NB32(dev, 0x88 + reg_off, DramTimingLo);    /*DCT Timing Low*/
-+              val = 2;                /* Tref = 7.8us */
-+              DramTimingHi |= val<<16;
-+
-+              val = 0;
-+              for (i=4;i>0;i--) {
-+                      val <<= 3;
-+                      val |= Trfc[i-1];
-+              }
-+              DramTimingHi |= val << 20;
-+
-+              dev = pDCTstat->dev_dct;
-+              /* Twr */
-+              val = pDCTstat->Twr;
-+              if (val == 10)
-+                      val = 9;
-+              else if (val == 12)
-+                      val = 10;
-+              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
-+              val -= Bias_TwrT;
-+              val <<= 4;
-+              dword = Get_NB32_DCT(dev, dct, 0x84);
-+              dword &= ~0x70;
-+              dword |= val;
-+              Set_NB32_DCT(dev, dct, 0x84, dword);
-+
-+              /* Tfaw */
-+              val = pDCTstat->Tfaw;
-+              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
-+              val -= Bias_TfawT;
-+              val >>= 1;
-+              val <<= 28;
-+              dword = Get_NB32_DCT(dev, dct, 0x94);
-+              dword &= ~0xf0000000;
-+              dword |= val;
-+              Set_NB32_DCT(dev, dct, 0x94, dword);
-+
-+              /* dev = pDCTstat->dev_dct; */
-+
-+              if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-+                      val = Get_NB32_DCT(dev, dct, 0x88);
-+                      val &= 0xFF000000;
-+                      DramTimingLo |= val;
-+              }
-+              Set_NB32_DCT(dev, dct, 0x88, DramTimingLo);     /*DCT Timing 
Low*/
- 
--      if (pDCTstat->Speed > 4) {
--              DramTimingHi |= 1 << DisAutoRefresh;
-+              if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-+                      DramTimingHi |= 1 << DisAutoRefresh;
-+              }
-+              DramTimingHi |= 0x000018FF;
-+              Set_NB32_DCT(dev, dct, 0x8c, DramTimingHi);     /*DCT Timing 
Hi*/
-       }
--      DramTimingHi |= 0x000018FF;
--      Set_NB32(dev, 0x8c + reg_off, DramTimingHi);    /*DCT Timing Hi*/
- 
-       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
-@@ -1303,6 +2840,8 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
-        * timing mode is 'Auto'.
-        */
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       /* Get primary timing (CAS Latency and Cycle Time) */
-       if (pDCTstat->Speed == 0) {
-               mctGet_MaxLoadFreq(pDCTstat);
-@@ -1312,6 +2851,7 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
- 
-               /* Go get best T and CL as specified by DIMM mfgs. and OEM */
-               SPDGetTCL_D(pMCTstat, pDCTstat, dct);
-+
-               /* skip callback mctForce800to1067_D */
-               pDCTstat->Speed = pDCTstat->DIMMAutoSpeed;
-               pDCTstat->CASL = pDCTstat->DIMMCASL;
-@@ -1344,7 +2884,10 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
-       u16 word;
- 
-       /* Get CPU Si Revision defined limit (NPT) */
--      proposedFreq = 800;      /* Rev F0 programmable max memclock is */
-+      if (is_fam15h())
-+              proposedFreq = 933;
-+      else
-+              proposedFreq = 800;      /* Rev F0 programmable max memclock is 
*/
- 
-       /*Get User defined limit if  "limit" mode */
-       if ( mctGet_NVbits(NV_MCTUSRTMGMODE) == 1) {
-@@ -1381,6 +2924,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-       u16 tCKmin16x;
-       u16 tCKproposed16x;
-       u8 CLactual, CLdesired, CLT_Fail;
-+      uint16_t min_frequency_tck16x;
- 
-       u8 smbaddr, byte = 0, bytex = 0;
- 
-@@ -1390,6 +2934,17 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-       tCKmin16x = 0;
-       CLT_Fail = 0;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-+      if (is_fam15h()) {
-+              uint16_t minimum_frequency_mhz = mctGet_NVbits(NV_MIN_MEMCLK);
-+              if (minimum_frequency_mhz == 0)
-+                      minimum_frequency_mhz = 333;
-+              min_frequency_tck16x = 16000 / minimum_frequency_mhz;
-+      } else {
-+              min_frequency_tck16x = 40;
-+      }
-+
-       for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
-               if (pDCTstat->DIMMValid & (1 << i)) {
-                       smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
-@@ -1419,27 +2974,44 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-                               tCKmin16x = byte * MTB16x;
-               }
-       }
--      /* calculate tCKproposed16x */
-+      /* calculate tCKproposed16x (proposed clock period in ns * 16) */
-       tCKproposed16x =  16000 / pDCTstat->PresetmaxFreq;
-       if (tCKmin16x > tCKproposed16x)
-               tCKproposed16x = tCKmin16x;
- 
--      /* mctHookTwo1333DimmOverride(); */
--      /* For UDIMM, if there are two DDR3-1333 on the same channel,
--         downgrade DDR speed to 1066. */
--
-       /* TODO: get user manual tCK16x(Freq.) and overwrite current 
tCKproposed16x if manual. */
--      if (tCKproposed16x == 20)
--              pDCTstat->TargetFreq = 7;
--      else if (tCKproposed16x <= 24) {
--              pDCTstat->TargetFreq = 6;
--              tCKproposed16x = 24;
--      } else if (tCKproposed16x <= 30) {
--              pDCTstat->TargetFreq = 5;
--              tCKproposed16x = 30;
-+      if (is_fam15h()) {
-+              if (tCKproposed16x == 17)
-+                      pDCTstat->TargetFreq = 0x16;
-+              else if (tCKproposed16x <= 20) {
-+                      pDCTstat->TargetFreq = 0x12;
-+                      tCKproposed16x = 20;
-+              } else if (tCKproposed16x <= 24) {
-+                      pDCTstat->TargetFreq = 0xe;
-+                      tCKproposed16x = 24;
-+              } else if (tCKproposed16x <= 30) {
-+                      pDCTstat->TargetFreq = 0xa;
-+                      tCKproposed16x = 30;
-+              } else if (tCKproposed16x <= 40) {
-+                      pDCTstat->TargetFreq = 0x6;
-+                      tCKproposed16x = 40;
-+              } else {
-+                      pDCTstat->TargetFreq = 0x4;
-+                      tCKproposed16x = 48;
-+              }
-       } else {
--              pDCTstat->TargetFreq = 4;
--              tCKproposed16x = 40;
-+              if (tCKproposed16x == 20)
-+                      pDCTstat->TargetFreq = 7;
-+              else if (tCKproposed16x <= 24) {
-+                      pDCTstat->TargetFreq = 6;
-+                      tCKproposed16x = 24;
-+              } else if (tCKproposed16x <= 30) {
-+                      pDCTstat->TargetFreq = 5;
-+                      tCKproposed16x = 30;
-+              } else {
-+                      pDCTstat->TargetFreq = 4;
-+                      tCKproposed16x = 40;
-+              }
-       }
-       /* Running through this loop twice:
-          - First time find tCL at target frequency
-@@ -1478,27 +3050,42 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-               /* get CL and T */
-               if (!CLT_Fail) {
-                       bytex = CLactual;
--                      if (tCKproposed16x == 20)
--                              byte = 7;
--                      else if (tCKproposed16x == 24)
--                              byte = 6;
--                      else if (tCKproposed16x == 30)
--                              byte = 5;
--                      else
--                              byte = 4;
-+                      if (is_fam15h()) {
-+                              if (tCKproposed16x == 17)
-+                                      byte = 0x16;
-+                              else if (tCKproposed16x == 20)
-+                                      byte = 0x12;
-+                              else if (tCKproposed16x == 24)
-+                                      byte = 0xe;
-+                              else if (tCKproposed16x == 30)
-+                                      byte = 0xa;
-+                              else if (tCKproposed16x == 40)
-+                                      byte = 0x6;
-+                              else
-+                                      byte = 0x4;
-+                      } else {
-+                              if (tCKproposed16x == 20)
-+                                      byte = 7;
-+                              else if (tCKproposed16x == 24)
-+                                      byte = 6;
-+                              else if (tCKproposed16x == 30)
-+                                      byte = 5;
-+                              else
-+                                      byte = 4;
-+                      }
-               } else {
-                       /* mctHookManualCLOverride */
-                       /* TODO: */
-               }
- 
--              if (tCKproposed16x != 40) {
-+              if (tCKproposed16x != min_frequency_tck16x) {
-                       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
-                               pDCTstat->DIMMAutoSpeed = byte;
-                               pDCTstat->DIMMCASL = bytex;
-                               break;
-                       } else {
-                               pDCTstat->TargetCASL = bytex;
--                              tCKproposed16x = 40;
-+                              tCKproposed16x = min_frequency_tck16x;
-                       }
-               } else {
-                       pDCTstat->DIMMAutoSpeed = byte;
-@@ -1519,29 +3106,21 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
- static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 dev;
--      u32 reg;
--      u32 val;
-+      if (!is_fam15h()) {
-+              mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
- 
--      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
-+              if (pDCTstat->GangedMode == 1) {
-+                      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
-+                      mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
-+              }
- 
--      if (pDCTstat->GangedMode == 1) {
--              mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
--              mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
--      }
-+              set_2t_configuration(pMCTstat, pDCTstat, dct);
- 
--      if ( pDCTstat->_2Tmode == 2) {
--              dev = pDCTstat->dev_dct;
--              reg = 0x94 + 0x100 * dct; /* Dram Configuration Hi */
--              val = Get_NB32(dev, reg);
--              val |= 1 << 20;                /* 2T CMD mode */
--              Set_NB32(dev, reg, val);
-+              mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
-+              mct_PlatformSpec(pMCTstat, pDCTstat, dct);
-+              if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
-+                      InitPhyCompensation(pMCTstat, pDCTstat, dct);
-       }
--
--      mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
--      mct_PlatformSpec(pMCTstat, pDCTstat, dct);
--      if (pDCTstat->DIMMAutoSpeed == 4)
--              InitPhyCompensation(pMCTstat, pDCTstat, dct);
-       mctHookAfterPSCfg();
- 
-       return pDCTstat->ErrCode;
-@@ -1553,11 +3132,11 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-       u32 DramControl, DramTimingLo, Status;
-       u32 DramConfigLo, DramConfigHi, DramConfigMisc, DramConfigMisc2;
-       u32 val;
--      u32 reg_off;
-       u32 dev;
-       u16 word;
-       u32 dword;
-       u8 byte;
-+      uint32_t offset;
- 
-       DramConfigLo = 0;
-       DramConfigHi = 0;
-@@ -1577,12 +3156,10 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-       Status = pDCTstat->Status;
- 
-       dev = pDCTstat->dev_dct;
--      reg_off = 0x100 * dct;
--
- 
-       /* Build Dram Control Register Value */
--      DramConfigMisc2 = Get_NB32 (dev, 0xA8 + reg_off);       /* Dram 
Control*/
--      DramControl = Get_NB32 (dev, 0x78 + reg_off);           /* Dram 
Control*/
-+      DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xA8);         /* Dram 
Control*/
-+      DramControl = Get_NB32_DCT(dev, dct, 0x78);             /* Dram 
Control*/
- 
-       /* FIXME: Skip mct_checkForDxSupport */
-       /* REV_CALL mct_DoRdPtrInit if not Dx */
-@@ -1624,8 +3201,12 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-       DramConfigLo = mct_DisDllShutdownSR(pMCTstat, pDCTstat, DramConfigLo, 
dct);
- 
-       /* Build Dram Config Hi Register Value */
-+      if (is_fam15h())
-+              offset = 0x0;
-+      else
-+              offset = 0x1;
-       dword = pDCTstat->Speed;
--      DramConfigHi |= dword - 1;      /* get MemClk encoding */
-+      DramConfigHi |= dword - offset; /* get MemClk encoding */
-       DramConfigHi |= 1 << MemClkFreqVal;
- 
-       if (Status & (1 << SB_Registered))
-@@ -1658,7 +3239,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-               val = 0x0f; /* recommended setting (default) */
-       DramConfigHi |= val << 24;
- 
--      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx))
-+      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx | 
AMD_FAM15_ALL))
-               DramConfigHi |= 1 << DcqArbBypassEn;
- 
-       /* Build MemClkDis Value from Dram Timing Lo and
-@@ -1669,7 +3250,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-           NV_AllMemClks <>0 AND SB_DiagClks ==0 */
- 
-       /* Dram Timing Low (owns Clock Enable bits) */
--      DramTimingLo = Get_NB32(dev, 0x88 + reg_off);
-+      DramTimingLo = Get_NB32_DCT(dev, dct, 0x88);
-       if (mctGet_NVbits(NV_AllMemClks) == 0) {
-               /* Special Jedec SPD diagnostic bit - "enable all clocks" */
-               if (!(pDCTstat->Status & (1<<SB_DiagClks))) {
-@@ -1700,28 +3281,34 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-                               }
-                               dword++ ;
-                       }
-+                      DramTimingLo &= ~(0xff << 24);
-                       DramTimingLo |= byte << 24;
-               }
-       }
- 
--      printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %x\n", DramControl);
--      printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %x\n", DramTimingLo);
--      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %x\n", 
DramConfigMisc);
--      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %x\n", 
DramConfigMisc2);
--      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo: %x\n", DramConfigLo);
--      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi: %x\n", DramConfigHi);
-+      printk(BIOS_DEBUG, "AutoConfig_D: DramControl:     %08x\n", 
DramControl);
-+      printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo:    %08x\n", 
DramTimingLo);
-+      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc:  %08x\n", 
DramConfigMisc);
-+      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %08x\n", 
DramConfigMisc2);
-+      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo:    %08x\n", 
DramConfigLo);
-+      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi:    %08x\n", 
DramConfigHi);
- 
-       /* Write Values to the registers */
--      Set_NB32(dev, 0x78 + reg_off, DramControl);
--      Set_NB32(dev, 0x88 + reg_off, DramTimingLo);
--      Set_NB32(dev, 0xA0 + reg_off, DramConfigMisc);
-+      Set_NB32_DCT(dev, dct, 0x78, DramControl);
-+      Set_NB32_DCT(dev, dct, 0x88, DramTimingLo);
-+      Set_NB32_DCT(dev, dct, 0xa0, DramConfigMisc);
-       DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, 
DramConfigMisc2);
--      Set_NB32(dev, 0xA8 + reg_off, DramConfigMisc2);
--      Set_NB32(dev, 0x90 + reg_off, DramConfigLo);
-+      Set_NB32_DCT(dev, dct, 0xa8, DramConfigMisc2);
-+      Set_NB32_DCT(dev, dct, 0x90, DramConfigLo);
-       ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
--      dword = Get_NB32(dev, 0x94 + reg_off);
-+
-+      if (is_fam15h())
-+              InitDDRPhy(pMCTstat, pDCTstat, dct);
-+
-+      /* Write the DRAM Configuration High register, including memory 
frequency change */
-+      dword = Get_NB32_DCT(dev, dct, 0x94);
-       DramConfigHi |= dword;
--      mct_SetDramConfigHi_D(pDCTstat, dct, DramConfigHi);
-+      mct_SetDramConfigHi_D(pMCTstat, pDCTstat, dct, DramConfigHi);
-       mct_EarlyArbEn_D(pMCTstat, pDCTstat, dct);
-       mctHookAfterAutoCfg();
- 
-@@ -1731,6 +3318,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-       printk(BIOS_DEBUG, "AutoConfig: ErrStatus %x\n", pDCTstat->ErrStatus);
-       printk(BIOS_DEBUG, "AutoConfig: ErrCode %x\n", pDCTstat->ErrCode);
-       printk(BIOS_DEBUG, "AutoConfig: Done\n\n");
-+
- AutoConfig_exit:
-       return pDCTstat->ErrCode;
- }
-@@ -1748,14 +3336,12 @@ static void SPDSetBanks_D(struct MCTStatStruc 
*pMCTstat,
-       u32 val;
-       u32 reg;
-       u32 dev;
--      u32 reg_off;
-       u8 byte;
-       u16 word;
-       u32 dword;
-       u16 smbaddr;
- 
-       dev = pDCTstat->dev_dct;
--      reg_off = 0x100 * dct;
- 
-       BankAddrReg = 0;
-       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel+=2) {
-@@ -1820,10 +3406,10 @@ static void SPDSetBanks_D(struct MCTStatStruc 
*pMCTstat,
-                               /*set ChipSelect population indicator odd bits*/
-                               pDCTstat->CSPresent |= 1 << (ChipSel + 1);
- 
--                      reg = 0x60+(ChipSel<<1) + reg_off;      /*Dram CS Mask 
Register */
-+                      reg = 0x60+(ChipSel<<1);        /*Dram CS Mask Register 
*/
-                       val = csMask;
-                       val &= 0x1FF83FE0;      /* Mask out reserved bits.*/
--                      Set_NB32(dev, reg, val);
-+                      Set_NB32_DCT(dev, dct, reg, val);
-               } else {
-                       if (pDCTstat->DIMMSPDCSE & (1<<ChipSel))
-                               pDCTstat->CSTestFail |= (1<<ChipSel);
-@@ -1847,8 +3433,8 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
-       if (!pDCTstat->CSPresent)
-               pDCTstat->ErrCode = SC_StopError;
- 
--      reg = 0x80 + reg_off;           /* Bank Addressing Register */
--      Set_NB32(dev, reg, BankAddrReg);
-+      reg = 0x80;             /* Bank Addressing Register */
-+      Set_NB32_DCT(dev, dct, reg, BankAddrReg);
- 
-       pDCTstat->CSPresent_DCT[dct] = pDCTstat->CSPresent;
-       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
-@@ -1933,11 +3519,9 @@ static void StitchMemory_D(struct MCTStatStruc 
*pMCTstat,
-       u16 word;
-       u32 dev;
-       u32 reg;
--      u32 reg_off;
-       u32 val;
- 
-       dev = pDCTstat->dev_dct;
--      reg_off = 0x100 * dct;
- 
-       _DSpareEn = 0;
- 
-@@ -1974,11 +3558,11 @@ static void StitchMemory_D(struct MCTStatStruc 
*pMCTstat,
-               BiggestBank = 0;
-               for (q = 0; q < MAX_CS_SUPPORTED; q++) { /* from DIMMS to CS */
-                       if (pDCTstat->CSPresent & (1 << q)) {  /* bank present? 
*/
--                              reg  = 0x40 + (q << 2) + reg_off;  /* Base[q] 
reg.*/
--                              val = Get_NB32(dev, reg);
-+                              reg  = 0x40 + (q << 2);  /* Base[q] reg.*/
-+                              val = Get_NB32_DCT(dev, dct, reg);
-                               if (!(val & 3)) {       /* 
(CSEnable|Spare==1)bank is enabled already? */
--                                      reg = 0x60 + (q << 1) + reg_off; 
/*Mask[q] reg.*/
--                                      val = Get_NB32(dev, reg);
-+                                      reg = 0x60 + (q << 1); /*Mask[q] reg.*/
-+                                      val = Get_NB32_DCT(dev, dct, reg);
-                                       val >>= 19;
-                                       val++;
-                                       val <<= 19;
-@@ -1994,7 +3578,7 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
-               if (BiggestBank !=0) {
-                       curcsBase = nxtcsBase;          /* curcsBase=nxtcsBase*/
-                       /* DRAM CS Base b Address Register offset */
--                      reg = 0x40 + (b << 2) + reg_off;
-+                      reg = 0x40 + (b << 2);
-                       if (_DSpareEn) {
-                               BiggestBank = 0;
-                               val = 1 << Spare;       /* Spare Enable*/
-@@ -2013,7 +3597,7 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
-                                       }
-                               }
-                       }
--                      Set_NB32(dev, reg, val);
-+                      Set_NB32_DCT(dev, dct, reg, val);
-                       if (_DSpareEn)
-                               _DSpareEn = 0;
-                       else
-@@ -2024,9 +3608,9 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
-               /* bank present but disabled?*/
-               if ( pDCTstat->CSTestFail & (1 << p)) {
-                       /* DRAM CS Base b Address Register offset */
--                      reg = (p << 2) + 0x40 + reg_off;
-+                      reg = (p << 2) + 0x40;
-                       val = 1 << TestFail;
--                      Set_NB32(dev, reg, val);
-+                      Set_NB32_DCT(dev, dct, reg, val);
-               }
-       }
- 
-@@ -2064,7 +3648,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-       u16 i, j, k;
-       u8 smbaddr;
-       u8 SPDCtrl;
--      u16 RegDIMMPresent, MaxDimms;
-+      u16 RegDIMMPresent, LRDIMMPresent, MaxDimms;
-       u8 devwidth;
-       u16 DimmSlots;
-       u8 byte = 0, bytex;
-@@ -2077,6 +3661,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-       SPDCtrl = mctGet_NVbits(NV_SPDCHK_RESTRT);
- 
-       RegDIMMPresent = 0;
-+      LRDIMMPresent = 0;
-       pDCTstat->DimmQRPresent = 0;
- 
-       for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
-@@ -2115,6 +3700,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                               pDCTstat->DimmManufacturerID[i] 
|= ((uint64_t)mctRead_SPD(smbaddr, SPD_MANID_START + k)) << (k * 8);
-                                       for (k = 0; k < SPD_PARTN_LENGTH; k++)
-                                               pDCTstat->DimmPartNumber[i][k] 
= mctRead_SPD(smbaddr, SPD_PARTN_START + k);
-+                                      
pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
-                                       pDCTstat->DimmRevisionNumber[i] = 0;
-                                       for (k = 0; k < 2; k++)
-                                               pDCTstat->DimmRevisionNumber[i] 
|= ((uint16_t)mctRead_SPD(smbaddr, SPD_REVNO_START + k)) << (k * 8);
-@@ -2138,6 +3724,12 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                               } else {
-                                       pDCTstat->DimmRegistered[i] = 0;
-                               }
-+                              if (byte == JED_LRDIMM) {
-+                                      LRDIMMPresent |= 1 << i;
-+                                      pDCTstat->DimmLoadReduced[i] = 1;
-+                              } else {
-+                                      pDCTstat->DimmLoadReduced[i] = 0;
-+                              }
-                               /* Check ECC capable */
-                               byte = mctRead_SPD(smbaddr, SPD_BusWidth);
-                               if (byte & JED_ECC) {
-@@ -2221,6 +3813,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-       printk(BIOS_DEBUG, "\t DIMMPresence: DIMMValid=%x\n", 
pDCTstat->DIMMValid);
-       printk(BIOS_DEBUG, "\t DIMMPresence: DIMMPresent=%x\n", 
pDCTstat->DIMMPresent);
-       printk(BIOS_DEBUG, "\t DIMMPresence: RegDIMMPresent=%x\n", 
RegDIMMPresent);
-+      printk(BIOS_DEBUG, "\t DIMMPresence: LRDIMMPresent=%x\n", 
LRDIMMPresent);
-       printk(BIOS_DEBUG, "\t DIMMPresence: DimmECCPresent=%x\n", 
pDCTstat->DimmECCPresent);
-       printk(BIOS_DEBUG, "\t DIMMPresence: DimmPARPresent=%x\n", 
pDCTstat->DimmPARPresent);
-       printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx4Present=%x\n", 
pDCTstat->Dimmx4Present);
-@@ -2247,6 +3840,16 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                               pDCTstat->Status |= 1<<SB_Registered;
-                       }
-               }
-+              if (LRDIMMPresent != 0) {
-+                      if ((LRDIMMPresent ^ pDCTstat->DIMMValid) !=0) {
-+                              /* module type DIMM mismatch (reg'ed, 
unbuffered) */
-+                              pDCTstat->ErrStatus |= 1<<SB_DimmMismatchM;
-+                              pDCTstat->ErrCode = SC_StopError;
-+                      } else{
-+                              /* all DIMMs are registered */
-+                              pDCTstat->Status |= 1<<SB_LoadReduced;
-+                      }
-+              }
-               if (pDCTstat->DimmECCPresent != 0) {
-                       if ((pDCTstat->DimmECCPresent ^ pDCTstat->DIMMValid )== 
0) {
-                               /* all DIMMs are ECC capable */
-@@ -2284,6 +3887,26 @@ static u8 Get_DIMMAddress_D(struct DCTStatStruc 
*pDCTstat, u8 i)
-       return p[i];
- }
- 
-+static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      u8 err_code;
-+
-+      /* Preconfigure DCT0 */
-+      DCTPreInit_D(pMCTstat, pDCTstat, 0);
-+
-+      /* Configure DCT1 if unganged and enabled*/
-+      if (!pDCTstat->GangedMode) {
-+              if (pDCTstat->DIMMValidDCT[1] > 0) {
-+                      err_code = pDCTstat->ErrCode;           /* save DCT0 
errors */
-+                      pDCTstat->ErrCode = 0;
-+                      DCTPreInit_D(pMCTstat, pDCTstat, 1);
-+                      if (pDCTstat->ErrCode == 2)             /* DCT1 is not 
Running */
-+                              pDCTstat->ErrCode = err_code;   /* Using DCT0 
Error code to update pDCTstat.ErrCode */
-+              }
-+      }
-+}
-+
- static void mct_initDCT(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat)
- {
-@@ -2295,7 +3918,7 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
-       if (pDCTstat->ErrCode == SC_FatalErr) {
-               /* Do nothing goto exitDCTInit; any fatal errors? */
-       } else {
--              /* Configure DCT1 if unganged and enabled*/
-+              /* Configure DCT1 if unganged and enabled */
-               if (!pDCTstat->GangedMode) {
-                       if (pDCTstat->DIMMValidDCT[1] > 0) {
-                               err_code = pDCTstat->ErrCode;           /* save 
DCT0 errors */
-@@ -2305,17 +3928,21 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
-                                       pDCTstat->ErrCode = err_code;   /* 
Using DCT0 Error code to update pDCTstat.ErrCode */
-                       } else {
-                               val = 1 << DisDramInterface;
--                              Set_NB32(pDCTstat->dev_dct, 0x100 + 0x94, val);
-+                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
-+
-+                              /* To maximize power savings when 
DisDramInterface=1b,
-+                               * all of the MemClkDis bits should also be set.
-+                               */
-+                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x88, 
0xff000000);
-                       }
-               }
-       }
--/* exitDCTInit: */
- }
- 
- static void mct_DramInit(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat);
-+      mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat, dct);
-       mct_DramInit_Sw_D(pMCTstat, pDCTstat, dct);
-       /* mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct); */
- }
-@@ -2343,7 +3970,8 @@ static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
-               if (byte)
-                       pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO); /* Set 
temp. to avoid setting of ganged mode */
- 
--              if (!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) {
-+              if ((!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) && 
(pDCTstat->LogicalCPUID & AMD_FAM10_ALL)) {
-+                      /* Ganged channel mode not supported on Family 15h or 
higher */
-                       pDCTstat->GangedMode = 1;
-                       /* valid 128-bit mode population. */
-                       pDCTstat->Status |= 1 << SB_128bitmode;
-@@ -2387,10 +4015,8 @@ void Set_NB32_index(u32 dev, u32 index_reg, u32 index, 
u32 data)
- 
- u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index)
- {
--
-       u32 dword;
- 
--
-       index &= ~(1 << DctAccessWrite);
-       Set_NB32(dev, index_reg, index);
-       do {
-@@ -2405,7 +4031,6 @@ void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 
index, u32 data)
- {
-       u32 dword;
- 
--
-       Set_NB32(dev, index_reg + 0x4, data);
-       index |= (1 << DctAccessWrite);
-       Set_NB32(dev, index_reg, index);
-@@ -2420,16 +4045,17 @@ static u8 mct_BeforePlatformSpec(struct MCTStatStruc 
*pMCTstat,
- {
-       /* mct_checkForCxDxSupport_D */
-       if (pDCTstat->LogicalCPUID & AMD_DR_GT_Bx) {
-+              /* Family 10h Errata 322: Address and Command Fine Delay Values 
May Be Incorrect */
-               /* 1. Write 00000000h to F2x[1,0]9C_xD08E000 */
--              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 0x100, 
0x0D08E000, 0);
-+              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D08E000, 0);
-               /* 2. If DRAM Configuration Register[MemClkFreq] 
(F2x[1,0]94[2:0]) is
-                  greater than or equal to 011b (DDR-800 and higher),
-                  then write 00000080h to F2x[1,0]9C_xD02E001,
-                  else write 00000090h to F2x[1,0]9C_xD02E001. */
--              if (pDCTstat->Speed >= 4)
--                      Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 
0x100, 0xD02E001, 0x80);
-+              if (pDCTstat->Speed >= 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D02E001, 0x80);
-               else
--                      Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 
0x100, 0xD02E001, 0x90);
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D02E001, 0x90);
-       }
-       return pDCTstat->ErrCode;
- }
-@@ -2455,9 +4081,9 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
-               i_end = dct + 1;
-       }
-       for (i=i_start; i<i_end; i++) {
--              index_reg = 0x98 + (i * 0x100);
--              Set_NB32_index_wait(dev, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
--              Set_NB32_index_wait(dev, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
-+              index_reg = 0x98;
-+              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
-+              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
-       }
- 
-       return pDCTstat->ErrCode;
-@@ -2511,14 +4137,14 @@ static u8 mct_SPDCalcWidth(struct MCTStatStruc 
*pMCTstat,
-       }
- 
-       if (pDCTstat->DIMMValidDCT[0] == 0) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94);
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-               val |= 1 << DisDramInterface;
--              Set_NB32(pDCTstat->dev_dct, 0x94, val);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
-       }
-       if (pDCTstat->DIMMValidDCT[1] == 0) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-               val |= 1 << DisDramInterface;
--              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
-       }
- 
-       printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
-@@ -2648,21 +4274,20 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct)
- {
-       u32 reg;
--      u32 reg_off = 0x100 * dct;
-       u32 val;
-       u32 dword;
-       u32 dev = pDCTstat->dev_dct;
- 
--      Get_DqsRcvEnGross_Diff(pDCTstat, dev, 0x98 + reg_off);
--      Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98 + reg_off);
-+      Get_DqsRcvEnGross_Diff(pDCTstat, dev, dct, 0x98);
-+      Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98);
-       Get_Trdrd(pMCTstat, pDCTstat, dct);
-       Get_Twrwr(pMCTstat, pDCTstat, dct);
-       Get_Twrrd(pMCTstat, pDCTstat, dct);
-       Get_TrwtTO(pMCTstat, pDCTstat, dct);
-       Get_TrwtWB(pMCTstat, pDCTstat);
- 
--      reg = 0x8C + reg_off;           /* Dram Timing Hi */
--      val = Get_NB32(dev, reg);
-+      reg = 0x8C;             /* Dram Timing Hi */
-+      val = Get_NB32_DCT(dev, dct, reg);
-       val &= 0xffff0300;
-       dword = pDCTstat->TrwtTO;
-       val |= dword << 4;
-@@ -2674,10 +4299,10 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
-       val |= dword << 14;
-       dword = pDCTstat->TrwtWB;
-       val |= dword;
--      Set_NB32(dev, reg, val);
-+      Set_NB32_DCT(dev, dct, reg, val);
- 
--      reg = 0x78 + reg_off;
--      val = Get_NB32(dev, reg);
-+      reg = 0x78;
-+      val = Get_NB32_DCT(dev, dct, reg);
-       val &= 0xFFFFC0FF;
-       dword = pDCTstat->Twrrd >> 2;
-       val |= dword << 8;
-@@ -2685,7 +4310,7 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
-       val |= dword << 10;
-       dword = pDCTstat->Trdrd >> 2;
-       val |= dword << 12;
--      Set_NB32(dev, reg, val);
-+      Set_NB32_DCT(dev, dct, reg, val);
- }
- 
- static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
-@@ -2755,18 +4380,17 @@ static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
- static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
-                          struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 reg_off =  0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 val1, val2;
- 
--      val1 = Get_NB32(dev, reg_off + 0x88) & 0xF;
--      val2 = (Get_NB32(dev, reg_off + 0x84) >> 20) & 7;
-+      val1 = Get_NB32_DCT(dev, dct, 0x88) & 0xF;
-+      val2 = (Get_NB32_DCT(dev, dct, 0x84) >> 20) & 7;
- 
-       return val1 - val2;
- }
- 
- static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
--                                      u32 dev, u32 index_reg)
-+                                      u32 dev, uint8_t dct, u32 index_reg)
- {
-       u8 Smallest, Largest;
-       u32 val;
-@@ -2776,12 +4400,12 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
-          DqsRcvEnGrossDelay of any other DIMM is equal to the Critical
-          Gross Delay Difference (CGDD) */
-       /* DqsRcvEn byte 1,0 */
--      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x10);
-+      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x10);
-       Largest = val & 0xFF;
-       Smallest = (val >> 8) & 0xFF;
- 
-       /* DqsRcvEn byte 3,2 */
--      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x11);
-+      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x11);
-       byte = val & 0xFF;
-       bytex = (val >> 8) & 0xFF;
-       if (bytex < Smallest)
-@@ -2790,7 +4414,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
-               Largest = byte;
- 
-       /* DqsRcvEn byte 5,4 */
--      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x20);
-+      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x20);
-       byte = val & 0xFF;
-       bytex = (val >> 8) & 0xFF;
-       if (bytex < Smallest)
-@@ -2799,7 +4423,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
-               Largest = byte;
- 
-       /* DqsRcvEn byte 7,6 */
--      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x21);
-+      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x21);
-       byte = val & 0xFF;
-       bytex = (val >> 8) & 0xFF;
-       if (bytex < Smallest)
-@@ -2809,7 +4433,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
- 
-       if (pDCTstat->DimmECCPresent> 0) {
-               /*DqsRcvEn Ecc */
--              val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x12);
-+              val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 
0x12);
-               byte = val & 0xFF;
-               bytex = (val >> 8) & 0xFF;
-               if (bytex < Smallest)
-@@ -2873,7 +4497,7 @@ static void Get_WrDatGross_Diff(struct DCTStatStruc 
*pDCTstat,
- }
- 
- static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
--                                      u32 dev, u32 index_reg,
-+                                      u32 dev, uint8_t dct, u32 index_reg,
-                                       u32 index)
- {
-       u8 Smallest, Largest;
-@@ -2891,7 +4515,7 @@ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
- 
-       for (i=0; i < 8; i+=2) {
-               if ( pDCTstat->DIMMValid & (1 << i)) {
--                      val = Get_NB32_index_wait(dev, index_reg, index);
-+                      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
index);
-                       val &= 0x00E000E0;
-                       byte = (val >> 5) & 0xFF;
-                       if (byte < Smallest)
-@@ -2929,7 +4553,7 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
-       Smallest = 3;
-       Largest = 0;
-       for (i=0; i < 2; i++) {
--              val = Get_NB32_index_wait(dev, index_reg, index);
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-               val &= 0x60606060;
-               val >>= 5;
-               for (j=0; j < 4; j++) {
-@@ -2945,7 +4569,7 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
- 
-       if (pDCTstat->DimmECCPresent > 0) {
-               index++;
--              val = Get_NB32_index_wait(dev, index_reg, index);
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-               val &= 0x00000060;
-               val >>= 5;
-               byte = val & 0xFF;
-@@ -2965,25 +4589,30 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
- static void mct_PhyController_Config(struct MCTStatStruc *pMCTstat,
-                                    struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 index_reg = 0x98 + 0x100 * dct;
-+      uint8_t index;
-+      uint32_t dword;
-+      u32 index_reg = 0x98;
-       u32 dev = pDCTstat->dev_dct;
--      u32 val;
- 
--      if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3)) {
-+      if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3 | 
AMD_FAM15_ALL)) {
-               if (pDCTstat->Dimmx4Present == 0) {
--                      /* Set bit7 RxDqsUDllPowerDown  to register F2x[1, 
0]98_x0D0F0F13 for power saving */
--                      val = Get_NB32_index_wait(dev, index_reg, 0x0D0F0F13); 
/* Agesa v3 v6 might be wrong here. */
--                      val |= 1 << 7; /* BIOS should set this bit when x4 
DIMMs are not present */
--                      Set_NB32_index_wait(dev, index_reg, 0x0D0F0F13, val);
-+                      /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 
0]98_x0D0F0F13 for
-+                       * additional power saving when x4 DIMMs are not 
present.
-+                       */
-+                      for (index = 0; index < 0x9; index++) {
-+                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0013 | (index << 8));
-+                              dword |= (0x1 << 7);                            
/* RxDqsUDllPowerDown = 1 */
-+                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0013 | (index << 8), dword);
-+                      }
-               }
-       }
- 
--      if (pDCTstat->LogicalCPUID & AMD_DR_DAC2_OR_C3) {
-+      if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_FAM15_ALL)) {
-               if (pDCTstat->DimmECCPresent == 0) {
-                       /* Set bit4 PwrDn to register F2x[1, 0]98_x0D0F0830 for 
power saving */
--                      val = Get_NB32_index_wait(dev, index_reg, 0x0D0F0830);
--                      val |= 1 << 4; /* BIOS should set this bit if ECC DIMMs 
are not present */
--                      Set_NB32_index_wait(dev, index_reg, 0x0D0F0830, val);
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0830);
-+                      dword |= 1 << 4; /* BIOS should set this bit if ECC 
DIMMs are not present */
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0830, dword);
-               }
-       }
- 
-@@ -3024,21 +4653,61 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
-                               val &= ~(1 << 12);
- 
-                       val &= 0x0FFFFFFF;
--                      switch (pDCTstat->Speed) {
--                      case 4:
--                              val |= 0x50000000; /* 5 for DDR800 */
--                              break;
--                      case 5:
--                              val |= 0x60000000; /* 6 for DDR1066 */
--                              break;
--                      case 6:
--                              val |= 0x80000000; /* 8 for DDR800 */
--                              break;
--                      default:
--                              val |= 0x90000000; /* 9 for DDR1600 */
--                              break;
-+                      if (!is_fam15h()) {
-+                              switch (pDCTstat->Speed) {
-+                              case 4:
-+                                      val |= 0x50000000; /* 5 for DDR800 */
-+                                      break;
-+                              case 5:
-+                                      val |= 0x60000000; /* 6 for DDR1066 */
-+                                      break;
-+                              case 6:
-+                                      val |= 0x80000000; /* 8 for DDR800 */
-+                                      break;
-+                              default:
-+                                      val |= 0x90000000; /* 9 for DDR1600 */
-+                                      break;
-+                              }
-                       }
-                       Set_NB32(pDCTstat->dev_dct, 0x1B0, val);
-+
-+                      if (is_fam15h()) {
-+                              uint8_t wm1;
-+                              uint8_t wm2;
-+
-+                              switch (pDCTstat->Speed) {
-+                              case 0x4:
-+                                      wm1 = 0x3;
-+                                      wm2 = 0x4;
-+                                      break;
-+                              case 0x6:
-+                                      wm1 = 0x3;
-+                                      wm2 = 0x5;
-+                                      break;
-+                              case 0xa:
-+                                      wm1 = 0x4;
-+                                      wm2 = 0x6;
-+                                      break;
-+                              case 0xe:
-+                                      wm1 = 0x5;
-+                                      wm2 = 0x8;
-+                                      break;
-+                              case 0x12:
-+                                      wm1 = 0x6;
-+                                      wm2 = 0x9;
-+                                      break;
-+                              default:
-+                                      wm1 = 0x7;
-+                                      wm2 = 0xa;
-+                                      break;
-+                              }
-+
-+                              val = Get_NB32(pDCTstat->dev_dct, 0x1B4);
-+                              val &= ~(0x3ff);
-+                              val |= ((wm2 & 0x1f) << 5);
-+                              val |= (wm1 & 0x1f);
-+                              Set_NB32(pDCTstat->dev_dct, 0x1B4, val);
-+                      }
-               }
-       }
- 
-@@ -3055,16 +4724,103 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
-       }
- }
- 
-+void mct_ForceNBPState0_En_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      /* Force the NB P-state to P0 */
-+      uint32_t dword;
-+      uint32_t dword2;
-+
-+      dword = Get_NB32(pDCTstat->dev_nbctl, 0x174);
-+      if (!(dword & 0x1)) {
-+              dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
-+              pDCTstat->SwNbPstateLoDis = (dword >> 14) & 0x1;
-+              pDCTstat->NbPstateDisOnP0 = (dword >> 13) & 0x1;
-+              pDCTstat->NbPstateThreshold = (dword >> 9) & 0x7;
-+              pDCTstat->NbPstateHi = (dword >> 6) & 0x3;
-+              dword &= ~(0x1 << 14);          /* SwNbPstateLoDis = 0 */
-+              dword &= ~(0x1 << 13);          /* NbPstateDisOnP0 = 0 */
-+              dword &= ~(0x7 << 9);           /* NbPstateThreshold = 0 */
-+              dword &= ~(0x3 << 3);           /* NbPstateLo = NbPstateMaxVal 
*/
-+              dword |= ((dword & 0x3) << 3);
-+              Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
-+
-+              /* Wait until CurNbPState == NbPstateLo */
-+              do {
-+                      dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174);
-+              } while (((dword2 << 19) & 0x7) != (dword & 0x3));
-+
-+              dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
-+              dword &= ~(0x3 << 6);           /* NbPstateHi = 0 */
-+              dword |= (0x3 << 14);           /* SwNbPstateLoDis = 1 */
-+              Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
-+
-+              /* Wait until CurNbPState == 0 */
-+              do {
-+                      dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174);
-+              } while (((dword2 << 19) & 0x7) != 0);
-+      }
-+}
-+
-+void mct_ForceNBPState0_Dis_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      /* Restore normal NB P-state functionailty */
-+      uint32_t dword;
-+
-+      dword = Get_NB32(pDCTstat->dev_nbctl, 0x174);
-+      if (!(dword & 0x1)) {
-+              dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
-+              dword &= ~(0x1 << 14);                                  /* 
SwNbPstateLoDis*/
-+              dword |= ((pDCTstat->SwNbPstateLoDis & 0x1) << 14);
-+              dword &= ~(0x1 << 13);                                  /* 
NbPstateDisOnP0 */
-+              dword |= ((pDCTstat->NbPstateDisOnP0 & 0x1) << 13);
-+              dword &= ~(0x7 << 9);                                   /* 
NbPstateThreshold */
-+              dword |= ((pDCTstat->NbPstateThreshold & 0x7) << 9);
-+              dword &= ~(0x3 << 6);                                   /* 
NbPstateHi */
-+              dword |= ((pDCTstat->NbPstateHi & 0x3) << 3);
-+              Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
-+      }
-+}
-+
- static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat)
- {
--      mct_SetClToNB_D(pMCTstat, pDCTstat);
--      mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
-+      if (is_fam15h()) {
-+              msr_t p0_state_msr;
-+              uint8_t cpu_fid;
-+              uint8_t cpu_did;
-+              uint32_t cpu_divisor;
-+              uint8_t boost_states;
-+
-+              /* Retrieve the number of boost states */
-+              boost_states = (Get_NB32(pDCTstat->dev_link, 0x15c) >> 2) & 0x7;
-+
-+              /* Retrieve and store the TSC frequency (P0 COF) */
-+              p0_state_msr = rdmsr(0xc0010064 + boost_states);
-+              cpu_fid = p0_state_msr.lo & 0x3f;
-+              cpu_did = (p0_state_msr.lo >> 6) & 0x7;
-+              cpu_divisor = (0x1 << cpu_did);
-+              pMCTstat->TSCFreq = (100 * (cpu_fid + 0x10)) / cpu_divisor;
-+
-+              mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
-+      } else {
-+              /* K10 BKDG v3.62 section 2.8.9.2 */
-+              printk(BIOS_DEBUG, "mct_InitialMCT_D: clear_legacy_Mode\n");
-+              clear_legacy_Mode(pMCTstat, pDCTstat);
-+
-+              /* Northbridge configuration */
-+              mct_SetClToNB_D(pMCTstat, pDCTstat);
-+              mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
-+      }
- }
- 
- static u32 mct_NodePresent_D(void)
- {
-       u32 val;
--      val = 0x12001022;
-+      if (is_fam15h())
-+              val = 0x16001022;
-+      else
-+              val = 0x12001022;
-       return val;
- }
- 
-@@ -3097,14 +4853,13 @@ static void clear_legacy_Mode(struct MCTStatStruc 
*pMCTstat,
- 
-       /* Clear Legacy BIOS Mode bit */
-       reg = 0x94;
--      val = Get_NB32(dev, reg);
-+      val = Get_NB32_DCT(dev, 0, reg);
-       val &= ~(1<<LegacyBiosMode);
--      Set_NB32(dev, reg, val);
-+      Set_NB32_DCT(dev, 0, reg, val);
- 
--      reg = 0x94 + 0x100;
--      val = Get_NB32(dev, reg);
-+      val = Get_NB32_DCT(dev, 1, reg);
-       val &= ~(1<<LegacyBiosMode);
--      Set_NB32(dev, reg, val);
-+      Set_NB32_DCT(dev, 1, reg, val);
- }
- 
- static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
-@@ -3171,7 +4926,7 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
- {
-       u32 val;
-       u32 dev = pDCTstat->dev_dct;
--      u32 index_reg = 0x98 + 0x100 * dct;
-+      u32 index_reg = 0x98;
-       u32 index;
-       u16 word;
- 
-@@ -3186,9 +4941,9 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
-       }
-       word = (~word) & 0xFF;
-       index  = 0x0c;
--      val = Get_NB32_index_wait(dev, index_reg, index);
-+      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-       val |= word;
--      Set_NB32_index_wait(dev, index_reg, index, val);
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
- }
- 
- static void SetCKETriState(struct MCTStatStruc *pMCTstat,
-@@ -3196,7 +4951,7 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
- {
-       u32 val;
-       u32 dev;
--      u32 index_reg = 0x98 + 0x100 * dct;
-+      u32 index_reg = 0x98;
-       u32 index;
-       u16 word;
- 
-@@ -3208,14 +4963,14 @@ static void SetCKETriState(struct MCTStatStruc 
*pMCTstat,
-       word = pDCTstat->CSPresent;
- 
-       index  = 0x0c;
--      val = Get_NB32_index_wait(dev, index_reg, index);
-+      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-       if ((word & 0x55) == 0)
-               val |= 1 << 12;
- 
-       if ((word & 0xAA) == 0)
-               val |= 1 << 13;
- 
--      Set_NB32_index_wait(dev, index_reg, index, val);
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
- }
- 
- static void SetODTTriState(struct MCTStatStruc *pMCTstat,
-@@ -3223,7 +4978,7 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
- {
-       u32 val;
-       u32 dev;
--      u32 index_reg = 0x98 + 0x100 * dct;
-+      u32 index_reg = 0x98;
-       u8 cs;
-       u32 index;
-       u8 odt;
-@@ -3257,86 +5012,281 @@ static void SetODTTriState(struct MCTStatStruc 
*pMCTstat,
-       }
- 
-       index  = 0x0C;
--      val = Get_NB32_index_wait(dev, index_reg, index);
-+      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-       val |= ((odt & 0xFF) << 8);     /* set bits 11:8 ODTTriState[3:0] */
--      Set_NB32_index_wait(dev, index_reg, index, val);
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
-+
-+}
-+
-+/* Family 15h */
-+static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat, u8 dct)
-+{
-+      uint8_t index;
-+      uint32_t dword;
-+      uint8_t ddr_voltage_index;
-+      uint8_t amd_voltage_level_index = 0;
-+      uint32_t index_reg = 0x98;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
- 
-+      /* Find current DDR supply voltage for this DCT */
-+      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
-+
-+      /* Fam15h BKDG v3.14 section 2.10.5.3
-+       * The remainder of the Phy Initialization algorithm picks up in 
phyAssistedMemFnceTraining
-+       */
-+      for (dct = 0; dct < 2; dct++) {
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 
0x80000000);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 
0x00000118);
-+
-+              /* Program desired VDDIO level */
-+              if (ddr_voltage_index & 0x4) {
-+                      /* 1.25V */
-+                      amd_voltage_level_index = 0x2;
-+              } else if (ddr_voltage_index & 0x2) {
-+                      /* 1.35V */
-+                      amd_voltage_level_index = 0x1;
-+              } else if (ddr_voltage_index & 0x1) {
-+                      /* 1.50V */
-+                      amd_voltage_level_index = 0x0;
-+              }
-+
-+              /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */
-+              for (index = 0; index < 0x9; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f001f | (index << 8));
-+                      dword &= ~(0x3 << 3);
-+                      dword |= (amd_voltage_level_index << 3);
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f 
| (index << 8), dword);
-+              }
-+
-+              /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */
-+              for (index = 0; index < 0x3; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f201f | (index << 8));
-+                      dword &= ~(0x3 << 3);
-+                      dword |= (amd_voltage_level_index << 3);
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f 
| (index << 8), dword);
-+              }
-+              for (index = 0; index < 0x2; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f801f | (index << 8));
-+                      dword &= ~(0x3 << 3);
-+                      dword |= (amd_voltage_level_index << 3);
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f 
| (index << 8), dword);
-+              }
-+              for (index = 0; index < 0x1; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc01f | (index << 8));
-+                      dword &= ~(0x3 << 3);
-+                      dword |= (amd_voltage_level_index << 3);
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f 
| (index << 8), dword);
-+              }
-+
-+              /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f4009);
-+              dword &= ~(0x0000c00c);
-+              dword |= (amd_voltage_level_index << 14);
-+              dword |= (amd_voltage_level_index << 2);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f4009, dword);
-+      }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-       u8 i;
--      u32 index_reg = 0x98 + 0x100 * dct;
-+      u32 index_reg = 0x98;
-       u32 dev = pDCTstat->dev_dct;
--      u32 val;
-       u32 valx = 0;
--      u32 dword;
-+      uint8_t index;
-+      uint32_t dword;
-       const u8 *p;
- 
--      val = Get_NB32_index_wait(dev, index_reg, 0x00);
--      dword = 0;
--      for (i=0; i < 6; i++) {
--              switch (i) {
--                      case 0:
--                      case 4:
--                              p = Table_Comp_Rise_Slew_15x;
--                              valx = p[(val >> 16) & 3];
--                              break;
--                      case 1:
--                      case 5:
--                              p = Table_Comp_Fall_Slew_15x;
--                              valx = p[(val >> 16) & 3];
--                              break;
--                      case 2:
--                              p = Table_Comp_Rise_Slew_20x;
--                              valx = p[(val >> 8) & 3];
--                              break;
--                      case 3:
--                              p = Table_Comp_Fall_Slew_20x;
--                              valx = p[(val >> 8) & 3];
--                              break;
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-+      if (is_fam15h()) {
-+              /* Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 
2.10.5.3.4 */
-+              uint32_t tx_pre;
-+              uint32_t drive_strength;
-+
-+              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
-+              dword |= (0x3 << 13);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
-+
-+              /* Determine TxPreP/TxPreN for data lanes (Stage 1) */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
-+              drive_strength = (dword >> 20) & 0x7;   /* DqsDrvStren */
-+              tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, 
drive_strength);
-+
-+              /* Program TxPreP/TxPreN for data lanes (Stage 1) */
-+              for (index = 0; index < 0x9; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0006 | (index << 8));
-+                      dword &= ~(0xfff);
-+                      dword |= tx_pre;
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0006 
| (index << 8), dword);
-+              }
- 
-+              /* Determine TxPreP/TxPreN for data lanes (Stage 2) */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
-+              drive_strength = (dword >> 16) & 0x7;   /* DataDrvStren */
-+              tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, 
drive_strength);
-+
-+              /* Program TxPreP/TxPreN for data lanes (Stage 2) */
-+              for (index = 0; index < 0x9; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f000a | (index << 8));
-+                      dword &= ~(0xfff);
-+                      dword |= tx_pre;
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000a 
| (index << 8), dword);
-+              }
-+              for (index = 0; index < 0x9; index++) {
-+                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0002 | (index << 8));
-+                      dword &= ~(0xfff);
-+                      dword |= (0x8000 | tx_pre);
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0002 
| (index << 8), dword);
-               }
--              dword |= valx << (5 * i);
--      }
- 
--      /* Override/Exception */
--      if (!pDCTstat->GangedMode) {
--              i = 0; /* use i for the dct setting required */
--              if (pDCTstat->MAdimms[0] < 4)
--                      i = 1;
--              if (((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) && 
(pDCTstat->MAdimms[i] == 4)) {
--                      dword &= 0xF18FFF18;
--                      index_reg = 0x98;       /* force dct = 0 */
-+              /* Determine TxPreP/TxPreN for command/address lines (Stage 1) 
*/
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
-+              drive_strength = (dword >> 4) & 0x7;    /* CsOdtDrvStren */
-+              tx_pre = 
fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
-+
-+              /* Program TxPreP/TxPreN for command/address lines (Stage 1) */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8006);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8006, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f800a);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f800a, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8002);
-+              dword &= ~(0xfff);
-+              dword |= (0x8000 | tx_pre);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8002, dword);
-+
-+              /* Determine TxPreP/TxPreN for command/address lines (Stage 2) 
*/
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
-+              drive_strength = (dword >> 8) & 0x7;    /* AddrCmdDrvStren */
-+              tx_pre = 
fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
-+
-+              /* Program TxPreP/TxPreN for command/address lines (Stage 2) */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8106);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8106, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f810a);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f810a, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc006);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc006, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc00a);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00a, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc00e);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00e, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc012);
-+              dword &= ~(0xfff);
-+              dword |= tx_pre;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc012, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8102);
-+              dword &= ~(0xfff);
-+              dword |= (0x8000 | tx_pre);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8102, dword);
-+
-+              /* Determine TxPreP/TxPreN for command/address lines (Stage 3) 
*/
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
-+              drive_strength = (dword >> 0) & 0x7;    /* CkeDrvStren */
-+              tx_pre = 
fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
-+
-+              /* Program TxPreP/TxPreN for command/address lines (Stage 3) */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc002);
-+              dword &= ~(0xfff);
-+              dword |= (0x8000 | tx_pre);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc002, dword);
-+
-+              /* Determine TxPreP/TxPreN for clock lines */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
-+              drive_strength = (dword >> 12) & 0x7;   /* ClkDrvStren */
-+              tx_pre = fam15h_phy_predriver_clk_calibration_code(pDCTstat, 
dct, drive_strength);
-+
-+              /* Program TxPreP/TxPreN for clock lines */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f2002);
-+              dword &= ~(0xfff);
-+              dword |= (0x8000 | tx_pre);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2002, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f2102);
-+              dword &= ~(0xfff);
-+              dword |= (0x8000 | tx_pre);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2102, dword);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f2202);
-+              dword &= ~(0xfff);
-+              dword |= (0x8000 | tx_pre);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2202, dword);
-+      } else {
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00);
-+              dword = 0;
-+              for (i=0; i < 6; i++) {
-+                      switch (i) {
-+                              case 0:
-+                              case 4:
-+                                      p = Table_Comp_Rise_Slew_15x;
-+                                      valx = p[(dword >> 16) & 3];
-+                                      break;
-+                              case 1:
-+                              case 5:
-+                                      p = Table_Comp_Fall_Slew_15x;
-+                                      valx = p[(dword >> 16) & 3];
-+                                      break;
-+                              case 2:
-+                                      p = Table_Comp_Rise_Slew_20x;
-+                                      valx = p[(dword >> 8) & 3];
-+                                      break;
-+                              case 3:
-+                                      p = Table_Comp_Fall_Slew_20x;
-+                                      valx = p[(dword >> 8) & 3];
-+                                      break;
-+                      }
-+                      dword |= valx << (5 * i);
-               }
-+
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0a, dword);
-       }
- 
--      Set_NB32_index_wait(dev, index_reg, 0x0a, dword);
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 reg;
--      u32 val;
--      u32 dev = pDCTstat->dev_dct;
--
--      /* GhEnhancement #18429 modified by askar: For low NB CLK :
--       * Memclk ratio, the DCT may need to arbitrate early to avoid
--       * unnecessary bubbles.
--       * bit 19 of F2x[1,0]78 Dram  Control Register, set this bit only when
--       * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 (inclusive)
--       */
--      reg = 0x78 + 0x100 * dct;
--      val = Get_NB32(dev, reg);
--
--      if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
--              val |= (1 << EarlyArbEn);
--      else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
--              val |= (1 << EarlyArbEn);
--
--      Set_NB32(dev, reg, val);
-+      if (!is_fam15h()) {
-+              u32 reg;
-+              u32 val;
-+              u32 dev = pDCTstat->dev_dct;
-+
-+              /* GhEnhancement #18429 modified by askar: For low NB CLK :
-+              * Memclk ratio, the DCT may need to arbitrate early to avoid
-+              * unnecessary bubbles.
-+              * bit 19 of F2x[1,0]78 Dram  Control Register, set this bit 
only when
-+              * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 
(inclusive)
-+              */
-+              reg = 0x78;
-+              val = Get_NB32_DCT(dev, dct, reg);
-+
-+              if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
-+                      val |= (1 << EarlyArbEn);
-+              else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
-+                      val |= (1 << EarlyArbEn);
-+
-+              Set_NB32_DCT(dev, dct, reg, val);
-+      }
- }
- 
- static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
-@@ -3359,9 +5309,9 @@ static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc 
*pMCTstat,
-               NbDid |= 1;
- 
-       reg = 0x94;
--      val = Get_NB32(dev, reg);
-+      val = Get_NB32_DCT(dev, 0, reg);
-       if (!(val & (1 << MemClkFreqVal)))
--              val = Get_NB32(dev, reg + 0x100);       /* get the DCT1 value */
-+              val = Get_NB32_DCT(dev, 1, reg);        /* get the DCT1 value */
- 
-       val &= 0x07;
-       val += 3;
-@@ -3430,28 +5380,204 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc 
*pMCTstat,
- }
- 
- static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat)
-+                                      struct DCTStatStruc *pDCTstat, u8 dct)
-+{
-+      mct_ProgramODT_D(pMCTstat, pDCTstat, dct);
-+}
-+
-+static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat, u8 dct)
- {
-       u8 i;
--      u32 reg_off, dword;
-+      u32 dword;
-       u32 dev = pDCTstat->dev_dct;
- 
--      if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      if (is_fam15h()) {
-+              /* Obtain number of DIMMs on channel */
-+              uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+              uint8_t rank_count_dimm0;
-+              uint8_t rank_count_dimm1;
-+              uint32_t odt_pattern_0;
-+              uint32_t odt_pattern_1;
-+              uint32_t odt_pattern_2;
-+              uint32_t odt_pattern_3;
-+              uint8_t write_odt_duration;
-+              uint8_t read_odt_duration;
-+              uint8_t write_odt_delay;
-+              uint8_t read_odt_delay;
-+
-+              /* Select appropriate ODT pattern for installed DIMMs
-+               * Refer to the Fam15h BKDG Rev. 3.14, page 149 onwards
-+               */
-+              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED]) {
-+                      if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      if (rank_count_dimm1 == 1) {
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x00020000;
-+                                      } else if (rank_count_dimm1 == 2) {
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x08020000;
-+                                      } else if (rank_count_dimm1 == 4) {
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x020a0000;
-+                                              odt_pattern_3 = 0x080a0000;
-+                                      } else {
-+                                              /* Fallback */
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x08020000;
-+                                      }
-+                              } else {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x01010202;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x09030603;
-+                                      } else if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 == 4)) {
-+                                              odt_pattern_0 = 0x01010000;
-+                                              odt_pattern_1 = 0x01010a0a;
-+                                              odt_pattern_2 = 0x01090000;
-+                                              odt_pattern_3 = 0x01030e0b;
-+                                      } else if ((rank_count_dimm0 == 4) && 
(rank_count_dimm1 < 4)) {
-+                                              odt_pattern_0 = 0x00000202;
-+                                              odt_pattern_1 = 0x05050202;
-+                                              odt_pattern_2 = 0x00000206;
-+                                              odt_pattern_3 = 0x0d070203;
-+                                      } else if ((rank_count_dimm0 == 4) && 
(rank_count_dimm1 == 4)) {
-+                                              odt_pattern_0 = 0x05050a0a;
-+                                              odt_pattern_1 = 0x05050a0a;
-+                                              odt_pattern_2 = 0x050d0a0e;
-+                                              odt_pattern_3 = 0x05070a0b;
-+                                      } else {
-+                                              /* Fallback */
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x00000000;
-+                                      }
-+                              }
-+                      } else {
-+                              /* FIXME
-+                               * 3 DIMMs per channel UNIMPLEMENTED
-+                               */
-+                              odt_pattern_0 = 0x00000000;
-+                              odt_pattern_1 = 0x00000000;
-+                              odt_pattern_2 = 0x00000000;
-+                              odt_pattern_3 = 0x00000000;
-+                      }
-+              } else if 
(pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
-+                      /* TODO
-+                       * Load reduced dimms UNIMPLEMENTED
-+                       */
-+                      odt_pattern_0 = 0x00000000;
-+                      odt_pattern_1 = 0x00000000;
-+                      odt_pattern_2 = 0x00000000;
-+                      odt_pattern_3 = 0x00000000;
-+              } else {
-+                      if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      if (rank_count_dimm1 == 1) {
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x00020000;
-+                                      } else if (rank_count_dimm1 == 2) {
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x08020000;
-+                                      } else {
-+                                              /* Fallback */
-+                                              odt_pattern_0 = 0x00000000;
-+                                              odt_pattern_1 = 0x00000000;
-+                                              odt_pattern_2 = 0x00000000;
-+                                              odt_pattern_3 = 0x08020000;
-+                                      }
-+                              } else {
-+                                      /* 2 DIMMs detected */
-+                                      odt_pattern_0 = 0x00000000;
-+                                      odt_pattern_1 = 0x01010202;
-+                                      odt_pattern_2 = 0x00000000;
-+                                      odt_pattern_3 = 0x09030603;
-+                              }
-+                      } else {
-+                              /* FIXME
-+                               * 3 DIMMs per channel UNIMPLEMENTED
-+                               */
-+                              odt_pattern_0 = 0x00000000;
-+                              odt_pattern_1 = 0x00000000;
-+                              odt_pattern_2 = 0x00000000;
-+                              odt_pattern_3 = 0x00000000;
-+                      }
-+              }
-+
-+              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
-+                      /* TODO
-+                       * Load reduced dimms UNIMPLEMENTED
-+                       */
-+                      write_odt_duration = 0x0;
-+                      read_odt_duration = 0x0;
-+                      write_odt_delay = 0x0;
-+                      read_odt_delay = 0x0;
-+              } else {
-+                      uint8_t tcl;
-+                      uint8_t tcwl;
-+                      tcl = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
-+                      tcwl = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
-+
-+                      write_odt_duration = 0x6;
-+                      read_odt_duration = 0x6;
-+                      write_odt_delay = 0x0;
-+                      if (tcl > tcwl)
-+                              read_odt_delay = tcl - tcwl;
-+                      else
-+                              read_odt_delay = 0x0;
-+              }
-+
-+              /* Program ODT pattern */
-+              Set_NB32_DCT(dev, dct, 0x230, odt_pattern_1);
-+              Set_NB32_DCT(dev, dct, 0x234, odt_pattern_0);
-+              Set_NB32_DCT(dev, dct, 0x238, odt_pattern_3);
-+              Set_NB32_DCT(dev, dct, 0x23c, odt_pattern_2);
-+              dword = Get_NB32_DCT(dev, dct, 0x240);
-+              dword &= ~(0x7 << 12);                          /* 
WrOdtOnDuration = write_odt_duration */
-+              dword |= (write_odt_duration & 0x7) << 12;
-+              dword &= ~(0x7 << 8);                           /* 
WrOdtTrnOnDly = write_odt_delay */
-+              dword |= (write_odt_delay & 0x7) << 8;
-+              dword &= ~(0xf << 4);                           /* 
RdOdtOnDuration = read_odt_duration */
-+              dword |= (read_odt_duration & 0xf) << 4;
-+              dword &= ~(0xf);                                /* 
RdOdtTrnOnDly = read_odt_delay */
-+              dword |= (read_odt_delay & 0xf);
-+              Set_NB32_DCT(dev, dct, 0x240, dword);
-+      } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
-               if (pDCTstat->Speed == 3)
-                       dword = 0x00000800;
-               else
-                       dword = 0x00000000;
-               for (i=0; i < 2; i++) {
--                      reg_off = 0x100 * i;
--                      Set_NB32(dev,  0x98 + reg_off, 0x0D000030);
--                      Set_NB32(dev,  0x9C + reg_off, dword);
--                      Set_NB32(dev,  0x98 + reg_off, 0x4D040F30);
--
--                      /* FIXME
--                       * Mainboards need to be able to specify the maximum 
number of DIMMs installable per channel
--                       * For now assume a maximum of 2 DIMMs per channel can 
be installed
--                       */
--                      uint8_t MaxDimmsInstallable = 2;
-+                      Set_NB32_DCT(dev, i, 0x98, 0x0D000030);
-+                      Set_NB32_DCT(dev, i, 0x9C, dword);
-+                      Set_NB32_DCT(dev, i, 0x98, 0x4D040F30);
- 
-                       /* Obtain number of DIMMs on channel */
-                       uint8_t dimm_count = pDCTstat->MAdimms[i];
-@@ -3463,7 +5589,7 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
-                       uint32_t odt_pattern_3;
- 
-                       /* Select appropriate ODT pattern for installed DIMMs
--                       * Refer to the BKDG Rev. 3.62, page 120 onwards
-+                       * Refer to the Fam10h BKDG Rev. 3.62, page 120 onwards
-                        */
-                       if 
(pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) {
-                               if (MaxDimmsInstallable == 2) {
-@@ -3574,10 +5700,10 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
-                       }
- 
-                       /* Program ODT pattern */
--                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x180, 
odt_pattern_1);
--                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x181, 
odt_pattern_0);
--                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x182, 
odt_pattern_3);
--                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x183, 
odt_pattern_2);
-+                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x180, 
odt_pattern_1);
-+                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, 
odt_pattern_0);
-+                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, 
odt_pattern_3);
-+                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, 
odt_pattern_2);
-               }
-       }
- }
-@@ -3585,34 +5711,32 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
- static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct, val;
- 
-       /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
-       if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) {
--              Set_NB32(dev,  0x9C + reg_off, 0x1C);
--              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE006);
--              Set_NB32(dev,  0x9C + reg_off, 0x13D);
--              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE007);
-+              Set_NB32_DCT(dev, dct, 0x9C, 0x1C);
-+              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006);
-+              Set_NB32_DCT(dev, dct, 0x9C, 0x13D);
-+              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007);
- 
--              val = Get_NB32(dev, 0x90 + reg_off);
-+              val = Get_NB32_DCT(dev, dct, 0x90);
-               val &= ~(1 << 27/* DisDllShutdownSR */);
--              Set_NB32(dev, 0x90 + reg_off, val);
-+              Set_NB32_DCT(dev, dct, 0x90, val);
-       }
- }
- 
- static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u32 
DramConfigLo, u8 dct)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
- 
-       /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
-       if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) {
--              Set_NB32(dev,  0x9C + reg_off, 0x7D0);
--              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE006);
--              Set_NB32(dev,  0x9C + reg_off, 0x190);
--              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE007);
-+              Set_NB32_DCT(dev, dct, 0x9C, 0x7D0);
-+              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006);
-+              Set_NB32_DCT(dev, dct, 0x9C, 0x190);
-+              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007);
- 
-               DramConfigLo |=  /* DisDllShutdownSR */ 1 << 27;
-       }
-@@ -3704,52 +5828,61 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
-                               DramMRS |= 1 << 23;
-               }
-       }
--      /*
--       DRAM MRS Register
--       DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
--      */
--      DramMRS |= 1 << 2;
--      /* Dram nominal termination: */
--      byte = pDCTstat->MAdimms[dct];
--      if (!(pDCTstat->Status & (1 << SB_Registered))) {
--              DramMRS |= 1 << 7; /* 60 ohms */
--              if (byte & 2) {
--                      if (pDCTstat->Speed < 6)
--                              DramMRS |= 1 << 8; /* 40 ohms */
--                      else
--                              DramMRS |= 1 << 9; /* 30 ohms */
-+
-+      if (is_fam15h()) {
-+              DramMRS |= (0x1 << 23);         /* PchgPDModeSel = 1 */
-+      } else {
-+              /*
-+              DRAM MRS Register
-+              DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = 
Rzq/7)
-+              */
-+              DramMRS |= 1 << 2;
-+              /* Dram nominal termination: */
-+              byte = pDCTstat->MAdimms[dct];
-+              if (!(pDCTstat->Status & (1 << SB_Registered))) {
-+                      DramMRS |= 1 << 7; /* 60 ohms */
-+                      if (byte & 2) {
-+                              if (pDCTstat->Speed < 6)
-+                                      DramMRS |= 1 << 8; /* 40 ohms */
-+                              else
-+                                      DramMRS |= 1 << 9; /* 30 ohms */
-+                      }
-               }
--      }
--      /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
--      if (!(pDCTstat->Status & (1 << SB_Registered))) {
--              if (byte >= 2) {
--                      if (pDCTstat->Speed == 7)
--                              DramMRS |= 1 << 10;
--                      else
--                              DramMRS |= 1 << 11;
-+              /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
-+              if (!(pDCTstat->Status & (1 << SB_Registered))) {
-+                      if (byte >= 2) {
-+                              if (pDCTstat->Speed == 7)
-+                                      DramMRS |= 1 << 10;
-+                              else
-+                                      DramMRS |= 1 << 11;
-+                      }
-+              } else {
-+                      DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, 
byte);
-               }
--      } else {
--              DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, byte);
-+
-+              /* Qoff=0, output buffers enabled */
-+              /* Tcwl */
-+              DramMRS |= (pDCTstat->Speed - 4) << 20;
-+              /* ASR=1, auto self refresh */
-+              /* SRT=0 */
-+              DramMRS |= 1 << 18;
-       }
- 
-       /* burst length control */
-       if (pDCTstat->Status & (1 << SB_128bitmode))
-               DramMRS |= 1 << 1;
--      /* Qoff=0, output buffers enabled */
--      /* Tcwl */
--      DramMRS |= (pDCTstat->Speed - 4) << 20;
--      /* ASR=1, auto self refresh */
--      /* SRT=0 */
--      DramMRS |= 1 << 18;
--
--      dword = Get_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84);
--      dword &= ~0x00FC2F8F;
-+
-+      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
-+      if (is_fam15h())
-+              dword &= ~0x00800003;
-+      else
-+              dword &= ~0x00fc2f8f;
-       dword |= DramMRS;
--      Set_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84, dword);
-+      Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword);
- }
- 
--void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct,
--                              u32 DramConfigHi)
-+void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, u32 dct, u32 
DramConfigHi)
- {
-       /* Bug#15114: Comp. update interrupted by Freq. change can cause
-        * subsequent update to be invalid during any MemClk frequency change:
-@@ -3778,45 +5911,86 @@ void mct_SetDramConfigHi_D(struct DCTStatStruc 
*pDCTstat, u32 dct,
-        */
- 
-       u32 dev = pDCTstat->dev_dct;
--      u32 index_reg = 0x98 + 0x100 * dct;
-+      u32 index_reg = 0x98;
-       u32 index;
- 
--      u32 val;
-+      uint32_t dword;
-+
-+      if (is_fam15h()) {
-+              /* Initial setup for frequency change
-+               * 9C_x0000_0004 must be configured before MemClkFreqVal is set
-+               */
- 
--      index = 0x08;
--      val = Get_NB32_index_wait(dev, index_reg, index);
--      if (!(val & (1 << DisAutoComp)))
--              Set_NB32_index_wait(dev, index_reg, index, val | (1 << 
DisAutoComp));
-+              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0x190 */
-+              dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
index_reg, 0x0d0fe006);
-+              dword &= ~(0x0000ffff);
-+              dword |= 0x00000190;
-+              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 
0x0d0fe006, dword);
- 
--      mct_Wait(100);
-+              dword = Get_NB32_DCT(dev, dct, 0x94);
-+              dword &= ~(1 << MemClkFreqVal);
-+              Set_NB32_DCT(dev, dct, 0x94, dword);
- 
--      Set_NB32(dev, 0x94 + 0x100 * dct, DramConfigHi);
-+              dword = DramConfigHi;
-+              dword &= ~(1 << MemClkFreqVal);
-+              Set_NB32_DCT(dev, dct, 0x94, dword);
-+
-+              mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
-+              set_2t_configuration(pMCTstat, pDCTstat, dct);
-+              mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
-+              mct_PlatformSpec(pMCTstat, pDCTstat, dct);
-+      } else {
-+              index = 0x08;
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-+              if (!(dword & (1 << DisAutoComp)))
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, 
dword | (1 << DisAutoComp));
-+
-+              mct_Wait(100);
-+      }
-+
-+      /* Program the DRAM Configuration High register */
-+      Set_NB32_DCT(dev, dct, 0x94, DramConfigHi);
-+
-+      if (is_fam15h()) {
-+              /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
-+              do {
-+                      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
-+              } while (dword & (1 << FreqChgInProg));
-+
-+              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0xf */
-+              dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
index_reg, 0x0d0fe006);
-+              dword &= ~(0x0000ffff);
-+              dword |= 0x0000000f;
-+              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 
0x0d0fe006, dword);
-+      }
- }
- 
- static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstatA)
- {
--      u8 Node;
--      struct DCTStatStruc *pDCTstat;
-+      if (!is_fam15h()) {
-+              u8 Node;
-+              struct DCTStatStruc *pDCTstat;
- 
--      /* Errata 178
--       *
--       * Bug#15115: Uncertainty In The Sync Chain Leads To Setup Violations
--       *            In TX FIFO
--       * Solution: BIOS should program DRAM Control Register[RdPtrInit] =
--       *            5h, (F2x[1, 0]78[3:0] = 5h).
--       * Silicon Status: Fixed In Rev B0
--       *
--       * Bug#15880: Determine validity of reset settings for DDR PHY timing.
--       * Solution: At least, set WrDqs fine delay to be 0 for DDR3 training.
--       */
--      for (Node = 0; Node < 8; Node++) {
--              pDCTstat = pDCTstatA + Node;
-+              /* Errata 178
-+               *
-+               * Bug#15115: Uncertainty In The Sync Chain Leads To Setup 
Violations
-+               *            In TX FIFO
-+               * Solution: BIOS should program DRAM Control 
Register[RdPtrInit] =
-+               *            5h, (F2x[1, 0]78[3:0] = 5h).
-+               * Silicon Status: Fixed In Rev B0
-+               *
-+               * Bug#15880: Determine validity of reset settings for DDR PHY 
timing.
-+               * Solution: At least, set WrDqs fine delay to be 0 for DDR3 
training.
-+               */
-+              for (Node = 0; Node < 8; Node++) {
-+                      pDCTstat = pDCTstatA + Node;
- 
--              if (pDCTstat->NodePresent) {
--                      mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
--                      mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
--                      mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
-+                      if (pDCTstat->NodePresent) {
-+                              mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
-+                              mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
-+                              mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
-+                      }
-               }
-       }
- }
-@@ -3827,7 +6001,6 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
- {
-       u8 Receiver;
-       u32 dev = pDCTstat->dev_dct;
--      u32 reg_off = 0x100 * dct;
-       u32 addr;
-       u32 lo, hi;
-       u8 wrap32dis = 0;
-@@ -3838,6 +6011,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc 
*pMCTstat,
-               return;
-       }
- 
-+      /* Skip reset DLL for Family 15h */
-+      if (is_fam15h()) {
-+              return;
-+      }
-+
-       addr = HWCR;
-       _RDMSR(addr, &lo, &hi);
-       if(lo & (1<<17)) {              /* save the old value */
-@@ -3857,11 +6035,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc 
*pMCTstat,
-                               mct_Read1LTestPattern_D(pMCTstat, pDCTstat, 
addr);      /* cache fills */
- 
-                               /* Write 0000_8000h to register 
F2x[1,0]9C_xD080F0C */
--                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00008000);
-+                              Set_NB32_index_wait_DCT(dev, dct, 0x98, 
0xD080F0C, 0x00008000);
-                               mct_Wait(80); /* wait >= 300ns */
- 
-                               /* Write 0000_0000h to register 
F2x[1,0]9C_xD080F0C */
--                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00000000);
-+                              Set_NB32_index_wait_DCT(dev, dct, 0x98, 
0xD080F0C, 0x00000000);
-                               mct_Wait(800); /* wait >= 2us */
-                               break;
-                       }
-@@ -3901,39 +6079,39 @@ static void mct_EnableDatIntlv_D(struct MCTStatStruc 
*pMCTstat,
- static void SetDllSpeedUp_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 val;
--      u32 dev = pDCTstat->dev_dct;
--      u32 reg_off = 0x100 * dct;
--
--      if (pDCTstat->Speed >= 7) { /* DDR1600 and above */
--              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F10 */
--              Set_NB32(dev, reg_off + 0x98, 0x0D080F10);
--              val = Get_NB32(dev, reg_off + 0x9C);
--              val |= 1 < 13;
--              Set_NB32(dev, reg_off + 0x9C, val);
--              Set_NB32(dev, reg_off + 0x98, 0x4D080F10);
--
--              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F11 */
--              Set_NB32(dev, reg_off + 0x98, 0x0D080F11);
--              val = Get_NB32(dev, reg_off + 0x9C);
--              val |= 1 < 13;
--              Set_NB32(dev, reg_off + 0x9C, val);
--              Set_NB32(dev, reg_off + 0x98, 0x4D080F11);
--
--              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D088F30 */
--              Set_NB32(dev, reg_off + 0x98, 0x0D088F30);
--              val = Get_NB32(dev, reg_off + 0x9C);
--              val |= 1 < 13;
--              Set_NB32(dev, reg_off + 0x9C, val);
--              Set_NB32(dev, reg_off + 0x98, 0x4D088F30);
--
--              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D08CF30 */
--              Set_NB32(dev, reg_off + 0x98, 0x0D08CF30);
--              val = Get_NB32(dev, reg_off + 0x9C);
--              val |= 1 < 13;
--              Set_NB32(dev, reg_off + 0x9C, val);
--              Set_NB32(dev, reg_off + 0x98, 0x4D08CF30);
--
-+      if (!is_fam15h()) {
-+              u32 val;
-+              u32 dev = pDCTstat->dev_dct;
-+
-+              if (pDCTstat->Speed >= mhz_to_memclk_config(800)) { /* DDR1600 
and above */
-+                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D080F10 */
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x0D080F10);
-+                      val = Get_NB32_DCT(dev, dct, 0x9C);
-+                      val |= 1 < 13;
-+                      Set_NB32_DCT(dev, dct, 0x9C, val);
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x4D080F10);
-+
-+                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D080F11 */
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x0D080F11);
-+                      val = Get_NB32_DCT(dev, dct, 0x9C);
-+                      val |= 1 < 13;
-+                      Set_NB32_DCT(dev, dct, 0x9C, val);
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x4D080F11);
-+
-+                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D088F30 */
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x0D088F30);
-+                      val = Get_NB32_DCT(dev, dct, 0x9C);
-+                      val |= 1 < 13;
-+                      Set_NB32_DCT(dev, dct, 0x9C, val);
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x4D088F30);
-+
-+                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D08CF30 */
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x0D08CF30);
-+                      val = Get_NB32_DCT(dev, dct, 0x9C);
-+                      val |= 1 < 13;
-+                      Set_NB32_DCT(dev, dct, 0x9C, val);
-+                      Set_NB32_DCT(dev, dct, 0x98, 0x4D08CF30);
-+              }
-       }
- }
- 
-@@ -3961,7 +6139,6 @@ static void SyncSetting(struct DCTStatStruc *pDCTstat)
- static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
- 
-       u32 val;
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
- 
-       if (pDCTstat->LogicalCPUID & (AMD_DR_B2 | AMD_DR_B3)) {
-@@ -3969,16 +6146,16 @@ static void AfterDramInit_D(struct DCTStatStruc 
*pDCTstat, u8 dct) {
-               val = Get_NB32(dev, 0x110);
-               if (!(val & (1 << DramEnabled))) {
-                       /* If 50 us expires while DramEnable =0 then do the 
following */
--                      val = Get_NB32(dev, 0x90 + reg_off);
-+                      val = Get_NB32_DCT(dev, dct, 0x90);
-                       val &= ~(1 << Width128);                /* Program 
Width128 = 0 */
--                      Set_NB32(dev, 0x90 + reg_off, val);
-+                      Set_NB32_DCT(dev, dct, 0x90, val);
- 
--                      val = Get_NB32_index_wait(dev, 0x98 + reg_off, 0x05);   
/* Perform dummy CSR read to F2x09C_x05 */
-+                      val = Get_NB32_index_wait_DCT(dev, dct, 0x98, 0x05);    
/* Perform dummy CSR read to F2x09C_x05 */
- 
-                       if (pDCTstat->GangedMode) {
--                              val = Get_NB32(dev, 0x90 + reg_off);
-+                              val = Get_NB32_DCT(dev, dct, 0x90);
-                               val |= 1 << Width128;           /* Program 
Width128 = 0 */
--                              Set_NB32(dev, 0x90 + reg_off, val);
-+                              Set_NB32_DCT(dev, dct, 0x90, val);
-                       }
-               }
-       }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index a947c2d..50fbff7 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -76,6 +76,8 @@
- /* #define PA_EXT_DCTADDL (((00 << 3)+5) << 8) */     /*Node x DCT function, 
Additional Registers PCI Address bits [15:0]*/
- 
- #define PA_NBMISC(Node)       ((((0x18+Node) << 3)+3) << 12)  /*Node 0 Misc 
PCI Address bits [15:0]*/
-+#define PA_LINK(Node) ((((0x18+Node) << 3)+4) << 12)  /*Node 0 Link Control 
bits [15:0]*/
-+#define PA_NBCTL(Node)        ((((0x18+Node) << 3)+5) << 12)  /*Node 0 NB 
Control PCI Address bits [15:0]*/
- /* #define PA_NBDEVOP (((00 << 3)+3) << 8) */  /*Node 0 Misc PCI Address bits 
[15:0]*/
- 
- #define DCC_EN                1               /* X:2:0x94[19]*/
-@@ -129,7 +131,7 @@
- #define X4Dimm                        12      /* func 2, offset 90h, bit 12*/
- #define UnBuffDimm            16      /* func 2, offset 90h, bit 16*/
- #define DimmEcEn              19      /* func 2, offset 90h, bit 19*/
--#define MemClkFreqVal         3       /* func 2, offset 94h, bit 3*/
-+#define MemClkFreqVal         ((is_fam15h())?7:3)     /* func 2, offset 94h, 
bit 3 or 7*/
- #define RDqsEn                        12      /* func 2, offset 94h, bit 12*/
- #define DisDramInterface      14      /* func 2, offset 94h, bit 14*/
- #define PowerDownEn           15      /* func 2, offset 94h, bit 15*/
-@@ -204,6 +206,7 @@
-       #define JED_PROBEMSK    0x40    /*Analysis Probe installed*/
-       #define JED_RDIMM       0x1     /* RDIMM */
-       #define JED_MiniRDIMM   0x5     /* Mini-RDIMM */
-+      #define JED_LRDIMM      0xb     /* Load-reduced DIMM */
- #define SPD_Density   4               /* Bank address bits,SDRAM capacity */
- #define SPD_Addressing        5               /* Row/Column address bits */
- #define SPD_Voltage   6               /* Supported voltage bitfield */
-@@ -297,6 +300,7 @@ struct MCTStatStruc {
-                                     of sub 4GB dram hole for HW remapping.*/
-       u32 Sub4GCacheTop;      /* If not zero, the 32-bit top of cacheable 
memory.*/
-       u32 SysLimit;           /* LIMIT[39:8] (system address)*/
-+      uint32_t TSCFreq;
- } __attribute__((packed));
- 
- 
/*=============================================================================
-@@ -320,7 +324,8 @@ struct MCTStatStruc {
- 
- struct DCTStatStruc {         /* A per Node structure*/
- /* DCTStatStruct_F -  start */
--      u8 Node_ID;             /* Node ID of current controller*/
-+      u8 Node_ID;             /* Node ID of current controller */
-+      uint8_t stopDCT;        /* Set if the DCT will be stopped */
-       u8 ErrCode;             /* Current error condition of Node
-               0= no error
-               1= Variance Error, DCT is running but not in an optimal 
configuration.
-@@ -464,7 +469,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-               /* CH A byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
-               /* CH B byte lane 0 - 7 minimum filtered window  passing DQS 
delay value*/
-               /* CH B byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
--      u32 LogicalCPUID;       /* The logical CPUID of the node*/
-+      uint64_t LogicalCPUID;  /* The logical CPUID of the node*/
-       u16 HostBiosSrvc1;      /* Word sized general purpose field for use by 
host BIOS.  Scratch space.*/
-       u32 HostBiosSrvc2;      /* Dword sized general purpose field for use by 
host BIOS.  Scratch space.*/
-       u16 DimmQRPresent;      /* QuadRank DIMM present?*/
-@@ -558,12 +563,20 @@ struct DCTStatStruc {            /* A per Node 
structure*/
-       u8 ClToNB_flag; /* is used to restore ClLinesToNbDis bit after memory */
-       u32 NodeSysBase;        /* for channel interleave usage */
- 
-+      /* Fam15h specific backup variables */
-+      uint8_t SwNbPstateLoDis;
-+      uint8_t NbPstateDisOnP0;
-+      uint8_t NbPstateThreshold;
-+      uint8_t NbPstateHi;
-+
- /* New for LB Support */
-       u8 NodePresent;
-       u32 dev_host;
-       u32 dev_map;
-       u32 dev_dct;
-       u32 dev_nbmisc;
-+      u32 dev_link;
-+      u32 dev_nbctl;
-       u8 TargetFreq;
-       u8 TargetCASL;
-       u8 CtrlWrd3;
-@@ -596,9 +609,10 @@ struct DCTStatStruc {             /* A per Node 
structure*/
-       uint8_t DimmBanks[MAX_DIMMS_SUPPORTED];
-       uint8_t DimmWidth[MAX_DIMMS_SUPPORTED];
-       uint8_t DimmRegistered[MAX_DIMMS_SUPPORTED];
-+      uint8_t DimmLoadReduced[MAX_DIMMS_SUPPORTED];
- 
-       uint64_t DimmManufacturerID[MAX_DIMMS_SUPPORTED];
--      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH];
-+      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
-       uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
-       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
- } __attribute__((packed));
-@@ -701,7 +715,64 @@ struct amd_s3_persistent_mct_channel_data {
-       /* Other (1 dword) */
-       uint32_t f3x58;
- 
--      /* TOTAL: 250 dwords */
-+      /* Family 15h-specific registers (90 dwords) */
-+      uint32_t f2x200;
-+      uint32_t f2x204;
-+      uint32_t f2x208;
-+      uint32_t f2x20c;
-+      uint32_t f2x210[4];                     /* [nb pstate] */
-+      uint32_t f2x214;
-+      uint32_t f2x218;
-+      uint32_t f2x21c;
-+      uint32_t f2x22c;
-+      uint32_t f2x230;
-+      uint32_t f2x234;
-+      uint32_t f2x238;
-+      uint32_t f2x23c;
-+      uint32_t f2x240;
-+      uint32_t f2x9cx0d0fe003;
-+      uint32_t f2x9cx0d0fe013;
-+      uint32_t f2x9cx0d0f0_8_0_1f[9];         /* [lane]*/
-+      uint32_t f2x9cx0d0f201f;
-+      uint32_t f2x9cx0d0f211f;
-+      uint32_t f2x9cx0d0f221f;
-+      uint32_t f2x9cx0d0f801f;
-+      uint32_t f2x9cx0d0f811f;
-+      uint32_t f2x9cx0d0f821f;
-+      uint32_t f2x9cx0d0fc01f;
-+      uint32_t f2x9cx0d0fc11f;
-+      uint32_t f2x9cx0d0fc21f;
-+      uint32_t f2x9cx0d0f4009;
-+      uint32_t f2x9cx0d0f0_8_0_02[9];         /* [lane]*/
-+      uint32_t f2x9cx0d0f0_8_0_06[9];         /* [lane]*/
-+      uint32_t f2x9cx0d0f0_8_0_0a[9];         /* [lane]*/
-+      uint32_t f2x9cx0d0f2002;
-+      uint32_t f2x9cx0d0f2102;
-+      uint32_t f2x9cx0d0f2202;
-+      uint32_t f2x9cx0d0f8002;
-+      uint32_t f2x9cx0d0f8006;
-+      uint32_t f2x9cx0d0f800a;
-+      uint32_t f2x9cx0d0f8102;
-+      uint32_t f2x9cx0d0f8106;
-+      uint32_t f2x9cx0d0f810a;
-+      uint32_t f2x9cx0d0fc002;
-+      uint32_t f2x9cx0d0fc006;
-+      uint32_t f2x9cx0d0fc00a;
-+      uint32_t f2x9cx0d0fc00e;
-+      uint32_t f2x9cx0d0fc012;
-+      uint32_t f2x9cx0d0f2031;
-+      uint32_t f2x9cx0d0f2131;
-+      uint32_t f2x9cx0d0f2231;
-+      uint32_t f2x9cx0d0f8031;
-+      uint32_t f2x9cx0d0f8131;
-+      uint32_t f2x9cx0d0f8231;
-+      uint32_t f2x9cx0d0fc031;
-+      uint32_t f2x9cx0d0fc131;
-+      uint32_t f2x9cx0d0fc231;
-+      uint32_t f2x9cx0d0f0_0_f_31[9];         /* [lane] */
-+      uint32_t f2x9cx0d0f8021;
-+
-+      /* TOTAL: 340 dwords */
- } __attribute__((packed));
- 
- struct amd_s3_persistent_node_data {
-@@ -746,18 +817,19 @@ struct amd_s3_persistent_data {
-       Local Configuration Status (DCTStatStruc.Status[31:0])
- 
===============================================================================*/
- #define SB_Registered         0       /* All DIMMs are Registered*/
--#define SB_ECCDIMMs           1       /* All banks ECC capable*/
--#define SB_PARDIMMs           2       /* All banks Addr/CMD Parity capable*/
--#define SB_DiagClks           3       /* Jedec ALL slots clock enable diag 
mode*/
--#define SB_128bitmode         4       /* DCT in 128-bit mode operation*/
--#define SB_64MuxedMode                5       /* DCT in 64-bit mux'ed mode.*/
--#define SB_2TMode             6       /* 2T CMD timing mode is enabled.*/
--#define SB_SWNodeHole         7       /* Remapping of Node Base on this Node 
to create a gap.*/
--#define SB_HWHole             8       /* Memory Hole created on this Node 
using HW remapping.*/
--#define SB_Over400MHz         9       /* DCT freq >= 400MHz flag*/
--#define SB_DQSPos_Pass2       10      /* Using for TrainDQSPos DIMM0/1, when 
freq>=400MHz*/
--#define SB_DQSRcvLimit                11      /* Using for DQSRcvEnTrain to 
know we have reached to upper bound.*/
--#define SB_ExtConfig          12      /* Indicator the default setting for 
extend PCI configuration support*/
-+#define SB_LoadReduced                1       /* All DIMMs are Load-Reduced*/
-+#define SB_ECCDIMMs           2       /* All banks ECC capable*/
-+#define SB_PARDIMMs           3       /* All banks Addr/CMD Parity capable*/
-+#define SB_DiagClks           4       /* Jedec ALL slots clock enable diag 
mode*/
-+#define SB_128bitmode         5       /* DCT in 128-bit mode operation*/
-+#define SB_64MuxedMode                6       /* DCT in 64-bit mux'ed mode.*/
-+#define SB_2TMode             7       /* 2T CMD timing mode is enabled.*/
-+#define SB_SWNodeHole         8       /* Remapping of Node Base on this Node 
to create a gap.*/
-+#define SB_HWHole             9       /* Memory Hole created on this Node 
using HW remapping.*/
-+#define SB_Over400MHz         10      /* DCT freq >= 400MHz flag*/
-+#define SB_DQSPos_Pass2               11      /* Using for TrainDQSPos 
DIMM0/1, when freq>=400MHz*/
-+#define SB_DQSRcvLimit                12      /* Using for DQSRcvEnTrain to 
know we have reached to upper bound.*/
-+#define SB_ExtConfig          13      /* Indicator the default setting for 
extend PCI configuration support*/
- 
- 
- 
/*===============================================================================
-@@ -775,17 +847,18 @@ struct amd_s3_persistent_data {
-                                           266=266MHz (DDR533)
-                                           333=333MHz (DDR667)
-                                           400=400MHz (DDR800)*/
--#define NV_ECC_CAP            4       /* Bus ECC capable (1-bits)
-+#define NV_MIN_MEMCLK         4       /* Minimum platform demonstrated 
Memclock (10-bits) */
-+#define NV_ECC_CAP            5       /* Bus ECC capable (1-bits)
-                                           0=Platform not capable
-                                           1=Platform is capable*/
--#define NV_4RANKType          5       /* Quad Rank DIMM slot type (2-bits)
-+#define NV_4RANKType          6       /* Quad Rank DIMM slot type (2-bits)
-                                           0=Normal
-                                           1=R4 (4-Rank Registered DIMMs in 
AMD server configuration)
-                                           2=S4 (Unbuffered SO-DIMMs)*/
--#define NV_BYPMAX             6       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
-+#define NV_BYPMAX             7       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
-                                           4=4 times bypass (normal for 
non-UMA systems)
-                                           7=7 times bypass (normal for UMA 
systems)*/
--#define NV_RDWRQBYP           7       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
-+#define NV_RDWRQBYP           8       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
-                                           2=8 times (normal for non-UMA 
systems)
-                                           3=16 times (normal for UMA 
systems)*/
- 
-@@ -848,8 +921,9 @@ struct amd_s3_persistent_data {
- #define NV_ECCRedir           54      /* Dram ECC Redirection enable*/
- #define NV_DramBKScrub                55      /* Dram ECC Background Scrubber 
CTL*/
- #define NV_L2BKScrub          56      /* L2 ECC Background Scrubber CTL*/
--#define NV_DCBKScrub          57      /* DCache ECC Background Scrubber CTL*/
--#define NV_CS_SpareCTL                58      /* Chip Select Spare Control 
bit 0:
-+#define NV_L3BKScrub          57      /* L3 ECC Background Scrubber CTL*/
-+#define NV_DCBKScrub          58      /* DCache ECC Background Scrubber CTL*/
-+#define NV_CS_SpareCTL                59      /* Chip Select Spare Control 
bit 0:
-                                              0=disable Spare
-                                              1=enable Spare */
-                                       /* Chip Select Spare Control bit 1-4:
-@@ -900,10 +974,12 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u16 RcvrEnDly, u8 FinalVa
- void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel);
- void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u32 dct);
- void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
--void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct, u32 
DramConfigHi);
-+void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u32 dct, u32 DramConfigHi);
- void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
- void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
- void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
-+void mct_ForceNBPState0_En_Fam15(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
-+void mct_ForceNBPState0_Dis_Fam15(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 Pass);
- void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 _DisableDramECC);
- u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-index c40ea1a..f6aa755 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-@@ -98,6 +98,15 @@ static u32 bsf(u32 x)
- 
- u32 SetUpperFSbase(u32 addr_hi);
- 
-+static void proc_MFENCE(void)
-+{
-+      __asm__ volatile (
-+              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
-+              "mfence\n\t"
-+              :::"memory"
-+      );
-+}
-+
- static void proc_CLFLUSH(u32 addr_hi)
- {
-       SetUpperFSbase(addr_hi);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
-index 126642b..3df262b 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -17,6 +18,8 @@
-  * Foundation, Inc.
-  */
- 
-+/* AM3/ASB2/C32/G34 DDR3 */
-+
- static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
-                               u32 *AddrTmgCTL, u32 *ODC_CTL,
-                               u8 *CMDmode);
-@@ -24,17 +27,23 @@ static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 
MAAload,
- void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
-                        struct DCTStatStruc *pDCTstat, u32 dct)
- {
--      Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
--                              pDCTstat->MAload[dct],
--                              &(pDCTstat->CH_ADDR_TMG[dct]), 
&(pDCTstat->CH_ODC_CTL[dct]),
--                              &pDCTstat->_2Tmode);
-+      if (is_fam15h()) {
-+              pDCTstat->CH_ADDR_TMG[dct] = 
fam15h_address_timing_compensation_code(pDCTstat, dct);
-+              pDCTstat->CH_ODC_CTL[dct] = 
fam15h_output_driver_compensation_code(pDCTstat, dct);
-+              pDCTstat->_2Tmode = fam15h_slow_access_mode(pDCTstat, dct);
-+      } else {
-+              Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
-+                                      pDCTstat->MAload[dct],
-+                                      &(pDCTstat->CH_ADDR_TMG[dct]), 
&(pDCTstat->CH_ODC_CTL[dct]),
-+                                      &pDCTstat->_2Tmode);
-+
-+              pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;        /* 60ohms */
-+      }
- 
-       pDCTstat->CH_EccDQSLike[0]  = 0x0403;
-       pDCTstat->CH_EccDQSScale[0] = 0x70;
-       pDCTstat->CH_EccDQSLike[1]  = 0x0403;
-       pDCTstat->CH_EccDQSScale[1] = 0x70;
--
--      pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;        /* 60ohms */
- }
- 
- /*
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
-index f1fd7a5..a1cdfa6 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -35,7 +36,6 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
- 
-       u32 dev;
-       u32 reg;
--      u32 reg_off;
-       u32 val;
-       u32 val_lo, val_hi;
- 
-@@ -44,16 +44,15 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
-       EnChipSels = 0;
- 
-       dev = pDCTstat->dev_dct;
--      reg_off = 0x100 * dct;
- 
-       ChipSel = 0;            /* Find out if current configuration is capable 
*/
-       while (DoIntlv && (ChipSel < MAX_CS_SUPPORTED)) {
--              reg = 0x40+(ChipSel<<2) + reg_off;      /* Dram CS Base 0 */
--              val = Get_NB32(dev, reg);
-+              reg = 0x40+(ChipSel<<2);        /* Dram CS Base 0 */
-+              val = Get_NB32_DCT(dev, dct, reg);
-               if ( val & (1<<CSEnable)) {
-                       EnChipSels++;
--                      reg = 0x60+((ChipSel>>1)<<2)+reg_off; /*Dram CS Mask 0 
*/
--                      val = Get_NB32(dev, reg);
-+                      reg = 0x60+((ChipSel>>1)<<2); /*Dram CS Mask 0 */
-+                      val = Get_NB32_DCT(dev, dct, reg);
-                       val >>= 19;
-                       val &= 0x3ff;
-                       val++;
-@@ -63,8 +62,8 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
-                               /*If mask sizes not same then skip */
-                               if (val != MemSize)
-                                       break;
--                      reg = 0x80 + reg_off;           /*Dram Bank Addressing 
*/
--                      val = Get_NB32(dev, reg);
-+                      reg = 0x80;             /*Dram Bank Addressing */
-+                      val = Get_NB32_DCT(dev, dct, reg);
-                       val >>= (ChipSel>>1)<<2;
-                       val &= 0x0f;
-                       if(EnChipSels == 1)
-@@ -103,8 +102,8 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
-               BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask);
- 
-               for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) {
--                      reg = 0x40+(ChipSel<<2) + reg_off;      /*Dram CS Base 
0 */
--                      val = Get_NB32(dev, reg);
-+                      reg = 0x40+(ChipSel<<2);        /*Dram CS Base 0 */
-+                      val = Get_NB32_DCT(dev, dct, reg);
-                       if (val & 3) {
-                               val_lo = val & AddrLoMask;
-                               val_hi = val & AddrHiMask;
-@@ -114,13 +113,13 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
-                               val_hi >>= BitDelta;
-                               val |= val_lo;
-                               val |= val_hi;
--                              Set_NB32(dev, reg, val);
-+                              Set_NB32_DCT(dev, dct, reg, val);
- 
-                               if(ChipSel & 1)
-                                       continue;
- 
--                              reg = 0x60 + ((ChipSel>>1)<<2) + reg_off; 
/*Dram CS Mask 0 */
--                              val = Get_NB32(dev, reg);
-+                              reg = 0x60 + ((ChipSel>>1)<<2); /*Dram CS Mask 
0 */
-+                              val = Get_NB32_DCT(dev, dct, reg);
-                               val_lo = val & AddrLoMask;
-                               val_hi = val & AddrHiMask;
-                               val &= AddrLoMaskN;
-@@ -129,7 +128,7 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
-                               val_hi >>= BitDelta;
-                               val |= val_lo;
-                               val |= val_hi;
--                              Set_NB32(dev, reg, val);
-+                              Set_NB32_DCT(dev, dct, reg, val);
-                       }
-               }
-       }       /* DoIntlv */
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index cc2f43a..740edae 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -18,6 +18,12 @@
-  * Foundation, Inc.
-  */
- 
-+static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay,
-+                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
-+
-+static void read_read_dqs_timing_control_registers(uint16_t* 
current_total_delay,
-+                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
-+
- static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u16 like,
-                               u8 scale, u8 ChipSel);
-@@ -37,7 +43,7 @@ static void FlushDQSTestPattern_D(struct DCTStatStruc 
*pDCTstat,
-                                       u32 addr_lo);
- static void SetTargetWTIO_D(u32 TestAddr);
- static void ResetTargetWTIO_D(void);
--void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index);
-+void ResetDCTWrPtr_D(u32 dev, uint8_t dct, u32 index_reg, u32 index);
- u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat);
- static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
-@@ -54,6 +60,7 @@ static void proc_IOCLFLUSH_D(u32 addr_hi);
- static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, u8 ChipSel);
- 
- #define DQS_TRAIN_DEBUG 0
-+// #define PRINT_PASS_FAIL_BITMAPS 1
- 
- static void print_debug_dqs(const char *str, u32 val, u8 level)
- {
-@@ -198,18 +205,20 @@ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
-               pDCTstat = pDCTstatA + Node;
- 
-               if (pDCTstat->DCTSysLimit) {
--                      val = Get_NB32(pDCTstat->dev_dct, 0x78);
--                      val |= 1 <<DqsRcvEnTrain;
--                      Set_NB32(pDCTstat->dev_dct, 0x78, val);
--                      val = Get_NB32(pDCTstat->dev_dct, 0x78 + 0x100);
--                      val |= 1 <<DqsRcvEnTrain;
--                      Set_NB32(pDCTstat->dev_dct, 0x78 + 0x100, val);
-+                      if (!is_fam15h()) {
-+                              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x78);
-+                              val |= 1 <<DqsRcvEnTrain;
-+                              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x78, val);
-+                              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x78);
-+                              val |= 1 <<DqsRcvEnTrain;
-+                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x78, val);
-+                      }
-                       mct_TrainRcvrEn_D(pMCTstat, pDCTstat, Pass);
-               }
-       }
- }
- 
--static void SetEccDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
-+static void SetEccDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
- {
-       u8 channel;
-@@ -268,68 +277,150 @@ static void CalcEccDQSPos_D(struct MCTStatStruc 
*pMCTstat,
-       pDCTstat->DQSDelay = (u8)DQSDelay;
- }
- 
--static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
-+static void read_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-+{
-+      uint32_t dword;
-+      uint32_t mask;
-+
-+      if (is_fam15h())
-+              mask = 0xff;
-+      else
-+              mask = 0x7f;
-+
-+      /* Lanes 0 - 3 */
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8));
-+      delay[3] = (dword >> 24) & mask;
-+      delay[2] = (dword >> 16) & mask;
-+      delay[1] = (dword >> 8) & mask;
-+      delay[0] = dword & mask;
-+
-+      /* Lanes 4 - 7 */
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8));
-+      delay[7] = (dword >> 24) & mask;
-+      delay[6] = (dword >> 16) & mask;
-+      delay[5] = (dword >> 8) & mask;
-+      delay[4] = dword & mask;
-+
-+      /* Lane 8 (ECC) */
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8));
-+      delay[8] = dword & mask;
-+}
-+
-+static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
- {
-       uint32_t dword;
-+      uint32_t mask;
-+
-+      if (is_fam15h())
-+              mask = 0xff;
-+      else
-+              mask = 0x7f;
- 
-       /* Lanes 0 - 3 */
--      dword = Get_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8));
--      dword &= ~0x7f7f7f7f;
--      dword |= (delay[3] & 0x7f) << 24;
--      dword |= (delay[2] & 0x7f) << 16;
--      dword |= (delay[1] & 0x7f) << 8;
--      dword |= delay[0] & 0x7f;
--      Set_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8), dword);
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8));
-+      dword &= ~(mask << 24);
-+      dword &= ~(mask << 16);
-+      dword &= ~(mask << 8);
-+      dword &= ~mask;
-+      dword |= (delay[3] & mask) << 24;
-+      dword |= (delay[2] & mask) << 16;
-+      dword |= (delay[1] & mask) << 8;
-+      dword |= delay[0] & mask;
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8), dword);
- 
-       /* Lanes 4 - 7 */
--      dword = Get_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8));
--      dword &= ~0x7f7f7f7f;
--      dword |= (delay[7] & 0x7f) << 24;
--      dword |= (delay[6] & 0x7f) << 16;
--      dword |= (delay[5] & 0x7f) << 8;
--      dword |= delay[4] & 0x7f;
--      Set_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8), dword);
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8));
-+      dword &= ~(mask << 24);
-+      dword &= ~(mask << 16);
-+      dword &= ~(mask << 8);
-+      dword &= ~mask;
-+      dword |= (delay[7] & mask) << 24;
-+      dword |= (delay[6] & mask) << 16;
-+      dword |= (delay[5] & mask) << 8;
-+      dword |= delay[4] & mask;
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8), dword);
- 
-       /* Lane 8 (ECC) */
--      dword = Get_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8));
--      dword &= ~0x0000007f;
--      dword |= delay[8] & 0x7f;
--      Set_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8), dword);
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8));
-+      dword &= ~mask;
-+      dword |= delay[8] & mask;
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8), dword);
- }
- 
--static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
-+static void read_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
- {
-       uint32_t dword;
-+      uint32_t mask;
-+
-+      if (is_fam15h())
-+              mask = 0x3e;
-+      else
-+              mask = 0x3f;
- 
-       /* Lanes 0 - 3 */
--      dword = Get_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8));
--      dword &= ~0x3f3f3f3f;
--      dword |= (delay[3] & 0x3f) << 24;
--      dword |= (delay[2] & 0x3f) << 16;
--      dword |= (delay[1] & 0x3f) << 8;
--      dword |= delay[0] & 0x3f;
--      Set_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8), dword);
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
-+      delay[3] = (dword >> 24) & mask;
-+      delay[2] = (dword >> 16) & mask;
-+      delay[1] = (dword >> 8) & mask;
-+      delay[0] = dword & mask;
- 
-       /* Lanes 4 - 7 */
--      dword = Get_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8));
--      dword &= ~0x3f3f3f3f;
--      dword |= (delay[7] & 0x3f) << 24;
--      dword |= (delay[6] & 0x3f) << 16;
--      dword |= (delay[5] & 0x3f) << 8;
--      dword |= delay[4] & 0x3f;
--      Set_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8), dword);
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
-+      delay[7] = (dword >> 24) & mask;
-+      delay[6] = (dword >> 16) & mask;
-+      delay[5] = (dword >> 8) & mask;
-+      delay[4] = dword & mask;
- 
-       /* Lane 8 (ECC) */
--      dword = Get_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8));
--      dword &= ~0x0000003f;
--      dword |= delay[8] & 0x3f;
--      Set_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8), dword);
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
-+      delay[8] = dword & mask;
-+}
-+
-+static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-+{
-+      uint32_t dword;
-+      uint32_t mask;
-+
-+      if (is_fam15h())
-+              mask = 0x3e;
-+      else
-+              mask = 0x3f;
-+
-+      /* Lanes 0 - 3 */
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
-+      dword &= ~(mask << 24);
-+      dword &= ~(mask << 16);
-+      dword &= ~(mask << 8);
-+      dword &= ~mask;
-+      dword |= (delay[3] & mask) << 24;
-+      dword |= (delay[2] & mask) << 16;
-+      dword |= (delay[1] & mask) << 8;
-+      dword |= delay[0] & mask;
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8), dword);
-+
-+      /* Lanes 4 - 7 */
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
-+      dword &= ~(mask << 24);
-+      dword &= ~(mask << 16);
-+      dword &= ~(mask << 8);
-+      dword &= ~mask;
-+      dword |= (delay[7] & mask) << 24;
-+      dword |= (delay[6] & mask) << 16;
-+      dword |= (delay[5] & mask) << 8;
-+      dword |= delay[4] & mask;
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8), dword);
-+
-+      /* Lane 8 (ECC) */
-+      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
-+      dword &= ~mask;
-+      dword |= delay[8] & mask;
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8), dword);
- }
- 
- /* DQS Position Training
-  * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.3
-  */
--static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
-+static void TrainDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat)
- {
-       u32 Errors;
-@@ -406,7 +497,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-               if (pDCTstat->DIMMValidDCT[Channel] == 0)       /* 
mct_BeforeTrainDQSRdWrPos_D */
-                       continue;
- 
--              index_reg = 0x98 + 0x100 * Channel;
-+              index_reg = 0x98;
- 
-               dual_rank = 0;
-               Receiver = mct_InitReceiver_D(pDCTstat, Channel);
-@@ -462,7 +553,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-                                       break;
- 
-                               /* Commit the current Write Data Timing 
settings to the hardware registers */
--                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
-+                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
- 
-                               /* Write the DRAM training pattern to the base 
test address */
-                               WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
-@@ -479,7 +570,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-                                                       
current_read_dqs_delay[lane] = test_read_dqs_delay;
- 
-                                       /* Commit the current Read DQS Timing 
Control settings to the hardware registers */
--                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
-+                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
- 
-                                       /* Initialize test result variable */
-                                       bytelane_test_results = 0xff;
-@@ -545,7 +636,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-                                               passing_dqs_delay_found[lane] = 
1;
- 
-                                               /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
--                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
-+                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
- 
-                                               /* Exit the DRAM Write Data 
Timing Loop */
-                                               
write_dqs_delay_stepping_done[lane] = 1;
-@@ -579,7 +670,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-                                       current_write_dqs_delay[lane] = 
test_write_dqs_delay;
- 
-                               /* Commit the current Write Data Timing 
settings to the hardware registers */
--                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
-+                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
- 
-                               /* Write the DRAM training pattern to the base 
test address */
-                               WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
-@@ -674,7 +765,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-                                               current_read_dqs_delay[lane] = 
(best_pos + (best_count / 2));
- 
-                                               /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
--                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
-+                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
- 
-                                               /* Save the final Read DQS 
Timing Control settings for later use */
-                                               
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_READDIR][lane] = 
current_read_dqs_delay[lane];
-@@ -717,7 +808,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-                                               current_write_dqs_delay[lane] = 
(best_pos + (best_count / 2));
- 
-                                               /* Commit the current Write 
Data Timing settings to the hardware registers */
--                                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
-+                                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
- 
-                                               /* Save the final Write Data 
Timing settings for later use */
-                                               
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_WRITEDIR][lane] = 
current_write_dqs_delay[lane];
-@@ -787,6 +878,831 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
-       printk(BIOS_DEBUG, "TrainDQSRdWrPos: Done\n\n");
- }
- 
-+/* Calcuate and set MaxRdLatency
-+ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.5
-+ */
-+static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct)
-+{
-+      uint8_t dimm;
-+      uint8_t lane;
-+      uint32_t dword;
-+      uint32_t dword2;
-+      uint32_t max_delay;
-+      uint8_t mem_clk = 0;
-+      uint8_t nb_pstate;
-+      uint32_t nb_clk;
-+      uint32_t p = 0;
-+      uint32_t n = 0;
-+      uint32_t t = 0;
-+      uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
-+      uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
-+
-+      uint32_t index_reg = 0x98;
-+      uint32_t dev = pDCTstat->dev_dct;
-+      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
-+
-+      /* P is specified in PhyCLKs (1/2 MEMCLKs) */
-+      for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
-+              /* 2.10.5.8.5 (2) */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000004);
-+              if ((!(dword & (0x1 << 21))) && (!(dword & (0x1 << 13))) && 
(!(dword & (0x1 << 5))))
-+                      p += 1;
-+              else
-+                      p += 2;
-+
-+              /* 2.10.5.8.5 (3) */
-+              dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210) & 
0xf;        /* Retrieve RdPtrInit */
-+              p += (9 - dword);
-+
-+              /* 2.10.5.8.5 (4) */
-+              p += 5;
-+
-+              /* 2.10.5.8.5 (5) */
-+              dword = Get_NB32_DCT(dev, dct, 0xa8);
-+              dword2 = Get_NB32_DCT(dev, dct, 0x90);
-+              if ((!(dword & (0x1 << 5))) && (!(dword2 & (0x1 << 16))))
-+                      p += 2;
-+
-+              /* 2.10.5.8.5 (6) */
-+              dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;   /* Retrieve Tcl 
*/
-+              p += (2 * (dword - 1));
-+
-+              /* 2.10.5.8.5 (7) */
-+              max_delay = 0;
-+              for (dimm = 0; dimm < 4; dimm++) {
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
dimm * 2))
-+                              continue;
-+
-+                      
read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
-+                      
read_read_dqs_timing_control_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
-+                      for (lane = 0; lane < MAX_BYTE_LANES; lane++)
-+                              if ((current_phy_phase_delay[lane] + 
current_read_dqs_delay[lane]) > max_delay)
-+                                      max_delay = 
(current_phy_phase_delay[lane] + current_read_dqs_delay[lane]);
-+              }
-+              p += (max_delay >> 5);
-+
-+              /* 2.10.5.8.5 (8) */
-+              p += 5;
-+
-+              /* 2.10.5.8.5 (9) */
-+              t += 800;
-+
-+              /* 2.10.5.8.5 (10) */
-+              mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
-+              dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 
4)));               /* Retrieve NbDid, NbFid */
-+              nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) 
& 0x1)?2:1);
-+              n = (((((uint64_t)p * 
1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + 
((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
-+
-+              /* 2.10.5.8.5 (11) */
-+              n -= 1;
-+
-+              /* 2.10.5.8.5 (12) */
-+              dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210);
-+              dword &= ~(0x3ff << 22);
-+              dword |= (((n - 1) & 0x3ff) << 22);
-+              Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
-+
-+              /* Save result for later use */
-+              pDCTstat->CH_MaxRdLat[dct] = n;
-+      }
-+}
-+
-+static void start_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver)
-+{
-+      uint32_t dword;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      /* 2.10.5.7.1.1
-+       * It appears that the DCT only supports 8-beat burst length mode,
-+       * so do nothing here...
-+       */
-+
-+      /* Wait for CmdSendInProg == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x250);
-+      } while (dword & (0x1 << 12));
-+
-+      /* Set CmdTestEnable = 1 */
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword |= (0x1 << 2);
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      /* 2.10.5.8.6.1.1 Send Activate Command (Target A) */
-+      dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
-+      dword |= ((0x1 << Receiver) << 22);
-+      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
-+      dword &= ~(0x3ffff);                            /* CmdAddress = 0 */
-+      dword |= (0x1 << 31);                           /* SendActCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x28c, dword);
-+
-+      /* Wait for SendActCmd == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      } while (dword & (0x1 << 31));
-+
-+      /* Wait 75 MEMCLKs. */
-+      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
-+
-+      /* 2.10.5.8.6.1.1 Send Activate Command (Target B) */
-+      dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
-+      dword |= ((0x1 << Receiver) << 22);
-+      dword &= ~(0x7 << 19);                          /* CmdBank = 1 */
-+      dword |= (0x1 << 19);
-+      dword &= ~(0x3ffff);                            /* CmdAddress = 0 */
-+      dword |= (0x1 << 31);                           /* SendActCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x28c, dword);
-+
-+      /* Wait for SendActCmd == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      } while (dword & (0x1 << 31));
-+
-+      /* Wait 75 MEMCLKs. */
-+      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
-+}
-+
-+static void stop_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver)
-+{
-+      uint32_t dword;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      /* 2.10.5.8.6.1.1 Send Precharge Command */
-+      /* Wait 25 MEMCLKs. */
-+      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
-+      dword |= ((0x1 << Receiver) << 22);
-+      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
-+      dword &= ~(0x3ffff);                            /* CmdAddress = 0x400 */
-+      dword |= 0x400;
-+      dword |= (0x1 << 30);                           /* SendPchgCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x28c, dword);
-+
-+      /* Wait for SendPchgCmd == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      } while (dword & (0x1 << 30));
-+
-+      /* Wait 25 MEMCLKs. */
-+      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
-+
-+      /* Set CmdTestEnable = 0 */
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword &= ~(0x1 << 2);
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+}
-+
-+static void read_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
-+{
-+      uint32_t dword;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      start_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, 
Receiver);
-+
-+      /* 2.10.5.8.6.1.2 */
-+      /* Configure DQMask */
-+      if (lane < 4) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
-+              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+      } else if (lane < 8) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-+              Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
-+      } else {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-+              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+      }
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x27c);
-+      dword &= ~(0xff);                               /* EccMask = 0 */
-+      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+      Set_NB32_DCT(dev, dct, 0x27c, dword);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x270);
-+      dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
-+//    dword |= (0x55555);
-+      dword |= (0x44443);                             /* Use AGESA seed */
-+      Set_NB32_DCT(dev, dct, 0x270, dword);
-+
-+      /* 2.10.5.8.4 */
-+      dword = Get_NB32_DCT(dev, dct, 0x260);
-+      dword &= ~(0x1fffff);                           /* CmdCount = 256 */
-+      dword |= 256;
-+      Set_NB32_DCT(dev, dct, 0x260, dword);
-+
-+      /* Configure Target A */
-+      dword = Get_NB32_DCT(dev, dct, 0x254);
-+      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
-+      dword |= (Receiver & 0x7) << 24;
-+      dword &= ~(0x7 << 21);                          /* TgtBank = 0 */
-+      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
-+      Set_NB32_DCT(dev, dct, 0x254, dword);
-+
-+      /* Configure Target B */
-+      dword = Get_NB32_DCT(dev, dct, 0x258);
-+      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
-+      dword |= (Receiver & 0x7) << 24;
-+      dword &= ~(0x7 << 21);                          /* TgtBank = 1 */
-+      dword |= (0x1 << 21);
-+      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
-+      Set_NB32_DCT(dev, dct, 0x258, dword);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
-+      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
-+      dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
-+      dword |= (0x1 << 8);
-+      dword &= ~(0x7 << 5);                           /* CmdType = 0 (Read) */
-+      dword |= (0x1 << 11);                           /* SendCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x250);
-+      } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword &= ~(0x1 << 11);                          /* SendCmd = 0 */
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      stop_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
-+}
-+
-+static void write_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
-+{
-+      uint32_t dword;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      start_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, 
Receiver);
-+
-+      /* 2.10.5.8.6.1.2 */
-+      /* Configure DQMask */
-+      if (lane < 4) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
-+              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+      } else if (lane < 8) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-+              Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
-+      } else {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-+              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+      }
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x27c);
-+      dword &= ~(0xff);                               /* EccMask = 0 */
-+      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+      Set_NB32_DCT(dev, dct, 0x27c, dword);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x270);
-+      dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
-+//    dword |= (0x55555);
-+      dword |= (0x44443);                             /* Use AGESA seed */
-+      Set_NB32_DCT(dev, dct, 0x270, dword);
-+
-+      /* 2.10.5.8.4 */
-+      dword = Get_NB32_DCT(dev, dct, 0x260);
-+      dword &= ~(0x1fffff);                           /* CmdCount = 256 */
-+      dword |= 256;
-+      Set_NB32_DCT(dev, dct, 0x260, dword);
-+
-+      /* Configure Target A */
-+      dword = Get_NB32_DCT(dev, dct, 0x254);
-+      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
-+      dword |= (Receiver & 0x7) << 24;
-+      dword &= ~(0x7 << 21);                          /* TgtBank = 0 */
-+      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
-+      Set_NB32_DCT(dev, dct, 0x254, dword);
-+
-+      /* Configure Target B */
-+      dword = Get_NB32_DCT(dev, dct, 0x258);
-+      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
-+      dword |= (Receiver & 0x7) << 24;
-+      dword &= ~(0x7 << 21);                          /* TgtBank = 1 */
-+      dword |= (0x1 << 21);
-+      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
-+      Set_NB32_DCT(dev, dct, 0x258, dword);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
-+      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
-+      dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
-+      dword |= (0x1 << 8);
-+      dword &= ~(0x7 << 5);                           /* CmdType = 1 (Write) 
*/
-+      dword |= (0x1 << 5);
-+      dword |= (0x1 << 11);                           /* SendCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x250);
-+      } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword &= ~(0x1 << 11);                          /* SendCmd = 0 */
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      stop_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
-+}
-+
-+/* DQS Position Training
-+ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.4
-+ */
-+static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t receiver_start, uint8_t receiver_end, uint8_t lane_start, uint8_t 
lane_end)
-+{
-+      uint8_t dimm;
-+      uint8_t lane;
-+      uint32_t dword;
-+      uint32_t Errors;
-+      uint8_t Receiver;
-+      uint8_t dual_rank;
-+      uint8_t write_iter;
-+      uint8_t read_iter;
-+      uint16_t initial_write_dqs_delay[MAX_BYTE_LANES];
-+      uint16_t initial_read_dqs_delay[MAX_BYTE_LANES];
-+      uint16_t initial_write_data_timing[MAX_BYTE_LANES];
-+      uint16_t current_write_data_delay[MAX_BYTE_LANES];
-+      uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
-+      uint16_t current_write_dqs_delay[MAX_BYTE_LANES];
-+      uint8_t passing_dqs_delay_found[MAX_BYTE_LANES];
-+      uint8_t dqs_results_array[2][(lane_end - lane_start)][32][32];          
/* [rank][lane][write step][read step] */
-+
-+      uint8_t last_pos = 0;
-+      uint8_t cur_count = 0;
-+      uint8_t best_pos = 0;
-+      uint8_t best_count = 0;
-+
-+      uint32_t index_reg = 0x98;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      /* Calculate and program MaxRdLatency */
-+      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct);
-+
-+      Errors = 0;
-+      dual_rank = 0;
-+      Receiver = mct_InitReceiver_D(pDCTstat, dct);
-+      if (receiver_start > Receiver)
-+              Receiver = receiver_start;
-+
-+      /* There are four receiver pairs, loosely associated with chipselects.
-+       * This is essentially looping over each DIMM.
-+       */
-+      for (; Receiver < receiver_end; Receiver += 2) {
-+              dimm = (Receiver >> 1);
-+              if ((Receiver & 0x1) == 0) {
-+                      /* Even rank of DIMM */
-+                      if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
Receiver+1))
-+                              dual_rank = 1;
-+                      else
-+                              dual_rank = 0;
-+              }
-+
-+              if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver)) {
-+                      continue;
-+              }
-+
-+              /* Initialize variables */
-+              for (lane = lane_start; lane < lane_end; lane++) {
-+                      passing_dqs_delay_found[lane] = 0;
-+              }
-+              memset(dqs_results_array, 0, sizeof(dqs_results_array));
-+
-+              /* Read initial read / write DQS delays */
-+              
read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, 
dimm, index_reg);
-+              read_dqs_read_data_timing_registers(initial_read_dqs_delay, 
dev, dct, dimm, index_reg);
-+
-+              /* Read current settings of other (previously trained) lanes */
-+              read_dqs_write_data_timing_registers(initial_write_data_timing, 
dev, dct, dimm, index_reg);
-+              memcpy(current_write_data_delay, initial_write_data_timing, 
sizeof(current_write_data_delay));
-+
-+              for (lane = lane_start; lane < lane_end; lane++) {
-+                      /* 2.10.5.8.4 (2)
-+                       * For each Write Data Delay value from Write DQS Delay 
to Write DQS Delay + 1 UI
-+                       */
-+                      for (current_write_data_delay[lane] = 
initial_write_dqs_delay[lane]; current_write_data_delay[lane] < 
(initial_write_dqs_delay[lane] + 0x20); current_write_data_delay[lane]++) {
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 16 
current_write_data_delay[lane] ", current_write_data_delay[lane], 6);
-+
-+                              /* 2.10.5.8.4 (2 A)
-+                               * Commit the current Write Data Timing 
settings to the hardware registers
-+                               */
-+                              
write_dqs_write_data_timing_registers(current_write_data_delay, dev, dct, dimm, 
index_reg);
-+
-+                              /* 2.10.5.8.4 (2 B)
-+                               * Write the DRAM training pattern to the test 
address
-+                               */
-+                              write_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, dct, Receiver, lane);
-+
-+                              /* Read current settings of other (previously 
trained) lanes */
-+                              
read_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
-+
-+                              /* 2.10.5.8.4 (2 C)
-+                               * For each Read DQS Delay value from 0 to 1 UI
-+                               */
-+                              for (current_read_dqs_delay[lane] = 0; 
current_read_dqs_delay[lane] < 0x40; current_read_dqs_delay[lane] += 2) {
-+                                      
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 current_read_dqs_delay[lane] ", 
current_read_dqs_delay[lane], 6);
-+
-+                                      /* 2.10.5.8.4 (2 A i)
-+                                       * Commit the current Read DQS Timing 
Control settings to the hardware registers
-+                                       */
-+                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
-+
-+                                      /* 2.10.5.8.4 (2 A ii)
-+                                       * Read the DRAM training pattern from 
the test address
-+                                       */
-+                                      
read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane);
-+
-+                                      /* 2.10.5.8.4 (2 A iii)
-+                                       * Record pass / fail status
-+                                       */
-+                                      dword = Get_NB32_DCT(dev, dct, 0x268) & 
0x3ffff;
-+                                      if (dword & (0x3 << (lane * 2)))
-+                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 0;    /* 
Fail */
-+                                      else
-+                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 1;    /* 
Pass */
-+                              }
-+                      }
-+
-+                      if (dual_rank && (Receiver & 0x1)) {
-+                              /* Overlay the previous rank test results with 
the current rank */
-+                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
-+                                      for (read_iter = 0; read_iter < 32; 
read_iter++) {
-+                                              if ((dqs_results_array[0][lane 
- lane_start][write_iter][read_iter])
-+                                                      && 
(dqs_results_array[1][lane - lane_start][write_iter][read_iter]))
-+                                                      
dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 1;
-+                                              else
-+                                                      
dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 0;
-+                                      }
-+                              }
-+                      }
-+
-+                      /* Determine location and length of longest consecutive 
string of read passing values
-+                       * Output is stored in best_pos and best_count
-+                       */
-+                      last_pos = 0;
-+                      cur_count = 0;
-+                      best_pos = 0;
-+                      best_count = 0;
-+                      for (write_iter = 0; write_iter < 32; write_iter++) {
-+                              for (read_iter = 0; read_iter < 32; 
read_iter++) {
-+                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 31)) {
-+                                              /* Pass */
-+                                              cur_count++;
-+                                      } else {
-+                                              /* Failure or end of loop */
-+                                              if (cur_count > best_count) {
-+                                                      best_count = cur_count;
-+                                                      best_pos = last_pos;
-+                                              }
-+                                              cur_count = 0;
-+                                              last_pos = read_iter;
-+                                      }
-+                              }
-+                              last_pos = 0;
-+                      }
-+
-+                      if (best_count > 2) {
-+                              /* Restore current settings of other 
(previously trained) lanes to the active array */
-+                              memcpy(current_read_dqs_delay, 
initial_read_dqs_delay, sizeof(current_read_dqs_delay));
-+
-+                              /* Program the Read DQS Timing Control register 
with the center of the passing window */
-+                              current_read_dqs_delay[lane] = ((best_pos << 1) 
+ ((best_count << 1) / 2));
-+                              passing_dqs_delay_found[lane] = 1;
-+
-+                              /* Commit the current Read DQS Timing Control 
settings to the hardware registers */
-+                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
-+
-+                              /* Save the final Read DQS Timing Control 
settings for later use */
-+                              pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 
1][DQS_READDIR][lane] = current_read_dqs_delay[lane];
-+
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 
largest read passing region ", best_count, 4);
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 
largest read passing region start ", best_pos, 4);
-+                      } else {
-+                              /* Reprogram the Read DQS Timing Control 
register with the original settings */
-+                              
write_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, 
index_reg);
-+                      }
-+
-+                      /* Determine location and length of longest consecutive 
string of write passing values
-+                       * Output is stored in best_pos and best_count
-+                       */
-+                      last_pos = 0;
-+                      cur_count = 0;
-+                      best_pos = 0;
-+                      best_count = 0;
-+                      for (read_iter = 0; read_iter < 32; read_iter++) {
-+                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
-+                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (write_iter < 31)) {
-+                                              /* Pass */
-+                                              cur_count++;
-+                                      } else {
-+                                              /* Failure or end of loop */
-+                                              if (cur_count > best_count) {
-+                                                      best_count = cur_count;
-+                                                      best_pos = last_pos;
-+                                              }
-+                                              cur_count = 0;
-+                                              last_pos = write_iter;
-+                                      }
-+                              }
-+                              last_pos = 0;
-+                      }
-+
-+                      if (best_count > 2) {
-+                              /* Restore current settings of other 
(previously trained) lanes to the active array */
-+                              memcpy(current_write_dqs_delay, 
initial_write_data_timing, sizeof(current_write_data_delay));
-+
-+                              /* Program the Write DQS Timing Control 
register with the optimal region within the passing window */
-+                              if (pDCTstat->Status & (1 << SB_LoadReduced))
-+                                      current_write_dqs_delay[lane] = 
((best_pos + initial_write_dqs_delay[lane]) + (best_count / 3));
-+                              else
-+                                      current_write_dqs_delay[lane] = 
((best_pos + initial_write_dqs_delay[lane]) + (best_count / 2));
-+                              passing_dqs_delay_found[lane] = 1;
-+
-+                              /* Commit the current Write DQS Timing Control 
settings to the hardware registers */
-+                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, 
index_reg);
-+
-+                              /* Save the final Write Data Timing settings 
for later use */
-+                              pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 
1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane];
-+
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 
largest write passing region ", best_count, 4);
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 
largest write passing region start ", best_pos, 4);
-+                      } else {
-+                              /* Reprogram the Write DQS Timing Control 
register with the original settings */
-+                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, 
index_reg);
-+                      }
-+              }
-+
-+#ifdef PRINT_PASS_FAIL_BITMAPS
-+              for (lane = lane_start; lane < lane_end; lane++) {
-+                      for (read_iter = 0; read_iter < 32; read_iter++) {
-+                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
-+                                      if (dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter])
-+                                              printk(BIOS_DEBUG, "+");
-+                                      else
-+                                              printk(BIOS_DEBUG, ".");
-+                              }
-+                              printk(BIOS_DEBUG, "\n");
-+                      }
-+                      printk(BIOS_DEBUG, "\n\n");
-+              }
-+#endif
-+
-+              /* Flag failure(s) if present */
-+              for (lane = lane_start; lane < lane_end; lane++) {
-+                      if (!passing_dqs_delay_found[lane]) {
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 121 
Unable to find passing region for lane ", lane, 2);
-+
-+                              /* Flag absence of passing window */
-+                              Errors |= 1 << SB_NODQSPOS;
-+                      }
-+              }
-+
-+              pDCTstat->TrainErrors |= Errors;
-+              pDCTstat->ErrStatus |= Errors;
-+
-+#if DQS_TRAIN_DEBUG > 0
-+              {
-+                      u8 val;
-+                      u8 i;
-+                      u8 ChannelDTD, ReceiverDTD, Dir;
-+                      u8 *p;
-+
-+                      for (Dir = 0; Dir < 2; Dir++) {
-+                              if (Dir == 1) {
-+                                      printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS WR:\n");
-+                              } else {
-+                                      printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS RD:\n");
-+                              }
-+                              for (ChannelDTD = 0; ChannelDTD < 2; 
ChannelDTD++) {
-+                                      printk(BIOS_DEBUG, "Channel: %02x\n", 
ChannelDTD);
-+                                      for (ReceiverDTD = 0; ReceiverDTD < 
MAX_CS_SUPPORTED; ReceiverDTD += 2) {
-+                                              printk(BIOS_DEBUG, 
"\t\tReceiver: %02x:", ReceiverDTD);
-+                                              p = 
pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
-+                                              for (i=0;i<8; i++) {
-+                                                      val  = p[i];
-+                                                      printk(BIOS_DEBUG, " 
%02x", val);
-+                                              }
-+                                              printk(BIOS_DEBUG, "\n");
-+                                      }
-+                              }
-+                      }
-+
-+              }
-+#endif
-+      }
-+
-+      /* Return 1 on success, 0 on failure */
-+      return !Errors;
-+}
-+
-+/* DQS Receiver Enable Cycle Training
-+ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.3
-+ */
-+static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      u32 Errors;
-+      u8 Receiver;
-+      u8 _DisableDramECC = 0;
-+      u8 _Wrap32Dis = 0, _SSE2 = 0;
-+
-+      u32 addr;
-+      u32 cr4;
-+      u32 lo, hi;
-+
-+      uint8_t dct;
-+      uint8_t prev;
-+      uint8_t dimm;
-+      uint8_t lane;
-+      uint32_t dword;
-+      uint32_t rx_en_offset;
-+      uint16_t initial_phy_phase_delay[MAX_BYTE_LANES];
-+      uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
-+      uint8_t dqs_results_array[1024];
-+
-+      uint16_t ren_step = 0x40;
-+      uint32_t index_reg = 0x98;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      print_debug_dqs("\nTrainDQSReceiverEnCyc: Node_ID ", pDCTstat->Node_ID, 
0);
-+      cr4 = read_cr4();
-+      if (cr4 & (1<<9)) {
-+              _SSE2 = 1;
-+      }
-+      cr4 |= (1<<9);          /* OSFXSR enable SSE2 */
-+      write_cr4(cr4);
-+
-+      addr = HWCR;
-+      _RDMSR(addr, &lo, &hi);
-+      if (lo & (1<<17)) {
-+              _Wrap32Dis = 1;
-+      }
-+      lo |= (1<<17);          /* HWCR.wrap32dis */
-+      _WRMSR(addr, lo, hi);   /* allow 64-bit memory references in real mode 
*/
-+
-+      /* Disable ECC correction of reads on the dram bus. */
-+      _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
-+
-+      Errors = 0;
-+
-+      for (dct = 0; dct < 2; dct++) {
-+              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
-+              dword &= ~(0x3 << 13);
-+              dword |= (0x1 << 13);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
-+      }
-+
-+      for (dct = 0; dct < 2; dct++) {
-+              /* 2.10.5.6 */
-+              fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 1);
-+
-+              /* 2.10.5.8.3 */
-+              Receiver = mct_InitReceiver_D(pDCTstat, dct);
-+
-+              /* There are four receiver pairs, loosely associated with 
chipselects.
-+               * This is essentially looping over each DIMM.
-+               */
-+              for (; Receiver < 8; Receiver += 2) {
-+                      dimm = (Receiver >> 1);
-+
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
Receiver)) {
-+                              continue;
-+                      }
-+
-+                      /* 2.10.5.8.3 (2) */
-+                      
read_dqs_receiver_enable_control_registers(initial_phy_phase_delay, dev, dct, 
dimm, index_reg);
-+
-+                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                              /* Initialize variables */
-+                              memset(dqs_results_array, 0, 
sizeof(dqs_results_array));
-+
-+                              /* 2.10.5.8.3 (1) */
-+                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0030 | (lane << 8));
-+                              dword |= (0x1 << 8);                            
                                /* BlockRxDqsLock = 1 */
-+                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0030 | (lane << 8), dword);
-+
-+                              /* 2.10.5.8.3 (3) */
-+                              rx_en_offset = (initial_phy_phase_delay[lane] + 
0x10) % 0x40;
-+
-+                              /* 2.10.5.8.3 (4) */
-+                              for (current_phy_phase_delay[lane] = 
rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; 
current_phy_phase_delay[lane] += ren_step) {
-+                                      /* 2.10.5.8.3 (4 A) */
-+                                      
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
-+
-+                                      /* Calculate and program MaxRdLatency */
-+                                      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, 
pDCTstat, dct);
-+
-+                                      /* 2.10.5.8.3 (4 B) */
-+                                      
dqs_results_array[current_phy_phase_delay[lane]] = 
TrainDQSRdWrPos_D_Fam15(pMCTstat, pDCTstat, dct, Receiver, Receiver + 2, lane, 
lane + 1);
-+                              }
-+
-+#ifdef PRINT_PASS_FAIL_BITMAPS
-+                              uint16_t iter;
-+                              for (iter = 0; iter < 0x3ff; iter++) {
-+                                      if (dqs_results_array[iter])
-+                                              printk(BIOS_DEBUG, "+");
-+                                      else
-+                                              printk(BIOS_DEBUG, ".");
-+                              }
-+                              printk(BIOS_DEBUG, "\n");
-+#endif
-+
-+                              /* 2.10.5.8.3 (5) */
-+                              prev = 0;
-+                              for (current_phy_phase_delay[lane] = 
rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; 
current_phy_phase_delay[lane] += ren_step) {
-+                                      if 
((dqs_results_array[current_phy_phase_delay[lane]] == 0) && (prev == 1)) {
-+                                              /* Restore last known good 
delay */
-+                                              current_phy_phase_delay[lane] 
-= ren_step;
-+
-+                                              /* 2.10.5.8.3 (5 A B) */
-+                                              current_phy_phase_delay[lane] 
-= 0x10;
-+
-+                                              /* Update hardware registers 
with final values */
-+                                              
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
-+                                              break;
-+                                      }
-+                                      prev = 
dqs_results_array[current_phy_phase_delay[lane]];
-+                              }
-+
-+                              /* 2.10.5.8.3 (6) */
-+                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0030 | (lane << 8));
-+                              dword &= ~(0x1 << 8);                           
                                /* BlockRxDqsLock = 0 */
-+                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0030 | (lane << 8), dword);
-+                      }
-+
-+#if DQS_TRAIN_DEBUG > 0
-+                      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc_D_Fam15 DQS 
receiver enable timing: ");
-+                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                              printk(BIOS_DEBUG, " %03x", 
current_phy_phase_delay[lane]);
-+                      }
-+                      printk(BIOS_DEBUG, "\n");
-+#endif
-+              }
-+      }
-+
-+      pDCTstat->TrainErrors |= Errors;
-+      pDCTstat->ErrStatus |= Errors;
-+
-+#if DQS_TRAIN_DEBUG > 0
-+      {
-+              u8 val;
-+              u8 i;
-+              u8 ChannelDTD, ReceiverDTD, Dir;
-+              u8 *p;
-+
-+              for (Dir = 0; Dir < 2; Dir++) {
-+                      if (Dir == 1) {
-+                              printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS WR:\n");
-+                      } else {
-+                              printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS RD:\n");
-+                      }
-+                      for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
-+                              printk(BIOS_DEBUG, "Channel: %02x\n", 
ChannelDTD);
-+                              for (ReceiverDTD = 0; ReceiverDTD < 
MAX_CS_SUPPORTED; ReceiverDTD += 2) {
-+                                      printk(BIOS_DEBUG, "\t\tReceiver: 
%02x:", ReceiverDTD);
-+                                      p = 
pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
-+                                      for (i=0;i<8; i++) {
-+                                              val  = p[i];
-+                                              printk(BIOS_DEBUG, " %02x", 
val);
-+                                      }
-+                                      printk(BIOS_DEBUG, "\n");
-+                              }
-+                      }
-+              }
-+
-+      }
-+#endif
-+      if (_DisableDramECC) {
-+              mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
-+      }
-+      if (!_Wrap32Dis) {
-+              addr = HWCR;
-+              _RDMSR(addr, &lo, &hi);
-+              lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
-+              _WRMSR(addr, lo, hi);
-+      }
-+      if (!_SSE2){
-+              cr4 = read_cr4();
-+              cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
-+              write_cr4(cr4);
-+      }
-+
-+      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: Status %x\n", 
pDCTstat->Status);
-+      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: TrainErrors %x\n", 
pDCTstat->TrainErrors);
-+      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: ErrStatus %x\n", 
pDCTstat->ErrStatus);
-+      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: ErrCode %x\n", 
pDCTstat->ErrCode);
-+      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: Done\n\n");
-+}
-+
- static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u32 *buffer)
- {
-@@ -869,18 +1785,17 @@ static u8 ChipSelPresent_D(struct MCTStatStruc 
*pMCTstat,
-       u32 val;
-       u32 reg;
-       u32 dev = pDCTstat->dev_dct;
--      u32 reg_off;
-+      uint8_t dct = 0;
-       u8 ret = 0;
- 
--      if (!pDCTstat->GangedMode) {
--              reg_off = 0x100 * Channel;
--      } else {
--              reg_off = 0;
--      }
-+      if (!pDCTstat->GangedMode)
-+              dct = Channel;
-+      else
-+              dct = 0;
- 
-       if (ChipSel < MAX_CS_SUPPORTED){
--              reg = 0x40 + (ChipSel << 2) + reg_off;
--              val = Get_NB32(dev, reg);
-+              reg = 0x40 + (ChipSel << 2);
-+              val = Get_NB32_DCT(dev, dct, reg);
-               if (val & ( 1 << 0))
-                       ret = 1;
-       }
-@@ -1085,12 +2000,12 @@ u32 SetUpperFSbase(u32 addr_hi)
-       return addr_hi << 8;
- }
- 
--void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index)
-+void ResetDCTWrPtr_D(u32 dev, uint8_t dct, u32 index_reg, u32 index)
- {
-       u32 val;
- 
--      val = Get_NB32_index_wait(dev, index_reg, index);
--      Set_NB32_index_wait(dev, index_reg, index, val);
-+      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
- }
- 
- void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
-@@ -1103,9 +2018,13 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
-       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-               pDCTstat = pDCTstatA + Node;
-               if (pDCTstat->DCTSysLimit) {
--                      TrainDQSRdWrPos_D(pMCTstat, pDCTstat);
--                      for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel 
+= 2) {
--                              SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
-+                      if (is_fam15h()) {
-+                              TrainDQSReceiverEnCyc_D_Fam15(pMCTstat, 
pDCTstat);
-+                      } else {
-+                              TrainDQSRdWrPos_D_Fam10(pMCTstat, pDCTstat);
-+                              for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; 
ChipSel += 2) {
-+                                      SetEccDQSRdWrPos_D_Fam10(pMCTstat, 
pDCTstat, ChipSel);
-+                              }
-                       }
-               }
-       }
-@@ -1126,19 +2045,18 @@ u8 mct_DisableDimmEccEn_D(struct MCTStatStruc 
*pMCTstat,
- 
-       dev = pDCTstat->dev_dct;
-       reg = 0x90;
--      val = Get_NB32(dev, reg);
-+      val = Get_NB32_DCT(dev, 0, reg);
-       if (val & (1<<DimmEcEn)) {
-               _DisableDramECC |= 0x01;
-               val &= ~(1<<DimmEcEn);
--              Set_NB32(dev, reg, val);
-+              Set_NB32_DCT(dev, 0, reg, val);
-       }
-       if (!pDCTstat->GangedMode) {
--              reg = 0x190;
--              val = Get_NB32(dev, reg);
-+              val = Get_NB32_DCT(dev, 1, reg);
-               if (val & (1<<DimmEcEn)) {
-                       _DisableDramECC |= 0x02;
-                       val &= ~(1<<DimmEcEn);
--                      Set_NB32(dev, reg, val);
-+                      Set_NB32_DCT(dev, 1, reg, val);
-               }
-       }
-       return _DisableDramECC;
-@@ -1157,15 +2075,14 @@ void mct_EnableDimmEccEn_D(struct MCTStatStruc 
*pMCTstat,
- 
-       if ((_DisableDramECC & 0x01) == 0x01) {
-               reg = 0x90;
--              val = Get_NB32(dev, reg);
-+              val = Get_NB32_DCT(dev, 0, reg);
-               val |= (1<<DimmEcEn);
--              Set_NB32(dev, reg, val);
-+              Set_NB32_DCT(dev, 0, reg, val);
-       }
-       if ((_DisableDramECC & 0x02) == 0x02) {
--              reg = 0x190;
--              val = Get_NB32(dev, reg);
-+              val = Get_NB32_DCT(dev, 1, reg);
-               val |= (1<<DimmEcEn);
--              Set_NB32(dev, reg, val);
-+              Set_NB32_DCT(dev, 1, reg, val);
-       }
- }
- 
-@@ -1177,7 +2094,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
- {
-       u8 ByteLane;
-       u32 val;
--      u32 index_reg = 0x98 + 0x100 * pDCTstat->Channel;
-+      u32 index_reg = 0x98;
-       u8 shift;
-       u32 dqs_delay = (u32)pDCTstat->DQSDelay;
-       u32 dev = pDCTstat->dev_dct;
-@@ -1205,7 +2122,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
- 
-               index += (ChipSel>>1) << 8;
- 
--              val = Get_NB32_index_wait(dev, index_reg, index);
-+              val = Get_NB32_index_wait_DCT(dev, pDCTstat->Channel, 
index_reg, index);
-               if (ByteLane < 8) {
-                       if (pDCTstat->Direction == DQS_WRITEDIR) {
-                               dqs_delay += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][ChipSel>>1][ByteLane];
-@@ -1215,7 +2132,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
-               }
-               val &= ~(0x7f << shift);
-               val |= (dqs_delay << shift);
--              Set_NB32_index_wait(dev, index_reg, index, val);
-+              Set_NB32_index_wait_DCT(dev, pDCTstat->Channel, index_reg, 
index, val);
-       }
- }
- 
-@@ -1241,7 +2158,7 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
-                               u8 Channel, u8 receiver, u8 *valid)
- {
-       u32 val;
--      u32 reg_off = 0;
-+      uint8_t dct = 0;
-       u32 reg;
-       u32 dword;
-       u32 dev = pDCTstat->dev_dct;
-@@ -1250,12 +2167,12 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
- 
- 
-       if (!pDCTstat->GangedMode) {
--              reg_off = 0x100 * Channel;
-+              dct = Channel;
-       }
- 
-       /* get the local base addr of the chipselect */
--      reg = 0x40 + (receiver << 2) + reg_off;
--      val = Get_NB32(dev, reg);
-+      reg = 0x40 + (receiver << 2);
-+      val = Get_NB32_DCT(dev, dct, reg);
- 
-       val &= ~0xe007c01f;
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-index 0c52791..11f1b2c 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -91,19 +92,21 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
- 
-       /* Construct these booleans, based on setup options, for easy handling
-       later in this procedure */
--      OB_NBECC = mctGet_NVbits(NV_NBECC);     /* MCA ECC (MCE) enable bit */
-+      OB_NBECC = mctGet_NVbits(NV_NBECC);                     /* MCA ECC 
(MCE) enable bit */
- 
--      OB_ECCRedir =  mctGet_NVbits(NV_ECCRedir);      /* ECC Redirection */
-+      OB_ECCRedir =  mctGet_NVbits(NV_ECCRedir);              /* ECC 
Redirection */
- 
--      OB_ChipKill = mctGet_NVbits(NV_ChipKill);       /* ECC Chip-kill mode */
-+      OB_ChipKill = mctGet_NVbits(NV_ChipKill);               /* ECC 
Chip-kill mode */
-+      OF_ScrubCTL = 0;                                        /* Scrub CTL 
for Dcache, L2, and dram */
- 
--      OF_ScrubCTL = 0;                /* Scrub CTL for Dcache, L2, and dram */
--      nvbits = mctGet_NVbits(NV_DCBKScrub);
--      /* mct_AdjustScrub_D(pDCTstatA, &nvbits); */ /* Need not adjust */
--      OF_ScrubCTL |= (u32) nvbits << 16;
-+      if (!is_fam15h()) {
-+              nvbits = mctGet_NVbits(NV_DCBKScrub);
-+              /* mct_AdjustScrub_D(pDCTstatA, &nvbits); */    /* Need not 
adjust */
-+              OF_ScrubCTL |= (u32) nvbits << 16;
- 
--      nvbits = mctGet_NVbits(NV_L2BKScrub);
--      OF_ScrubCTL |= (u32) nvbits << 8;
-+              nvbits = mctGet_NVbits(NV_L2BKScrub);
-+              OF_ScrubCTL |= (u32) nvbits << 8;
-+      }
- 
-       nvbits = mctGet_NVbits(NV_DramBKScrub);
-       OF_ScrubCTL |= nvbits;
-@@ -131,7 +134,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                                                       pDCTstat->ErrStatus |= 
(1 << SB_DramECCDis);
-                                               }
-                                               AllECC = 0;
--                                              LDramECC =0;
-+                                              LDramECC = 0;
-                                       }
-                               } else {
-                                       AllECC = 0;
-@@ -140,7 +143,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                                       if (OB_NBECC) {
-                                               mct_EnableDatIntlv_D(pMCTstat, 
pDCTstat);
-                                               dev = pDCTstat->dev_nbmisc;
--                                              reg =0x44;      /* MCA NB 
Configuration */
-+                                              reg = 0x44;     /* MCA NB 
Configuration */
-                                               val = Get_NB32(dev, reg);
-                                               val |= 1 << 22; /* EccEn */
-                                               Set_NB32(dev, reg, val);
-@@ -177,6 +180,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                       /*WE/RE is checked because memory config may have been 
*/
-                       if((val & 3)==3) {      /* Node has dram populated */
-                               if (isDramECCEn_D(pDCTstat)) {  /* if ECC is 
enabled on this dram */
-+                                      if (is_fam15h()) {
-+                                              /* Erratum 505 */
-+                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);
-+                                      }
-                                       dev = pDCTstat->dev_nbmisc;
-                                       val = curBase << 8;
-                                       if(OB_ECCRedir) {
-@@ -187,16 +194,18 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                                       Set_NB32(dev, 0x60, val); /* Dram Scrub 
Addr High */
-                                       Set_NB32(dev, 0x58, OF_ScrubCTL);       
/*Scrub Control */
- 
--                                      /* Divisor should not be set deeper than
--                                       * divide by 16 when Dcache scrubber or
--                                       * L2 scrubber is enabled.
--                                       */
--                                      if ((OF_ScrubCTL & (0x1F << 16)) || 
(OF_ScrubCTL & (0x1F << 8))) {
--                                              val = Get_NB32(dev, 0x84);
--                                              if ((val & 0xE0000000) > 
0x80000000) {  /* Get F3x84h[31:29]ClkDivisor for C1 */
--                                                      val &= 0x1FFFFFFF;      
/* If ClkDivisor is deeper than divide-by-16 */
--                                                      val |= 0x80000000;      
/* set it to divide-by-16 */
--                                                      Set_NB32(dev, 0x84, 
val);
-+                                      if (!is_fam15h()) {
-+                                              /* Divisor should not be set 
deeper than
-+                                               * divide by 16 when Dcache 
scrubber or
-+                                               * L2 scrubber is enabled.
-+                                               */
-+                                              if ((OF_ScrubCTL & (0x1F << 
16)) || (OF_ScrubCTL & (0x1F << 8))) {
-+                                                      val = Get_NB32(dev, 
0x84);
-+                                                      if ((val & 0xE0000000) 
> 0x80000000) {  /* Get F3x84h[31:29]ClkDivisor for C1 */
-+                                                              val &= 
0x1FFFFFFF;      /* If ClkDivisor is deeper than divide-by-16 */
-+                                                              val |= 
0x80000000;      /* set it to divide-by-16 */
-+                                                              Set_NB32(dev, 
0x84, val);
-+                                                      }
-                                               }
-                                       }
-                               }       /* this node has ECC enabled dram */
-@@ -267,8 +276,8 @@ static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat)
-       }
-       for(i=0; i<ch_end; i++) {
-               if(pDCTstat->DIMMValidDCT[i] > 0){
--                      reg = 0x90 + i * 0x100;         /* Dram Config Low */
--                      val = Get_NB32(dev, reg);
-+                      reg = 0x90;             /* Dram Config Low */
-+                      val = Get_NB32_DCT(dev, i, reg);
-                       if(val & (1<<DimmEcEn)) {
-                               /* set local flag 'dram ecc capable' */
-                               isDimmECCEn = 1;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
-index 0112732..a6b9dcb 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -25,8 +26,8 @@ void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat,
-       u32 dev = pDCTstat->dev_dct;
- 
-       /*flag for selecting HW/SW DRAM Init HW DRAM Init */
--      reg = 0x90 + 0x100 * dct; /*DRAM Configuration Low */
--      val = Get_NB32(dev, reg);
-+      reg = 0x90; /*DRAM Configuration Low */
-+      val = Get_NB32_DCT(dev, dct, reg);
-       val |= (1<<InitDram);
--      Set_NB32(dev, reg, val);
-+      Set_NB32_DCT(dev, dct, reg, val);
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-index 60bc01d..5e81808 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-@@ -18,10 +18,12 @@
-  * Foundation, Inc.
-  */
- 
--static void SetTargetFreq(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat);
--static void AgesaHwWlPhase1(sMCTStruct *pMCTData,
--                                      sDCTStruct *pDCTData, u8 dimm, u8 pass);
-+static void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
-+static void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
-+static void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
-+                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
- static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
-@@ -56,7 +58,7 @@ static void SetEccWrDQS_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pD
-                                       Addl_Index = 0x32;
-                               Addl_Index += DimmNum * 3;
- 
--                              val = Get_NB32_index_wait(pDCTstat->dev_dct, 
Channel * 0x100 + 0x98, Addl_Index);
-+                              val = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, Channel, 0x98, Addl_Index);
-                               if (OddByte)
-                                       val >>= 16;
-                               /* Save WrDqs to stack for later usage */
-@@ -74,13 +76,13 @@ static void EnableAutoRefresh_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStr
- {
-       u32 val;
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x8C);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
-       val &= ~(1 << DisAutoRefresh);
--      Set_NB32(pDCTstat->dev_dct, 0x8C, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
-       val &= ~(1 << DisAutoRefresh);
--      Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
- }
- 
- static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
-@@ -88,13 +90,13 @@ static void DisableAutoRefresh_D(struct MCTStatStruc 
*pMCTstat,
- {
-       u32 val;
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x8C);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
-       val |= 1 << DisAutoRefresh;
--      Set_NB32(pDCTstat->dev_dct, 0x8C, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
-       val |= 1 << DisAutoRefresh;
--      Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
- }
- 
- 
-@@ -118,8 +120,11 @@ static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
-               DIMMValid = pDCTstat->DIMMValid;
-               PrepareC_DCT(pMCTstat, pDCTstat, dct);
-               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
--                      if (DIMMValid & (1 << (dimm << 1)))
--                              AgesaHwWlPhase1(pDCTstat->C_MCTPtr, DCTPtr, 
dimm, FirstPass);
-+                      if (DIMMValid & (1 << (dimm << 1))) {
-+                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
-+                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
-+                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
-+                      }
-               }
-       }
- }
-@@ -146,27 +151,40 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
-               pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = 
pDCTstat->TargetFreq;
-               pDCTstat->CASL = pDCTstat->DIMMCASL = pDCTstat->TargetCASL;
-               SPD2ndTiming(pMCTstat, pDCTstat, dct);
--              ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
--              PlatformSpec_D(pMCTstat, pDCTstat, dct);
--              fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-+              if (!is_fam15h()) {
-+                      ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
-+                      PlatformSpec_D(pMCTstat, pDCTstat, dct);
-+                      fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-+              }
-               Restore_OnDimmMirror(pMCTstat, pDCTstat);
-               StartupDCT_D(pMCTstat, pDCTstat, dct);
-               Clear_OnDimmMirror(pMCTstat, pDCTstat);
-               SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
-               DisableAutoRefresh_D(pMCTstat, pDCTstat);
-               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
--                      if (DIMMValid & (1 << (dimm << 1)))
--                              AgesaHwWlPhase1(pDCTstat->C_MCTPtr, 
pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
-+                      if (DIMMValid & (1 << (dimm << 1))) {
-+                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
-+                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
-+                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
-+                      }
-               }
-       }
- }
- 
-+static uint16_t fam15h_next_highest_memclk_freq(uint16_t memclk_freq)
-+{
-+      uint16_t fam15h_next_highest_freq_tab[] = {0, 0, 0, 0, 0x6, 0, 0xa, 0, 
0, 0, 0xe, 0, 0, 0, 0x12, 0, 0, 0, 0x16, 0, 0, 0, 0x16};
-+      return fam15h_next_highest_freq_tab[memclk_freq];
-+}
-+
- /* Write Levelization Training
-  * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
-  */
- static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat)
-+                                      struct DCTStatStruc *pDCTstat, uint8_t 
Pass)
- {
-+      uint16_t final_target_freq;
-+
-       pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
-       pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
-       pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
-@@ -182,16 +200,39 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
-               pDCTstat->DIMMValidDCT[1] = pDCTstat->DIMMValidDCT[0];
-       }
- 
--      PhyWLPass1(pMCTstat, pDCTstat, 0);
--      PhyWLPass1(pMCTstat, pDCTstat, 1);
-+      if (Pass == FirstPass) {
-+              PhyWLPass1(pMCTstat, pDCTstat, 0);
-+              PhyWLPass1(pMCTstat, pDCTstat, 1);
-+      }
-+
-+      if (Pass == SecondPass) {
-+              if (pDCTstat->TargetFreq > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-+                      /* 8.Prepare the memory subsystem for the target MEMCLK 
frequency.
-+                       * NOTE: BIOS must program both DCTs to the same 
frequency.
-+                       * NOTE: Fam15h steps the frequency, Fam10h slams the 
frequency.
-+                       */
-+                      final_target_freq = pDCTstat->TargetFreq;
-+
-+                      while (pDCTstat->Speed != final_target_freq) {
-+                              if (is_fam15h())
-+                                      pDCTstat->TargetFreq = 
fam15h_next_highest_memclk_freq(pDCTstat->Speed);
-+                              else
-+                                      pDCTstat->TargetFreq = 
final_target_freq;
-+                              SetTargetFreq(pMCTstat, pDCTstat);
-+                              PhyWLPass2(pMCTstat, pDCTstat, 0);
-+                              PhyWLPass2(pMCTstat, pDCTstat, 1);
-+                      }
-+
-+                      pDCTstat->TargetFreq = final_target_freq;
- 
--      if (pDCTstat->TargetFreq > 4) {
--              /* 8.Prepare the memory subsystem for the target MEMCLK 
frequency.
--               * Note: BIOS must program both DCTs to the same frequency.
--               */
--              SetTargetFreq(pMCTstat, pDCTstat);
--              PhyWLPass2(pMCTstat, pDCTstat, 0);
--              PhyWLPass2(pMCTstat, pDCTstat, 1);
-+                      uint8_t dct;
-+                      for (dct = 0; dct < 2; dct++) {
-+                              sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+                              memcpy(pDCTData->WLGrossDelayFinalPass, 
pDCTData->WLGrossDelayPrevPass, sizeof(pDCTData->WLGrossDelayPrevPass));
-+                              memcpy(pDCTData->WLFineDelayFinalPass, 
pDCTData->WLFineDelayPrevPass, sizeof(pDCTData->WLFineDelayPrevPass));
-+                              pDCTData->WLCriticalGrossDelayFinalPass = 
pDCTData->WLCriticalGrossDelayPrevPass;
-+                      }
-+              }
-       }
- 
-       SetEccWrDQS_D(pMCTstat, pDCTstat);
-@@ -200,7 +241,7 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
- }
- 
- void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstatA)
-+                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Pass)
- {
-       u8 Node;
- 
-@@ -211,7 +252,7 @@ void mct_WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
-               if (pDCTstat->NodePresent) {
-                       mctSMBhub_Init(Node);
-                       Clear_OnDimmMirror(pMCTstat, pDCTstat);
--                      WriteLevelization_HW(pMCTstat, pDCTstat);
-+                      WriteLevelization_HW(pMCTstat, pDCTstat, Pass);
-                       Restore_OnDimmMirror(pMCTstat, pDCTstat);
-               }
-       }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-index cda9c6b..5ef4a2c 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-@@ -34,7 +34,7 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 
dct, u32 misc2)
- 
-               if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
-                       misc2 |= 1 << OdtSwizzle;
--              val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78);
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x78);
- 
-               val &= 7;
-               val = ((~val) & 0xff) + 1;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-index bd8b7fb..5ea7fa6 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -23,7 +24,6 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-       u8 Dimms, DimmNum, MaxDimm, Speed;
-       u32 val;
-       u32 dct = 0;
--      u32 reg_off = 0;
- 
-       DimmNum = (MrsChipSel >> 20) & 0xFE;
- 
-@@ -41,7 +41,6 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-               dct = 1;
-               DimmNum ++;
-       }
--      reg_off = 0x100 * dct;
-       Dimms = pDCTstat->MAdimms[dct];
- 
-       val = 0;
-@@ -95,21 +94,21 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
- static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat, u32 val)
- {
--      u32 reg_off = 0;
-+      uint8_t dct = 0;
-       u32 dev = pDCTstat->dev_dct;
- 
-       if (pDCTstat->CSPresent_DCT[0] > 0) {
--              reg_off = 0;
-+              dct = 0;
-       } else if (pDCTstat->CSPresent_DCT[1] > 0 ){
--              reg_off = 0x100;
-+              dct = 1;
-       }
- 
--      val |= Get_NB32(dev, reg_off + 0x7C) & ~0xFFFFFF;
-+      val |= Get_NB32_DCT(dev, dct, 0x7C) & ~0xFFFFFF;
-       val |= 1 << SendControlWord;
--      Set_NB32(dev, reg_off + 0x7C, val);
-+      Set_NB32_DCT(dev, dct, 0x7C, val);
- 
-       do {
--              val = Get_NB32(dev, reg_off + 0x7C);
-+              val = Get_NB32_DCT(dev, dct, 0x7C);
-       } while (val & (1 << SendControlWord));
- }
- 
-@@ -119,7 +118,6 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
-       u8 MrsChipSel;
-       u32 dev = pDCTstat->dev_dct;
-       u32 val, cw;
--      u32 reg_off = 0x100 * dct;
- 
-       mct_Wait(1600);
- 
-@@ -127,7 +125,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
- 
-       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
--                      val = Get_NB32(dev, reg_off + 0xA8);
-+                      val = Get_NB32_DCT(dev, dct, 0xa8);
-                       val &= ~(0xF << 8);
- 
-                       switch (MrsChipSel) {
-@@ -144,7 +142,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
-                       case 7:
-                               val |= (3 << 6) << 8;
-                       }
--                      Set_NB32(dev, reg_off + 0xA8 , val);
-+                      Set_NB32_DCT(dev, dct, 0xa8, val);
- 
-                       for (cw=0; cw <=15; cw ++) {
-                               mct_Wait(1600);
-@@ -171,10 +169,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
-       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
-                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
--                      val = Get_NB32(dev, 0xA8); /* TODO: dct * 0x100 + 0xA8 
*/
-+                      val = Get_NB32_DCT(dev, 0, 0xA8); /* TODO: dct 0 / 1 
select */
-                       val &= ~(0xFF << 8);
-                       val |= (0x3 << (MrsChipSel & 0xFE)) << 8;
--                      Set_NB32(dev, 0xA8, val); /* TODO: dct * 0x100 + 0xA8 */
-+                      Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 
select */
- 
-                       /* Resend control word 10 */
-                       mct_Wait(1600);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index b21b96a..51cbf16 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -18,17 +18,182 @@
-  * Foundation, Inc.
-  */
- 
-+static uint8_t fam15_dimm_dic(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
-+{
-+      uint8_t dic;
-+
-+      /* Calculate DIC based on recommendations in MR1_dct[1:0] */
-+      if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+              /* TODO
-+              * LRDIMM unimplemented
-+              */
-+              dic = 0x0;
-+      } else {
-+              dic = 0x1;
-+      }
-+
-+      return dic;
-+}
-+
-+static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
-+{
-+      uint8_t term = 0;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
-+      uint8_t frequency_index;
-+      uint8_t rank_count = pDCTData->DimmRanks[dimm];
-+
-+      if (is_fam15h())
-+              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
-+      else
-+              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
-+
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      if (is_fam15h()) {
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* TODO
-+                       * RDIMM unimplemented
-+                       */
-+              } else {
-+                      if (package_type == PT_GR) {
-+                              /* Socket G34: Fam15h BKDG v3.14 Table 56 */
-+                              if (MaxDimmsInstallable == 1) {
-+                                      term = 0x0;
-+                              } else if (MaxDimmsInstallable == 2) {
-+                                      if ((number_of_dimms == 2) && 
(frequency_index == 0x12)) {
-+                                              term = 0x1;
-+                                      } else if (number_of_dimms == 1) {
-+                                              term = 0x0;
-+                                      } else {
-+                                              term = 0x2;
-+                                      }
-+                              } else if (MaxDimmsInstallable == 3) {
-+                                      if (number_of_dimms == 1) {
-+                                              if (frequency_index <= 0xa) {
-+                                                      term = 0x2;
-+                                              } else {
-+                                                      if (rank_count < 3) {
-+                                                              term = 0x1;
-+                                                      } else {
-+                                                              term = 0x2;
-+                                                      }
-+                                              }
-+                                      } else if (number_of_dimms == 2) {
-+                                              term = 0x2;
-+                                      }
-+                              }
-+                      } else {
-+                              /* TODO
-+                              * Other sockets unimplemented
-+                              */
-+                      }
-+              }
-+      }
-+
-+      return term;
-+}
-+
-+static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
-+{
-+      uint8_t term = 0;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
-+      uint8_t frequency_index;
-+
-+      if (is_fam15h())
-+              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
-+      else
-+              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
-+
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      if (is_fam15h()) {
-+              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* TODO
-+                       * LRDIMM unimplemented
-+                       */
-+              } else if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* TODO
-+                       * RDIMM unimplemented
-+                       */
-+              } else {
-+                      if (package_type == PT_GR) {
-+                              /* Socket G34: Fam15h BKDG v3.14 Table 56 */
-+                              if (MaxDimmsInstallable == 1) {
-+                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6))
-+                                              term = 0x2;
-+                                      else if ((frequency_index == 0xa) || 
(frequency_index == 0xe))
-+                                              term = 0x1;
-+                                      else
-+                                              term = 0x3;
-+                              }
-+                              if (MaxDimmsInstallable == 2) {
-+                                      if (number_of_dimms == 1) {
-+                                              if (frequency_index <= 0x6) {
-+                                                      term = 0x2;
-+                                              } else if (frequency_index <= 
0xe) {
-+                                                      term = 0x1;
-+                                              } else {
-+                                                      term = 0x3;
-+                                              }
-+                                      } else {
-+                                              if (frequency_index <= 0xa) {
-+                                                      term = 0x3;
-+                                              } else if (frequency_index <= 
0xe) {
-+                                                      term = 0x5;
-+                                              } else {
-+                                                      term = 0x4;
-+                                              }
-+                                      }
-+                              } else if (MaxDimmsInstallable == 3) {
-+                                      if (number_of_dimms == 1) {
-+                                              term = 0x0;
-+                                      } else if (number_of_dimms == 2) {
-+                                              if (frequency_index <= 0xa) {
-+                                                      if (rank == 1) {
-+                                                              term = 0x0;
-+                                                      } else {
-+                                                              term = 0x3;
-+                                                      }
-+                                              } else if (frequency_index <= 
0xe) {
-+                                                      if (rank == 1) {
-+                                                              term = 0x0;
-+                                                      } else {
-+                                                              term = 0x5;
-+                                                      }
-+                                              }
-+                                      }
-+                              }
-+                      } else {
-+                              /* TODO
-+                               * Other sockets unimplemented
-+                               */
-+                      }
-+              }
-+      }
-+
-+      return term;
-+}
-+
- static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct);
- 
- static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 val;
- 
-       do {
--              val = Get_NB32(dev, reg_off + 0x98);
-+              val = Get_NB32_DCT(dev, dct, 0x98);
-       } while (!(val & (1 << DctAccessDone)));
- }
- 
-@@ -54,9 +219,15 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 
MR_register_setting,
-                       if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
-                       if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
-                       if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
--                      if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
--                      if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
--                      MR_register_setting &= ~0x301f8;
-+                      if (is_fam15h()) {
-+                              if (MR_register_setting & (1 << 18)) ret |= 1 
<< 19;
-+                              if (MR_register_setting & (1 << 19)) ret |= 1 
<< 18;
-+                              MR_register_setting &= ~0x000c01f8;
-+                      } else {
-+                              if (MR_register_setting & (1 << 16)) ret |= 1 
<< 17;
-+                              if (MR_register_setting & (1 << 17)) ret |= 1 
<< 16;
-+                              MR_register_setting &= ~0x000301f8;
-+                      }
-                       MR_register_setting |= ret;
-               }
-       }
-@@ -65,47 +236,76 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, 
u32 MR_register_setting,
- 
- static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 val;
- 
--      val = Get_NB32(dev, reg_off + 0x7C);
--      val &= ~0xFFFFFF;
-+      val = Get_NB32_DCT(dev, dct, 0x7c);
-+      val &= ~0x00ffffff;
-       val |= EMRS;
-       val |= 1 << SendMrsCmd;
--      Set_NB32(dev, reg_off + 0x7C, val);
-+      Set_NB32_DCT(dev, dct, 0x7c, val);
- 
-       do {
--              val = Get_NB32(dev, reg_off + 0x7C);
-+              val = Get_NB32_DCT(dev, dct, 0x7c);
-       } while (val & (1 << SendMrsCmd));
- }
- 
- static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret;
- 
--      ret = 0x20000;
--      ret |= MrsChipSel;
-+      if (is_fam15h()) {
-+              uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+
-+              /* The formula for chip select number is: CS = dimm*2+rank */
-+              uint8_t dimm = MrsChipSel / 2;
-+              uint8_t rank = MrsChipSel % 2;
- 
--      /* program MrsAddress[5:3]=CAS write latency (CWL):
--       * based on F2x[1,0]84[Tcwl] */
--      dword = Get_NB32(dev, reg_off + 0x84);
--      dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
-+              /* FIXME: These parameters should be configurable
-+               * For now, err on the side of caution and enable automatic 2x 
refresh
-+               * when the DDR temperature rises above the internal limits
-+               */
-+              uint8_t force_2x_self_refresh = 0;      /* ASR */
-+              uint8_t auto_2x_self_refresh = 1;       /* SRT */
- 
--      ret |= ((dword >> 20) & 7) << 3;
-+              ret = 0x80000;
-+              ret |= (MrsChipSel << 21);
- 
--      /* program MrsAddress[6]=auto self refresh method (ASR):
--         based on F2x[1,0]84[ASR]
--         program MrsAddress[7]=self refresh temperature range (SRT):
--         based on F2x[1,0]84[ASR and SRT] */
--      ret |= ((dword >> 18) & 3) << 6;
-+              /* Set self refresh parameters */
-+              ret |= (force_2x_self_refresh << 6);
-+              ret |= (auto_2x_self_refresh << 7);
- 
--      /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
--         based on F2x[1,0]84[DramTermDyn] */
--      ret |= ((dword >> 10) & 3) << 9;
-+              /* Obtain Tcwl, adjust, and set CWL with the adjusted value */
-+              dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
-+              ret |= ((dword - 5) << 3);
-+
-+              /* Obtain and set RttWr */
-+              ret |= (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 
9);
-+      } else {
-+              ret = 0x20000;
-+              ret |= (MrsChipSel << 20);
-+
-+              /* program MrsAddress[5:3]=CAS write latency (CWL):
-+               * based on F2x[1,0]84[Tcwl] */
-+              dword = Get_NB32_DCT(dev, dct, 0x84);
-+              dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
-+
-+              ret |= ((dword >> 20) & 7) << 3;
-+
-+              /* program MrsAddress[6]=auto self refresh method (ASR):
-+               * based on F2x[1,0]84[ASR]
-+               * program MrsAddress[7]=self refresh temperature range (SRT):
-+               * based on F2x[1,0]84[ASR and SRT]
-+               */
-+              ret |= ((dword >> 18) & 3) << 6;
-+
-+              /* program MrsAddress[10:9]=dynamic termination during writes 
(RTT_WR)
-+               * based on F2x[1,0]84[DramTermDyn]
-+               */
-+              ret |= ((dword >> 10) & 3) << 9;
-+      }
- 
-       return ret;
- }
-@@ -113,20 +313,28 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
- static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret;
- 
--      ret = 0x30000;
--      ret |= MrsChipSel;
-+      if (is_fam15h()) {
-+              ret = 0xc0000;
-+              ret |= (MrsChipSel << 21);
- 
--      /* program MrsAddress[1:0]=multi purpose register address location
--         (MPR Location):based on F2x[1,0]84[MprLoc]
--         program MrsAddress[2]=multi purpose register
--         (MPR):based on F2x[1,0]84[MprEn]
--      */
--      dword = Get_NB32(dev, reg_off + 0x84);
--      ret |= (dword >> 24) & 7;
-+              /* Program MPR and MPRLoc to 0 */
-+              // ret |= 0x0;          /* MPR */
-+              // ret |= (0x0 << 2);   /* MPRLoc */
-+      } else {
-+              ret = 0x30000;
-+              ret |= (MrsChipSel << 20);
-+
-+              /* program MrsAddress[1:0]=multi purpose register address 
location
-+               * (MPR Location):based on F2x[1,0]84[MprLoc]
-+               * program MrsAddress[2]=multi purpose register
-+               * (MPR):based on F2x[1,0]84[MprEn]
-+               */
-+              dword = Get_NB32_DCT(dev, dct, 0x84);
-+              ret |= (dword >> 24) & 7;
-+      }
- 
-       return ret;
- }
-@@ -134,48 +342,93 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
- static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret;
- 
--      ret = 0x10000;
--      ret |= MrsChipSel;
--
--      /* program MrsAddress[5,1]=output driver impedance control (DIC):
--       * based on F2x[1,0]84[DrvImpCtrl] */
--      dword = Get_NB32(dev, reg_off + 0x84);
--      if (dword & (1 << 3))
--              ret |= 1 << 5;
--      if (dword & (1 << 2))
--              ret |= 1 << 1;
--
--      /* program MrsAddress[9,6,2]=nominal termination resistance of ODT 
(RTT):
--         based on F2x[1,0]84[DramTerm] */
--      if (!(pDCTstat->Status & (1 << SB_Registered))) {
--              if (dword & (1 << 9))
--                      ret |= 1 << 9;
--              if (dword & (1 << 8))
--                      ret |= 1 << 6;
--              if (dword & (1 << 7))
--                      ret |= 1 << 2;
-+      if (is_fam15h()) {
-+              uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+
-+              /* Set defaults */
-+              uint8_t qoff = 0;       /* Enable output buffers */
-+              uint8_t wrlvl = 0;      /* Disable write levelling */
-+              uint8_t tqds = 0;
-+              uint8_t rttnom = 0;
-+              uint8_t dic = 0;
-+              uint8_t additive_latency = 0;
-+              uint8_t dll_enable = 0;
-+
-+              ret = 0x40000;
-+              ret |= (MrsChipSel << 21);
-+
-+              /* The formula for chip select number is: CS = dimm*2+rank */
-+              uint8_t dimm = MrsChipSel / 2;
-+              uint8_t rank = MrsChipSel % 2;
-+
-+              /* Determine if TQDS should be set */
-+              if ((pDCTstat->Dimmx8Present & (1 << dimm))
-+                      && (((dimm & 
0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0)
-+                      && (pDCTstat->Status & (1 << SB_LoadReduced)))
-+                      tqds = 1;
-+
-+              /* Obtain RttNom */
-+              rttnom = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
-+
-+              /* Obtain DIC */
-+              dic = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
-+
-+              /* Load data into MRS word */
-+              ret |= (qoff & 0x1) << 12;
-+              ret |= (tqds & 0x1) << 11;
-+              ret |= ((rttnom & 0x4) >> 2) << 9;
-+              ret |= ((rttnom & 0x2) >> 1) << 6;
-+              ret |= ((rttnom & 0x1) >> 0) << 2;
-+              ret |= (wrlvl & 0x1) << 7;
-+              ret |= ((dic & 0x2) >> 1) << 5;
-+              ret |= ((dic & 0x1) >> 0) << 1;
-+              ret |= (additive_latency & 0x3) << 3;
-+              ret |= (dll_enable & 0x1);
-       } else {
--              ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel);
--      }
-+              ret = 0x10000;
-+              ret |= (MrsChipSel << 20);
-+
-+              /* program MrsAddress[5,1]=output driver impedance control 
(DIC):
-+               * based on F2x[1,0]84[DrvImpCtrl]
-+               */
-+              dword = Get_NB32_DCT(dev, dct, 0x84);
-+              if (dword & (1 << 3))
-+                      ret |= 1 << 5;
-+              if (dword & (1 << 2))
-+                      ret |= 1 << 1;
-+
-+              /* program MrsAddress[9,6,2]=nominal termination resistance of 
ODT (RTT):
-+               * based on F2x[1,0]84[DramTerm]
-+               */
-+              if (!(pDCTstat->Status & (1 << SB_Registered))) {
-+                      if (dword & (1 << 9))
-+                              ret |= 1 << 9;
-+                      if (dword & (1 << 8))
-+                              ret |= 1 << 6;
-+                      if (dword & (1 << 7))
-+                              ret |= 1 << 2;
-+              } else {
-+                      ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, 
MrsChipSel);
-+              }
- 
--      /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
--      if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
--              u8 bit;
--              /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 
& x4 */
--              bit = (ret >> 21) << 1;
--              if ((dct & 1) != 0)
--                      bit ++;
--              if (pDCTstat->Dimmx8Present & (1 << bit))
--                      ret |= 1 << 11;
--      }
-+              /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
-+              if (Get_NB32_DCT(dev, dct, 0x94) & (1 << RDqsEn)) {
-+                      u8 bit;
-+                      /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when 
mixed x8 & x4 */
-+                      bit = (ret >> 21) << 1;
-+                      if ((dct & 1) != 0)
-+                              bit ++;
-+                      if (pDCTstat->Dimmx8Present & (1 << bit))
-+                              ret |= 1 << 11;
-+              }
- 
--      /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
--      if (dword & (1 << 13))
--              ret |= 1 << 12;
-+              /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
-+              if (dword & (1 << 13))
-+                      ret |= 1 << 12;
-+      }
- 
-       return ret;
- }
-@@ -183,60 +436,139 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
- static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret, dword2;
- 
--      ret = 0x00000;
--      ret |= MrsChipSel;
--
--      /* program MrsAddress[1:0]=burst length and control method
--         (BL):based on F2x[1,0]84[BurstCtrl] */
--      dword = Get_NB32(dev, reg_off + 0x84);
--      ret |= dword & 3;
--
--      /* program MrsAddress[3]=1 (BT):interleaved */
--      ret |= 1 << 3;
--
--      /* program MrsAddress[6:4,2]=read CAS latency
--         (CL):based on F2x[1,0]88[Tcl] */
--      dword2 = Get_NB32(dev, reg_off + 0x88);
--      ret |= (dword2 & 0x7) << 4;             /* F2x88[2:0] to 
MrsAddress[6:4] */
--      ret |= ((dword2 & 0x8) >> 3) << 2;      /* F2x88[3] to MrsAddress[2] */
--
--      /* program MrsAddress[12]=0 (PPD):slow exit */
--      if (dword & (1 << 23))
--              ret |= 1 << 12;
--
--      /* program MrsAddress[11:9]=write recovery for auto-precharge
--         (WR):based on F2x[1,0]84[Twr] */
--      ret |= ((dword >> 4) & 7) << 9;
--
--      /* program MrsAddress[8]=1 (DLL):DLL reset
--         just issue DLL reset at first time */
--      ret |= 1 << 8;
-+      if (is_fam15h()) {
-+              ret = 0x00000;
-+              ret |= (MrsChipSel << 21);
-+
-+              /* Set defaults */
-+              uint8_t ppd = 0;
-+              uint8_t wr_ap = 0;
-+              uint8_t dll_reset = 1;
-+              uint8_t test_mode = 0;
-+              uint8_t cas_latency = 0;
-+              uint8_t read_burst_type = 1;
-+              uint8_t burst_length = 0;
-+
-+              /* Obtain PchgPDModeSel */
-+              dword = Get_NB32_DCT(dev, dct, 0x84);
-+              ppd = (dword >> 23) & 0x1;
-+
-+              /* Obtain Twr */
-+              dword = Get_NB32_DCT(dev, dct, 0x22c) & 0x1f;
-+
-+              /* Calculate wr_ap (Fam15h BKDG v3.14 Table 82) */
-+              if (dword == 0x10)
-+                      wr_ap = 0x0;
-+              else if (dword == 0x5)
-+                      wr_ap = 0x1;
-+              else if (dword == 0x6)
-+                      wr_ap = 0x2;
-+              else if (dword == 0x7)
-+                      wr_ap = 0x3;
-+              else if (dword == 0x8)
-+                      wr_ap = 0x4;
-+              else if (dword == 0xa)
-+                      wr_ap = 0x5;
-+              else if (dword == 0xc)
-+                      wr_ap = 0x6;
-+              else if (dword == 0xe)
-+                      wr_ap = 0x7;
-+
-+              /* Obtain Tcl */
-+              dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
-+
-+              /* Calculate cas_latency (Fam15h BKDG v3.14 Table 83) */
-+              if (dword == 0x5)
-+                      cas_latency = 0x2;
-+              else if (dword == 0x6)
-+                      cas_latency = 0x4;
-+              else if (dword == 0x7)
-+                      cas_latency = 0x6;
-+              else if (dword == 0x8)
-+                      cas_latency = 0x8;
-+              else if (dword == 0x9)
-+                      cas_latency = 0xa;
-+              else if (dword == 0xa)
-+                      cas_latency = 0xc;
-+              else if (dword == 0xb)
-+                      cas_latency = 0xe;
-+              else if (dword == 0xc)
-+                      cas_latency = 0x1;
-+              else if (dword == 0xd)
-+                      cas_latency = 0x3;
-+              else if (dword == 0xe)
-+                      cas_latency = 0x5;
-+              else if (dword == 0xf)
-+                      cas_latency = 0x7;
-+              else if (dword == 0x10)
-+                      cas_latency = 0x9;
-+
-+              /* Obtain BurstCtrl */
-+              burst_length = Get_NB32_DCT(dev, dct, 0x84) & 0x3;
-+
-+              /* Load data into MRS word */
-+              ret |= (ppd & 0x1) << 12;
-+              ret |= (wr_ap & 0x3) << 9;
-+              ret |= (dll_reset & 0x1) << 8;
-+              ret |= (test_mode & 0x1) << 7;
-+              ret |= ((cas_latency & 0xe) >> 1) << 4;
-+              ret |= ((cas_latency & 0x1) >> 0) << 2;
-+              ret |= (read_burst_type & 0x1) << 3;
-+              ret |= (burst_length & 0x3);
-+      } else {
-+              ret = 0x00000;
-+              ret |= (MrsChipSel << 20);
-+
-+              /* program MrsAddress[1:0]=burst length and control method
-+              (BL):based on F2x[1,0]84[BurstCtrl] */
-+              dword = Get_NB32_DCT(dev, dct, 0x84);
-+              ret |= dword & 3;
-+
-+              /* program MrsAddress[3]=1 (BT):interleaved */
-+              ret |= 1 << 3;
-+
-+              /* program MrsAddress[6:4,2]=read CAS latency
-+              (CL):based on F2x[1,0]88[Tcl] */
-+              dword2 = Get_NB32_DCT(dev, dct, 0x88);
-+              ret |= (dword2 & 0x7) << 4;             /* F2x88[2:0] to 
MrsAddress[6:4] */
-+              ret |= ((dword2 & 0x8) >> 3) << 2;      /* F2x88[3] to 
MrsAddress[2] */
-+
-+              /* program MrsAddress[12]=0 (PPD):slow exit */
-+              if (dword & (1 << 23))
-+                      ret |= 1 << 12;
-+
-+              /* program MrsAddress[11:9]=write recovery for auto-precharge
-+              (WR):based on F2x[1,0]84[Twr] */
-+              ret |= ((dword >> 4) & 7) << 9;
-+
-+              /* program MrsAddress[8]=1 (DLL):DLL reset
-+              just issue DLL reset at first time */
-+              ret |= 1 << 8;
-+      }
- 
-       return ret;
- }
- 
- static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
- {
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword;
- 
-       /*1.Program MrsAddress[10]=1
-         2.Set SendZQCmd=1
-        */
--      dword = Get_NB32(dev, reg_off + 0x7C);
-+      dword = Get_NB32_DCT(dev, dct, 0x7C);
-       dword &= ~0xFFFFFF;
-       dword |= 1 << 10;
-       dword |= 1 << SendZQCmd;
--      Set_NB32(dev, reg_off + 0x7C, dword);
-+      Set_NB32_DCT(dev, dct, 0x7C, dword);
- 
-       /* Wait for SendZQCmd=0 */
-       do {
--              dword = Get_NB32(dev, reg_off + 0x7C);
-+              dword = Get_NB32_DCT(dev, dct, 0x7C);
-       } while (dword & (1 << SendZQCmd));
- 
-       /* 4.Wait 512 MEMCLKs */
-@@ -248,31 +580,30 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
- {
-       u8 MrsChipSel;
-       u32 dword;
--      u32 reg_off = 0x100 * dct;
-       u32 dev = pDCTstat->dev_dct;
- 
--      if (pDCTstat->DIMMAutoSpeed == 4) {
-+      if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-               /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
--              dword = Get_NB32(dev, reg_off + 0x7C);
-+              dword = Get_NB32_DCT(dev, dct, 0x7c);
-               dword |= 1 << EnDramInit;
--              Set_NB32(dev, reg_off + 0x7C, dword);
-+              Set_NB32_DCT(dev, dct, 0x7c, dword);
-               mct_DCTAccessDone(pDCTstat, dct);
- 
-               /* 4.wait 200us */
-               mct_Wait(40000);
- 
--              /* 5.On revision C processors, program F2x[1, 
0]7C[DeassertMemRstX] = 1. */
--              dword = Get_NB32(dev, reg_off + 0x7C);
-+              /* 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1. */
-+              dword = Get_NB32_DCT(dev, dct, 0x7c);
-               dword |= 1 << DeassertMemRstX;
--              Set_NB32(dev, reg_off + 0x7C, dword);
-+              Set_NB32_DCT(dev, dct, 0x7c, dword);
- 
-               /* 6.wait 500us */
-               mct_Wait(200000);
- 
-               /* 7.Program F2x[1,0]7C[AssertCke]=1 */
--              dword = Get_NB32(dev, reg_off + 0x7C);
-+              dword = Get_NB32_DCT(dev, dct, 0x7c);
-               dword |= 1 << AssertCke;
--              Set_NB32(dev, reg_off + 0x7C, dword);
-+              Set_NB32_DCT(dev, dct, 0x7c, dword);
- 
-               /* 8.wait 360ns */
-               mct_Wait(80);
-@@ -281,6 +612,13 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-                * must be done for each chip select pair */
-               if (pDCTstat->Status & (1 << SB_Registered))
-                       mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
-+
-+              /* The following steps are performed with load reduced DIMMs 
only and
-+               * must be done for each DIMM */
-+              // if (pDCTstat->Status & (1 << SB_LoadReduced))
-+                      /* TODO
-+                       * Implement LRDIMM configuration
-+                       */
-       }
- 
-       /* The following steps are performed once for unbuffered DIMMs and once 
for each
-@@ -289,23 +627,23 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
-                       u32 EMRS;
-                       /* 13.Send EMRS(2) */
--                      EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
-+                      EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel);
-                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
-                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
-                       /* 14.Send EMRS(3). Ordinarily at this time, 
MrsAddress[2:0]=000b */
--                      EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
-+                      EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel);
-                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
-                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
-                       /* 15.Send EMRS(1) */
--                      EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
-+                      EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel);
-                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
-                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
-                       /* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
--                      EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
-+                      EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel);
-                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
-                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
- 
--                      if (pDCTstat->DIMMAutoSpeed == 4)
-+                      if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
-                               if (!(pDCTstat->Status & (1 << SB_Registered)))
-                                       break; /* For UDIMM, only send MR 
commands once per channel */
-               }
-@@ -314,16 +652,15 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-                               MrsChipSel ++;
-       }
- 
--      mct_Wait(100000);
--
--      if (pDCTstat->DIMMAutoSpeed == 4) {
-+      if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-               /* 17.Send two ZQCL commands */
-               mct_SendZQCmd(pDCTstat, dct);
-               mct_SendZQCmd(pDCTstat, dct);
-+
-               /* 18.Program F2x[1,0]7C[EnDramInit]=0 */
--              dword = Get_NB32(dev, reg_off + 0x7C);
-+              dword = Get_NB32_DCT(dev, dct, 0x7C);
-               dword &= ~(1 << EnDramInit);
--              Set_NB32(dev, reg_off + 0x7C, dword);
-+              Set_NB32_DCT(dev, dct, 0x7C, dword);
-               mct_DCTAccessDone(pDCTstat, dct);
-       }
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 91e8f77..011a94f 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -23,7 +23,10 @@
-  Description: Receiver En and DQS Timing Training feature for DDR 3 MCT
- 
******************************************************************************/
- 
--static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
-+static int32_t abs(int32_t val);
-+static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, u8 Pass);
-+static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Pass);
- static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
-                                        struct DCTStatStruc *pDCTstat);
-@@ -32,7 +35,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
- static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Channel);
- static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, 
u16 DQSRcvEnDly);
--static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
-+static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat, u8 dct);
- static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat);
- 
-@@ -89,11 +92,154 @@ static void SetupRcvrPattern(struct MCTStatStruc 
*pMCTstat,
- void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat, u8 Pass)
- {
--      if(mct_checkNumberOfDqsRcvEn_1Pass(Pass))
--              dqsTrainRcvrEn_SW(pMCTstat, pDCTstat, Pass);
-+      if(mct_checkNumberOfDqsRcvEn_1Pass(Pass)) {
-+              if (is_fam15h())
-+                      dqsTrainRcvrEn_SW_Fam15(pMCTstat, pDCTstat, Pass);
-+              else
-+                      dqsTrainRcvrEn_SW_Fam10(pMCTstat, pDCTstat, Pass);
-+      }
- }
- 
--static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
-+static uint16_t fam15_receiver_enable_training_seed(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
-+{
-+      uint32_t dword;
-+      uint16_t seed = 0;
-+
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      uint8_t channel = dct;
-+      if (package_type == PT_GR) {
-+              /* Get the internal node number */
-+              dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
-+              dword = (dword >> 30) & 0x3;
-+              if (dword == 1) {
-+                      channel += 2;
-+              }
-+      }
-+
-+      if (pDCTstat->Status & (1 << SB_Registered)) {
-+              if (package_type == PT_GR) {
-+                      /* Socket G34: Fam15h BKDG v3.14 Table 99 */
-+                      if (MaxDimmsInstallable == 1) {
-+                              if (channel == 0)
-+                                      seed = 0x43;
-+                              else if (channel == 1)
-+                                      seed = 0x3f;
-+                              else if (channel == 2)
-+                                      seed = 0x3a;
-+                              else if (channel == 3)
-+                                      seed = 0x35;
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (channel == 0)
-+                                      seed = 0x54;
-+                              else if (channel == 1)
-+                                      seed = 0x4d;
-+                              else if (channel == 2)
-+                                      seed = 0x45;
-+                              else if (channel == 3)
-+                                      seed = 0x40;
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              if (channel == 0)
-+                                      seed = 0x6b;
-+                              else if (channel == 1)
-+                                      seed = 0x5e;
-+                              else if (channel == 2)
-+                                      seed = 0x4b;
-+                              else if (channel == 3)
-+                                      seed = 0x3d;
-+                      }
-+              } else if (package_type == PT_C3) {
-+                      /* Socket C32: Fam15h BKDG v3.14 Table 100 */
-+                      if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable 
== 2)) {
-+                              if (channel == 0)
-+                                      seed = 0x3f;
-+                              else if (channel == 1)
-+                                      seed = 0x3e;
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              if (channel == 0)
-+                                      seed = 0x47;
-+                              else if (channel == 1)
-+                                      seed = 0x38;
-+                      }
-+              }
-+      } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+              if (package_type == PT_GR) {
-+                      /* Socket G34: Fam15h BKDG v3.14 Table 99 */
-+                      if (MaxDimmsInstallable == 1) {
-+                              if (channel == 0)
-+                                      seed = 0x123;
-+                              else if (channel == 1)
-+                                      seed = 0x122;
-+                              else if (channel == 2)
-+                                      seed = 0x112;
-+                              else if (channel == 3)
-+                                      seed = 0x102;
-+                      }
-+              } else if (package_type == PT_C3) {
-+                      /* Socket C32: Fam15h BKDG v3.14 Table 100 */
-+                      if (channel == 0)
-+                              seed = 0x132;
-+                      else if (channel == 1)
-+                              seed = 0x122;
-+              }
-+      } else {
-+              if (package_type == PT_GR) {
-+                      /* Socket G34: Fam15h BKDG v3.14 Table 99 */
-+                      if (MaxDimmsInstallable == 1) {
-+                              if (channel == 0)
-+                                      seed = 0x3e;
-+                              else if (channel == 1)
-+                                      seed = 0x38;
-+                              else if (channel == 2)
-+                                      seed = 0x37;
-+                              else if (channel == 3)
-+                                      seed = 0x31;
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (channel == 0)
-+                                      seed = 0x51;
-+                              else if (channel == 1)
-+                                      seed = 0x4a;
-+                              else if (channel == 2)
-+                                      seed = 0x46;
-+                              else if (channel == 3)
-+                                      seed = 0x3f;
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              if (channel == 0)
-+                                      seed = 0x5e;
-+                              else if (channel == 1)
-+                                      seed = 0x52;
-+                              else if (channel == 2)
-+                                      seed = 0x48;
-+                              else if (channel == 3)
-+                                      seed = 0x3c;
-+                      }
-+              } else if (package_type == PT_C3) {
-+                      /* Socket C32: Fam15h BKDG v3.14 Table 100 */
-+                      if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable 
== 2)) {
-+                              if (channel == 0)
-+                                      seed = 0x39;
-+                              else if (channel == 1)
-+                                      seed = 0x32;
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              if (channel == 0)
-+                                      seed = 0x45;
-+                              else if (channel == 1)
-+                                      seed = 0x37;
-+                      }
-+              } else if (package_type == PT_M2) {
-+                      /* Socket AM3: Fam15h BKDG v3.14 Table 101 */
-+                      seed = 0x3a;
-+              }
-+      }
-+
-+      return seed;
-+}
-+
-+static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
- {
-       uint8_t lane;
-       uint32_t dword;
-@@ -111,7 +257,7 @@ static void 
read_dqs_write_timing_control_registers(uint16_t* current_total_dela
-               if (lane == 8)
-                       wdt_reg = 0x32;
-               wdt_reg += dimm * 3;
--              dword = Get_NB32_index_wait(dev, index_reg, wdt_reg);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg);
-               if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1))
-                       current_total_delay[lane] = (dword & 0x00ff0000) >> 16;
-               if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0))
-@@ -119,12 +265,124 @@ static void 
read_dqs_write_timing_control_registers(uint16_t* current_total_dela
-       }
- }
- 
--static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
-+#ifdef UNUSED_CODE
-+static void write_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t dword;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+              uint32_t ret_reg;
-+              if ((lane == 0) || (lane == 1))
-+                      ret_reg = 0x30;
-+              if ((lane == 2) || (lane == 3))
-+                      ret_reg = 0x31;
-+              if ((lane == 4) || (lane == 5))
-+                      ret_reg = 0x40;
-+              if ((lane == 6) || (lane == 7))
-+                      ret_reg = 0x41;
-+              if (lane == 8)
-+                      ret_reg = 0x32;
-+              ret_reg += dimm * 3;
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
-+              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
-+                      dword &= ~(0xff << 16);
-+                      dword |= (current_total_delay[lane] & 0xff) << 16;
-+              }
-+              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0)) {
-+                      dword &= ~0xff;
-+                      dword |= current_total_delay[lane] & 0xff;
-+              }
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
-+      }
-+}
-+#endif
-+
-+static void write_write_data_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t dword;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+              uint32_t wdt_reg;
-+
-+              /* Calculate Write Data Timing register location */
-+              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
-+                      wdt_reg = 0x1;
-+              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
-+                      wdt_reg = 0x2;
-+              if (lane == 8)
-+                      wdt_reg = 0x3;
-+              wdt_reg |= (dimm << 8);
-+
-+              /* Set Write Data Timing register values */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg);
-+              if ((lane == 7) || (lane == 3)) {
-+                      dword &= ~(0x7f << 24);
-+                      dword |= (current_total_delay[lane] & 0x7f) << 24;
-+              }
-+              if ((lane == 6) || (lane == 2)) {
-+                      dword &= ~(0x7f << 16);
-+                      dword |= (current_total_delay[lane] & 0x7f) << 16;
-+              }
-+              if ((lane == 5) || (lane == 1)) {
-+                      dword &= ~(0x7f << 8);
-+                      dword |= (current_total_delay[lane] & 0x7f) << 8;
-+              }
-+              if ((lane == 8) || (lane == 4) || (lane == 0)) {
-+                      dword &= ~0x7f;
-+                      dword |= current_total_delay[lane] & 0x7f;
-+              }
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg, dword);
-+      }
-+}
-+
-+static void read_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t mask;
-+      uint32_t dword;
-+
-+      if (is_fam15h())
-+              mask = 0x3ff;
-+      else
-+              mask = 0x1ff;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+              uint32_t ret_reg;
-+              if ((lane == 0) || (lane == 1))
-+                      ret_reg = 0x10;
-+              if ((lane == 2) || (lane == 3))
-+                      ret_reg = 0x11;
-+              if ((lane == 4) || (lane == 5))
-+                      ret_reg = 0x20;
-+              if ((lane == 6) || (lane == 7))
-+                      ret_reg = 0x21;
-+              if (lane == 8)
-+                      ret_reg = 0x12;
-+              ret_reg += dimm * 3;
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
-+              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
-+                      current_total_delay[lane] = (dword & (mask << 16)) >> 
16;
-+              }
-+              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0)) {
-+                      current_total_delay[lane] = dword & mask;
-+              }
-+      }
-+}
-+
-+static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
- {
-       uint8_t lane;
-+      uint32_t mask;
-       uint32_t dword;
- 
--      for (lane = 0; lane < 8; lane++) {
-+      if (is_fam15h())
-+              mask = 0x3ff;
-+      else
-+              mask = 0x1ff;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-               uint32_t ret_reg;
-               if ((lane == 0) || (lane == 1))
-                       ret_reg = 0x10;
-@@ -134,17 +392,125 @@ static void 
write_dqs_receiver_enable_control_registers(uint16_t* current_total_
-                       ret_reg = 0x20;
-               if ((lane == 6) || (lane == 7))
-                       ret_reg = 0x21;
-+              if (lane == 8)
-+                      ret_reg = 0x12;
-               ret_reg += dimm * 3;
--              dword = Get_NB32_index_wait(dev, index_reg, ret_reg);
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
-               if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
--                      dword &= ~(0x1ff << 16);
--                      dword |= (current_total_delay[lane] & 0x1ff) << 16;
-+                      dword &= ~(mask << 16);
-+                      dword |= (current_total_delay[lane] & mask) << 16;
-               }
--              if ((lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
--                      dword &= ~0x1ff;
--                      dword |= current_total_delay[lane] & 0x1ff;
-+              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0)) {
-+                      dword &= ~mask;
-+                      dword |= current_total_delay[lane] & mask;
-               }
--              Set_NB32_index_wait(dev, index_reg, ret_reg, dword);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
-+      }
-+}
-+
-+static void read_dram_phase_recovery_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t dword;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+              uint32_t prc_reg;
-+
-+              /* Calculate DRAM Phase Recovery Control register location */
-+              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
-+                      prc_reg = 0x50;
-+              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
-+                      prc_reg = 0x51;
-+              if (lane == 8)
-+                      prc_reg = 0x52;
-+
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg);
-+              if ((lane == 7) || (lane == 3)) {
-+                      current_total_delay[lane] = (dword >> 24) & 0x7f;
-+              }
-+              if ((lane == 6) || (lane == 2)) {
-+                      current_total_delay[lane] = (dword >> 16) & 0x7f;
-+              }
-+              if ((lane == 5) || (lane == 1)) {
-+                      current_total_delay[lane] = (dword >> 8) & 0x7f;
-+              }
-+              if ((lane == 8) || (lane == 4) || (lane == 0)) {
-+                      current_total_delay[lane] = dword & 0x7f;
-+              }
-+      }
-+}
-+
-+static void write_dram_phase_recovery_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t dword;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+              uint32_t prc_reg;
-+
-+              /* Calculate DRAM Phase Recovery Control register location */
-+              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
-+                      prc_reg = 0x50;
-+              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
-+                      prc_reg = 0x51;
-+              if (lane == 8)
-+                      prc_reg = 0x52;
-+
-+              /* Set DRAM Phase Recovery Control register values */
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg);
-+              if ((lane == 7) || (lane == 3)) {
-+                      dword &= ~(0x7f << 24);
-+                      dword |= (current_total_delay[lane] & 0x7f) << 24;
-+              }
-+              if ((lane == 6) || (lane == 2)) {
-+                      dword &= ~(0x7f << 16);
-+                      dword |= (current_total_delay[lane] & 0x7f) << 16;
-+              }
-+              if ((lane == 5) || (lane == 1)) {
-+                      dword &= ~(0x7f << 8);
-+                      dword |= (current_total_delay[lane] & 0x7f) << 8;
-+              }
-+              if ((lane == 8) || (lane == 4) || (lane == 0)) {
-+                      dword &= ~0x7f;
-+                      dword |= current_total_delay[lane] & 0x7f;
-+              }
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg, dword);
-+      }
-+}
-+
-+static void read_read_dqs_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
-+{
-+      uint8_t lane;
-+      uint32_t dword;
-+
-+      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+              uint32_t rdt_reg;
-+
-+              /* Calculate DRAM Read DQS Timing register location */
-+              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
-+                      rdt_reg = 0x5;
-+              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
-+                      rdt_reg = 0x6;
-+              if (lane == 8)
-+                      rdt_reg = 0x7;
-+              rdt_reg |= (dimm << 8);
-+
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, rdt_reg);
-+              if ((lane == 7) || (lane == 3)) {
-+                      current_total_delay[lane] = (dword >> 24) & 0x3f;
-+              }
-+              if ((lane == 6) || (lane == 2)) {
-+                      current_total_delay[lane] = (dword >> 16) & 0x3f;
-+              }
-+              if ((lane == 5) || (lane == 1)) {
-+                      current_total_delay[lane] = (dword >> 8) & 0x3f;
-+              }
-+              if ((lane == 8) || (lane == 4) || (lane == 0)) {
-+                      current_total_delay[lane] = dword & 0x3f;
-+              }
-+
-+              if (is_fam15h())
-+                      current_total_delay[lane] >>= 1;
-       }
- }
- 
-@@ -160,10 +526,11 @@ static uint32_t 
convert_testaddr_and_channel_to_address(struct DCTStatStruc *pDC
-       return testaddr;
- }
- 
--/* DQS Receiver Enable Training
-- * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
-+/* DQS Receiver Enable Training (Family 10h)
-+ * Algorithm detailed in:
-+ * The Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
-  */
--static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
-+static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 Pass)
- {
-       u8 Channel;
-@@ -171,7 +538,6 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-       u8 Addl_Index = 0;
-       u8 Receiver;
-       u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
--      u8 Final_Value;
-       u16 CTLRMaxDelay;
-       u16 MaxDelay_CH[2];
-       u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B;
-@@ -188,6 +554,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-       u32 lo, hi;
- 
-       uint32_t dword;
-+      uint8_t dimm;
-       uint8_t rank;
-       uint8_t lane;
-       uint16_t current_total_delay[MAX_BYTE_LANES];
-@@ -214,14 +581,13 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-       }
- 
-       for (ch = ch_start; ch < ch_end; ch++) {
--              reg = 0x78 + (0x100 * ch);
--              val = Get_NB32(dev, reg);
-+              reg = 0x78;
-+              val = Get_NB32_DCT(dev, ch, reg);
-               val &= ~(0x3ff << 22);
--              val |= (0x0c8 << 22);           /* Max Rd Lat */
--              Set_NB32(dev, reg, val);
-+              val |= (0x0c8 << 22);           /* MaxRdLatency = 0xc8 */
-+              Set_NB32_DCT(dev, ch, reg, val);
-       }
- 
--      Final_Value = 1;
-       if (Pass == FirstPass) {
-               mct_InitDQSPos4RcvrEn_D(pMCTstat, pDCTstat);
-       } else {
-@@ -260,7 +626,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
- 
-               CTLRMaxDelay = 0;
-               MaxDelay_CH[Channel] = 0;
--              index_reg = 0x98 + 0x100 * Channel;
-+              index_reg = 0x98;
- 
-               Receiver = mct_InitReceiver_D(pDCTstat, Channel);
-               /* There are four receiver pairs, loosely associated with 
chipselects.
-@@ -268,6 +634,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                */
-               for (; Receiver < 8; Receiver += 2) {
-                       Addl_Index = (Receiver >> 1) * 3 + 0x10;
-+                      dimm = (Receiver >> 1);
- 
-                       print_debug_dqs("\t\tTrainRcvEnd52: index ", 
Addl_Index, 2);
- 
-@@ -284,45 +651,14 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                       /* 2.8.9.9.2 (1, 6)
-                        * Retrieve gross and fine timing fields from write DQS 
registers
-                        */
--                      
read_dqs_write_timing_control_registers(current_total_delay, dev, (Receiver >> 
1), index_reg);
-+                      
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
- 
-                       /* 2.8.9.9.2 (1)
-                        * Program the Write Data Timing and Write ECC Timing 
register to
-                        * the values stored in the DQS Write Timing Control 
register
-                        * for each lane
-                        */
--                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
--                              uint32_t wdt_reg;
--
--                              /* Calculate Write Data Timing register 
location */
--                              if ((lane == 0) || (lane == 1) || (lane == 2) 
|| (lane == 3))
--                                      wdt_reg = 0x1;
--                              if ((lane == 4) || (lane == 5) || (lane == 6) 
|| (lane == 7))
--                                      wdt_reg = 0x2;
--                              if (lane == 8)
--                                      wdt_reg = 0x3;
--                              wdt_reg |= ((Receiver / 2) << 8);
--
--                              /* Set Write Data Timing register values */
--                              dword = Get_NB32_index_wait(dev, index_reg, 
wdt_reg);
--                              if ((lane == 7) || (lane == 3)) {
--                                      dword &= ~(0x7f << 24);
--                                      dword |= (current_total_delay[lane] & 
0x7f) << 24;
--                              }
--                              if ((lane == 6) || (lane == 2)) {
--                                      dword &= ~(0x7f << 16);
--                                      dword |= (current_total_delay[lane] & 
0x7f) << 16;
--                              }
--                              if ((lane == 5) || (lane == 1)) {
--                                      dword &= ~(0x7f << 8);
--                                      dword |= (current_total_delay[lane] & 
0x7f) << 8;
--                              }
--                              if ((lane == 8) || (lane == 4) || (lane == 0)) {
--                                      dword &= ~0x7f;
--                                      dword |= current_total_delay[lane] & 
0x7f;
--                              }
--                              Set_NB32_index_wait(dev, index_reg, wdt_reg, 
dword);
--                      }
-+                      
write_write_data_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
- 
-                       /* 2.8.9.9.2 (2)
-                        * Program the Read DQS Timing Control and the Read DQS 
ECC Timing Control registers
-@@ -336,12 +672,12 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                                       rdt_reg = 0x6;
-                               if (lane == 8)
-                                       rdt_reg = 0x7;
--                              rdt_reg |= ((Receiver / 2) << 8);
-+                              rdt_reg |= (dimm << 8);
-                               if (lane == 8)
-                                       dword = 0x0000003f;
-                               else
-                                       dword = 0x3f3f3f3f;
--                              Set_NB32_index_wait(dev, index_reg, rdt_reg, 
dword);
-+                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, rdt_reg, dword);
-                       }
- 
-                       /* 2.8.9.9.2 (3)
-@@ -371,7 +707,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", 
TestAddr1B, 2);
- 
-                       /* 2.8.9.9.2 (4, 5)
--                       * Write 1 cache line of the appropriate test pattern 
to each test addresse
-+                       * Write 1 cache line of the appropriate test pattern 
to each test address
-                        */
-                       mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, 
0); /* rank 0 of DIMM, testpattern 0 */
-                       mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0B, 1); /* rank 0 of DIMM, testpattern 1 */
-@@ -390,7 +726,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                       /* 2.8.9.9.2 (6)
-                        * Write gross and fine timing fields to read DQS 
registers
-                        */
--                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
- 
-                       /* 2.8.9.9.2 (7)
-                        * Loop over all delay values up to 1 MEMCLK (0x40 
delay steps) from the initial delay values
-@@ -417,8 +753,8 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                                       break;
- 
-                               /* 2.8.9.9.2 (7 A)
--                              * Loop over all ranks
--                              */
-+                               * Loop over all ranks
-+                               */
-                               for (rank = 0; rank < (_2Ranks + 1); rank++) {
-                                       /* 2.8.9.9.2 (7 A a-d)
-                                        * Read the first test address of the 
current rank
-@@ -434,17 +770,17 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                                                */
-                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
-                                               result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
--                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
-                                               result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
--                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-                                       } else {
-                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
-                                               result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
--                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
-                                               result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
--                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-                                       }
-                                       /* 2.8.9.9.2 (7 A e)
-                                        * Compare both read patterns and flag 
passing ranks/lanes
-@@ -533,7 +869,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-                               }
- 
-                               /* Update delays in hardware */
--                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
-+                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
- 
-                               /* Save previous results for comparison in the 
next iteration */
-                               for (lane = 0; lane < 8; lane++)
-@@ -587,7 +923,483 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
-               mct_SetMaxLatency_D(pDCTstat, Channel, CTLRMaxDelay); /* 
program Ch A/B MaxAsyncLat to correspond with max delay */
-       }
- 
--      ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
-+      for (Channel = 0; Channel < 2; Channel++) {
-+              ResetDCTWrPtr_D(dev, Channel, index_reg, Addl_Index);
-+      }
-+
-+      if(_DisableDramECC) {
-+              mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
-+      }
-+
-+      if (Pass == FirstPass) {
-+              /*Disable DQSRcvrEn training mode */
-+              mct_DisableDQSRcvEn_D(pDCTstat);
-+      }
-+
-+      if(!_Wrap32Dis) {
-+              msr = HWCR;
-+              _RDMSR(msr, &lo, &hi);
-+              lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
-+              _WRMSR(msr, lo, hi);
-+      }
-+      if(!_SSE2){
-+              cr4 = read_cr4();
-+              cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
-+              write_cr4(cr4);
-+      }
-+
-+#if DQS_TRAIN_DEBUG > 0
-+      {
-+              u8 ChannelDTD;
-+              printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
-+              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
-+                      printk(BIOS_DEBUG, "Channel:%x: %x\n",
-+                             ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]);
-+              }
-+      }
-+#endif
-+
-+#if DQS_TRAIN_DEBUG > 0
-+      {
-+              u16 valDTD;
-+              u8 ChannelDTD, ReceiverDTD;
-+              u8 i;
-+              u16 *p;
-+
-+              printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
-+              for(ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
-+                      printk(BIOS_DEBUG, "Channel:%x\n", ChannelDTD);
-+                      for(ReceiverDTD = 0; ReceiverDTD<8; ReceiverDTD+=2) {
-+                              printk(BIOS_DEBUG, "\t\tReceiver:%x:", 
ReceiverDTD);
-+                              p = 
pDCTstat->CH_D_B_RCVRDLY[ChannelDTD][ReceiverDTD>>1];
-+                              for (i=0;i<8; i++) {
-+                                      valDTD = p[i];
-+                                      printk(BIOS_DEBUG, " %03x", valDTD);
-+                              }
-+                              printk(BIOS_DEBUG, "\n");
-+                      }
-+              }
-+      }
-+#endif
-+
-+      printk(BIOS_DEBUG, "TrainRcvrEn: Status %x\n", pDCTstat->Status);
-+      printk(BIOS_DEBUG, "TrainRcvrEn: ErrStatus %x\n", pDCTstat->ErrStatus);
-+      printk(BIOS_DEBUG, "TrainRcvrEn: ErrCode %x\n", pDCTstat->ErrCode);
-+      printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
-+}
-+
-+/* DQS Receiver Enable Training Pattern Generation (Family 15h)
-+ * Algorithm detailed in:
-+ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2 (4)
-+ */
-+static void generate_dram_receiver_enable_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver)
-+{
-+      uint32_t dword;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      /* 2.10.5.7.1.1
-+       * It appears that the DCT only supports 8-beat burst length mode,
-+       * so do nothing here...
-+       */
-+
-+      /* Wait for CmdSendInProg == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x250);
-+      } while (dword & (0x1 << 12));
-+
-+      /* Set CmdTestEnable = 1 */
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword |= (0x1 << 2);
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      /* 2.10.5.8.6.1.1 Send Activate Command */
-+      dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
-+      dword |= ((0x1 << Receiver) << 22);
-+      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
-+      dword &= ~(0x3ffff);                            /* CmdAddress = 0 */
-+      dword |= (0x1 << 31);                           /* SendActCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x28c, dword);
-+
-+      /* Wait for SendActCmd == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      } while (dword & (0x1 << 31));
-+
-+      /* Wait 75 MEMCLKs. */
-+      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
-+
-+      /* 2.10.5.8.6.1.2 */
-+      Set_NB32_DCT(dev, dct, 0x274, 0x0);             /* DQMask = 0 */
-+      Set_NB32_DCT(dev, dct, 0x278, 0x0);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x27c);
-+      dword &= ~(0xff);                               /* EccMask = 0 */
-+      if (pDCTstat->DimmECCPresent == 0)
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+      Set_NB32_DCT(dev, dct, 0x27c, dword);
-+
-+      /* 2.10.5.8.6.1.2 */
-+      dword = Get_NB32_DCT(dev, dct, 0x270);
-+      dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
-+//    dword |= (0x55555);
-+      dword |= (0x44443);                             /* Use AGESA seed */
-+      Set_NB32_DCT(dev, dct, 0x270, dword);
-+
-+      /* 2.10.5.8.2 (4) */
-+      dword = Get_NB32_DCT(dev, dct, 0x260);
-+      dword &= ~(0x1fffff);                           /* CmdCount = 192 */
-+      dword |= 192;
-+      Set_NB32_DCT(dev, dct, 0x260, dword);
-+
-+#if 0
-+      /* TODO: This applies to Fam15h model 10h and above only */
-+      /* Program Bubble Count and CmdStreamLen */
-+      dword = Get_NB32_DCT(dev, dct, 0x25c);
-+      dword &= ~(0x3ff << 12);                        /* BubbleCnt = 0 */
-+      dword &= ~(0x3ff << 22);                        /* BubbleCnt2 = 0 */
-+      dword &= ~(0xff);                               /* CmdStreamLen = 1 */
-+      dword |= 0x1;
-+      Set_NB32_DCT(dev, dct, 0x25c, dword);
-+#endif
-+
-+      /* Configure Target A */
-+      dword = Get_NB32_DCT(dev, dct, 0x254);
-+      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
-+      dword |= (Receiver & 0x7) << 24;
-+      dword &= ~(0x7 << 21);                          /* TgtBank = 0 */
-+      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
-+      Set_NB32_DCT(dev, dct, 0x254, dword);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
-+      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
-+      dword &= ~(0x3 << 8);                           /* CmdTgt = 0 (Target 
A) */
-+      dword &= ~(0x7 << 5);                           /* CmdType = 0 (Read) */
-+      dword |= (0x1 << 11);                           /* SendCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x250);
-+      } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword &= ~(0x1 << 11);                          /* SendCmd = 0 */
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+
-+      /* 2.10.5.8.6.1.1 Send Precharge Command */
-+      /* Wait 25 MEMCLKs. */
-+      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
-+
-+      dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
-+      dword |= ((0x1 << Receiver) << 22);
-+      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
-+      dword &= ~(0x3ffff);                            /* CmdAddress = 0x400 */
-+      dword |= 0x400;
-+      dword |= (0x1 << 30);                           /* SendPchgCmd = 1 */
-+      Set_NB32_DCT(dev, dct, 0x28c, dword);
-+
-+      /* Wait for SendPchgCmd == 0 */
-+      do {
-+              dword = Get_NB32_DCT(dev, dct, 0x28c);
-+      } while (dword & (0x1 << 30));
-+
-+      /* Wait 25 MEMCLKs. */
-+      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
-+
-+      /* Set CmdTestEnable = 0 */
-+      dword = Get_NB32_DCT(dev, dct, 0x250);
-+      dword &= ~(0x1 << 2);
-+      Set_NB32_DCT(dev, dct, 0x250, dword);
-+}
-+
-+/* DQS Receiver Enable Training (Family 15h)
-+ * Algorithm detailed in:
-+ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2
-+ * This algorithm runs once at the lowest supported MEMCLK,
-+ * then once again at the highest supported MEMCLK.
-+ */
-+static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, u8 Pass)
-+{
-+      u8 Channel;
-+      u8 _2Ranks;
-+      u8 Addl_Index = 0;
-+      u8 Receiver;
-+      u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
-+      u32 Errors;
-+
-+      u32 val;
-+      u32 dev;
-+      u32 index_reg;
-+      u32 ch_start, ch_end, ch;
-+      u32 msr;
-+      u32 cr4;
-+      u32 lo, hi;
-+
-+      uint32_t dword;
-+      uint8_t dimm;
-+      uint8_t rank;
-+      uint8_t lane;
-+      uint8_t mem_clk;
-+      uint16_t initial_seed;
-+      uint16_t current_total_delay[MAX_BYTE_LANES];
-+      uint16_t dqs_ret_pass1_total_delay[MAX_BYTE_LANES];
-+      uint16_t rank0_current_total_delay[MAX_BYTE_LANES];
-+      uint16_t phase_recovery_delays[MAX_BYTE_LANES];
-+      uint16_t seed[MAX_BYTE_LANES];
-+      uint16_t seed_gross[MAX_BYTE_LANES];
-+      uint16_t seed_fine[MAX_BYTE_LANES];
-+      uint16_t seed_pre_gross[MAX_BYTE_LANES];
-+
-+      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
-+
-+      print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
-+      print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
-+
-+      dev = pDCTstat->dev_dct;
-+      index_reg = 0x98;
-+      ch_start = 0;
-+      ch_end = 2;
-+
-+      for (ch = ch_start; ch < ch_end; ch++) {
-+              uint8_t max_rd_latency = 0x55;
-+              uint8_t p_state;
-+
-+              /* 2.10.5.6 */
-+              fam15EnableTrainingMode(pMCTstat, pDCTstat, ch, 1);
-+
-+              /* 2.10.5.2 */
-+              for (p_state = 0; p_state < 3; p_state++) {
-+                      val = Get_NB32_DCT_NBPstate(dev, ch, p_state, 0x210);
-+                      val &= ~(0x3ff << 22);                  /* MaxRdLatency 
= max_rd_latency */
-+                      val |= (max_rd_latency & 0x3ff) << 22;
-+                      Set_NB32_DCT_NBPstate(dev, ch, p_state, 0x210, val);
-+              }
-+      }
-+
-+      if (Pass != FirstPass) {
-+              pDCTstat->DimmTrainFail = 0;
-+              pDCTstat->CSTrainFail = ~pDCTstat->CSPresent;
-+      }
-+
-+      cr4 = read_cr4();
-+      if(cr4 & ( 1 << 9)) {   /* save the old value */
-+              _SSE2 = 1;
-+      }
-+      cr4 |= (1 << 9);        /* OSFXSR enable SSE2 */
-+      write_cr4(cr4);
-+
-+      msr = HWCR;
-+      _RDMSR(msr, &lo, &hi);
-+      /* FIXME: Why use SSEDIS */
-+      if(lo & (1 << 17)) {    /* save the old value */
-+              _Wrap32Dis = 1;
-+      }
-+      lo |= (1 << 17);        /* HWCR.wrap32dis */
-+      lo &= ~(1 << 15);       /* SSEDIS */
-+      _WRMSR(msr, lo, hi);    /* Setting wrap32dis allows 64-bit memory 
references in real mode */
-+
-+      _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
-+
-+      Errors = 0;
-+      dev = pDCTstat->dev_dct;
-+
-+      for (Channel = 0; Channel < 2; Channel++) {
-+              print_debug_dqs("\tTrainRcvEn51: Node ", pDCTstat->Node_ID, 1);
-+              print_debug_dqs("\tTrainRcvEn51: Channel ", Channel, 1);
-+              pDCTstat->Channel = Channel;
-+
-+              mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
-+
-+              Receiver = mct_InitReceiver_D(pDCTstat, Channel);
-+              /* There are four receiver pairs, loosely associated with 
chipselects.
-+               * This is essentially looping over each DIMM.
-+               */
-+              for (; Receiver < 8; Receiver += 2) {
-+                      Addl_Index = (Receiver >> 1) * 3 + 0x10;
-+                      dimm = (Receiver >> 1);
-+
-+                      print_debug_dqs("\t\tTrainRcvEnd52: index ", 
Addl_Index, 2);
-+
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
-+                              continue;
-+                      }
-+
-+                      /* Retrieve the total delay values from pass 1 of DQS 
receiver enable training */
-+                      if (Pass != FirstPass) {
-+                              
read_dqs_receiver_enable_control_registers(dqs_ret_pass1_total_delay, dev, 
Channel, dimm, index_reg);
-+                      }
-+
-+                      /* 2.10.5.8.2
-+                       * Loop over all ranks
-+                       */
-+                      if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver+1))
-+                              _2Ranks = 1;
-+                      else
-+                              _2Ranks = 0;
-+                      for (rank = 0; rank < (_2Ranks + 1); rank++) {
-+                              /* 2.10.5.8.2 (1)
-+                               * Specify the target DIMM to be trained
-+                               * Set TrNibbleSel = 0
-+                               *
-+                               * TODO: Add support for x4 DIMMs
-+                               */
-+                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
-+                              dword &= ~(0x3 << 4);           /* TrDimmSel */
-+                              dword |= ((dimm & 0x3) << 4);
-+                              dword &= ~(0x1 << 2);           /* TrNibbleSel 
*/
-+                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
-+
-+                              /* 2.10.5.8.2 (2)
-+                               * Retrieve gross and fine timing fields from 
write DQS registers
-+                               */
-+                              
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-+
-+                              /* 2.10.5.8.2.1
-+                               * Generate the DQS Receiver Enable Training 
Seed Values
-+                               */
-+                              if (Pass == FirstPass) {
-+                                      initial_seed = 
fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, 
package_type);
-+
-+                                      /* Adjust seed for the minimum platform 
supported frequency */
-+                                      initial_seed = (uint16_t) 
(((((uint64_t) initial_seed) *
-+                                              fam15h_freq_tab[mem_clk] * 100) 
/ (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
-+
-+                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
-+                                              uint16_t wl_pass1_delay;
-+                                              wl_pass1_delay = 
current_total_delay[lane];
-+
-+                                              seed[lane] = initial_seed + 
wl_pass1_delay;
-+                                      }
-+                              } else {
-+                                      uint8_t addr_prelaunch = 0;             
/* TODO: Fetch the correct value from RC2[0] */
-+                                      uint16_t register_delay;
-+                                      int16_t seed_prescaling;
-+
-+                                      memcpy(current_total_delay, 
dqs_ret_pass1_total_delay, sizeof(current_total_delay));
-+                                      if ((pDCTstat->Status & (1 << 
SB_Registered))) {
-+                                              if (addr_prelaunch)
-+                                                      register_delay = 0x30;
-+                                              else
-+                                                      register_delay = 0x20;
-+                                      } else if ((pDCTstat->Status & (1 << 
SB_LoadReduced))) {
-+                                              /* TODO
-+                                              * Load reduced DIMM support 
unimplemented
-+                                              */
-+                                              register_delay = 0x0;
-+                                      } else {
-+                                              register_delay = 0x0;
-+                                      }
-+
-+                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
-+                                              seed_prescaling = 
current_total_delay[lane] - register_delay - 0x20;
-+                                              seed[lane] = (uint16_t) 
(register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 
100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
-+                                      }
-+                              }
-+
-+                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                                      seed_gross[lane] = (seed[lane] >> 5) & 
0x1f;
-+                                      seed_fine[lane] = seed[lane] & 0x1f;
-+
-+                                      /*if (seed_gross[lane] == 0)
-+                                              seed_pre_gross[lane] = 0;
-+                                      else */if (seed_gross[lane] & 0x1)
-+                                              seed_pre_gross[lane] = 1;
-+                                      else
-+                                              seed_pre_gross[lane] = 2;
-+
-+                                      /* Calculate phase recovery delays */
-+                                      phase_recovery_delays[lane] = 
((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
-+
-+                                      /* Set the gross delay.
-+                                       * NOTE: While the BKDG states to only 
program DqsRcvEnGrossDelay, this appears
-+                                       * to have been a misprint as 
DqsRcvEnFineDelay should be set to zero as well.
-+                                       */
-+                                      current_total_delay[lane] = 
((seed_gross[lane] & 0x1f) << 5);
-+                              }
-+
-+                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
-+                               * Program PhRecFineDly and PhRecGrossDly
-+                               */
-+                              
write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, 
Channel, dimm, index_reg);
-+
-+                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
-+                               * Program the DQS Receiver Enable delay values 
for each lane
-+                               */
-+                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-+
-+                              /* 2.10.5.8.2 (3)
-+                               * Program DqsRcvTrEn = 1
-+                               */
-+                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
-+                              dword |= (0x1 << 13);
-+                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
-+
-+                              /* 2.10.5.8.2 (4)
-+                               * Issue 192 read requests to the target rank
-+                               */
-+                              
generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, Receiver + (rank & 0x1));
-+
-+                              /* 2.10.5.8.2 (5)
-+                               * Program DqsRcvTrEn = 0
-+                               */
-+                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
-+                              dword &= ~(0x1 << 13);
-+                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
-+
-+                              /* 2.10.5.8.2 (6)
-+                               * Read PhRecGrossDly, PhRecFineDly
-+                               */
-+                              
read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, 
dimm, index_reg);
-+
-+                              /* 2.10.5.8.2 (7)
-+                               * Calculate and program the DQS Receiver 
Enable delay values
-+                               */
-+                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
-+                                      current_total_delay[lane] = 
(phase_recovery_delays[lane] & 0x1f);
-+                                      current_total_delay[lane] |= 
((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - 
seed_pre_gross[lane] + 1) << 5);
-+                                      if (lane == 8)
-+                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
-+                                      else
-+                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
-+                              }
-+                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-+
-+                              if (rank == 0) {
-+                                      /* Back up the Rank 0 delays for later 
use */
-+                                      memcpy(rank0_current_total_delay, 
current_total_delay, sizeof(current_total_delay));
-+                              }
-+
-+                              if (rank == 1) {
-+                                      /* 2.10.5.8.2 (8)
-+                                       * Compute the average delay across 
both ranks and program the result into
-+                                       * the DQS Receiver Enable delay 
registers
-+                                       */
-+                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
-+                                              current_total_delay[lane] = 
(rank0_current_total_delay[lane] + current_total_delay[lane]) / 2;
-+                                              if (lane == 8)
-+                                                      
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
-+                                              else
-+                                                      
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
-+                                      }
-+                                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-+                              }
-+                      }
-+
-+#if DQS_TRAIN_DEBUG > 0
-+                      for (lane = 0; lane < 8; lane++)
-+                              print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
-+#endif
-+              }
-+      }
-+
-+      /* Calculate and program MaxRdLatency */
-+      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel);
- 
-       if(_DisableDramECC) {
-               mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
-@@ -674,10 +1486,10 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc 
*pDCTstat)
-       }
- 
-       for (ch=0; ch<ch_end; ch++) {
--              reg = 0x78 + 0x100 * ch;
--              val = Get_NB32(dev, reg);
-+              reg = 0x78;
-+              val = Get_NB32_DCT(dev, ch, reg);
-               val &= ~(1 << DqsRcvEnTrain);
--              Set_NB32(dev, reg, val);
-+              Set_NB32_DCT(dev, ch, reg, val);
-       }
- }
- 
-@@ -718,7 +1530,7 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u16 RcvrEnDly,
-               /* get the register index from table */
-               index = Table_DQSRcvEn_Offset[i >> 1];
-               index += Addl_Index;    /* DIMMx DqsRcvEn byte0 */
--              val = Get_NB32_index_wait(dev, index_reg, index);
-+              val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, index);
-               if(i & 1) {
-                       /* odd byte lane */
-                       val &= ~(0x1ff << 16);
-@@ -728,7 +1540,7 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u16 RcvrEnDly,
-                       val &= ~0x1ff;
-                       val |= (RcvrEnDly & 0x1ff);
-               }
--              Set_NB32_index_wait(dev, index_reg, index, val);
-+              Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
-       }
- 
- }
-@@ -742,7 +1554,6 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
-       u32 reg;
-       u32 SubTotal;
-       u32 index_reg;
--      u32 reg_off;
-       u32 val;
- 
-       uint8_t cpu_val_n;
-@@ -777,17 +1588,16 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
-               Channel = 0;
- 
-       dev = pDCTstat->dev_dct;
--      reg_off = 0x100 * Channel;
--      index_reg = 0x98 + reg_off;
-+      index_reg = 0x98;
- 
-       /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs 
units.*/
--      val = Get_NB32(dev, 0x88 + reg_off);
-+      val = Get_NB32_DCT(dev, Channel, 0x88);
-       SubTotal = ((val & 0x0f) + 4) << 1;     /* SubTotal is 1/2 Memclk unit 
*/
- 
-       /* If registered DIMMs are being used then
-        *  add 1 MEMCLK to the sub-total.
-        */
--      val = Get_NB32(dev, 0x90 + reg_off);
-+      val = Get_NB32_DCT(dev, Channel, 0x90);
-       if(!(val & (1 << UnBuffDimm)))
-               SubTotal += 2;
- 
-@@ -795,7 +1605,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
-        *  add 1, else add 2 to the sub-total.
-        *  if (AddrCmdSetup || CsOdtSetup || CkeSetup) then K := K + 2;
-        */
--      val = Get_NB32_index_wait(dev, index_reg, 0x04);
-+      val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04);
-       if(!(val & 0x00202020))
-               SubTotal += 1;
-       else
-@@ -803,7 +1613,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
- 
-       /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
-        * then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
--      val = Get_NB32(dev, 0x78 + reg_off);
-+      val = Get_NB32_DCT(dev, Channel, 0x78);
-       SubTotal += 8 - (val & 0x0f);
- 
-       /* Convert bits 7-5 (also referred to as the coarse delay) of
-@@ -824,7 +1634,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
-        * clocks (NCLKs)
-        */
-       SubTotal *= 200 * ((Get_NB32(pDCTstat->dev_nbmisc, 0xd4) & 0x1f) + 4);
--      SubTotal /= freq_tab[((Get_NB32(pDCTstat->dev_dct, 0x94 + reg_off) & 
0x7) - 3)];
-+      SubTotal /= freq_tab[((Get_NB32_DCT(pDCTstat->dev_dct, Channel, 0x94) & 
0x7) - 3)];
-       SubTotal = (SubTotal + (2 - 1)) / 2;    /* Round up */
- 
-       /* Add "N" NCLKs to the sub-total. "N" represents part of the
-@@ -841,13 +1651,13 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
-       /* Program the F2x[1, 0]78[MaxRdLatency] register with
-        * the total delay value (in NCLKs).
-        */
--      reg = 0x78 + reg_off;
--      val = Get_NB32(dev, reg);
-+      reg = 0x78;
-+      val = Get_NB32_DCT(dev, Channel, reg);
-       val &= ~(0x3ff << 22);
-       val |= (SubTotal & 0x3ff) << 22;
- 
-       /* program MaxRdLatency to correspond with current delay */
--      Set_NB32(dev, reg, val);
-+      Set_NB32_DCT(dev, Channel, reg, val);
- }
- 
- static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
-@@ -877,7 +1687,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
-       u32 dword;
-       u8 dn = 4; /* TODO: Rev C could be 4 */
-       u32 dev = pDCTstat->dev_dct;
--      u32 index_reg = 0x98 + 0x100 * Channel;
-+      u32 index_reg = 0x98;
- 
-       /* FIXME: add Cx support */
-       dword = 0x00000000;
-@@ -885,7 +1695,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
-               for(j=0; j<dn; j++)
-                       /* DIMM0 Write Data Timing Low */
-                       /* DIMM0 Write ECC Timing */
--                      Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, 
dword);
-+                      Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 
0x100 * j, dword);
-       }
- 
-       /* errata #180 */
-@@ -893,13 +1703,13 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
-       for(i=5; i<=6; i++) {
-               for(j=0; j<dn; j++)
-                       /* DIMM0 Read DQS Timing Control Low */
--                      Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, 
dword);
-+                      Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 
0x100 * j, dword);
-       }
- 
-       dword = 0x0000002f;
-       for(j=0; j<dn; j++)
-               /* DIMM0 Read DQS ECC Timing Control */
--              Set_NB32_index_wait(dev, index_reg, 7 + 0x100 * j, dword);
-+              Set_NB32_index_wait_DCT(dev, Channel, index_reg, 7 + 0x100 * j, 
dword);
- }
- 
- void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel)
-@@ -912,13 +1722,13 @@ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, 
u8 Channel)
-       u32 val;
- 
-       dev = pDCTstat->dev_dct;
--      index_reg = 0x98 + Channel * 0x100;
-+      index_reg = 0x98;
-       index = 0x12;
-       p = pDCTstat->CH_D_BC_RCVRDLY[Channel];
-       print_debug_dqs("\t\tSetEccDQSRcvrPos: Channel ", Channel,  2);
-       for(ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
-               val = p[ChipSel>>1];
--              Set_NB32_index_wait(dev, index_reg, index, val);
-+              Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
-               print_debug_dqs_pair("\t\tSetEccDQSRcvrPos: ChipSel ",
-                                       ChipSel, " rcvr_delay ",  val, 2);
-               index += 3;
-@@ -1002,95 +1812,305 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
-       u8 Node = 0;
-       struct DCTStatStruc *pDCTstat;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       /* FIXME: skip for Ax */
--      while (Node < MAX_NODES_SUPPORTED) {
-+      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-               pDCTstat = pDCTstatA + Node;
-+              if (!pDCTstat->NodePresent)
-+                      continue;
-+
-+              if (pDCTstat->DCTSysLimit) {
-+                      if (is_fam15h()) {
-+                              /* Fam15h BKDG v3.14 section 2.10.5.3.3
-+                               * This picks up where InitDDRPhy left off
-+                               */
-+                              uint8_t dct;
-+                              uint8_t index;
-+                              uint32_t dword;
-+                              uint32_t datc_backup;
-+                              uint32_t training_dword;
-+                              uint32_t fence2_config_dword;
-+                              uint32_t fence_tx_pad_config_dword;
-+                              uint32_t index_reg = 0x98;
-+                              uint32_t dev = pDCTstat->dev_dct;
-+
-+                              for (dct = 0; dct < 2; dct++) {
-+                                      if (!pDCTstat->DIMMValidDCT[dct])
-+                                              continue;
-+
-+                                      /* Back up D18F2x9C_x0000_0004_dct[1:0] 
*/
-+                                      datc_backup = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004);
-+
-+                                      /* FenceTrSel = 0x2 */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x00000008);
-+                                      dword &= ~(0x3 << 6);
-+                                      dword |= (0x2 << 6);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000008, dword);
-+
-+                                      /* Set phase recovery seed values */
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000050, 0x13131313);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000051, 0x13131313);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000052, 0x00000013);
-+
-+                                      training_dword = 
fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-+
-+                                      /* Save calculated fence value to the 
TX DLL */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
-+                                      dword &= ~(0x1f << 26);
-+                                      dword |= ((training_dword & 0x1f) << 
26);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0000000c, dword);
-+
-+                                      /* 
D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x1 */
-+                                      for (index = 0; index < 0x9; index++) {
-+                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
-+                                              dword &= ~(0x7 << 12);
-+                                              dword |= (0x1 << 12);
-+                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f000f | (index << 8), dword);
-+                                      }
-+
-+                                      /* FenceTrSel = 0x1 */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x00000008);
-+                                      dword &= ~(0x3 << 6);
-+                                      dword |= (0x1 << 6);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000008, dword);
-+
-+                                      /* Set phase recovery seed values */
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000050, 0x13131313);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000051, 0x13131313);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000052, 0x00000013);
-+
-+                                      training_dword = 
fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-+
-+                                      /* Save calculated fence value to the 
RX DLL */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
-+                                      dword &= ~(0x1f << 21);
-+                                      dword |= ((training_dword & 0x1f) << 
21);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0000000c, dword);
-+
-+                                      /* 
D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x0 */
-+                                      for (index = 0; index < 0x9; index++) {
-+                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
-+                                              dword &= ~(0x7 << 12);
-+                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f000f | (index << 8), dword);
-+                                      }
-+
-+                                      /* FenceTrSel = 0x3 */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x00000008);
-+                                      dword &= ~(0x3 << 6);
-+                                      dword |= (0x3 << 6);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000008, dword);
-+
-+                                      /* Set phase recovery seed values */
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000050, 0x13131313);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000051, 0x13131313);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000052, 0x00000013);
-+
-+                                      fence_tx_pad_config_dword = 
fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-+
-+                                      /* Save calculated fence value to the 
TX Pad */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
-+                                      dword &= ~(0x1f << 16);
-+                                      dword |= ((fence_tx_pad_config_dword & 
0x1f) << 16);
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0000000c, dword);
-+
-+                                      /* Program 
D18F2x9C_x0D0F_[C,8,2][2:0]31_dct[1:0] */
-+                                      training_dword = 
fence_tx_pad_config_dword;
-+                                      if (fence_tx_pad_config_dword < 16)
-+                                              training_dword |= (0x1 << 4);
-+                                      else
-+                                              training_dword = 0;
-+                                      for (index = 0; index < 0x3; index++) {
-+                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2031 | (index << 8));
-+                                              dword &= ~(0x1f);
-+                                              dword |= (training_dword & 
0x1f);
-+                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f2031 | (index << 8), dword);
-+                                      }
-+                                      for (index = 0; index < 0x3; index++) {
-+                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8031 | (index << 8));
-+                                              dword &= ~(0x1f);
-+                                              dword |= (training_dword & 
0x1f);
-+                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f8031 | (index << 8), dword);
-+                                      }
-+                                      for (index = 0; index < 0x3; index++) {
-+                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc031 | (index << 8));
-+                                              dword &= ~(0x1f);
-+                                              dword |= (training_dword & 
0x1f);
-+                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0fc031 | (index << 8), dword);
-+                                      }
-+
-+                                      /* Assemble Fence2 configuration word 
(Fam15h BKDG v3.14 page 331) */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
-+                                      fence2_config_dword = 0;
-+
-+                                      /* TxPad */
-+                                      training_dword = (dword >> 16) & 0x1f;
-+                                      if (training_dword < 16)
-+                                              training_dword |= 0x10;
-+                                      else
-+                                              training_dword = 0;
-+                                      fence2_config_dword |= training_dword;
-+
-+                                      /* RxDll */
-+                                      training_dword = (dword >> 21) & 0x1f;
-+                                      if (training_dword < 16)
-+                                              training_dword |= 0x10;
-+                                      else
-+                                              training_dword = 0;
-+                                      fence2_config_dword |= (training_dword 
<< 10);
-+
-+                                      /* TxDll */
-+                                      training_dword = (dword >> 26) & 0x1f;
-+                                      if (training_dword < 16)
-+                                              training_dword |= 0x10;
-+                                      else
-+                                              training_dword = 0;
-+                                      fence2_config_dword |= (training_dword 
<< 5);
-+
-+                                      /* Program 
D18F2x9C_x0D0F_0[F,8:0]31_dct[1:0] */
-+                                      for (index = 0; index < 0x9; index++) {
-+                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0031 | (index << 8));
-+                                              dword &= ~(0x7fff);
-+                                              dword |= fence2_config_dword;
-+                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f0031 | (index << 8), dword);
-+                                      }
- 
--              if(pDCTstat->DCTSysLimit) {
--                      fenceDynTraining_D(pMCTstat, pDCTstat, 0);
--                      fenceDynTraining_D(pMCTstat, pDCTstat, 1);
-+                                      /* Restore D18F2x9C_x0000_0004_dct[1:0] 
*/
-+                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000004, datc_backup);
-+                              }
-+                      } else {
-+                              fenceDynTraining_D(pMCTstat, pDCTstat, 0);
-+                              fenceDynTraining_D(pMCTstat, pDCTstat, 1);
-+                      }
-               }
--              Node++;
-       }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
--static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
-+static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-       u16 avRecValue;
-       u32 val;
-       u32 dev;
--      u32 index_reg = 0x98 + 0x100 * dct;
-+      u32 index_reg = 0x98;
-       u32 index;
- 
--      /* BIOS first programs a seed value to the phase recovery engine
--       *  (recommended 19) registers.
--       * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
--       * F2x[1,0]9C_x52.) .
--       */
-       dev = pDCTstat->dev_dct;
--      for (index = 0x50; index <= 0x52; index ++) {
--              val = (FenceTrnFinDlySeed & 0x1F);
--              if (index != 0x52) {
--                      val |= val << 8 | val << 16 | val << 24;
-+
-+      if (is_fam15h()) {
-+              /* Set F2x[1,0]9C_x08[PhyFenceTrEn] */
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
-+              val |= 1 << PhyFenceTrEn;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-+
-+              /* Wait 2000 MEMCLKs */
-+              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 2000);
-+
-+              /* Clear F2x[1,0]9C_x08[PhyFenceTrEn] */
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
-+              val &= ~(1 << PhyFenceTrEn);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-+
-+              /* BIOS reads the phase recovery engine registers
-+               * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52.
-+               * Average the fine delay components only.
-+               */
-+              avRecValue = 0;
-+              for (index = 0x50; index <= 0x52; index++) {
-+                      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
index);
-+                      avRecValue += val & 0x1f;
-+                      if (index != 0x52) {
-+                              avRecValue += (val >> 8) & 0x1f;
-+                              avRecValue += (val >> 16) & 0x1f;
-+                              avRecValue += (val >> 24) & 0x1f;
-+                      }
-               }
--              Set_NB32_index_wait(dev, index_reg, index, val);
--      }
- 
--      /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
--      val = Get_NB32_index_wait(dev, index_reg, 0x08);
--      val |= 1 << PhyFenceTrEn;
--      Set_NB32_index_wait(dev, index_reg, 0x08, val);
--
--      /* Wait 200 MEMCLKs. */
--      mct_Wait(50000);                /* wait 200us */
--
--      /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
--      val = Get_NB32_index_wait(dev, index_reg, 0x08);
--      val &= ~(1 << PhyFenceTrEn);
--      Set_NB32_index_wait(dev, index_reg, 0x08, val);
--
--      /* BIOS reads the phase recovery engine registers
--       * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
--      avRecValue = 0;
--      for (index = 0x50; index <= 0x52; index ++) {
--              val = Get_NB32_index_wait(dev, index_reg, index);
--              avRecValue += val & 0x7F;
--              if (index != 0x52) {
--                      avRecValue += (val >> 8) & 0x7F;
--                      avRecValue += (val >> 16) & 0x7F;
--                      avRecValue += (val >> 24) & 0x7F;
-+              val = avRecValue / 9;
-+              if (avRecValue % 9)
-+                      val++;
-+              avRecValue = val;
-+
-+              if (avRecValue < 6)
-+                      avRecValue = 0;
-+              else
-+                      avRecValue -= 6;
-+
-+              return avRecValue;
-+      } else {
-+              /* BIOS first programs a seed value to the phase recovery engine
-+               *  (recommended 19) registers.
-+               * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
-+               * F2x[1,0]9C_x52.) .
-+               */
-+              for (index = 0x50; index <= 0x52; index ++) {
-+                      val = (FenceTrnFinDlySeed & 0x1F);
-+                      if (index != 0x52) {
-+                              val |= val << 8 | val << 16 | val << 24;
-+                      }
-+                      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, 
val);
-               }
--      }
- 
--      val = avRecValue / 9;
--      if (avRecValue % 9)
--              val++;
--      avRecValue = val;
-+              /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
-+              val |= 1 << PhyFenceTrEn;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-+
-+              /* Wait 200 MEMCLKs. */
-+              mct_Wait(50000);                /* wait 200us */
-+
-+              /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
-+              val &= ~(1 << PhyFenceTrEn);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-+
-+              /* BIOS reads the phase recovery engine registers
-+               * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
-+              avRecValue = 0;
-+              for (index = 0x50; index <= 0x52; index ++) {
-+                      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
index);
-+                      avRecValue += val & 0x7F;
-+                      if (index != 0x52) {
-+                              avRecValue += (val >> 8) & 0x7F;
-+                              avRecValue += (val >> 16) & 0x7F;
-+                              avRecValue += (val >> 24) & 0x7F;
-+                      }
-+              }
- 
--      /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
--      /* inlined mct_AdjustFenceValue() */
--      /* TODO: The RBC0 is not supported. */
--      /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
--              avRecValue -= 3;
--      else
--      */
--      if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
--              avRecValue -= 8;
--      else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
--              avRecValue -= 8;
--      else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
--              avRecValue -= 8;
--
--      val = Get_NB32_index_wait(dev, index_reg, 0x0C);
--      val &= ~(0x1F << 16);
--      val |= (avRecValue & 0x1F) << 16;
--      Set_NB32_index_wait(dev, index_reg, 0x0C, val);
--
--      /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control Register
--       * delays (both channels). */
--      val = Get_NB32_index_wait(dev, index_reg, 0x04);
--      Set_NB32_index_wait(dev, index_reg, 0x04, val);
-+              val = avRecValue / 9;
-+              if (avRecValue % 9)
-+                      val++;
-+              avRecValue = val;
-+
-+              /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
-+              /* inlined mct_AdjustFenceValue() */
-+              /* TODO: The RBC0 is not supported. */
-+              /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
-+                      avRecValue -= 3;
-+              else
-+              */
-+              if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
-+                      avRecValue -= 8;
-+              else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
-+                      avRecValue -= 8;
-+              else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
-+                      avRecValue -= 8;
-+
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C);
-+              val &= ~(0x1F << 16);
-+              val |= (avRecValue & 0x1F) << 16;
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C, val);
-+
-+              /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control 
Register
-+               * delays (both channels).
-+               */
-+              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x04);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x04, val);
-+
-+              return avRecValue;
-+      }
- }
- 
- void mct_Wait(u32 cycles)
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
-index f01e011..55068ce 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
-@@ -21,8 +21,14 @@
- u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass)
- {
-       u8 ret = 1;
--      if (pass == SecondPass)
--              ret = 0;
-+
-+      if (is_fam15h()) {
-+              /* Fam15h needs two passes */
-+              ret = 1;
-+      } else {
-+              if (pass == SecondPass)
-+                      ret = 0;
-+      }
- 
-       return ret;
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
-index 920f514..68acc75 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
-@@ -218,12 +218,12 @@ static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc 
*pDCTstat,
-       }
- 
-       dev = pDCTstat->dev_dct;
--      reg = 0x78 + Channel * 0x100;
--      val = Get_NB32(dev, reg);
-+      reg = 0x78;
-+      val = Get_NB32_DCT(dev, Channel, reg);
-       val &= ~(0x3ff<<22);
-       val |= MaxRdLatVal<<22;
-       /* program MaxRdLatency to correspond with current delay */
--      Set_NB32(dev, reg, val);
-+      Set_NB32_DCT(dev, Channel, reg, val);
- }
- 
- static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr)
-@@ -320,30 +320,28 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
-       u32 valx;
-       u32 valxx;
-       u32 index_reg;
--      u32 reg_off;
-       u32 dev;
- 
-       if(pDCTstat->GangedMode)
-               Channel =  0;
- 
--      index_reg = 0x98 + 0x100 * Channel;
-+      index_reg = 0x98;
- 
--      reg_off = 0x100 * Channel;
-       dev = pDCTstat->dev_dct;
- 
-       /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs 
units.*/
--      val = Get_NB32(dev, 0x88 + reg_off);
-+      val = Get_NB32_DCT(dev, Channel, 0x88);
-       SubTotal = ((val & 0x0f) + 1) << 1;     /* SubTotal is 1/2 Memclk unit 
*/
- 
-       /* If registered DIMMs are being used then add 1 MEMCLK to the 
sub-total*/
--      val = Get_NB32(dev, 0x90 + reg_off);
-+      val = Get_NB32_DCT(dev, Channel, 0x90);
-       if(!(val & (1 << UnBuffDimm)))
-               SubTotal += 2;
- 
-       /*If the address prelaunch is setup for 1/2 MEMCLKs then add 1,
-        *  else add 2 to the sub-total. if (AddrCmdSetup || CsOdtSetup
-        *  || CkeSetup) then K := K + 2; */
--      val = Get_NB32_index_wait(dev, index_reg, 0x04);
-+      val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04);
-       if(!(val & 0x00202020))
-               SubTotal += 1;
-       else
-@@ -351,7 +349,7 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
- 
-       /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
-        *  then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
--      val = Get_NB32(dev, 0x78 + reg_off);
-+      val = Get_NB32_DCT(dev, Channel, 0x78);
-       SubTotal += 8 - (val & 0x0f);
- 
-       /* Convert bits 7-5 (also referred to as the course delay) of the 
current
-@@ -367,7 +365,7 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
- 
-       /*New formula:
-       SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
--      val = Get_NB32(dev, 0x94 + reg_off);
-+      val = Get_NB32_DCT(dev, Channel, 0x94);
-       /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
-       val &= 7;
-       if (val >= 3) {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-index 1c3e322..0ff4484 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-@@ -83,6 +83,12 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
-               pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 0;
-       }
- 
-+      if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+              pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED] = 1;
-+      } else {
-+              pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED] = 0;
-+      }
-+
-       pDCTstat->C_DCTPtr[dct]->RegMan1Present = pDCTstat->RegMan1Present;
- 
-       for (dimm = 0; dimm < MAX_TOTAL_DIMMS; dimm++) {
-@@ -103,13 +109,13 @@ void EnableZQcalibration(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDC
- {
-       u32 val;
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x94);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-       val |= 1 << 11;
--      Set_NB32(pDCTstat->dev_dct, 0x94, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-       val |= 1 << 11;
--      Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
- }
- 
- void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
-@@ -117,15 +123,15 @@ void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
- {
-       u32 val;
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x94);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-       val &= ~(1 << 11);
-       val &= ~(1 << 10);
--      Set_NB32(pDCTstat->dev_dct, 0x94, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
- 
--      val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
-+      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-       val &= ~(1 << 11);
-       val &= ~(1 << 10);
--      Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
-+      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
- }
- 
- static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
-@@ -142,23 +148,23 @@ static void EnterSelfRefresh(struct MCTStatStruc 
*pMCTstat,
- 
-       /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
-       if (DCT0Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x90);
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
-               val |= 1 << EnterSelfRef;
--              Set_NB32(pDCTstat->dev_dct, 0x90, val);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
-       }
-       if (DCT1Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
-               val |= 1 << EnterSelfRef;
--              Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
-       }
-       /* Wait until the hardware resets F2x[1, 0]90[EnterSelfRefresh]=0. */
-       if (DCT0Present)
-               do {
--                      val = Get_NB32(pDCTstat->dev_dct, 0x90);
-+                      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
-               } while (val & (1 <<EnterSelfRef));
-       if (DCT1Present)
-               do {
--                      val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
-+                      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
-               } while (val & (1 <<EnterSelfRef));
- }
- 
-@@ -168,8 +174,11 @@ static void EnterSelfRefresh(struct MCTStatStruc 
*pMCTstat,
- static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat)
- {
--      u8 DCT0Present, DCT1Present;
--      u32 val;
-+      uint8_t DCT0Present;
-+      uint8_t DCT1Present;
-+      uint32_t dword;
-+      uint32_t mask;
-+      uint32_t offset;
- 
-       DCT0Present = pDCTstat->DIMMValidDCT[0];
-       if (pDCTstat->GangedMode)
-@@ -177,76 +186,134 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
-       else
-               DCT1Present = pDCTstat->DIMMValidDCT[1];
- 
--      /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
--      if (DCT0Present) {
--              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
--              val |= 1 << DisAutoComp;
--              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
--      }
--      if (DCT1Present) {
--              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
--              val |= 1 << DisAutoComp;
--              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
-+      if (is_fam15h()) {
-+              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0x190 */
-+              if (DCT0Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 0x0d0fe006);
-+                      dword &= ~(0x0000ffff);
-+                      dword |= 0x00000190;
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 
0x0d0fe006, dword);
-+              }
-+              if (DCT1Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 0x0d0fe006);
-+                      dword &= ~(0x0000ffff);
-+                      dword |= 0x00000190;
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 
0x0d0fe006, dword);
-+              }
-+      } else {
-+              /* Program F2x[1, 0]9C[DisAutoComp]=1. */
-+              if (DCT0Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 8);
-+                      dword |= 1 << DisAutoComp;
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8, 
dword);
-+                      mct_Wait(100);  /* Wait for 5us */
-+              }
-+              if (DCT1Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 8);
-+                      dword |= 1 << DisAutoComp;
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8, 
dword);
-+                      mct_Wait(100);  /* Wait for 5us */
-+              }
-       }
- 
-       /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
-       if (DCT0Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94);
--              val &= ~(1 << MemClkFreqVal);
--              Set_NB32(pDCTstat->dev_dct, 0x94, val);
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-+              dword &= ~(1 << MemClkFreqVal);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
-       }
-       if (DCT1Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
--              val &= ~(1 << MemClkFreqVal);
--              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-+              dword &= ~(1 << MemClkFreqVal);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
-       }
- 
-       /* Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK 
frequency. */
-+      if (is_fam15h()) {
-+              offset = 0x0;
-+              mask = 0x1f;
-+      } else {
-+              offset = 0x1;
-+              mask = 0x7;
-+      }
-       if (DCT0Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94);
--              val &= 0xFFFFFFF8;
--              val |= pDCTstat->TargetFreq - 1;
--              Set_NB32(pDCTstat->dev_dct, 0x94, val);
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-+              dword &= ~mask;
-+              dword |= (pDCTstat->TargetFreq - offset) & mask;
-+              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
-       }
-       if (DCT1Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
--              val &= 0xFFFFFFF8;
--              val |= pDCTstat->TargetFreq - 1;
--              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-+              dword &= ~mask;
-+              dword |= (pDCTstat->TargetFreq - offset) & mask;
-+              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
-+      }
-+
-+      if (is_fam15h()) {
-+              if (DCT0Present) {
-+                      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 0);
-+                      set_2t_configuration(pMCTstat, pDCTstat, 0);
-+                      mct_BeforePlatformSpec(pMCTstat, pDCTstat, 0);
-+                      mct_PlatformSpec(pMCTstat, pDCTstat, 0);
-+              }
-+              if (DCT1Present) {
-+                      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
-+                      set_2t_configuration(pMCTstat, pDCTstat, 1);
-+                      mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
-+                      mct_PlatformSpec(pMCTstat, pDCTstat, 1);
-+              }
-       }
- 
-       /* Program F2x[1, 0]94[MemClkFreqVal] = 1. */
-       if (DCT0Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94);
--              val |= 1 << MemClkFreqVal;
--              Set_NB32(pDCTstat->dev_dct, 0x94, val);
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-+              dword |= 1 << MemClkFreqVal;
-+              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
-       }
-       if (DCT1Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
--              val |= 1 << MemClkFreqVal;
--              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-+              dword |= 1 << MemClkFreqVal;
-+              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
-       }
- 
-       /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
-       if (DCT0Present)
-               do {
--                      val = Get_NB32(pDCTstat->dev_dct, 0x94);
--              } while (val & (1 << FreqChgInProg));
-+                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-+              } while (dword & (1 << FreqChgInProg));
-       if (DCT1Present)
-               do {
--                      val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
--              } while (val & (1 << FreqChgInProg));
--
--      /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
--      if (DCT0Present) {
--              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
--              val &= ~(1 << DisAutoComp);
--              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
--      }
--      if (DCT1Present) {
--              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
--              val &= ~(1 << DisAutoComp);
--              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
-+                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-+              } while (dword & (1 << FreqChgInProg));
-+
-+      if (is_fam15h()) {
-+              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0xf */
-+              if (DCT0Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 0x0d0fe006);
-+                      dword &= ~(0x0000ffff);
-+                      dword |= 0x0000000f;
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 
0x0d0fe006, dword);
-+              }
-+              if (DCT1Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 0x0d0fe006);
-+                      dword &= ~(0x0000ffff);
-+                      dword |= 0x0000000f;
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 
0x0d0fe006, dword);
-+              }
-+      } else {
-+              /* Program F2x[1, 0]9C[DisAutoComp] = 0. */
-+              if (DCT0Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 8);
-+                      dword &= ~(1 << DisAutoComp);
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8, 
dword);
-+                      mct_Wait(15000);        /* Wait for 750us */
-+              }
-+              if (DCT1Present) {
-+                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 8);
-+                      dword &= ~(1 << DisAutoComp);
-+                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8, 
dword);
-+                      mct_Wait(15000);        /* Wait for 750us */
-+              }
-       }
- }
- 
-@@ -267,29 +334,46 @@ static void ExitSelfRefresh(struct MCTStatStruc 
*pMCTstat,
- 
-       /* Program F2x[1, 0]90[ExitSelfRef]=1 for both DCTs. */
-       if (DCT0Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x90);
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
-               val |= 1 << ExitSelfRef;
--              Set_NB32(pDCTstat->dev_dct, 0x90, val);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
-       }
-       if (DCT1Present) {
--              val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
-               val |= 1 << ExitSelfRef;
--              Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
-       }
-       /* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0. */
-       if (DCT0Present)
-               do {
--                      val = Get_NB32(pDCTstat->dev_dct, 0x90);
-+                      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
-               } while (val & (1 << ExitSelfRef));
-       if (DCT1Present)
-               do {
--                      val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
-+                      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
-               } while (val & (1 << ExitSelfRef));
- }
- 
- void SetTargetFreq(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat)
- {
-+      uint32_t dword;
-+      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+
-+      if (is_fam15h()) {
-+              /* Program F2x[1, 0]90[DisDllShutDownSR]=1. */
-+              if (pDCTstat->DIMMValidDCT[0]) {
-+                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
-+                      dword |= (0x1 << 27);
-+                      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, dword);
-+              }
-+              if (pDCTstat->DIMMValidDCT[1]) {
-+                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
-+                      dword |= (0x1 << 27);
-+                      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, dword);
-+              }
-+      }
-+
-       /* Program F2x[1,0]90[EnterSelfRefresh]=1.
-        * Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
-        */
-@@ -305,11 +389,38 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
-        */
-       ChangeMemClk(pMCTstat, pDCTstat);
- 
-+      if (is_fam15h()) {
-+              uint8_t dct;
-+              for (dct = 0; dct < 2; dct++) {
-+                      if (pDCTstat->DIMMValidDCT[dct]) {
-+                              phyAssistedMemFnceTraining(pMCTstat, pDCTstat);
-+                              InitPhyCompensation(pMCTstat, pDCTstat, dct);
-+                      }
-+              }
-+      }
-+
-       /* Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
-        * Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
-        */
-       ExitSelfRefresh(pMCTstat, pDCTstat);
- 
-+      if (is_fam15h()) {
-+              if ((package_type == PT_C3) || (package_type == PT_GR)) {
-+                      /* Socket C32 or G34 */
-+                      /* Program F2x[1, 0]90[DisDllShutDownSR]=0. */
-+                      if (pDCTstat->DIMMValidDCT[0]) {
-+                              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 
0x90);
-+                              dword &= ~(0x1 << 27);
-+                              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, dword);
-+                      }
-+                      if (pDCTstat->DIMMValidDCT[1]) {
-+                              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 
0x90);
-+                              dword &= ~(0x1 << 27);
-+                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, dword);
-+                      }
-+              }
-+      }
-+
-       /* wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns */
-       mct_Wait(250);
- 
-@@ -336,13 +447,13 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
- static void Modify_OnDimmMirror(struct DCTStatStruc *pDCTstat, u8 dct, u8 set)
- {
-       u32 val;
--      u32 reg_off = dct * 0x100 + 0x44;
--      while (reg_off < (dct * 0x100 + 0x60)) {
--              val = Get_NB32(pDCTstat->dev_dct, reg_off);
-+      u32 reg = 0x44;
-+      while (reg < 0x60) {
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, dct, reg);
-               if (val & (1 << CSEnable))
-                       set ? (val |= 1 << onDimmMirror) : (val &= 
~(1<<onDimmMirror));
--              Set_NB32(pDCTstat->dev_dct, reg_off, val);
--              reg_off += 8;
-+              Set_NB32_DCT(pDCTstat->dev_dct, dct, reg, val);
-+              reg += 8;
-       }
- }
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index 9f42d54..7ea7901 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -30,13 +30,22 @@
-  *
-  *----------------------------------------------------------------------------
-  */
--u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue);
--u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue);
--void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL 
wl);
--void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm);
--void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass);
--void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 
targetAddr);
--void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm);
-+u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
MRSValue);
-+u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
MRSValue);
-+void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+      u8 dct, u8 dimm, BOOL wl);
-+void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm);
-+void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass);
-+void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, u8 targetAddr, uint8_t pass);
-+void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass);
-+
-+static int32_t abs(int32_t val) {
-+      if (val < 0)
-+              val *= -1;
-+
-+      return val;
-+}
-+
- /*
-  
*-----------------------------------------------------------------------------
-  *            EXPORTED FUNCTIONS
-@@ -62,34 +71,55 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 
dimm);
-  *       OUT
-  
*-----------------------------------------------------------------------------
-  */
--void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
--              u8 dimm, u8 pass)
-+void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+              u8 dct, u8 dimm, u8 pass)
- {
-       u8 ByteLane;
-       u32 Value, Addr;
-       u16 Addl_Data_Offset, Addl_Data_Port;
-+      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- 
-       pDCTData->WLPass = pass;
-       /* 1. Specify the target DIMM that is to be trained by programming
-        * F2x[1, 0]9C_x08[TrDimmSel].
-        */
--      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
-+      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
--                      TrDimmSelEnd,(u32)dimm);
-+                      TrDimmSelEnd, (u32)dimm);
-+
-+      if (is_fam15h()) {
-+              /* Set TrNibbleSel = 0
-+               *
-+               * TODO: Add support for x4 DIMMs
-+               */
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
-+                              2, (u32)0);
-+      }
-+
-       /* 2. Prepare the DIMMs for write levelization using DDR3-defined
-        * MR commands. */
--      prepareDimms(pMCTData, pDCTData,dimm, TRUE);
-+      prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
-+
-       /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
-        *    satisfy DDR3-defined internal DRAM timing.
-        */
--      pMCTData->AgesaDelay(40);
-+      if (is_fam15h())
-+              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
-+      else
-+              pMCTData->AgesaDelay(40);
-+
-       /* 4. Configure the processor's DDR phy for write levelization 
training: */
--      procConifg(pMCTData,pDCTData, dimm, pass);
-+      procConfig(pMCTstat, pDCTstat, dct, dimm, pass);
-+
-       /* 5. Begin write levelization training:
--       *  Program F2x[1, 0]9C_x08[WrtLevelTrEn]=1. */
--      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
--              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-+       *  Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
-+      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL))
-+      {
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, 
WrtLvTrEn, 1);
-+      }
-       else
-       {
-               /* Broadcast write to all D3Dbyte chipset register offset 0xc
-@@ -98,7 +128,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
-                * retain value of 3:2 (Trdimmsel)
-                * reset bit 5 (FrzPR)
-                */
--              if (pDCTData->DctTrain)
-+              if (dct)
-               {
-                       Addl_Data_Offset=0x198;
-                       Addl_Data_Port=0x19C;
-@@ -123,29 +153,127 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
-                               DctAccessDone, DctAccessDone)) == 0);
-       }
- 
-+      if (is_fam15h())
-+              proc_MFENCE();
-+
-       /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
--      pMCTData->AgesaDelay(140);
-+      if (is_fam15h())
-+              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 200);
-+      else
-+              pMCTData->AgesaDelay(140);
-+
-       /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
--      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
-+      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
-+
-       /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
-        * to get the gross and fine delay settings
-        * for the target DIMM and save these values. */
--      ByteLane = 0;
--      while (ByteLane < MAX_BYTE_LANES)
--      {
--              getWLByteDelay(pDCTData,ByteLane, dimm);
--              setWLByteDelay(pDCTData,ByteLane, dimm, 1);
--              ByteLane++;
-+      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-+              getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass);
-+      }
-+
-+      pDCTData->WLCriticalGrossDelayPrevPass = 0x1f;
-+}
-+
-+void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+              u8 dct, u8 dimm, u8 pass)
-+{
-+      u8 ByteLane;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+
-+      if (is_fam15h()) {
-+              int32_t gross_diff[MAX_BYTE_LANES];
-+              int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
-+              uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
-+
-+              /* Calculate the Critical Gross Delay */
-+              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-+                      /* Calculate the gross delay differential for this lane 
*/
-+                      gross_diff[ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane] + 
pDCTData->WLGrossDelay[index+ByteLane];
-+                      gross_diff[ByteLane] -= 
pDCTData->WLSeedPreGrossDelay[index+ByteLane];
-+
-+                      /* WrDqDqsEarly values greater than 2 are reserved */
-+                      if (gross_diff[ByteLane] < -2)
-+                              gross_diff[ByteLane] = -2;
-+
-+                      /* Update the Critical Gross Delay */
-+                      if (gross_diff[ByteLane] < cgd)
-+                              cgd = gross_diff[ByteLane];
-+              }
-+
-+              pDCTData->WLCriticalGrossDelayPrevPass = cgd;
-+
-+              /* Compensate for occasional noise/instability causing sporadic 
training failure */
-+              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-+                      uint16_t total_delay_seed = 
((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
-+                      uint16_t total_delay_phy = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
-+                      if (abs(total_delay_phy - total_delay_seed) > 0x20) {
-+                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value\n", __func__);
-+                              pDCTData->WLGrossDelay[index+ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane];
-+                              pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
-+                      }
-+              }
-+      }
-+}
-+
-+void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+              u8 dct, u8 dimm, u8 pass)
-+{
-+      u8 ByteLane;
-+      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+
-+      if (is_fam15h()) {
-+              uint32_t dword;
-+              int32_t gross_diff[MAX_BYTE_LANES];
-+              int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
-+              uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
-+
-+              /* Apply offset(s) if needed */
-+              if (cgd < 0) {
-+                      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
-+                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= abs(cgd) */
-+                      dword |= ((abs(cgd) & 0x3) << 24);
-+                      Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
-+
-+                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                              /* Calculate the gross delay differential for 
this lane */
-+                              gross_diff[ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane] + 
pDCTData->WLGrossDelay[index+ByteLane];
-+                              gross_diff[ByteLane] -= 
pDCTData->WLSeedPreGrossDelay[index+ByteLane];
-+
-+                              /* Prevent underflow in the presence of noise / 
instability*/
-+                              if (gross_diff[ByteLane] < cgd)
-+                                      gross_diff[ByteLane] = cgd;
-+
-+                              pDCTData->WLGrossDelay[index+ByteLane] = 
(gross_diff[ByteLane] + (abs(cgd) & 0x3));
-+                      }
-+              } else {
-+                      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
-+                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= 0 */
-+                      Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
-+              }
-+      }
-+
-+      /* Write the adjusted gross and fine delay settings
-+       * to the target DIMM. */
-+      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-+              setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass);
-       }
- 
-       /* 6. Configure DRAM Phy Control Register so that the phy stops driving
-        *    write levelization ODT. */
--      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
-+      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, 0);
- 
-+      if (is_fam15h())
-+              proc_MFENCE();
-+
-       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
--      pMCTData->AgesaDelay(10);
-+      if (is_fam15h())
-+              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
-+      else
-+              pMCTData->AgesaDelay(10);
- 
-       /* 7. Program the target DIMM back to normal operation by configuring
-        * the following (See section 2.8.5.4.1.1
-@@ -155,7 +283,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
-        * For a two DIMM system, program the Rtt value for the target DIMM
-        * to the normal operating termination:
-        */
--      prepareDimms(pMCTData, pDCTData,dimm,FALSE);
-+      prepareDimms(pMCTstat, pDCTstat, dct, dimm, FALSE);
- }
- 
- /*----------------------------------------------------------------------------
-@@ -165,7 +293,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
-  */
- 
- 
/*-----------------------------------------------------------------------------
-- * u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
-+ * u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 
MRSValue)
-  *
-  * Description:
-  *    This function swaps the bits in MSR register value
-@@ -177,12 +305,17 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
-  *
-  * 
----------------------------------------------------------------------------
-  */
--u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
-+u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
MRSValue)
- {
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-       u32 tempW, tempW1;
- 
--      tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
--                      FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
-+      if (is_fam15h())
-+              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                              FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, 
MrsChipSelEndFam15);
-+      else
-+              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                      FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, 
MrsChipSelEndFam10);
-       if (tempW1 & 1)
-       {
-               if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
-@@ -201,7 +334,7 @@ u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
- }
- 
- 
/*-----------------------------------------------------------------------------
-- *  u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
-+ *  u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
-  *
-  *  Description:
-  *       This function swaps the bits in MSR register value
-@@ -213,12 +346,17 @@ u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
-  *
-  * 
----------------------------------------------------------------------------
-  */
--u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
-+u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
- {
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-       u32 tempW, tempW1;
- 
--      tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
--                      FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
-+      if (is_fam15h())
-+              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                              FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, 
MrsChipSelEndFam15);
-+      else
-+              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                              FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, 
MrsChipSelEndFam10);
-       if (tempW1 & 1)
-       {
-               if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
-@@ -269,7 +407,7 @@ static uint16_t 
unbuffered_dimm_nominal_termination_emrs(uint8_t number_of_dimms
-       return term;
- }
- 
--static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank)
-+static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count)
- {
-       uint16_t term;
- 
-@@ -300,27 +438,27 @@ static uint16_t 
unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms
-  *
-  *  Description:
-  *       This function prepares DIMMS for training
-- *
-- *   Parameters:
-- *       IN  OUT   *DCTData - Pointer to buffer with information about each 
DCT
-- *             *SPDData - Pointer to buffer with information about each DIMMs
-- *                        SPD information
-- *             *MCTData - Pointer to buffer with runtime parameters,
-- *       IN   Dimm - Logical DIMM number
-- *             WL - indicates if the routine is used for Write levelization
-- *                  training
-- *
-- *       OUT
-- *
-+ *       Fam10h: BKDG Rev. 3.62 section 2.8.9.9.1
-+ *       Fam15h: BKDG Rev. 3.14 section 2.10.5.8.1
-  * 
----------------------------------------------------------------------------
-  */
--void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL 
wl)
-+void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+      u8 dct, u8 dimm, BOOL wl)
- {
-       u32 tempW, tempW1, tempW2, MrsBank;
-       u8 rank, currDimm, MemClkFreq;
-+      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
- 
--      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
-+      if (is_fam15h()) {
-+              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                      FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
-+      } else {
-+              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
-                       FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
-+      }
-       /* Configure the DCT to send initialization MR commands to the target 
DIMM
-        * by programming the F2x[1,0]7C register using the following steps.
-        */
-@@ -328,52 +466,95 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-       while ((rank < pDCTData->DimmRanks[dimm]) && (rank < 2))
-       {
-               /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank to 
be trained. */
--              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
--                      DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, dimm*2+rank);
-+              if (is_fam15h())
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsChipSelStartFam15, 
MrsChipSelEndFam15, dimm*2+rank);
-+              else
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsChipSelStartFam10, 
MrsChipSelEndFam10, dimm*2+rank);
-+
-               /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate 
internal DRAM
-                * register that defines the required DDR3-defined function for 
write
-                * levelization.
-                */
--              MrsBank = swapBankBits(pDCTData,1);
--              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
--                      DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
-+              MrsBank = swapBankBits(pDCTstat, dct, 1);
-+              if (is_fam15h())
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, 
MrsBank);
-+              else
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, 
MrsBank);
-+
-               /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required 
DDR3-defined function
-                * for write levelization.
-                */
-               tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0 */
- 
--              /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 
& x4 */
--              tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
--                              FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
--              if (tempW2)
--              {
--                      if (pDCTData->DimmX8Present[dimm])
--                              tempW |= 0x800;
-+              /* Retrieve normal settings of the MRS control word and clear 
Rtt_Nom */
-+              if (is_fam15h()) {
-+                      tempW = mct_MR1(pMCTstat, pDCTstat, dct, dimm*2+rank) & 
0xffff;
-+                      tempW &= ~(0x0244);
-+              } else {
-+                      /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when 
mixed x8 & x4 */
-+                      tempW2 = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                                      FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, 
RDqsEn);
-+                      if (tempW2)
-+                      {
-+                              if (pDCTData->DimmX8Present[dimm])
-+                                      tempW |= 0x800;
-+                      }
-               }
- 
-               /* determine Rtt_Nom for WL & Normal mode */
--              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
--                      tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, 
wl, MemClkFreq, rank);
--              } else {
-+              if (is_fam15h()) {
-                       if (wl) {
--                              if (rank == 0) {
--                                      /* Get Rtt_WR for the current DIMM and 
rank */
--                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
--
--                                      /* Convert dynamic termination code to 
corresponding nominal termination code */
--                                      if (dynamic_term == 0x200)
--                                              tempW1 = 0x04;
--                                      else if (dynamic_term == 0x400)
--                                              tempW1 = 0x40;
--                                      else
--                                              tempW1 = 0x0;
-+                              if (number_of_dimms > 1) {
-+                                      if (rank == 0) {
-+                                              /* Get Rtt_WR for the current 
DIMM and rank */
-+                                              tempW2 = fam15_rttwr(pDCTstat, 
dct, dimm, rank, package_type);
-+                                      } else {
-+                                              tempW2 = fam15_rttnom(pDCTstat, 
dct, dimm, rank, package_type);
-+                                      }
-                               } else {
--                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                      tempW2 = fam15_rttnom(pDCTstat, dct, 
dimm, rank, package_type);
-                               }
-                       } else {
--                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                              tempW2 = fam15_rttnom(pDCTstat, dct, dimm, 
rank, package_type);
-+                      }
-+                      tempW1 = 0;
-+                      tempW1 |= ((tempW2 & 0x4) >> 2) << 9;
-+                      tempW1 |= ((tempW2 & 0x2) >> 1) << 6;
-+                      tempW1 |= ((tempW2 & 0x1) >> 0) << 2;
-+              } else {
-+                      if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                              tempW1 = RttNomTargetRegDimm(pMCTData, 
pDCTData, dimm, wl, MemClkFreq, rank);
-+                      } else {
-+                              if (wl) {
-+                                      if (number_of_dimms > 1) {
-+                                              if (rank == 0) {
-+                                                      /* Get Rtt_WR for the 
current DIMM and rank */
-+                                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm]);
-+
-+                                                      /* Convert dynamic 
termination code to corresponding nominal termination code */
-+                                                      if (dynamic_term == 
0x200)
-+                                                              tempW1 = 0x04;
-+                                                      else if (dynamic_term 
== 0x400)
-+                                                              tempW1 = 0x40;
-+                                                      else
-+                                                              tempW1 = 0x0;
-+                                              } else {
-+                                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                              }
-+                                      } else {
-+                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                      }
-+                              } else {
-+                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                              }
-                       }
-               }
-+
-+              /* Apply Rtt_Nom to the MRS control word */
-               tempW=tempW|tempW1;
- 
-               /* All ranks of the target DIMM are set to write levelization 
mode. */
-@@ -393,68 +574,105 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-                               tempW = bitTestSet(tempW1, Qoff);
-                       }
-               }
--              /* Program MrsAddress[5,1]=output driver impedance control 
(DIC):
--               * based on F2x[1,0]84[DrvImpCtrl]
--               */
--              tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
--                              FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, 
DrvImpCtrlEnd);
-+
-+              /* Program MrsAddress[5,1]=output driver impedance control 
(DIC) */
-+              if (is_fam15h()) {
-+                      tempW1 = fam15_dimm_dic(pDCTstat, dct, dimm, rank, 
package_type);
-+              } else {
-+                      /* Read DIC from F2x[1,0]84[DrvImpCtrl] */
-+                      tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                                      FUN_DCT, DRAM_MRS_REGISTER, 
DrvImpCtrlStart, DrvImpCtrlEnd);
-+              }
-+
-+              /* Apply DIC to the MRS control word */
-               if (bitTest(tempW1, 1))
-                       tempW = bitTestSet(tempW, 5);
-               if (bitTest(tempW1, 0))
-                       tempW = bitTestSet(tempW, 1);
- 
--              tempW = swapAddrBits_wl(pDCTData, tempW);
-+              tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
-+
-+              if (is_fam15h())
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsAddressStartFam15, 
MrsAddressEndFam15, tempW);
-+              else
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsAddressStartFam10, 
MrsAddressEndFam10, tempW);
- 
--              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
--                      DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
-               /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
-                * the specified DIMM.
-                */
--              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
-+              set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
-               /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. 
*/
--              while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
-+              while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
-                               FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 
0x1)
-               {
-               }
-+
-               /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate 
internal DRAM
-                * register that defines the required DDR3-defined function for 
Rtt_WR.
-                */
--              MrsBank = swapBankBits(pDCTData,2);
--              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
--                      DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
-+              MrsBank = swapBankBits(pDCTstat, dct, 2);
-+              if (is_fam15h())
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, 
MrsBank);
-+              else
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, 
MrsBank);
-+
-               /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required 
DDR3-defined function
-                * for Rtt_WR (DRAMTermDyn).
-                */
-               tempW = 0;/* PASR = 0,*/
--              /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
--               * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
--              tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
--                              FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, 
PCI_MAX_HIGH);
--              if (bitTest(tempW1,19))
--              {tempW = bitTestSet(tempW, 7);}
--              if (bitTest(tempW1,18))
--              {tempW = bitTestSet(tempW, 6);}
--              /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
--              tempW=tempW|((tempW1&0x00700000)>>17);
--              /* workaround for DR-B0 */
--              if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && 
(pDCTData->Status[DCT_STATUS_REGISTERED]))
--                      tempW+=0x8;
-+
-+              /* Retrieve normal settings of the MRS control word and clear 
Rtt_WR */
-+              if (is_fam15h()) {
-+                      tempW = mct_MR2(pMCTstat, pDCTstat, dct, dimm*2+rank) & 
0xffff;
-+                      tempW &= ~(0x0600);
-+              } else {
-+                      /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
-+                      * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
-+                      tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                                      FUN_DCT, DRAM_MRS_REGISTER, 
PCI_MIN_LOW, PCI_MAX_HIGH);
-+                      if (bitTest(tempW1,19))
-+                      {tempW = bitTestSet(tempW, 7);}
-+                      if (bitTest(tempW1,18))
-+                      {tempW = bitTestSet(tempW, 6);}
-+                      /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
-+                      tempW=tempW|((tempW1&0x00700000)>>17);
-+                      /* workaround for DR-B0 */
-+                      if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && 
(pDCTData->Status[DCT_STATUS_REGISTERED]))
-+                              tempW+=0x8;
-+              }
-+
-               /* determine Rtt_WR for WL & Normal mode */
--              if (pDCTData->Status[DCT_STATUS_REGISTERED])
--                      tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, 
MemClkFreq, rank);
--              else
--                      tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
-+              if (is_fam15h()) {
-+                      tempW1 = (fam15_rttwr(pDCTstat, dct, dimm, rank, 
package_type) << 9);
-+              } else {
-+                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
-+                              tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, 
wl, MemClkFreq, rank);
-+                      else
-+                              tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm]);
-+              }
-+
-+              /* Apply Rtt_WR to the MRS control word */
-               tempW=tempW|tempW1;
--              tempW = swapAddrBits_wl(pDCTData,tempW);
--              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
--                      DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
-+              tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
-+              if (is_fam15h())
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsAddressStartFam15, 
MrsAddressEndFam15, tempW);
-+              else
-+                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_INIT, MrsAddressStartFam10, 
MrsAddressEndFam10, tempW);
-+
-               /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
-                  the specified DIMM.*/
--              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
-+              set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
-+
-               /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. 
*/
--              while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
-+              while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
-                               FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 
0x1)
-               {
-               }
-@@ -473,97 +691,163 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-                               rank = 0;
-                               while ((rank < pDCTData->DimmRanks[currDimm]) 
&& (rank < 2))
-                               {
--
-                                       /* Program F2x[1, 0]7C[MrsChipSel[2:0]] 
for the current rank
-                                        * to be trained.
-                                        */
--                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
--                                              FUN_DCT, DRAM_INIT, 
MrsChipSelStart, MrsChipSelEnd, currDimm*2+rank);
-+                                      if (is_fam15h())
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
-+                                                      FUN_DCT, DRAM_INIT, 
MrsChipSelStartFam15, MrsChipSelEndFam15, currDimm*2+rank);
-+                                      else
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
-+                                                      FUN_DCT, DRAM_INIT, 
MrsChipSelStartFam10, MrsChipSelEndFam10, currDimm*2+rank);
-+
-                                       /* Program F2x[1, 0]7C[MrsBank[2:0]] 
for the appropriate internal
-                                        * DRAM register that defines the 
required DDR3-defined function
-                                        * for write levelization.
-                                        */
--                                      MrsBank = swapBankBits(pDCTData,1);
--                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
--                                              FUN_DCT, DRAM_INIT, 
MrsBankStart, MrsBankEnd, MrsBank);
-+                                      MrsBank = swapBankBits(pDCTstat, dct, 
1);
-+                                      if (is_fam15h())
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
-+                                                      FUN_DCT, DRAM_INIT, 
MrsBankStartFam15, MrsBankEndFam15, MrsBank);
-+                                      else
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
-+                                                      FUN_DCT, DRAM_INIT, 
MrsBankStartFam10, MrsBankEndFam10, MrsBank);
-+
-                                       /* Program F2x[1, 
0]7C[MrsAddress[15:0]] to the required
-                                        * DDR3-defined function for write 
levelization.
-                                        */
-                                       tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 
0, TDQS = 0, Level=0, Qoff=0 */
- 
--                                      /* Set TDQS=1b for x8 DIMM, TDQS=0b for 
x4 DIMM, when mixed x8 & x4 */
--                                      tempW2 = get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
--                                                      FUN_DCT, 
DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
--                                      if (tempW2)
--                                      {
--                                              if 
(pDCTData->DimmX8Present[currDimm])
--                                                      tempW |= 0x800;
-+                                      /* Retrieve normal settings of the MRS 
control word and clear Rtt_Nom */
-+                                      if (is_fam15h()) {
-+                                              tempW = mct_MR1(pMCTstat, 
pDCTstat, dct, dimm*2+rank) & 0xffff;
-+                                              tempW &= ~(0x0244);
-+                                      } else {
-+                                              /* Set TDQS=1b for x8 DIMM, 
TDQS=0b for x4 DIMM, when mixed x8 & x4 */
-+                                              tempW2 = get_Bits(pDCTData, 
dct, pDCTData->NodeId,
-+                                                              FUN_DCT, 
DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
-+                                              if (tempW2)
-+                                              {
-+                                                      if 
(pDCTData->DimmX8Present[currDimm])
-+                                                              tempW |= 0x800;
-+                                              }
-                                       }
- 
-                                       /* determine Rtt_Nom for WL & Normal 
mode */
--                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
--                                              tempW1 = 
RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
--                                      else
--                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                      if (is_fam15h()) {
-+                                              tempW2 = fam15_rttnom(pDCTstat, 
dct, dimm, rank, package_type);
-+                                              tempW1 = 0;
-+                                              tempW1 |= ((tempW2 & 0x4) >> 2) 
<< 9;
-+                                              tempW1 |= ((tempW2 & 0x2) >> 1) 
<< 6;
-+                                              tempW1 |= ((tempW2 & 0x1) >> 0) 
<< 2;
-+                                      } else {
-+                                              if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
-+                                                      tempW1 = 
RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
-+                                              else
-+                                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                      }
-+
-+                                      /* Apply Rtt_Nom to the MRS control 
word */
-                                       tempW=tempW|tempW1;
--                                      /* program MrsAddress[5,1]=output 
driver impedance control (DIC):
--                                       * based on F2x[1,0]84[DrvImpCtrl] */
--                                      tempW1 = get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
--                                                      FUN_DCT, 
DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
-+
-+                                      /* Program MrsAddress[5,1]=output 
driver impedance control (DIC) */
-+                                      if (is_fam15h()) {
-+                                              tempW1 = 
fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
-+                                      } else {
-+                                              /* Read DIC from 
F2x[1,0]84[DrvImpCtrl] */
-+                                              tempW1 = get_Bits(pDCTData, 
dct, pDCTData->NodeId,
-+                                                              FUN_DCT, 
DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
-+                                      }
-+
-+                                      /* Apply DIC to the MRS control word */
-                                       if (bitTest(tempW1,1))
-                                       {tempW = bitTestSet(tempW, 5);}
-                                       if (bitTest(tempW1,0))
-                                       {tempW = bitTestSet(tempW, 1);}
--                                      tempW = swapAddrBits_wl(pDCTData,tempW);
--                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
--                                              FUN_DCT, DRAM_INIT, 
MrsAddressStart, MrsAddressEnd, tempW);
-+
-+                                      tempW = swapAddrBits_wl(pDCTstat, dct, 
tempW);
-+
-+                                      if (is_fam15h())
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
-+                                                      FUN_DCT, DRAM_INIT, 
MrsAddressStartFam15, MrsAddressEndFam15, tempW);
-+                                      else
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
-+                                                      FUN_DCT, DRAM_INIT, 
MrsAddressStartFam10, MrsAddressEndFam10, tempW);
-+
-                                       /* Program F2x[1, 0]7C[SendMrsCmd]=1 to 
initiate the command
-                                        * to the specified DIMM.
-                                        */
--                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
-+                                      set_Bits(pDCTData, dct, 
pDCTData->NodeId,
-                                               FUN_DCT, DRAM_INIT, SendMrsCmd, 
SendMrsCmd, 1);
-+
-                                       /* Wait for F2x[1, 0]7C[SendMrsCmd] to 
be cleared by hardware. */
--                                      while ((get_Bits(pDCTData, 
pDCTData->CurrDct,
-+                                      while ((get_Bits(pDCTData, dct,
-                                                       pDCTData->NodeId, 
FUN_DCT, DRAM_INIT,
-                                                       SendMrsCmd, 
SendMrsCmd)) == 1);
-+
-                                       /* Program F2x[1, 0]7C[MrsBank[2:0]] 
for the appropriate internal DRAM
-                                        * register that defines the required 
DDR3-defined function for Rtt_WR.
-                                        */
--                                      MrsBank = swapBankBits(pDCTData,2);
--                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
--                                              DRAM_INIT, MrsBankStart, 
MrsBankEnd, MrsBank);
-+                                      MrsBank = swapBankBits(pDCTstat, dct, 
2);
-+                                      if (is_fam15h())
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
-+                                                      DRAM_INIT, 
MrsBankStartFam15, MrsBankEndFam15, MrsBank);
-+                                      else
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
-+                                                      DRAM_INIT, 
MrsBankStartFam10, MrsBankEndFam10, MrsBank);
-+
-                                       /* Program F2x[1, 
0]7C[MrsAddress[15:0]] to the required DDR3-defined function
-                                        * for Rtt_WR (DRAMTermDyn).
-                                        */
-                                       tempW = 0;/* PASR = 0,*/
--                                      /* program 
MrsAddress[7,6,5:3]=SRT,ASR,CWL,
--                                       * based on 
F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
--                                      tempW1 = get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
--                                                      FUN_DCT, 
DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
--                                      if (bitTest(tempW1,19))
--                                      {tempW = bitTestSet(tempW, 7);}
--                                      if (bitTest(tempW1,18))
--                                      {tempW = bitTestSet(tempW, 6);}
--                                      /* tempW=tempW|(((tempW1>>20)&0x7)<<3); 
*/
--                                      tempW=tempW|((tempW1&0x00700000)>>17);
--                                      /* workaround for DR-B0 */
--                                      if ((pDCTData->LogicalCPUID & 
AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
--                                              tempW+=0x8;
-+
-+                                      /* Retrieve normal settings of the MRS 
control word and clear Rtt_WR */
-+                                      if (is_fam15h()) {
-+                                              tempW = mct_MR2(pMCTstat, 
pDCTstat, dct, dimm*2+rank) & 0xffff;
-+                                              tempW &= ~(0x0600);
-+                                      } else {
-+                                              /* program 
MrsAddress[7,6,5:3]=SRT,ASR,CWL,
-+                                              * based on 
F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
-+                                              tempW1 = get_Bits(pDCTData, 
dct, pDCTData->NodeId,
-+                                                              FUN_DCT, 
DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
-+                                              if (bitTest(tempW1,19))
-+                                              {tempW = bitTestSet(tempW, 7);}
-+                                              if (bitTest(tempW1,18))
-+                                              {tempW = bitTestSet(tempW, 6);}
-+                                              /* 
tempW=tempW|(((tempW1>>20)&0x7)<<3); */
-+                                              
tempW=tempW|((tempW1&0x00700000)>>17);
-+                                              /* workaround for DR-B0 */
-+                                              if ((pDCTData->LogicalCPUID & 
AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
-+                                                      tempW+=0x8;
-+                                      }
-+
-                                       /* determine Rtt_WR for WL & Normal 
mode */
--                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
--                                              tempW1 = RttWrRegDimm(pMCTData, 
pDCTData, currDimm, wl, MemClkFreq, rank);
--                                      else
--                                              tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                      if (is_fam15h()) {
-+                                              tempW1 = (fam15_rttwr(pDCTstat, 
dct, dimm, rank, package_type) << 9);
-+                                      } else {
-+                                              if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
-+                                                      tempW1 = 
RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
-+                                              else
-+                                                      tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm]);
-+                                      }
-+
-+                                      /* Apply Rtt_WR to the MRS control word 
*/
-                                       tempW=tempW|tempW1;
--                                      tempW = swapAddrBits_wl(pDCTData,tempW);
--                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
--                                              DRAM_INIT, MrsAddressStart, 
MrsAddressEnd, tempW);
-+                                      tempW = swapAddrBits_wl(pDCTstat, dct, 
tempW);
-+                                      if (is_fam15h())
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
-+                                                      DRAM_INIT, 
MrsAddressStartFam15, MrsAddressEndFam15, tempW);
-+                                      else
-+                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
-+                                                      DRAM_INIT, 
MrsAddressStartFam10, MrsAddressEndFam10, tempW);
-+
-                                       /* Program F2x[1, 0]7C[SendMrsCmd]=1 to 
initiate the command to
-                                          the specified DIMM.*/
--                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
-+                                      set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
-                                               DRAM_INIT, SendMrsCmd, 
SendMrsCmd, 1);
-+
-                                       /* Wait for F2x[1, 0]7C[SendMrsCmd] to 
be cleared by hardware. */
--                                      while ((get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
-+                                      while ((get_Bits(pDCTData, dct, 
pDCTData->NodeId,
-                                                       FUN_DCT, DRAM_INIT, 
SendMrsCmd, SendMrsCmd)) == 0x1)
-                                       {
-                                       }
-@@ -587,29 +871,60 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
-  *       OUT
-  * 
----------------------------------------------------------------------------
-  */
--void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
-+void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm)
- {
-+      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+
-       u8 WrLvOdt1=0;
- 
--      if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
--              if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
--                      WrLvOdt1 = 0x03;
--              } else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) 
{
--                      WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
-+      if (is_fam15h()) {
-+              /* Convert DIMM number to CS */
-+              uint32_t dword;
-+              uint8_t cs;
-+              uint8_t rank = 0;
-+
-+              cs = (dimm * 2) + rank;
-+
-+              /* Fetch preprogammed ODT pattern from configuration registers 
*/
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
((cs>3)?0x23c:0x238));
-+              if ((cs == 7) || (cs == 3))
-+                      WrLvOdt1 = ((dword >> 24) & 0xf);
-+              else if ((cs == 6) || (cs == 2))
-+                      WrLvOdt1 = ((dword >> 16) & 0xf);
-+              else if ((cs == 5) || (cs == 1))
-+                      WrLvOdt1 = ((dword >> 8) & 0xf);
-+              else if ((cs == 4) || (cs == 0))
-+                      WrLvOdt1 = (dword & 0xf);
-+      } else {
-+              if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
-+                      if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
-+                              WrLvOdt1 = 0x03;
-+                      } else if 
(bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
-+                              WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
-+                      } else {
-+                              WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
-+                      }
-               } else {
--                      WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
-+                      WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
-               }
--      } else {
--              WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
-       }
- 
--      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
-+      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
- 
- }
- 
-+#ifdef UNUSED_CODE
-+static uint16_t fam15h_next_lowest_memclk_freq(uint16_t memclk_freq)
-+{
-+      uint16_t fam15h_next_lowest_freq_tab[] = {0, 0, 0, 0, 0x4, 0, 0x4, 0, 
0, 0, 0x6, 0, 0, 0, 0xa, 0, 0, 0, 0xe, 0, 0, 0, 0x12};
-+      return fam15h_next_lowest_freq_tab[memclk_freq];
-+}
-+#endif
-+
- 
/*-----------------------------------------------------------------------------
-- * void procConifg(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
-+ * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
-  *
-  *  Description:
-  *       This function programs the ODT values for the NB
-@@ -622,31 +937,43 @@ void programODT(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm)
-  *       OUT
-  * 
----------------------------------------------------------------------------
-  */
--void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
-+void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass)
- {
--      u8 ByteLane, Seed_Gross, Seed_Fine, MemClkFreq;
-+      u8 ByteLane, MemClkFreq;
-+      int32_t Seed_Gross;
-+      int32_t Seed_Fine;
-+      uint8_t Seed_PreGross;
-       u32 Value, Addr;
-       u16 Addl_Data_Offset, Addl_Data_Port;
--      u16 freq_tab[] = {400, 533, 667, 800};
-+      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-+      u16 fam10h_freq_tab[] = {400, 533, 667, 800};
-+      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
- 
--      /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
--      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
--                              FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
-+      if (is_fam15h()) {
-+              /* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 
667MHz; 0x12: 800MHz; 0x16: 933MHz */
-+              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                                      FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
-+      } else {
-+              /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
-+              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
-+                                      FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
-+      }
- 
-       /* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for 
the
-        * current memory subsystem configuration.
-        */
--      programODT(pMCTData, pDCTData, dimm);
-+      programODT(pMCTstat, pDCTstat, dct, dimm);
- 
-       /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
--      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) {
--              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-+      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL)) {
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, 
WrLvOdtEn, (u32)1);
-       }
-       else
-       {
-               /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 
0 for Rev.B */
--              if (pDCTData->DctTrain)
-+              if (dct)
-               {
-                       Addl_Data_Offset=0x198;
-                       Addl_Data_Port=0x19C;
-@@ -669,33 +996,94 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
-                               DctAccessDone, DctAccessDone)) == 0);
-       }
- 
-+      if (is_fam15h())
-+              proc_MFENCE();
-+
-       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
--      pMCTData->AgesaDelay(10);
-+      if (is_fam15h())
-+              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
-+      else
-+              pMCTData->AgesaDelay(10);
-+
-+      /* Program write levelling seed values */
-       if (pass == 1)
-       {
--              if (pDCTData->Status[DCT_STATUS_REGISTERED])
--              {
--                      if(pDCTData->RegMan1Present & 
((1<<(dimm*2+pDCTData->DctTrain))))
-+              /* Pass 1 */
-+              if (is_fam15h()) {
-+                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
-+                      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+                      uint16_t Seed_Total = 0;
-+                      if (package_type == PT_GR) {
-+                              /* Socket G34: Fam15h BKDG v3.14 Table 96 */
-+                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                      Seed_Total = 0x41;
-+                              } else if 
(pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
-+                                      Seed_Total = 0x0;
-+                              } else {
-+                                      Seed_Total = 0xf;
-+                              }
-+                      } else if (package_type == PT_C3) {
-+                              /* Socket C32: Fam15h BKDG v3.14 Table 97 */
-+                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                      Seed_Total = 0x3e;
-+                              } else if 
(pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
-+                                      Seed_Total = 0x0;
-+                              } else {
-+                                      Seed_Total = 0x12;
-+                              }
-+                      } else if (package_type == PT_M2) {
-+                              /* Socket AM3: Fam15h BKDG v3.14 Table 98 */
-+                              Seed_Total = 0xf;
-+                      }
-+                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
-+                              Seed_Total += ((AddrCmdPrelaunch)?0x10:0x0);
-+
-+                      /* Adjust seed for the minimum platform supported 
frequency */
-+                      Seed_Total = (int32_t) (((((int64_t) Seed_Total) *
-+                              fam15h_freq_tab[MemClkFreq] * 100) / 
(mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
-+
-+                      Seed_Gross = (Seed_Total >> 5) & 0x1f;
-+                      Seed_Fine = Seed_Total & 0x1f;
-+
-+                      /* Save seed values for later use */
-+                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                              
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
-+                              
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+
-+                              if (Seed_Gross == 0)
-+                                      Seed_PreGross = 0;
-+                              else if (Seed_Gross & 0x1)
-+                                      Seed_PreGross = 1;
-+                              else
-+                                      Seed_PreGross = 2;
-+
-+                              
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-+                      }
-+              } else {
-+                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
-                       {
--                              Seed_Gross = 0x02;
--                              Seed_Fine = 0x16;
-+                              if(pDCTData->RegMan1Present & 
((1<<(dimm*2+dct))))
-+                              {
-+                                      Seed_Gross = 0x02;
-+                                      Seed_Fine = 0x16;
-+                              }
-+                              else
-+                              {
-+                                      Seed_Gross = 0x02;
-+                                      Seed_Fine = 0x00;
-+                              }
-                       }
-                       else
-                       {
--                              Seed_Gross = 0x02;
--                              Seed_Fine = 0x00;
--                      }
--              }
--              else
--              {
--                      if (MemClkFreq == 6) {
--                              /* DDR-800 */
--                              Seed_Gross = 0x00;
--                              Seed_Fine = 0x1a;
--                      } else {
--                              /* Use settings for DDR-400 (interpolated from 
BKDG) */
--                              Seed_Gross = 0x00;
--                              Seed_Fine = 0x0d;
-+                              if (MemClkFreq == 6) {
-+                                      /* DDR-800 */
-+                                      Seed_Gross = 0x00;
-+                                      Seed_Fine = 0x1a;
-+                              } else {
-+                                      /* Use settings for DDR-400 
(interpolated from BKDG) */
-+                                      Seed_Gross = 0x00;
-+                                      Seed_Fine = 0x0d;
-+                              }
-                       }
-               }
-               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
-@@ -711,39 +1099,91 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
-                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
-                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
-               }
--      } else {                /* Pass 2 */
-+      } else {
-+              /* Pass 2 */
-               /* From BKDG, Write Leveling Seed Value. */
--              u32 RegisterDelay, SeedTotal;
--              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
--              {
--                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
--                              RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) 
== 0) ? 0x20 : 0x30; */
--                      else
--                              RegisterDelay = 0;
--                      SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
--                              
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
--                      /* SeedTotalPreScaling = (the total delay value in 
F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
--                         training) - RegisterDelay. */
--                      SeedTotal = (uint16_t) (RegisterDelay + ((((uint64_t) 
SeedTotal - RegisterDelay) *
--                                                              
freq_tab[MemClkFreq-3] * 100) / (freq_tab[0] * 100)));
--                      Seed_Gross = SeedTotal / 32;
--                      Seed_Fine = SeedTotal & 0x1f;
--                      if (Seed_Gross == 0)
--                              Seed_Gross = 0;
--                      else if (Seed_Gross & 0x1)
--                              Seed_Gross = 1;
--                      else
--                              Seed_Gross = 2;
--                      pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
--                      pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
-+              if (is_fam15h()) {
-+                      uint32_t RegisterDelay;
-+                      int32_t SeedTotal;
-+                      int32_t SeedTotalPreScaling;
-+                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
-+
-+                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                      if (AddrCmdPrelaunch)
-+                                              RegisterDelay = 0x30;
-+                                      else
-+                                              RegisterDelay = 0x20;
-+                              } else {
-+                                      RegisterDelay = 0;
-+                              }
-+                              /* Retrieve WrDqDqsEarly */
-+                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId), FUN_DCT, 0xa8), 25, 24, 
&Value);
-+
-+                              /* Calculate adjusted seed values */
-+                              SeedTotal = 
(pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
-+                                      
((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5);
-+                              SeedTotalPreScaling = (SeedTotal - 
RegisterDelay - (0x20 * Value));
-+                              SeedTotal = (int32_t) (RegisterDelay + 
((((int64_t) SeedTotalPreScaling) *
-+                                      fam15h_freq_tab[MemClkFreq] * 100) / 
(fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
-+
-+                              if (SeedTotal >= 0) {
-+                                      Seed_Gross = SeedTotal / 32;
-+                                      Seed_Fine = SeedTotal % 32;
-+                              } else {
-+                                      Seed_Gross = (SeedTotal / 32) - 1;
-+                                      Seed_Fine = (SeedTotal % 32) + 32;
-+                              }
-+
-+                              if (Seed_Gross == 0)
-+                                      Seed_PreGross = 0;
-+                              else if (Seed_Gross & 0x1)
-+                                      Seed_PreGross = 1;
-+                              else
-+                                      Seed_PreGross = 2;
-+
-+                              /* Save seed values for later use */
-+                              
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
-+                              
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+                              
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-+
-+                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-+                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+                      }
-+              } else {
-+                      u32 RegisterDelay, SeedTotal;
-+                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
-+                      {
-+                              if (pDCTData->Status[DCT_STATUS_REGISTERED])
-+                                      RegisterDelay = 0x20; /* TODO: ((RCW2 & 
BIT0) == 0) ? 0x20 : 0x30; */
-+                              else
-+                                      RegisterDelay = 0;
-+                              SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
-+                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
-+                              /* SeedTotalPreScaling = (the total delay value 
in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
-+                              training) - RegisterDelay. */
-+                              SeedTotal = (uint16_t) (RegisterDelay + 
((((uint64_t) SeedTotal - RegisterDelay) *
-+                                                                      
fam10h_freq_tab[MemClkFreq-3] * 100) / (fam10h_freq_tab[0] * 100)));
-+                              Seed_Gross = SeedTotal / 32;
-+                              Seed_Fine = SeedTotal & 0x1f;
-+                              if (Seed_Gross == 0)
-+                                      Seed_Gross = 0;
-+                              else if (Seed_Gross & 0x1)
-+                                      Seed_Gross = 1;
-+                              else
-+                                      Seed_Gross = 2;
-+                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
-+                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+                      }
-               }
-       }
- 
--      setWLByteDelay(pDCTData, ByteLane, dimm, 0);
-+      pDCTData->WLPrevMemclkFreq = MemClkFreq;
-+      setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass);
- }
- 
- 
/*-----------------------------------------------------------------------------
-- *  void setWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm){
-+ *  void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm){
-  *
-  *  Description:
-  *       This function writes the write levelization byte delay for the Phase
-@@ -763,8 +1203,9 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
-  *
-  
*-----------------------------------------------------------------------------
-  */
--void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
-+void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, u8 targetAddr, uint8_t pass)
- {
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, 
offsetAddr;
-       u32 addr, fineDelayValue, grossDelayValue, ValueLow, ValueHigh, 
EccValue, tempW;
- 
-@@ -777,22 +1218,26 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
-               EccValue = 0;
-               while (ByteLane < MAX_BYTE_LANES)
-               {
--                      /* This subtract 0xC workaround might be temporary. */
--                      if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present 
& (1<<(dimm*2+pDCTData->DctTrain))))
--                      {
--                              tempW = (pDCTData->WLGrossDelay[index+ByteLane] 
<< 5) | pDCTData->WLFineDelay[index+ByteLane];
--                              tempW -= 0xC;
--                              pDCTData->WLGrossDelay[index+ByteLane] = 
(u8)(tempW >> 5);
--                              pDCTData->WLFineDelay[index+ByteLane] = 
(u8)(tempW & 0x1F);
--                      }
--                      grossDelayValue = 
pDCTData->WLGrossDelay[index+ByteLane];
--                      /* Adjust seed gross delay overflow (greater than 3):
--                       *      - Program seed gross delay as 2 (gross is 4 or 
6) or 1 (gross is 5).
--                       *      - Keep original seed gross delay for later 
reference.
--                       */
--                      if(grossDelayValue >= 3)
--                      {
--                              grossDelayValue = (grossDelayValue&1)? 1 : 2;
-+                      if (is_fam15h()) {
-+                              grossDelayValue = 
pDCTData->WLGrossDelay[index+ByteLane];
-+                      } else {
-+                              /* This subtract 0xC workaround might be 
temporary. */
-+                              if ((pDCTData->WLPass==2) && 
(pDCTData->RegMan1Present & (1<<(dimm*2+dct))))
-+                              {
-+                                      tempW = 
(pDCTData->WLGrossDelay[index+ByteLane] << 5) | 
pDCTData->WLFineDelay[index+ByteLane];
-+                                      tempW -= 0xC;
-+                                      pDCTData->WLGrossDelay[index+ByteLane] 
= (u8)(tempW >> 5);
-+                                      pDCTData->WLFineDelay[index+ByteLane] = 
(u8)(tempW & 0x1F);
-+                              }
-+                              grossDelayValue = 
pDCTData->WLGrossDelay[index+ByteLane];
-+                              /* Adjust seed gross delay overflow (greater 
than 3):
-+                               *      - Program seed gross delay as 2 (gross 
is 4 or 6) or 1 (gross is 5).
-+                               *      - Keep original seed gross delay for 
later reference.
-+                               */
-+                              if(grossDelayValue >= 3)
-+                              {
-+                                      grossDelayValue = (grossDelayValue&1)? 
1 : 2;
-+                              }
-                       }
-                       fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
-                       if (ByteLane < 4)
-@@ -803,15 +1248,16 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
-                               EccValue = ((grossDelayValue << 5) | 
fineDelayValue);
-                       ByteLane++;
-               }
--              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                               DRAM_CONT_ADD_PHASE_REC_CTRL_LOW, 0, 31, 
(u32)ValueLow);
--              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                               DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH, 0, 31, 
(u32)ValueHigh);
--              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                               DRAM_CONT_ADD_ECC_PHASE_REC_CTRL, 0, 31, 
(u32)EccValue);
-       }
-       else
-       {
-+              /* Fam10h BKDG Rev. 3.62 2.8.9.9.1 (6) */
-               index = (u8)(MAX_BYTE_LANES * dimm);
-               grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
-               fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
-@@ -841,16 +1287,24 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
-               grossStartLoc = (u8)(fineEndLoc + 1);
-               grossEndLoc = (u8)(grossStartLoc + 1);
- 
--              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                               (u16)addr, fineStartLoc, 
fineEndLoc,(u32)fineDelayValue);
--              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                               (u16)addr, grossStartLoc, grossEndLoc, 
(u32)grossDelayValue);
-+
-+              pDCTData->WLFineDelayPrevPass[index+ByteLane] = fineDelayValue;
-+              pDCTData->WLGrossDelayPrevPass[index+ByteLane] = 
grossDelayValue;
-+              if (pass == FirstPass) {
-+                      pDCTData->WLFineDelayFirstPass[index+ByteLane] = 
fineDelayValue;
-+                      pDCTData->WLGrossDelayFirstPass[index+ByteLane] = 
grossDelayValue;
-+                      pDCTData->WLCriticalGrossDelayFirstPass = 
pDCTData->WLCriticalGrossDelayPrevPass;
-+              }
-       }
- 
- }
- 
- 
/*-----------------------------------------------------------------------------
-- *  void getWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm)
-+ *  void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm)
-  *
-  *  Description:
-  *       This function reads the write levelization byte delay from the Phase
-@@ -868,8 +1322,9 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 
dimm, u8 targetAddr)
-  *
-  
*-----------------------------------------------------------------------------
-  */
--void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm)
-+void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass)
- {
-+      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, 
index;
-       u32 addr, fine, gross;
-       tempB = 0;
-@@ -890,25 +1345,31 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm)
-       grossStartLoc = (u8)(fineEndLoc + 1);
-       grossEndLoc = (u8)(grossStartLoc + 1);
- 
--      fine = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
-+      fine = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
-                               FUN_DCT, (u16)addr, fineStartLoc, fineEndLoc);
--      gross = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
-+      gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
-                               FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
--      /* Adjust seed gross delay overflow (greater than 3):
--       * - Adjust the trained gross delay to the original seed gross delay.
--       */
--      if (pDCTData->WLGrossDelay[index+ByteLane] >= 3) {
--              gross += pDCTData->WLGrossDelay[index+ByteLane];
--              if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
--                      gross -= 1;
--              else
--                      gross -= 2;
--      } else if ((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 
3)) {
--              /* If seed gross delay is 0 but PRE result gross delay is 3, it 
is negative.
--               * We will then round the negative number to 0.
-+
-+      if (!is_fam15h()) {
-+              /* Adjust seed gross delay overflow (greater than 3):
-+               * - Adjust the trained gross delay to the original seed gross 
delay.
-                */
--              gross = 0;
--              fine = 0;
-+              if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
-+              {
-+                      gross += pDCTData->WLGrossDelay[index+ByteLane];
-+                      if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
-+                              gross -= 1;
-+                      else
-+                              gross -= 2;
-+              }
-+              else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross 
== 3))
-+              {
-+                      /* If seed gross delay is 0 but PRE result gross delay 
is 3, it is negative.
-+                       * We will then round the negative number to 0.
-+                       */
-+                      gross = 0;
-+                      fine = 0;
-+              }
-       }
-       pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
-       pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
-index 0466c77..cf6afaa 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -134,24 +135,48 @@ static u32 get_Bits(sDCTStruct *pDCTData,
-               u16 offset, u8 low, u8 high)
- {
-       u32 temp;
-+      uint32_t dword;
-+
-       /* ASSERT(node < MAX_NODES); */
-       if (dct == BOTH_DCTS)
-       {
-               /* Registers exist on DCT0 only */
-+              if (is_fam15h())
-+              {
-+                      /* Select DCT 0 */
-+                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+                      dword &= ~0x1;
-+                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+              }
-+
-               AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, 
low, &temp);
-       }
-       else
-       {
--              if (dct == 1)
-+              if (is_fam15h())
-               {
--                      /* Write to dct 1 */
--                      offset += 0x100;
-+                      /* Select DCT */
-+                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+                      dword &= ~0x1;
-+                      dword |= (dct & 0x1);
-+                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+
-+                      /* Read from the selected DCT */
-                       AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
-               }
-               else
-               {
--                      /* Write to dct 0 */
--                      AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
-+                      if (dct == 1)
-+                      {
-+                              /* Read from dct 1 */
-+                              offset += 0x100;
-+                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
-+                      }
-+                      else
-+                      {
-+                              /* Read from dct 0 */
-+                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
-+                      }
-               }
-       }
-       return temp;
-@@ -184,25 +209,49 @@ static void set_Bits(sDCTStruct *pDCTData,
-               u16 offset, u8 low, u8 high, u32 value)
- {
-       u32 temp;
-+      uint32_t dword;
-+
-       temp = value;
- 
-       if (dct == BOTH_DCTS)
-       {
-               /* Registers exist on DCT0 only */
-+              if (is_fam15h())
-+              {
-+                      /* Select DCT 0 */
-+                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+                      dword &= ~0x1;
-+                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+              }
-+
-               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, 
low, &temp);
-       }
-       else
-       {
--              if (dct == 1)
-+              if (is_fam15h())
-               {
--                      /* Write to dct 1 */
--                      offset += 0x100;
-+                      /* Select DCT */
-+                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+                      dword &= ~0x1;
-+                      dword |= (dct & 0x1);
-+                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
-+
-+                      /* Write to the selected DCT */
-                       AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
-               }
-               else
-               {
--                      /* Write to dct 0 */
--                      AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
-+                      if (dct == 1)
-+                      {
-+                              /* Write to dct 1 */
-+                              offset += 0x100;
-+                              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
-+                      }
-+                      else
-+                      {
-+                              /* Write to dct 0 */
-+                              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
-+                      }
-               }
-       }
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-index f846d87..162340e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -33,7 +34,8 @@
- #define C_MAX_DIMMS 4         /* Maximum Number of DIMMs on each DCT */
- 
- /* STATUS Definition */
--#define DCT_STATUS_REGISTERED 3       /* Registered DIMMs support */
-+#define DCT_STATUS_REGISTERED 3               /* Registered DIMMs support */
-+#define DCT_STATUS_LOAD_REDUCED 4     /* Load-Reduced DIMMs support */
- #define DCT_STATUS_OnDimmMirror 24    /* OnDimmMirror support */
- 
- /* PCI Defintions */
-@@ -78,12 +80,18 @@
- #define SendMrsCmd 26
- #define Qoff 12
- #define MRS_Level 7
--#define MrsAddressStart 0
--#define MrsAddressEnd 15
--#define MrsBankStart 16
--#define MrsBankEnd 18
--#define MrsChipSelStart 20
--#define MrsChipSelEnd 22
-+#define MrsAddressStartFam10 0
-+#define MrsAddressEndFam10 15
-+#define MrsAddressStartFam15 0
-+#define MrsAddressEndFam15 17
-+#define MrsBankStartFam10 16
-+#define MrsBankEndFam10 18
-+#define MrsBankStartFam15 18
-+#define MrsBankEndFam15 20
-+#define MrsChipSelStartFam10 20
-+#define MrsChipSelEndFam10 22
-+#define MrsChipSelStartFam15 21
-+#define MrsChipSelEndFam15 23
- #define ASR 18
- #define SRT 19
- #define DramTermDynStart 10
-@@ -115,10 +123,32 @@ typedef struct _sDCTStruct
-       u8 DctTrain;                    /* Current DCT being trained */
-       u8 CurrDct;                     /* Current DCT number (0 or 1) */
-       u8 DctCSPresent;                /* Current DCT CS mapping */
-+      int32_t WLSeedGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];    /* Write 
Levelization Seed Gross Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      int32_t WLSeedFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write 
Levelization Seed Fine Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      int32_t WLSeedPreGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write 
Levelization Seed Pre-Gross Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-       u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write Levelization 
Gross Delay */
-                                                       /* per byte Lane Per 
Logical DIMM*/
-       u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];      /* Write Levelization 
Fine Delay */
-                                                       /* per byte Lane Per 
Logical DIMM*/
-+      u8 WLGrossDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];    /* First-Pass 
Write Levelization Gross Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      u8 WLFineDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* First-Pass 
Write Levelization Fine Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      u8 WLGrossDelayPrevPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* Previous 
Pass Write Levelization Gross Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      u8 WLFineDelayPrevPass[MAX_BYTE_LANES*MAX_LDIMMS];      /* Previous 
Pass Write Levelization Fine Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      u8 WLGrossDelayFinalPass[MAX_BYTE_LANES*MAX_LDIMMS];    /* Final-Pass 
Write Levelization Gross Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      u8 WLFineDelayFinalPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* Final-Pass 
Write Levelization Fine Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      int32_t WLCriticalGrossDelayFirstPass;
-+      int32_t WLCriticalGrossDelayPrevPass;
-+      int32_t WLCriticalGrossDelayFinalPass;
-+      uint16_t WLPrevMemclkFreq;
-       u16 RegMan1Present;
-       u8 DimmPresent[MAX_TOTAL_DIMMS];/* Indicates which DIMMs are present */
-                                       /* from Total Number of DIMMs(per 
Node)*/
-@@ -132,7 +162,7 @@ typedef struct _sDCTStruct
-                                       /* per byte lane */
-       u8 MaxDimmsInstalled;           /* Max Dimms Installed for current DCT 
*/
-       u8 DimmRanks[MAX_TOTAL_DIMMS];  /* Total Number of Ranks(per Dimm) */
--      u32 LogicalCPUID;
-+      uint64_t LogicalCPUID;
-       u8 WLPass;
- } sDCTStruct;
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index c9bcac1..aa23951 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -18,6 +18,7 @@
-  */
- 
- #include <string.h>
-+#include <arch/cpu.h>
- #include <arch/acpi.h>
- #include <cpu/x86/msr.h>
- #include <device/device.h>
-@@ -32,6 +33,23 @@
- 
- #define S3NV_FILE_NAME "s3nv"
- 
-+#ifdef __RAMSTAGE__
-+static inline uint8_t is_fam15h(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      return fam15h;
-+}
-+#endif
-+
- static ssize_t get_s3nv_file_offset(void);
- 
- ssize_t get_s3nv_file_offset(void)
-@@ -47,6 +65,28 @@ ssize_t get_s3nv_file_offset(void)
-       return s3nv_region.region.offset;
- }
- 
-+static uint32_t read_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg) {
-+      if (is_fam15h()) {
-+              uint32_t dword;
-+#ifdef __PRE_RAM__
-+              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-+#else
-+              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
-+#endif
-+
-+              /* Select DCT */
-+              dword = pci_read_config32(dev_fn1, 0x10c);
-+              dword &= ~0x1;
-+              dword |= (dct & 0x1);
-+              pci_write_config32(dev_fn1, 0x10c, dword);
-+      } else {
-+              /* Apply offset */
-+              reg += dct * 0x100;
-+      }
-+
-+      return pci_read_config32(dev, reg);
-+}
-+
- static uint32_t read_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index)
- {
-       uint32_t dword;
-@@ -61,12 +101,54 @@ static uint32_t read_amd_dct_index_register(device_t dev, 
uint32_t index_ctl_reg
-       return dword;
- }
- 
-+static uint32_t read_amd_dct_index_register_dct(device_t dev, uint8_t node, 
uint8_t dct, uint32_t index_ctl_reg, uint32_t index)
-+{
-+      if (is_fam15h()) {
-+              uint32_t dword;
-+#ifdef __PRE_RAM__
-+              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-+#else
-+              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
-+#endif
-+
-+              /* Select DCT */
-+              dword = pci_read_config32(dev_fn1, 0x10c);
-+              dword &= ~0x1;
-+              dword |= (dct & 0x1);
-+              pci_write_config32(dev_fn1, 0x10c, dword);
-+      } else {
-+              /* Apply offset */
-+              index_ctl_reg += dct * 0x100;
-+      }
-+
-+      return read_amd_dct_index_register(dev, index_ctl_reg, index);
-+}
-+
- #ifdef __RAMSTAGE__
- static uint64_t rdmsr_uint64_t(unsigned long index) {
-       msr_t msr = rdmsr(index);
-       return (((uint64_t)msr.hi) << 32) | ((uint64_t)msr.lo);
- }
- 
-+static uint32_t read_config32_dct_nbpstate(device_t dev, uint8_t node, 
uint8_t dct, uint8_t nb_pstate, uint32_t reg) {
-+      uint32_t dword;
-+      device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
-+
-+      /* Select DCT */
-+      dword = pci_read_config32(dev_fn1, 0x10c);
-+      dword &= ~0x1;
-+      dword |= (dct & 0x1);
-+      pci_write_config32(dev_fn1, 0x10c, dword);
-+
-+      /* Select NB Pstate index */
-+      dword = pci_read_config32(dev_fn1, 0x10c);
-+      dword &= ~(0x3 << 4);
-+      dword |= (nb_pstate & 0x3) << 4;
-+      pci_write_config32(dev_fn1, 0x10c, dword);
-+
-+      return pci_read_config32(dev, reg);
-+}
-+
- void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
- {
-       uint8_t i;
-@@ -82,7 +164,8 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
-               device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
-               device_t dev_fn2 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 2));
-               device_t dev_fn3 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 3));
--              if ((!dev_fn1) || (!dev_fn2) || (!dev_fn3)) {
-+              /* Test for node presence */
-+              if ((!dev_fn1) || (pci_read_config32(dev_fn1, PCI_VENDOR_ID) == 
0xffffffff)) {
-                       persistent_data->node[node].node_present = 0;
-                       continue;
-               }
-@@ -95,22 +178,22 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
-                       data->f2x110 = pci_read_config32(dev_fn2, 0x110);
- 
-                       /* Stage 2 */
--                      data->f1x40 = pci_read_config32(dev_fn1, 0x40 + (0x100 
* channel));
--                      data->f1x44 = pci_read_config32(dev_fn1, 0x44 + (0x100 
* channel));
--                      data->f1x48 = pci_read_config32(dev_fn1, 0x48 + (0x100 
* channel));
--                      data->f1x4c = pci_read_config32(dev_fn1, 0x4c + (0x100 
* channel));
--                      data->f1x50 = pci_read_config32(dev_fn1, 0x50 + (0x100 
* channel));
--                      data->f1x54 = pci_read_config32(dev_fn1, 0x54 + (0x100 
* channel));
--                      data->f1x58 = pci_read_config32(dev_fn1, 0x58 + (0x100 
* channel));
--                      data->f1x5c = pci_read_config32(dev_fn1, 0x5c + (0x100 
* channel));
--                      data->f1x60 = pci_read_config32(dev_fn1, 0x60 + (0x100 
* channel));
--                      data->f1x64 = pci_read_config32(dev_fn1, 0x64 + (0x100 
* channel));
--                      data->f1x68 = pci_read_config32(dev_fn1, 0x68 + (0x100 
* channel));
--                      data->f1x6c = pci_read_config32(dev_fn1, 0x6c + (0x100 
* channel));
--                      data->f1x70 = pci_read_config32(dev_fn1, 0x70 + (0x100 
* channel));
--                      data->f1x74 = pci_read_config32(dev_fn1, 0x74 + (0x100 
* channel));
--                      data->f1x78 = pci_read_config32(dev_fn1, 0x78 + (0x100 
* channel));
--                      data->f1x7c = pci_read_config32(dev_fn1, 0x7c + (0x100 
* channel));
-+                      data->f1x40 = read_config32_dct(dev_fn1, node, channel, 
0x40);
-+                      data->f1x44 = read_config32_dct(dev_fn1, node, channel, 
0x44);
-+                      data->f1x48 = read_config32_dct(dev_fn1, node, channel, 
0x48);
-+                      data->f1x4c = read_config32_dct(dev_fn1, node, channel, 
0x4c);
-+                      data->f1x50 = read_config32_dct(dev_fn1, node, channel, 
0x50);
-+                      data->f1x54 = read_config32_dct(dev_fn1, node, channel, 
0x54);
-+                      data->f1x58 = read_config32_dct(dev_fn1, node, channel, 
0x58);
-+                      data->f1x5c = read_config32_dct(dev_fn1, node, channel, 
0x5c);
-+                      data->f1x60 = read_config32_dct(dev_fn1, node, channel, 
0x60);
-+                      data->f1x64 = read_config32_dct(dev_fn1, node, channel, 
0x64);
-+                      data->f1x68 = read_config32_dct(dev_fn1, node, channel, 
0x68);
-+                      data->f1x6c = read_config32_dct(dev_fn1, node, channel, 
0x6c);
-+                      data->f1x70 = read_config32_dct(dev_fn1, node, channel, 
0x70);
-+                      data->f1x74 = read_config32_dct(dev_fn1, node, channel, 
0x74);
-+                      data->f1x78 = read_config32_dct(dev_fn1, node, channel, 
0x78);
-+                      data->f1x7c = read_config32_dct(dev_fn1, node, channel, 
0x7c);
-                       data->f1xf0 = pci_read_config32(dev_fn1, 0xf0);
-                       data->f1x120 = pci_read_config32(dev_fn1, 0x120);
-                       data->f1x124 = pci_read_config32(dev_fn1, 0x124);
-@@ -134,75 +217,144 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
-                       data->msrc001001f = rdmsr_uint64_t(0xc001001f);
- 
-                       /* Stage 3 */
--                      data->f2x40 = pci_read_config32(dev_fn2, 0x40 + (0x100 
* channel));
--                      data->f2x44 = pci_read_config32(dev_fn2, 0x44 + (0x100 
* channel));
--                      data->f2x48 = pci_read_config32(dev_fn2, 0x48 + (0x100 
* channel));
--                      data->f2x4c = pci_read_config32(dev_fn2, 0x4c + (0x100 
* channel));
--                      data->f2x50 = pci_read_config32(dev_fn2, 0x50 + (0x100 
* channel));
--                      data->f2x54 = pci_read_config32(dev_fn2, 0x54 + (0x100 
* channel));
--                      data->f2x58 = pci_read_config32(dev_fn2, 0x58 + (0x100 
* channel));
--                      data->f2x5c = pci_read_config32(dev_fn2, 0x5c + (0x100 
* channel));
--                      data->f2x60 = pci_read_config32(dev_fn2, 0x60 + (0x100 
* channel));
--                      data->f2x64 = pci_read_config32(dev_fn2, 0x64 + (0x100 
* channel));
--                      data->f2x68 = pci_read_config32(dev_fn2, 0x68 + (0x100 
* channel));
--                      data->f2x6c = pci_read_config32(dev_fn2, 0x6c + (0x100 
* channel));
--                      data->f2x78 = pci_read_config32(dev_fn2, 0x78 + (0x100 
* channel));
--                      data->f2x7c = pci_read_config32(dev_fn2, 0x7c + (0x100 
* channel));
--                      data->f2x80 = pci_read_config32(dev_fn2, 0x80 + (0x100 
* channel));
--                      data->f2x84 = pci_read_config32(dev_fn2, 0x84 + (0x100 
* channel));
--                      data->f2x88 = pci_read_config32(dev_fn2, 0x88 + (0x100 
* channel));
--                      data->f2x8c = pci_read_config32(dev_fn2, 0x8c + (0x100 
* channel));
--                      data->f2x90 = pci_read_config32(dev_fn2, 0x90 + (0x100 
* channel));
--                      data->f2xa4 = pci_read_config32(dev_fn2, 0xa4 + (0x100 
* channel));
--                      data->f2xa8 = pci_read_config32(dev_fn2, 0xa8 + (0x100 
* channel));
-+                      data->f2x40 = read_config32_dct(dev_fn2, node, channel, 
0x40);
-+                      data->f2x44 = read_config32_dct(dev_fn2, node, channel, 
0x44);
-+                      data->f2x48 = read_config32_dct(dev_fn2, node, channel, 
0x48);
-+                      data->f2x4c = read_config32_dct(dev_fn2, node, channel, 
0x4c);
-+                      data->f2x50 = read_config32_dct(dev_fn2, node, channel, 
0x50);
-+                      data->f2x54 = read_config32_dct(dev_fn2, node, channel, 
0x54);
-+                      data->f2x58 = read_config32_dct(dev_fn2, node, channel, 
0x58);
-+                      data->f2x5c = read_config32_dct(dev_fn2, node, channel, 
0x5c);
-+                      data->f2x60 = read_config32_dct(dev_fn2, node, channel, 
0x60);
-+                      data->f2x64 = read_config32_dct(dev_fn2, node, channel, 
0x64);
-+                      data->f2x68 = read_config32_dct(dev_fn2, node, channel, 
0x68);
-+                      data->f2x6c = read_config32_dct(dev_fn2, node, channel, 
0x6c);
-+                      data->f2x78 = read_config32_dct(dev_fn2, node, channel, 
0x78);
-+                      data->f2x7c = read_config32_dct(dev_fn2, node, channel, 
0x7c);
-+                      data->f2x80 = read_config32_dct(dev_fn2, node, channel, 
0x80);
-+                      data->f2x84 = read_config32_dct(dev_fn2, node, channel, 
0x84);
-+                      data->f2x88 = read_config32_dct(dev_fn2, node, channel, 
0x88);
-+                      data->f2x8c = read_config32_dct(dev_fn2, node, channel, 
0x8c);
-+                      data->f2x90 = read_config32_dct(dev_fn2, node, channel, 
0x90);
-+                      data->f2xa4 = read_config32_dct(dev_fn2, node, channel, 
0xa4);
-+                      data->f2xa8 = read_config32_dct(dev_fn2, node, channel, 
0xa8);
-+
-+                      /* Family 15h-specific configuration */
-+                      if (is_fam15h()) {
-+                              data->f2x200 = read_config32_dct(dev_fn2, node, 
channel, 0x200);
-+                              data->f2x204 = read_config32_dct(dev_fn2, node, 
channel, 0x204);
-+                              data->f2x208 = read_config32_dct(dev_fn2, node, 
channel, 0x208);
-+                              data->f2x20c = read_config32_dct(dev_fn2, node, 
channel, 0x20c);
-+                              for (i=0; i<4; i++)
-+                                      data->f2x210[i] = 
read_config32_dct_nbpstate(dev_fn2, node, channel, i, 0x210);
-+                              data->f2x214 = read_config32_dct(dev_fn2, node, 
channel, 0x214);
-+                              data->f2x218 = read_config32_dct(dev_fn2, node, 
channel, 0x218);
-+                              data->f2x21c = read_config32_dct(dev_fn2, node, 
channel, 0x21c);
-+                              data->f2x22c = read_config32_dct(dev_fn2, node, 
channel, 0x22c);
-+                              data->f2x230 = read_config32_dct(dev_fn2, node, 
channel, 0x230);
-+                              data->f2x234 = read_config32_dct(dev_fn2, node, 
channel, 0x234);
-+                              data->f2x238 = read_config32_dct(dev_fn2, node, 
channel, 0x238);
-+                              data->f2x23c = read_config32_dct(dev_fn2, node, 
channel, 0x23c);
-+                              data->f2x240 = read_config32_dct(dev_fn2, node, 
channel, 0x240);
-+
-+                              data->f2x9cx0d0fe003 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe003);
-+                              data->f2x9cx0d0fe013 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe013);
-+                              for (i=0; i<9; i++)
-+                                      data->f2x9cx0d0f0_8_0_1f[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f001f | (i 
<< 8));
-+                              data->f2x9cx0d0f201f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f201f);
-+                              data->f2x9cx0d0f211f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f211f);
-+                              data->f2x9cx0d0f221f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f221f);
-+                              data->f2x9cx0d0f801f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f801f);
-+                              data->f2x9cx0d0f811f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f811f);
-+                              data->f2x9cx0d0f821f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f821f);
-+                              data->f2x9cx0d0fc01f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc01f);
-+                              data->f2x9cx0d0fc11f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc11f);
-+                              data->f2x9cx0d0fc21f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc21f);
-+                              data->f2x9cx0d0f4009 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f4009);
-+                              for (i=0; i<9; i++)
-+                                      data->f2x9cx0d0f0_8_0_02[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0002 | (i 
<< 8));
-+                              for (i=0; i<9; i++)
-+                                      data->f2x9cx0d0f0_8_0_06[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0006 | (i 
<< 8));
-+                              for (i=0; i<9; i++)
-+                                      data->f2x9cx0d0f0_8_0_0a[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f000a | (i 
<< 8));
-+
-+                              data->f2x9cx0d0f2002 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2002);
-+                              data->f2x9cx0d0f2102 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2102);
-+                              data->f2x9cx0d0f2202 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2202);
-+                              data->f2x9cx0d0f8002 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8002);
-+                              data->f2x9cx0d0f8006 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8006);
-+                              data->f2x9cx0d0f800a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f800a);
-+                              data->f2x9cx0d0f8102 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8102);
-+                              data->f2x9cx0d0f8106 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8106);
-+                              data->f2x9cx0d0f810a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f810a);
-+                              data->f2x9cx0d0fc002 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc002);
-+                              data->f2x9cx0d0fc006 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc006);
-+                              data->f2x9cx0d0fc00a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00a);
-+                              data->f2x9cx0d0fc00e = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00e);
-+                              data->f2x9cx0d0fc012 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc012);
-+
-+                              data->f2x9cx0d0f2031 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2031);
-+                              data->f2x9cx0d0f2131 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2131);
-+                              data->f2x9cx0d0f2231 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2231);
-+                              data->f2x9cx0d0f8031 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8031);
-+                              data->f2x9cx0d0f8131 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8131);
-+                              data->f2x9cx0d0f8231 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8231);
-+                              data->f2x9cx0d0fc031 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc031);
-+                              data->f2x9cx0d0fc131 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc131);
-+                              data->f2x9cx0d0fc231 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc231);
-+                              for (i=0; i<9; i++)
-+                                      data->f2x9cx0d0f0_0_f_31[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0031 | (i 
<< 8));
-+
-+                              data->f2x9cx0d0f8021 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8021);
-+                      }
- 
-                       /* Stage 4 */
--                      data->f2x94 = pci_read_config32(dev_fn2, 0x94 + (0x100 
* channel));
-+                      data->f2x94 = read_config32_dct(dev_fn2, node, channel, 
0x94);
- 
-                       /* Stage 6 */
-                       for (i=0; i<9; i++)
-                               for (j=0; j<3; j++)
--                                      data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
--                      data->f2x9cx00 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x00);
--                      data->f2x9cx0a = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0a);
--                      data->f2x9cx0c = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0c);
-+                                      data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i 
<< 8) | (j * 4));
-+                      data->f2x9cx00 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x00);
-+                      data->f2x9cx0a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0a);
-+                      data->f2x9cx0c = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0c);
- 
-                       /* Stage 7 */
--                      data->f2x9cx04 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x04);
-+                      data->f2x9cx04 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x04);
- 
-                       /* Stage 9 */
--                      data->f2x9cx0d0fe006 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe006);
--                      data->f2x9cx0d0fe007 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe007);
-+                      data->f2x9cx0d0fe006 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe006);
-+                      data->f2x9cx0d0fe007 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe007);
- 
-                       /* Stage 10 */
-                       for (i=0; i<12; i++)
--                              data->f2x9cx10[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x10 + i);
-+                              data->f2x9cx10[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x10 + i);
-                       for (i=0; i<12; i++)
--                              data->f2x9cx20[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x20 + i);
-+                              data->f2x9cx20[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x20 + i);
-                       for (i=0; i<4; i++)
-                               for (j=0; j<3; j++)
--                                      data->f2x9cx3_0_0_3_1[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x01 + i) + 
(0x100 * j));
-+                                      data->f2x9cx3_0_0_3_1[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x01 + i) + 
(0x100 * j));
-                       for (i=0; i<4; i++)
-                               for (j=0; j<3; j++)
--                                      data->f2x9cx3_0_0_7_5[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x05 + i) + 
(0x100 * j));
--                      data->f2x9cx0d = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0d);
-+                                      data->f2x9cx3_0_0_7_5[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x05 + i) + 
(0x100 * j));
-+                      data->f2x9cx0d = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d);
-                       for (i=0; i<9; i++)
--                              data->f2x9cx0d0f0_f_0_13[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0013 | (i 
<< 8));
-+                              data->f2x9cx0d0f0_f_0_13[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0013 | (i 
<< 8));
-                       for (i=0; i<9; i++)
--                              data->f2x9cx0d0f0_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0030 | (i 
<< 8));
-+                              data->f2x9cx0d0f0_f_0_30[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0030 | (i 
<< 8));
-                       for (i=0; i<4; i++)
--                              data->f2x9cx0d0f2_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f2030 | (i 
<< 8));
-+                              data->f2x9cx0d0f2_f_0_30[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2030 | (i 
<< 8));
-                       for (i=0; i<2; i++)
-                               for (j=0; j<3; j++)
--                                      data->f2x9cx0d0f8_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
--                      data->f2x9cx0d0f812f = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f812f);
-+                                      data->f2x9cx0d0f8_8_4_0[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i 
<< 8) | (j * 4));
-+                      data->f2x9cx0d0f812f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f812f);
- 
-                       /* Stage 11 */
-                       if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-                               for (i=0; i<12; i++)
--                                      data->f2x9cx30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x30 + i);
-+                                      data->f2x9cx30[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x30 + i);
-                               for (i=0; i<12; i++)
--                                      data->f2x9cx40[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x40 + i);
-+                                      data->f2x9cx40[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x40 + i);
-                       }
- 
-                       /* Other */
-@@ -212,6 +364,43 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
-       }
- }
- #else
-+static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg, uint32_t value) {
-+      if (is_fam15h()) {
-+              uint32_t dword;
-+              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-+
-+              /* Select DCT */
-+              dword = pci_read_config32(dev_fn1, 0x10c);
-+              dword &= ~0x1;
-+              dword |= (dct & 0x1);
-+              pci_write_config32(dev_fn1, 0x10c, dword);
-+      } else {
-+              /* Apply offset */
-+              reg += dct * 0x100;
-+      }
-+
-+      pci_write_config32(dev, reg, value);
-+}
-+
-+static void write_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t 
dct, uint8_t nb_pstate, uint32_t reg, uint32_t value) {
-+      uint32_t dword;
-+      device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-+
-+      /* Select DCT */
-+      dword = pci_read_config32(dev_fn1, 0x10c);
-+      dword &= ~0x1;
-+      dword |= (dct & 0x1);
-+      pci_write_config32(dev_fn1, 0x10c, dword);
-+
-+      /* Select NB Pstate index */
-+      dword = pci_read_config32(dev_fn1, 0x10c);
-+      dword &= ~(0x3 << 4);
-+      dword |= (nb_pstate & 0x3) << 4;
-+      pci_write_config32(dev_fn1, 0x10c, dword);
-+
-+      pci_write_config32(dev, reg, value);
-+}
-+
- static void write_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index, uint32_t value)
- {
-       uint32_t dword;
-@@ -223,6 +412,25 @@ static void write_amd_dct_index_register(device_t dev, 
uint32_t index_ctl_reg, u
-               dword = pci_read_config32(dev, index_ctl_reg);
-       } while (!(dword & (1 << 31)));
- }
-+
-+static void write_amd_dct_index_register_dct(device_t dev, uint8_t node, 
uint8_t dct, uint32_t index_ctl_reg, uint32_t index, uint32_t value)
-+{
-+      if (is_fam15h()) {
-+              uint32_t dword;
-+              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-+
-+              /* Select DCT */
-+              dword = pci_read_config32(dev_fn1, 0x10c);
-+              dword &= ~0x1;
-+              dword |= (dct & 0x1);
-+              pci_write_config32(dev_fn1, 0x10c, dword);
-+      } else {
-+              /* Apply offset */
-+              index_ctl_reg += dct * 0x100;
-+      }
-+
-+      return write_amd_dct_index_register(dev, index_ctl_reg, index, value);
-+}
- #endif
- 
- #ifdef __PRE_RAM__
-@@ -262,31 +470,31 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       if (!persistent_data->node[node].node_present)
-                               continue;
- 
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x40 + 
(0x100 * channel), data->f1x40);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x44 + 
(0x100 * channel), data->f1x44);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x48 + 
(0x100 * channel), data->f1x48);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x4c + 
(0x100 * channel), data->f1x4c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x50 + 
(0x100 * channel), data->f1x50);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x54 + 
(0x100 * channel), data->f1x54);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x58 + 
(0x100 * channel), data->f1x58);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x5c + 
(0x100 * channel), data->f1x5c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x60 + 
(0x100 * channel), data->f1x60);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x64 + 
(0x100 * channel), data->f1x64);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x68 + 
(0x100 * channel), data->f1x68);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x6c + 
(0x100 * channel), data->f1x6c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x70 + 
(0x100 * channel), data->f1x70);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x74 + 
(0x100 * channel), data->f1x74);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x78 + 
(0x100 * channel), data->f1x78);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x7c + 
(0x100 * channel), data->f1x7c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0xf0 + 
(0x100 * channel), data->f1xf0);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x120 + 
(0x100 * channel), data->f1x120);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x124 + 
(0x100 * channel), data->f1x124);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x10c + 
(0x100 * channel), data->f2x10c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x114 + 
(0x100 * channel), data->f2x114);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x118 + 
(0x100 * channel), data->f2x118);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x11c + 
(0x100 * channel), data->f2x11c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x1b0 + 
(0x100 * channel), data->f2x1b0);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x44 + 
(0x100 * channel), data->f3x44);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x40, data->f1x40);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x44, data->f1x44);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x48, data->f1x48);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x4c, data->f1x4c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x50, data->f1x50);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x54, data->f1x54);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x58, data->f1x58);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x5c, data->f1x5c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x60, data->f1x60);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x64, data->f1x64);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x68, data->f1x68);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x6c, data->f1x6c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x70, data->f1x70);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x74, data->f1x74);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x78, data->f1x78);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x7c, data->f1x7c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0xf0, data->f1xf0);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x120, data->f1x120);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x124, data->f1x124);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x10c, data->f2x10c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x114, data->f2x114);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x118, data->f2x118);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x11c, data->f2x11c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x1b0, data->f2x1b0);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 
channel, 0x44, data->f3x44);
-                       for (i=0; i<16; i++) {
-                               wrmsr_uint64_t(0x00000200 | i, 
data->msr0000020[i]);
-                       }
-@@ -313,31 +521,97 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       if (!persistent_data->node[node].node_present)
-                               continue;
- 
--                      ganged = !!(data->f2x110 & 0x10);
-+                      if (is_fam15h())
-+                              ganged = 0;
-+                      else
-+                              ganged = !!(data->f2x110 & 0x10);
-                       if ((ganged == 1) && (channel > 0))
-                               continue;
- 
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x40 + 
(0x100 * channel), data->f2x40);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x44 + 
(0x100 * channel), data->f2x44);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x48 + 
(0x100 * channel), data->f2x48);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x4c + 
(0x100 * channel), data->f2x4c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x50 + 
(0x100 * channel), data->f2x50);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x54 + 
(0x100 * channel), data->f2x54);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x58 + 
(0x100 * channel), data->f2x58);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x5c + 
(0x100 * channel), data->f2x5c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x60 + 
(0x100 * channel), data->f2x60);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x64 + 
(0x100 * channel), data->f2x64);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x68 + 
(0x100 * channel), data->f2x68);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x6c + 
(0x100 * channel), data->f2x6c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x78 + 
(0x100 * channel), data->f2x78);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x7c + 
(0x100 * channel), data->f2x7c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x80 + 
(0x100 * channel), data->f2x80);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x84 + 
(0x100 * channel), data->f2x84);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x88 + 
(0x100 * channel), data->f2x88);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x8c + 
(0x100 * channel), data->f2x8c);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), data->f2x90);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa4 + 
(0x100 * channel), data->f2xa4);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa8 + 
(0x100 * channel), data->f2xa8);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x40, data->f2x40);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x44, data->f2x44);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x48, data->f2x48);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x4c, data->f2x4c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x50, data->f2x50);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x54, data->f2x54);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x58, data->f2x58);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x5c, data->f2x5c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x60, data->f2x60);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x64, data->f2x64);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x68, data->f2x68);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x6c, data->f2x6c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x78, data->f2x78);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x7c, data->f2x7c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x80, data->f2x80);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x84, data->f2x84);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x88, data->f2x88);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x8c, data->f2x8c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x90, data->f2x90);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0xa4, data->f2xa4);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0xa8, data->f2xa8);
-+              }
-+      }
-+
-+      /* Family 15h-specific configuration */
-+      if (is_fam15h()) {
-+              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+                      for (channel = 0; channel < 2; channel++) {
-+                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
-+                              if (!persistent_data->node[node].node_present)
-+                                      continue;
-+
-+                              /* Initialize DCT */
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0000000b, 0x80000000);
-+                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe013);
-+                              dword &= ~0xffff;
-+                              dword |= 0x118;
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, dword);
-+
-+                              /* Restore values */
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x200, data->f2x200);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x204, data->f2x204);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x208, data->f2x208);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x20c, data->f2x20c);
-+                              for (i=0; i<4; i++)
-+                                      write_config32_dct_nbpstate(PCI_DEV(0, 
0x18 + node, 2), node, channel, i, 0x210, data->f2x210[i]);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x214, data->f2x214);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x218, data->f2x218);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x21c, data->f2x21c);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x22c, data->f2x22c);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x230, data->f2x230);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x234, data->f2x234);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x238, data->f2x238);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x23c, data->f2x23c);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x240, data->f2x240);
-+
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, data->f2x9cx0d0fe013);
-+                              for (i=0; i<9; i++)
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f001f | (i << 8), data->f2x9cx0d0f0_8_0_1f[i]);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f201f, data->f2x9cx0d0f201f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f211f, data->f2x9cx0d0f211f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f221f, data->f2x9cx0d0f221f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f801f, data->f2x9cx0d0f801f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f811f, data->f2x9cx0d0f811f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f821f, data->f2x9cx0d0f821f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc01f, data->f2x9cx0d0fc01f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc11f, data->f2x9cx0d0fc11f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc21f, data->f2x9cx0d0fc21f);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f4009, data->f2x9cx0d0f4009);
-+
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2031, data->f2x9cx0d0f2031);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2131, data->f2x9cx0d0f2131);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2231, data->f2x9cx0d0f2231);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8031, data->f2x9cx0d0f8031);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8131, data->f2x9cx0d0f8131);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8231, data->f2x9cx0d0f8231);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc031, data->f2x9cx0d0fc031);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc131, data->f2x9cx0d0fc131);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc231, data->f2x9cx0d0fc231);
-+                              for (i=0; i<9; i++)
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0031 | (i << 8), data->f2x9cx0d0f0_0_f_31[i]);
-+
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8021, data->f2x9cx0d0f8021);
-+                      }
-               }
-       }
- 
-@@ -348,33 +622,44 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       if (!persistent_data->node[node].node_present)
-                               continue;
- 
--                      ganged = !!(data->f2x110 & 0x10);
-+                      if (is_fam15h())
-+                              ganged = 0;
-+                      else
-+                              ganged = !!(data->f2x110 & 0x10);
-                       if ((ganged == 1) && (channel > 0))
-                               continue;
- 
--                      /* Disable PHY auto-compensation engine */
--                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
--                      if (!(dword & (1 << 30))) {
--                              dword |= (1 << 30);
--                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08, dword);
--
--                              /* Wait for 5us */
--                              mct_Wait(100);
-+                      if (is_fam15h()) {
-+                              /* Program PllLockTime = 0x190 */
-+                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe006);
-+                              dword &= ~0xffff;
-+                              dword |= 0x190;
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword);
-+
-+                              /* Program MemClkFreqVal = 0 */
-+                              dword = read_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x94);
-+                              dword &= (0x1 << 7);
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x94, dword);
-+
-+                              /* Restore DRAM Adddress/Timing Control 
Register */
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04);
-+                      } else {
-+                              /* Disable PHY auto-compensation engine */
-+                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x08);
-+                              if (!(dword & (1 << 30))) {
-+                                      dword |= (1 << 30);
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x08, dword);
-+
-+                                      /* Wait for 5us */
-+                                      mct_Wait(100);
-+                              }
-                       }
- 
-                       /* Restore DRAM Configuration High Register */
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x94 + 
(0x100 * channel), data->f2x94);
--
--                      /* Enable PHY auto-compensation engine */
--                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
--                      dword &= ~(1 << 30);
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x08, dword);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x94, data->f2x94);
-               }
-       }
- 
--      /* Wait for 750us */
--      mct_Wait(15000);
--
-       /* Stage 5 */
-       for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-               for (channel = 0; channel < 2; channel++) {
-@@ -382,17 +667,40 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       if (!persistent_data->node[node].node_present)
-                               continue;
- 
--                      ganged = !!(data->f2x110 & 0x10);
-+                      if (is_fam15h())
-+                              ganged = 0;
-+                      else
-+                              ganged = !!(data->f2x110 & 0x10);
-                       if ((ganged == 1) && (channel > 0))
-                               continue;
- 
-+                      dct_enabled = !(data->f2x94 & (1 << 14));
-+                      if (!dct_enabled)
-+                              continue;
-+
-                       /* Wait for any pending PHY frequency changes to 
complete */
-                       do {
--                              dword = read_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x08);
-+                              dword = read_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x94);
-                       } while (dword & (1 << 21));
-+
-+                      if (is_fam15h()) {
-+                              /* Program PllLockTime = 0xf */
-+                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe006);
-+                              dword &= ~0xffff;
-+                              dword |= 0xf;
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword);
-+                      } else {
-+                              /* Enable PHY auto-compensation engine */
-+                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x08);
-+                              dword &= ~(1 << 30);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x08, dword);
-+                      }
-               }
-       }
- 
-+      /* Wait for 750us */
-+      mct_Wait(15000);
-+
-       /* Stage 6 */
-       for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-               for (channel = 0; channel < 2; channel++) {
-@@ -402,10 +710,49 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
- 
-                       for (i=0; i<9; i++)
-                               for (j=0; j<3; j++)
--                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x00, data->f2x9cx00);
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0a, data->f2x9cx0a);
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0c, data->f2x9cx0c);
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
-+                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x00, data->f2x9cx00);
-+                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0a, data->f2x9cx0a);
-+                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0c, data->f2x9cx0c);
-+              }
-+      }
-+
-+      /* Family 15h-specific configuration */
-+      if (is_fam15h()) {
-+              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+                      for (channel = 0; channel < 2; channel++) {
-+                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
-+                              if (!persistent_data->node[node].node_present)
-+                                      continue;
-+
-+                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe003);
-+                              dword |= (0x3 << 13);                   /* 
DisAutoComp, DisablePredriverCal = 1 */
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, dword);
-+
-+                              for (i=0; i<9; i++)
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0006 | (i << 8), data->f2x9cx0d0f0_8_0_06[i]);
-+                              for (i=0; i<9; i++)
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f000a | (i << 8), data->f2x9cx0d0f0_8_0_0a[i]);
-+                              for (i=0; i<9; i++)
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0002 | (i << 8), (0x8000 | data->f2x9cx0d0f0_8_0_02[i]));
-+
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8006, data->f2x9cx0d0f8006);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f800a, data->f2x9cx0d0f800a);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8106, data->f2x9cx0d0f8106);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f810a, data->f2x9cx0d0f810a);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc006, data->f2x9cx0d0fc006);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc00a, data->f2x9cx0d0fc00a);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc00e, data->f2x9cx0d0fc00e);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc012, data->f2x9cx0d0fc012);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8002, (0x8000 | 
data->f2x9cx0d0f8002));
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8102, (0x8000 | 
data->f2x9cx0d0f8102));
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc002, (0x8000 | 
data->f2x9cx0d0fc002));
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2002, (0x8000 | 
data->f2x9cx0d0f2002));
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2102, (0x8000 | 
data->f2x9cx0d0f2102));
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2202, (0x8000 | 
data->f2x9cx0d0f2202));
-+
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, data->f2x9cx0d0fe003);
-+                      }
-               }
-       }
- 
-@@ -416,11 +763,15 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       if (!persistent_data->node[node].node_present)
-                               continue;
- 
--                      ganged = !!(data->f2x110 & 0x10);
-+                      if (is_fam15h())
-+                              ganged = 0;
-+                      else
-+                              ganged = !!(data->f2x110 & 0x10);
-                       if ((ganged == 1) && (channel > 0))
-                               continue;
- 
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x04, data->f2x9cx04);
-+                      if (!is_fam15h())
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04);
-               }
-       }
- 
-@@ -435,16 +786,19 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       if (!dct_enabled)
-                               continue;
- 
--                      ganged = !!(data->f2x110 & 0x10);
-+                      if (is_fam15h())
-+                              ganged = 0;
-+                      else
-+                              ganged = !!(data->f2x110 & 0x10);
-                       if ((ganged == 1) && (channel > 0))
-                               continue;
- 
-                       printk(BIOS_SPEW, "Taking DIMMs out of self refresh 
node: %d channel: %d\n", node, channel);
- 
-                       /* Exit self refresh mode */
--                      dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 
0x90 + (0x100 * channel));
-+                      dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x90);
-                       dword |= (1 << 1);
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), dword);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x90, dword);
-               }
-       }
- 
-@@ -463,12 +817,12 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
- 
-                       /* Wait for transition from self refresh mode to 
complete */
-                       do {
--                              dword = pci_read_config32(PCI_DEV(0, 0x18 + 
node, 2), 0x90 + (0x100 * channel));
-+                              dword = read_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x90);
-                       } while (dword & (1 << 1));
- 
-                       /* Restore registers */
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe006, data->f2x9cx0d0fe006);
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe007, data->f2x9cx0d0fe007);
-+                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d0fe006, data->f2x9cx0d0fe006);
-+                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d0fe007, data->f2x9cx0d0fe007);
-               }
-       }
- 
-@@ -480,26 +834,26 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                               continue;
- 
-                       for (i=0; i<12; i++)
--                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x10 + i, data->f2x9cx10[i]);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x10 + i, data->f2x9cx10[i]);
-                       for (i=0; i<12; i++)
--                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x20 + i, data->f2x9cx20[i]);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x20 + i, data->f2x9cx20[i]);
-                       for (i=0; i<4; i++)
-                               for (j=0; j<3; j++)
--                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j), 
data->f2x9cx3_0_0_3_1[i][j]);
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
-                       for (i=0; i<4; i++)
-                               for (j=0; j<3; j++)
--                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j), 
data->f2x9cx3_0_0_7_5[i][j]);
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d, data->f2x9cx0d);
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
-+                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d, data->f2x9cx0d);
-                       for (i=0; i<9; i++)
--                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8), 
data->f2x9cx0d0f0_f_0_13[i]);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f0013 | (i << 8), 
data->f2x9cx0d0f0_f_0_13[i]);
-                       for (i=0; i<9; i++)
--                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8), 
data->f2x9cx0d0f0_f_0_30[i]);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f0030 | (i << 8), 
data->f2x9cx0d0f0_f_0_30[i]);
-                       for (i=0; i<4; i++)
--                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8), 
data->f2x9cx0d0f2_f_0_30[i]);
-+                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2030 | (i << 8), 
data->f2x9cx0d0f2_f_0_30[i]);
-                       for (i=0; i<2; i++)
-                               for (j=0; j<3; j++)
--                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f8_8_4_0[i][j]);
--                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0f812f, data->f2x9cx0d0f812f);
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f8_8_4_0[i][j]);
-+                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d0f812f, data->f2x9cx0d0f812f);
-               }
-       }
- 
-@@ -512,9 +866,9 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                                       continue;
- 
-                               for (i=0; i<12; i++)
--                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x30 + i, data->f2x9cx30[i]);
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x30 + i, data->f2x9cx30[i]);
-                               for (i=0; i<12; i++)
--                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x40 + i, data->f2x9cx40[i]);
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x40 + i, data->f2x9cx40[i]);
-                       }
-               }
-       }
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti.h 
b/src/northbridge/amd/amdmct/wrappers/mcti.h
-index 38e66e1..2aba377 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti.h
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -62,10 +63,15 @@ UPDATE AS NEEDED
- #endif
- 
- #ifndef MEM_MAX_LOAD_FREQ
--#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
-- #define MEM_MAX_LOAD_FREQ            800
--#else
-- #define MEM_MAX_LOAD_FREQ            400
-+#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005    /* AMD_FAM10_DDR3 */
-+ #define MEM_MAX_LOAD_FREQ                    933
-+ #define MEM_MIN_PLATFORM_FREQ_FAM10          400
-+ #define MEM_MIN_PLATFORM_FREQ_FAM15          333
-+#else                                          /* AMD_FAM10_DDR2 */
-+ #define MEM_MAX_LOAD_FREQ                    400
-+ #define MEM_MIN_PLATFORM_FREQ_FAM10          200
-+ /* DDR2 not available on Family 15h */
-+ #define MEM_MIN_PLATFORM_FREQ_FAM15          0
- #endif
- #endif
- 
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index 47260f2..1d4eade 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -44,7 +44,7 @@
- #define MINIMUM_DRAM_BELOW_4G 0x1000000
- 
- static const uint16_t ddr2_limits[4] = {400, 333, 266, 200};
--static const uint16_t ddr3_limits[4] = {800, 666, 533, 400};
-+static const uint16_t ddr3_limits[16] = {933, 800, 666, 533, 400, 333, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0};
- 
- static u16 mctGet_NVbits(u8 index)
- {
-@@ -81,12 +81,19 @@ static u16 mctGet_NVbits(u8 index)
-               if (get_option(&nvram, "max_mem_clock") == CB_SUCCESS) {
-                       int limit = val;
-                       if (IS_ENABLED(CONFIG_DIMM_DDR3))
--                              limit = ddr3_limits[nvram & 3];
-+                              limit = ddr3_limits[nvram & 0xf];
-                       else if (IS_ENABLED(CONFIG_DIMM_DDR2))
--                              limit = ddr2_limits[nvram & 3];
-+                              limit = ddr2_limits[nvram & 0x3];
-                       val = min(limit, val);
-               }
-               break;
-+      case NV_MIN_MEMCLK:
-+              /* Minimum platform supported memclk */
-+              if (is_fam15h())
-+                      val =  MEM_MIN_PLATFORM_FREQ_FAM15;
-+              else
-+                      val =  MEM_MIN_PLATFORM_FREQ_FAM10;
-+              break;
-       case NV_ECC_CAP:
- #if SYSTEM_TYPE == SERVER
-               val = 1;        /* memory bus ECC capable */
-@@ -254,6 +261,9 @@ static u16 mctGet_NVbits(u8 index)
-       case NV_L2BKScrub:
-               val = 0;        /* Disabled - See L2Scrub in BKDG */
-               break;
-+      case NV_L3BKScrub:
-+              val = 0;        /* Disabled - See L3Scrub in BKDG */
-+              break;
-       case NV_DCBKScrub:
-               val = 0;        /* Disabled - See DcacheScrub in BKDG */
-               break;
-@@ -299,10 +309,14 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
-       pDCTstat->PresetmaxFreq = mctGet_NVbits(NV_MAX_MEMCLK);
- 
-       /* Determine the number of installed DIMMs */
-+      uint8_t dimm;
-       int ch1_count = 0;
-       int ch2_count = 0;
-       uint8_t ch1_registered = 0;
-       uint8_t ch2_registered = 0;
-+      uint8_t ch1_voltage = 0;
-+      uint8_t ch2_voltage = 0;
-+      uint8_t highest_rank_count[2];
-       int i;
-       for (i = 0; i < 15; i = i + 2) {
-               if (pDCTstat->DIMMValid & (1 << i))
-@@ -321,8 +335,26 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
-               printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 2: %d DIMM(s) 
detected\n", ch2_count);
-       }
- 
-+#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
-+      for (i = 0; i < 15; i = i + 2) {
-+              if (pDCTstat->DIMMValid & (1 << i))
-+                      ch1_voltage |= pDCTstat->DimmConfiguredVoltage[i];
-+              if (pDCTstat->DIMMValid & (1 << (i + 1)))
-+                      ch2_voltage |= pDCTstat->DimmConfiguredVoltage[i + 1];
-+      }
-+#endif
-+
-+      for (i = 0; i < 2; i++) {
-+              sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[i];
-+              highest_rank_count[i] = 0x0;
-+              for (dimm = 0; dimm < 8; dimm++) {
-+                      if (pDCTData->DimmRanks[dimm] > highest_rank_count[i])
-+                              highest_rank_count[i] = 
pDCTData->DimmRanks[dimm];
-+              }
-+      }
-+
-       /* Set limits if needed */
--      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
(ch1_registered || ch2_registered), pDCTstat->PresetmaxFreq);
-+      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
max(highest_rank_count[0], highest_rank_count[1]), (ch1_registered || 
ch2_registered), (ch1_voltage | ch2_voltage), pDCTstat->PresetmaxFreq);
- }
- 
- #ifdef UNUSED_CODE
-@@ -486,7 +518,7 @@ static void mctHookAfterAnyTraining(void)
- {
- }
- 
--static u32 mctGetLogicalCPUID_D(u8 node)
-+static uint64_t mctGetLogicalCPUID_D(u8 node)
- {
-       return mctGetLogicalCPUID(node);
- }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0033-cpu-amd-family_10h-family_15h-Use-correct-label-for-.patch
 
b/resources/libreboot/patch/kgpe-d16/0033-cpu-amd-family_10h-family_15h-Use-correct-label-for-.patch
new file mode 100644
index 0000000..91195af
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0033-cpu-amd-family_10h-family_15h-Use-correct-label-for-.patch
@@ -0,0 +1,28 @@
+From 24270e39badca612e98db97d736a6f8270f0e036 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 20 Oct 2015 01:17:34 -0500
+Subject: [PATCH 033/143] cpu/amd/family_10h-family_15h: Use correct label for
+ break state
+
+Change-Id: I07e517f239807cbe76037308f0beff80c9a6f2ba
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/fidvid.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
+index 5b1c581..86e3179 100644
+--- a/src/cpu/amd/family_10h-family_15h/fidvid.c
++++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
+@@ -860,7 +860,7 @@ static void init_fidvid_bsp_stage1(u32 ap_apicid, void *gp)
+       while (--loop > 0) {
+               if (lapic_remote_read(ap_apicid, LAPIC_MSG_REG, &readback) != 0)
+                       continue;
+-              if ((readback & 0x3f) == 1) {
++              if ((readback & 0x3f) == F10_APSTATE_RESET) {
+                       timeout = 0;
+                       break;  /* target ap is in stage 1 */
+               }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0034-cpu-amd-Add-initial-AMD-Family-15h-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0034-cpu-amd-Add-initial-AMD-Family-15h-support.patch
new file mode 100644
index 0000000..fa979fe
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0034-cpu-amd-Add-initial-AMD-Family-15h-support.patch
@@ -0,0 +1,16249 @@
+From 429c96728e6a22e1d53f801c8bd4075a91fe422b Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 16 Oct 2015 13:51:51 -0500
+Subject: [PATCH 034/143] cpu/amd: Add initial AMD Family 15h support
+
+TEST: Booted ASUS KGPE-D16 with single Opteron 6380
+ * Unbuffered DDR3 DIMMs tested and working
+ * Suspend to RAM (S3) tested and working
+
+Conflicts:
+
+       src/cpu/amd/car/disable_cache_as_ram.c
+
+Change-Id: Idffd2ce36ce183fbfa087e5ba69a9148f084b45e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/car/cache_as_ram.inc                   |  130 +-
+ src/cpu/amd/car/disable_cache_as_ram.c             |   79 +-
+ src/cpu/amd/family_10h-family_15h/defaults.h       |  266 +-
+ src/cpu/amd/family_10h-family_15h/fidvid.c         |  237 +-
+ src/cpu/amd/family_10h-family_15h/init_cpus.c      |  232 +-
+ .../amd/family_10h-family_15h/model_10xxx_init.c   |   92 +-
+ src/cpu/amd/family_10h-family_15h/powernow_acpi.c  |   50 +-
+ src/cpu/amd/family_10h-family_15h/processor_name.c |  194 +-
+ .../amd/family_10h-family_15h/update_microcode.c   |    6 +
+ src/cpu/amd/model_fxx/init_cpus.c                  |    2 +-
+ src/cpu/amd/quadcore/quadcore.c                    |  109 +-
+ src/cpu/amd/quadcore/quadcore_id.c                 |   43 +-
+ src/include/cpu/amd/model_10xxx_msr.h              |    7 +
+ src/mainboard/advansus/a785e-i/romstage.c          |    2 +-
+ src/mainboard/amd/bimini_fam10/romstage.c          |    2 +-
+ src/mainboard/amd/mahogany_fam10/romstage.c        |    2 +-
+ .../amd/serengeti_cheetah_fam10/romstage.c         |    2 +-
+ src/mainboard/amd/tilapia_fam10/romstage.c         |    2 +-
+ src/mainboard/asus/kfsn4-dre/romstage.c            |    2 +-
+ src/mainboard/asus/kgpe-d16/romstage.c             |    4 +-
+ src/mainboard/asus/m4a78-em/romstage.c             |    2 +-
+ src/mainboard/asus/m4a785-m/romstage.c             |    2 +-
+ src/mainboard/asus/m5a88-v/romstage.c              |    2 +-
+ src/mainboard/avalue/eax-785e/romstage.c           |    2 +-
+ src/mainboard/gigabyte/ma785gm/romstage.c          |    2 +-
+ src/mainboard/gigabyte/ma785gmt/romstage.c         |    2 +-
+ src/mainboard/gigabyte/ma78gm/romstage.c           |    2 +-
+ src/mainboard/hp/dl165_g6_fam10/romstage.c         |    2 +-
+ src/mainboard/iei/kino-780am2-fam10/romstage.c     |    2 +-
+ src/mainboard/jetway/pa78vm5/romstage.c            |    2 +-
+ src/mainboard/msi/ms9652_fam10/romstage.c          |    2 +-
+ src/mainboard/supermicro/h8dmr_fam10/romstage.c    |    2 +-
+ src/mainboard/supermicro/h8qme_fam10/romstage.c    |    2 +-
+ src/mainboard/supermicro/h8scm_fam10/romstage.c    |    2 +-
+ src/mainboard/tyan/s2912_fam10/romstage.c          |    2 +-
+ src/northbridge/amd/amdfam10/Kconfig               |    2 +-
+ src/northbridge/amd/amdfam10/Makefile.inc          |    2 +
+ src/northbridge/amd/amdfam10/amdfam10.h            |    6 +-
+ src/northbridge/amd/amdfam10/amdfam10_util.c       |   13 +-
+ src/northbridge/amd/amdfam10/link_control.c        |   86 +
+ src/northbridge/amd/amdfam10/misc_control.c        |    7 +
+ src/northbridge/amd/amdfam10/nb_control.c          |   85 +
+ src/northbridge/amd/amdfam10/northbridge.c         |  233 +-
+ src/northbridge/amd/amdfam10/raminit_amdmct.c      |  304 +-
+ src/northbridge/amd/amdht/h3ncmn.c                 |  171 +-
+ src/northbridge/amd/amdht/ht_wrapper.c             |   43 +-
+ src/northbridge/amd/amdmct/amddefs.h               |   78 +-
+ src/northbridge/amd/amdmct/mct/mct_d.c             |    4 +-
+ src/northbridge/amd/amdmct/mct/mct_d.h             |   20 +-
+ src/northbridge/amd/amdmct/mct/mctpro_d.c          |   21 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c        | 3187 ++++++++++++++++----
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h        |  124 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h    |    9 +
+ src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c     |   21 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c     |   27 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c     | 1087 ++++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c     |   55 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c       |    7 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c       |  105 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctproc.c      |    2 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctrci.c       |   24 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c       |  585 +++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c       | 1342 ++++++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c     |   10 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c      |   20 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctwl.c        |  255 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c      | 1007 +++++--
+ src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c     |   69 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h       |   46 +-
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c      |  652 +++-
+ src/northbridge/amd/amdmct/wrappers/mcti.h         |   14 +-
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c       |   43 +-
+ 72 files changed, 9192 insertions(+), 2067 deletions(-)
+ create mode 100644 src/northbridge/amd/amdfam10/link_control.c
+ create mode 100644 src/northbridge/amd/amdfam10/nb_control.c
+
+diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
+index 0b2bc60..6542906 100644
+--- a/src/cpu/amd/car/cache_as_ram.inc
++++ b/src/cpu/amd/car/cache_as_ram.inc
+@@ -32,18 +32,23 @@
+ #define CacheSizeAPStack      CONFIG_DCACHE_AP_STACK_SIZE
+ 
+ #define MSR_MCFG_BASE         0xC0010058
+-#define MSR_FAM10             0xC001102A
++#define MSR_BU_CFG2           0xC001102A
+ 
+ #define jmp_if_k8(x)          comisd  %xmm2, %xmm1; jb x
++#define jmp_if_not_fam15h(x)  comisd  %xmm3, %xmm1; jb x
++#define jmp_if_fam15h(x)      comisd  %xmm3, %xmm1; jae x
+ 
+ #define CPUID_MASK            0x0ff00f00
+ #define CPUID_VAL_FAM10_ROTATED       0x0f000010
++#define CPUID_VAL_FAM15_ROTATED       0x0f000060
+ 
+ /*
+  * XMM map:
+  *   xmm1: CPU family
+  *   xmm2: Fam10h comparison value
+- *   xmm3: Backup EBX
++ *   xmm3: Fam15h comparison value
++ *   xmm4: Backup EBX
++ *   xmm5: Coreboot init detect
+  */
+ 
+       /* Save the BIST result. */
+@@ -63,7 +68,7 @@ cache_as_ram_setup:
+       movl    %eax, %cr4
+ 
+       /* Figure out the CPU family. */
+-      cvtsi2sd %ebx, %xmm3
++      cvtsi2sd %ebx, %xmm4
+       movl    $0x01, %eax
+       cpuid
+       /* Base family is bits 8..11, extended family is bits 20..27. */
+@@ -73,13 +78,16 @@ cache_as_ram_setup:
+       cvtsi2sd %eax, %xmm1
+       movl    $CPUID_VAL_FAM10_ROTATED, %eax
+       cvtsi2sd %eax, %xmm2
+-      cvtsd2si %xmm3, %ebx
++      movl    $CPUID_VAL_FAM15_ROTATED, %eax
++      cvtsi2sd %eax, %xmm3
++      cvtsd2si %xmm4, %ebx
+ 
+       /* Check if cpu_init_detected. */
+       movl    $MTRR_DEF_TYPE_MSR, %ecx
+       rdmsr
+       andl    $MTRR_DEF_TYPE_EN, %eax
+       movl    %eax, %ebx      /* We store the status. */
++      cvtsi2sd %ebx, %xmm5
+ 
+       jmp_if_k8(CAR_FAM10_out_post_errata)
+ 
+@@ -120,21 +128,24 @@ cache_as_ram_setup:
+ 
+ CAR_FAM10_out:
+ 
++      jmp_if_fam15h(CAR_FAM10_errata_applied)
+       /*
+        * Errata 193: Disable clean copybacks to L3 cache to allow cached ROM.
+        * Re-enable it in after RAM is initialized and before CAR is disabled.
+        */
+-      movl    $MSR_FAM10, %ecx
++      movl    $MSR_BU_CFG2, %ecx
+       rdmsr
+-      bts     $15, %eax
++      bts     $15, %eax       /* Set bit 15 in EDX:EAX (bit 15 in EAX). */
+       wrmsr
+ 
+       /* Erratum 343, RevGuide for Fam10h, Pub#41322 Rev. 3.33 */
+-      movl    $MSR_FAM10, %ecx
++      movl    $MSR_BU_CFG2, %ecx
+       rdmsr
+       bts     $35-32, %edx    /* Set bit 35 in EDX:EAX (bit 3 in EDX). */
+       wrmsr
+ 
++CAR_FAM10_errata_applied:
++
+ #if CONFIG_MMCONF_SUPPORT
+    #if (CONFIG_MMCONF_BASE_ADDRESS > 0xFFFFFFFF)
+    #error "MMCONF_BASE_ADDRESS too big"
+@@ -169,6 +180,63 @@ CAR_FAM10_out:
+ 
+ CAR_FAM10_out_post_errata:
+ 
++      /* Fam15h APIC IDs do not depend on NB config bit 54 */
++      jmp_if_not_fam15h(skip_nb54_set)
++      movl    $0xc001001f, %ecx       /* NB_CFG_MSR */
++      rdmsr
++      bts     $(54 - 32), %edx        /* Set NB config bit 54 */
++      wrmsr
++
++skip_nb54_set:
++      /* On Fam15h CPUs each compute unit's MTRRs are shared between two 
cores */
++      jmp_if_not_fam15h(skip_cu_check)
++
++      /* Get the initial APIC ID. */
++      movl    $1, %eax
++      cpuid
++      movl    %ebx, %eax
++
++      /* Restore init detect */
++      cvtsd2si %xmm5, %ebx
++
++      /* Determine if this is the second core to start in a compute unit; if 
so, wait for first core start, clear init detect and skip MTRR init */
++      bt      $24, %eax
++      jnc     skip_cu_check           /* First core in the compute unit jumps 
to skip_cu_check */
++
++      /* Determine if this is the second core to start in a compute unit; if 
so, clear init detect and skip MTRR init */
++      /* Busywait until the first core sets up the MTRRs */
++check_init_detect_1:
++      /* Check if cpu_init_detected. */
++      movl    $MTRR_DEF_TYPE_MSR, %ecx
++      rdmsr
++      andl    $MTRR_DEF_TYPE_EN, %eax
++      cmp     $0x00000000, %eax
++      je      check_init_detect_1     /* First core has not yet started */
++
++check_init_detect_2:
++      movl    $SYSCFG_MSR, %ecx
++      rdmsr
++      andl    $(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrVarDramEn), %eax
++      cmp     $0x00000000, %eax
++      je      check_init_detect_2     /* First core has not yet started */
++
++      /* First core has now started */
++      movl    $0x00000000, %ebx       /* Clear init detect flag */
++      cvtsi2sd %ebx, %xmm5
++      jmp     fam10_mtrr_setup_complete
++
++skip_cu_check:
++
++      jmp_if_not_fam15h(CAR_FAM15_errata_applied)
++
++      /* Erratum 714, RevGuide for Fam15h, Pub#48063 Rev. 3.24 */
++      movl    $MSR_BU_CFG2, %ecx
++      rdmsr
++      bts     $8, %eax        /* Set bit 8 in EDX:EAX (bit 8 in EAX). */
++      wrmsr
++
++CAR_FAM15_errata_applied:
++
+       /* Set MtrrFixDramModEn for clear fixed MTRR. */
+ enable_fixed_mtrr_dram_modify:
+       movl    $SYSCFG_MSR, %ecx
+@@ -337,8 +405,42 @@ wbcache_post_fam10_setup:
+       orl     $(SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn), %eax
+       wrmsr
+ 
++fam10_mtrr_setup_complete:
+       post_code(0xa1)
+ 
++      /* Disable conversion of INVD to WBINVD (INVDWBINVD = 0) */
++      mov     $0xc0010015, %ecx
++      rdmsr
++      btr     $4, %eax
++      wrmsr
++
++jmp_if_not_fam15h(fam15_car_msr_setup_complete)
++      /* Disable streaming store (DisSS = 1) */
++      mov     $0xc0011020, %ecx
++      rdmsr
++      bts     $28, %eax
++      wrmsr
++
++      /* Disable speculative ITLB reloads (DisSpecTlbRld = 1) */
++      mov     $0xc0011021, %ecx
++      rdmsr
++      bts     $9, %eax
++      wrmsr
++
++      /* Disable speculative DTLB reloads (DisSpecTlbRld = 1) and set DisHwPf 
= 1 */
++      mov     $0xc0011022, %ecx
++      rdmsr
++      bts     $4, %eax
++      bts     $13, %eax
++      wrmsr
++
++      /* Disable CR0 combining (CombineCr0Cd = 0) */
++      mov     $0xc001102b, %ecx
++      rdmsr
++      btr     $49-32, %edx
++      wrmsr
++fam15_car_msr_setup_complete:
++
+       /* Enable cache. */
+       movl    %cr0, %eax
+       andl    $(~(CR0_CacheDisable | CR0_NoWriteThrough)), %eax
+@@ -393,9 +495,6 @@ CAR_FAM10_ap:
+        * to reverse it.
+        */
+ 
+-      /* Store our init detected. */
+-      movl    %ebx, %esi
+-
+       /* Get the coreid bits at first. */
+       movl    $0x80000008, %eax
+       cpuid
+@@ -414,6 +513,8 @@ CAR_FAM10_ap:
+       movl    %edi, %ecx              /* CoreID bits */
+       bt      $(54 - 32), %edx
+       jc      roll_cfg
++
++      /* Fam10h NB config bit 54 was not set */
+       rolb    %cl, %bl
+ roll_cfg:
+ 
+@@ -423,8 +524,8 @@ roll_cfg:
+       movl    $(CacheBase + (CacheSize - (CacheSizeBSPStack + 
CacheSizeBSPSlush))), %esp
+       subl    %eax, %esp
+ 
+-      /* Retrive init detected. */
+-      movl    %esi, %ebx
++      /* Restore init detect */
++      cvtsd2si %xmm5, %ebx
+ 
+       post_code(0xa4)
+ 
+@@ -437,6 +538,8 @@ CAR_FAM10_ap_out:
+       andl    $~(3 << 9), %eax
+       movl    %eax, %cr4
+ 
++      post_code(0xa6)
++
+       /* Restore the BIST result. */
+       movl    %ebp, %eax
+ 
+@@ -444,6 +547,9 @@ CAR_FAM10_ap_out:
+       movl    %esp, %ebp
+       pushl   %ebx            /* Init detected. */
+       pushl   %eax            /* BIST */
++
++      post_code(0xa7)
++
+       call    cache_as_ram_main
+ 
+       /* We will not go back. */
+diff --git a/src/cpu/amd/car/disable_cache_as_ram.c 
b/src/cpu/amd/car/disable_cache_as_ram.c
+index 5eccf79..86180ee 100644
+--- a/src/cpu/amd/car/disable_cache_as_ram.c
++++ b/src/cpu/amd/car/disable_cache_as_ram.c
+@@ -19,7 +19,7 @@
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc.
+  *
+- * be warned, this file will be used other cores and core 0 / node 0
++ * WARNING: this file will be used by both any AP cores and core 0 / node 0
+  */
+ 
+ #include <cpu/x86/cache.h>
+@@ -34,41 +34,80 @@ static inline __attribute__((always_inline)) uint32_t 
amd_fam1x_cpu_family(void)
+       return family;
+ }
+ 
+-static inline __attribute__((always_inline)) void disable_cache_as_ram(void)
++static inline __attribute__((always_inline)) void 
disable_cache_as_ram(uint8_t skip_sharedc_config)
+ {
+       msr_t msr;
++      uint32_t family;
+ 
+-      /* disable cache */
+-      write_cr0(read_cr0() | CR0_CacheDisable);
++      if (!skip_sharedc_config) {
++              /* disable cache */
++              write_cr0(read_cr0() | CR0_CacheDisable);
+ 
+-      msr.lo = 0;
+-      msr.hi = 0;
+-      wrmsr(MTRR_FIX_4K_C8000, msr);
++              msr.lo = 0;
++              msr.hi = 0;
++              wrmsr(MTRR_FIX_4K_C8000, msr);
+ #if CONFIG_DCACHE_RAM_SIZE > 0x8000
+-      wrmsr(MTRR_FIX_4K_C0000, msr);
++              wrmsr(MTRR_FIX_4K_C0000, msr);
+ #endif
+ #if CONFIG_DCACHE_RAM_SIZE > 0x10000
+-      wrmsr(MTRR_FIX_4K_D0000, msr);
++              wrmsr(MTRR_FIX_4K_D0000, msr);
+ #endif
+ #if CONFIG_DCACHE_RAM_SIZE > 0x18000
+-      wrmsr(MTRR_FIX_4K_D8000, msr);
++              wrmsr(MTRR_FIX_4K_D8000, msr);
+ #endif
+-      /* disable fixed mtrr from now on, it will be enabled by ramstage 
again*/
++              /* disable fixed mtrr from now on, it will be enabled by 
ramstage again */
++              msr = rdmsr(SYSCFG_MSR);
++              msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | 
SYSCFG_MSR_MtrrFixDramModEn);
++              wrmsr(SYSCFG_MSR, msr);
++
++              /* Set the default memory type and disable fixed and enable 
variable MTRRs */
++              msr.hi = 0;
++              msr.lo = (1 << 11);
++
++              wrmsr(MTRR_DEF_TYPE_MSR, msr);
++
++              enable_cache();
++      }
+ 
+-      msr = rdmsr(SYSCFG_MSR);
+-      msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrFixDramModEn);
+-      wrmsr(SYSCFG_MSR, msr);
++      /* INVDWBINVD = 1 */
++      msr = rdmsr(0xc0010015);
++      msr.lo |= (0x1 << 4);
++      wrmsr(0xc0010015, msr);
+ 
+-      /* Set the default memory type and disable fixed and enable variable 
MTRRs */
+-      msr.hi = 0;
+-      msr.lo = (1 << 11);
++      family = amd_fam1x_cpu_family();
+ 
+-      wrmsr(MTRR_DEF_TYPE_MSR, msr);
++#if IS_ENABLED(CPU_AMD_MODEL_10XXX)
++      if (family >= 0x6f) {
++              /* Family 15h or later */
+ 
+-      enable_cache();
++              /* DisSS = 0 */
++              msr = rdmsr(0xc0011020);
++              msr.lo &= ~(0x1 << 28);
++              wrmsr(0xc0011020, msr);
++
++              if (!skip_sharedc_config) {
++                      /* DisSpecTlbRld = 0 */
++                      msr = rdmsr(0xc0011021);
++                      msr.lo &= ~(0x1 << 9);
++                      wrmsr(0xc0011021, msr);
++
++                      /* Erratum 714: SpecNbReqDis = 0 */
++                      msr = rdmsr(BU_CFG2_MSR);
++                      msr.lo &= ~(0x1 << 8);
++                      wrmsr(BU_CFG2_MSR, msr);
++              }
++
++              /* DisSpecTlbRld = 0 */
++              /* DisHwPf = 0 */
++              msr = rdmsr(0xc0011022);
++              msr.lo &= ~(0x1 << 4);
++              msr.lo &= ~(0x1 << 13);
++              wrmsr(0xc0011022, msr);
++      }
++#endif
+ }
+ 
+ static void disable_cache_as_ram_bsp(void)
+ {
+-      disable_cache_as_ram();
++      disable_cache_as_ram(0);
+ }
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index 6fd1a7e..24f87ba 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2008 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -25,41 +26,65 @@
+  */
+ static const struct {
+       u32 msr;
+-      u32 revision;
++      uint64_t revision;
+       u32 platform;
+       u32 data_lo;
+       u32 data_hi;
+       u32 mask_lo;
+       u32 mask_hi;
+ } fam10_msr_default[] = {
+-      { TOP_MEM2, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { TOP_MEM2, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00000000, 0x00000000,
+         0xFFFFFFFF, 0xFFFFFFFF },
+ 
+-      { SYSCFG, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { SYSCFG, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         3 << 21, 0x00000000,
+         3 << 21, 0x00000000 },        /* [MtrrTom2En]=1,[TOM2EnWB] = 1*/
+ 
+-      { HWCR, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        1 << 4, 0x00000000,
+-        1 << 4, 0x00000000 },         /* [INVD_WBINVD]=1 */
++      { MC1_CTL_MASK, AMD_OR_B2, AMD_PTYPE_ALL,
++        1 << 18, 0x00000000,
++        1 << 18, 0x00000000 },        /* Erratum 586: [DEIBP]=1 */
+ 
+-      { MC4_CTL_MASK, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { MC1_CTL_MASK, AMD_OR_B2, AMD_PTYPE_ALL,
++        1 << 15, 0x00000000,
++        1 << 15, 0x00000000 },        /* Erratum 593: [BSRP]=1 */
++
++      { MC1_CTL_MASK, AMD_OR_C0, AMD_PTYPE_ALL,
++        1 << 15, 0x00000000,
++        1 << 15, 0x00000000 },        /* Erratum 739: [BSRP]=1 */
++
++      { 0xc0011000, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        1 << 16, 0x00000000,
++        1 << 16, 0x00000000 },        /* Erratum 608: [bit 16]=1 */
++
++      { 0xc0011000, AMD_OR_C0, AMD_PTYPE_ALL,
++        1 << 15, 0x00000000,
++        1 << 15, 0x00000000 },        /* Erratum 727: [bit 15]=1 */
++
++      { MC4_CTL_MASK, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0xF << 19, 0x00000000,
+         0xF << 19, 0x00000000 },      /* [RtryHt[0..3]]=1 */
+ 
++      { MC4_CTL_MASK, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++        1 << 10, 0x00000000,
++        1 << 10, 0x00000000 },        /* [GartTblWkEn]=1 */
++
+       { DC_CFG, AMD_FAM10_ALL, AMD_PTYPE_SVR,
+         0x00000000, 0x00000004,
+-        0x00000000, 0x0000000C },     /* [REQ_CTR] = 1 for Server */
++        0x00000000, 0x0000000C },     /* Family 10h: [REQ_CTR] = 1 for Server 
*/
+ 
+       { DC_CFG, AMD_DR_Bx, AMD_PTYPE_SVR,
+         0x00000000, 0x00000000,
+         0x00000000, 0x00000C00 },     /* Erratum 326 */
+ 
+-      { NB_CFG, AMD_FAM10_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC,
++      { NB_CFG, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC | AMD_PTYPE_MC,
+         0x00000000, 1 << 22,
+         0x00000000, 1 << 22 },        /* [ApicInitIDLo]=1 */
+ 
++      { NB_CFG, AMD_FAM15_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC,
++        1 << 23, 0x00000000,
++        1 << 23, 0x00000000 },        /* Erratum 663: [bit 23]=1 */
++
+       { BU_CFG2, AMD_DR_Bx, AMD_PTYPE_ALL,
+         1 << 29, 0x00000000,
+         1 << 29, 0x00000000 },        /* For Bx Smash1GPages=1 */
+@@ -72,6 +97,14 @@ static const struct {
+         0 << 1, 0x00000000,
+         1 << 1, 0x00000000 },         /* IDX_MATCH_ALL=0 */
+ 
++      { IC_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
++        0x00000000, 1 << (39-32),
++        0x00000000, 1 << (39-32)},    /* C0 or above [DisLoopPredictor]=1 */
++
++      { IC_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
++        0xf << 1, 0x00000000,
++        0xf << 1, 0x00000000},        /* C0 or above [DisIcWayFilter]=0xf */
++
+       { BU_CFG, AMD_DR_LT_B3, AMD_PTYPE_ALL,
+         1 << 21, 0x00000000,
+         1 << 21, 0x00000000 },        /* Erratum #254 DR B1 BU_CFG[21]=1 */
+@@ -80,19 +113,51 @@ static const struct {
+         1 << 23, 0x00000000,
+         1 << 23, 0x00000000 },        /* Erratum #309 BU_CFG[23]=1 */
+ 
++      { BU_CFG, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0 << 10, 0x00000000,
++        1 << 10, 0x00000000 },        /* [DcacheAgressivePriority]=0 */
++
+       /* CPUID_EXT_FEATURES */
+-      { CPUIDFEATURES, AMD_FAM10_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC,
++      { CPUIDFEATURES, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC | 
AMD_PTYPE_MC,
+         1 << 28, 0x00000000,
+         1 << 28, 0x00000000 },        /* [HyperThreadFeatEn]=1 */
+ 
+-      { CPUIDFEATURES, AMD_FAM10_ALL, AMD_PTYPE_DC,
++      { CPUIDFEATURES, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC,
+         0x00000000, 1 << (33-32),
+         0x00000000, 1 << (33-32) },   /* [ExtendedFeatEn]=1 */
+ 
++      { DE_CFG, AMD_OR_B2, AMD_PTYPE_ALL,
++        1 << 10, 0x00000000,
++        1 << 10, 0x00000000 },        /* Bx [ResyncPredSingleDispDis]=1 */
++
+       { BU_CFG2, AMD_DRBH_Cx, AMD_PTYPE_ALL,
+         0x00000000, 1 << (35-32),
+         0x00000000, 1 << (35-32) },   /* Erratum 343 (set to 0 after CAR, in 
post_cache_as_ram()/model_10xxx_init() )  */
+ 
++      { BU_CFG3, AMD_OR_B2, AMD_PTYPE_ALL,
++        0x00000000, 1 << (42-32),
++        0x00000000, 1 << (42-32)},    /* Bx [PwcDisableWalkerSharing]=1 */
++
++      { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL,
++        1 << 22, 0x00000000,
++        1 << 22, 0x00000000},         /* C0 or above [PfcDoubleStride]=1 */
++
++      { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
++        0x00000000, 1 << (54-32),
++        0x00000000, 1 << (54-32)},    /* C0 or above [LateSbzResync]=1 */
++
++      { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL,
++        1 << 23, 0x00000000,
++        1 << 23, 0x00000000},         /* C0 or above [DisScbThreshold]=1 */
++
++      { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL,
++        1 << 14, 0x00000000,
++        1 << 14, 0x00000000},         /* C0 or above 
[ForceSmcCheckFlowStDis]=1 */
++
++      { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL,
++        1 << 12, 0x00000000,
++        1 << 12, 0x00000000},         /* C0 or above [ForceBusLockDis]=1 */
++
+       { OSVW_ID_Length, AMD_DR_Bx | AMD_DR_Cx | AMD_DR_Dx, AMD_PTYPE_ALL,
+         0x00000004, 0x00000000,
+         0x00000004, 0x00000000},      /* B0 or Above, OSVW_ID_Length is 0004h 
*/
+@@ -105,9 +170,45 @@ static const struct {
+         0x00000000, 1 << (50-32),
+         0x00000000, 1 << (50-32)},    /* D0 or Above, RdMmExtCfgQwEn*/
+ 
++      { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x0 << (36-32),
++        0x00000000, 0x3 << (36-32)},  /* [ThrottleNbInterface]=0 */
++
++      { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        1 << 10, 0x00000000,
++        1 << 10, 0x00000000},         /* [VicResyncChkEn]=1 */
++
++      { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        1 << 11, 0x00000000,
++        1 << 11, 0x00000000},         /* Erratum 503: [bit 11]=1 */
++
+       { CPU_ID_EXT_FEATURES_MSR, AMD_DR_Dx, AMD_PTYPE_ALL,
+         0x00000000, 1 << (51 - 32),
+         0x00000000, 1 << (51 - 32)},  /* G34_PKG | C32_PKG | S1G4_PKG | 
ASB2_PKG */
++
++      { CPU_ID_EXT_FEATURES_MSR, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 1 << (56 - 32),
++        0x00000000, 1 << (56 - 32)},  /* [PerfCtrExtNB]=1 */
++
++      { CPU_ID_EXT_FEATURES_MSR, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 1 << (55 - 32),
++        0x00000000, 1 << (55 - 32)},  /* [PerfCtrExtCore]=1 */
++
++      { IBS_OP_DATA3, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0 << 16, 0x00000000,
++        1 << 16, 0x00000000},         /* [IbsDcMabHit]=0 */
++
++      { MC4_MISC0, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x1 << (52-32),
++        0x00000000, 0xf << (52-32)},  /* [LvtOffset]=1 */
++
++      { MC4_MISC1, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x1 << (52-32),
++        0x00000000, 0xf << (52-32)},  /* [LvtOffset]=1 */
++
++      { MC4_MISC2, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x1 << (52-32),
++        0x00000000, 0xf << (52-32)},  /* [LvtOffset]=1 */
+ };
+ 
+ 
+@@ -117,37 +218,46 @@ static const struct {
+ static const struct {
+       u8  function;
+       u16 offset;
+-      u32 revision;
++      uint64_t revision;
+       u32 platform;
+       u32 data;
+       u32 mask;
+ } fam10_pci_default[] = {
+ 
+       /* Function 0 - HT Config */
++      { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++        0x000e0000, 0x000e0000 },             /* [19:17] for 8bit APIC config 
*/
++
++      { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++        0x00400000, 0x00600000 },             /* [22:21] DsNpReqLmt = 10b */
+ 
+-      { 0, 0x68, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        0x004E4800, 0x006E6800 },     /* [19:17] for 8bit APIC config,
+-        [14:13] BufPriRel = 2h [11] RspPassPW set,
+-        [22:21] DsNpReqLmt = 10b */
++      { 0, 0x68, AMD_FAM10_LT_D, AMD_PTYPE_ALL,
++        0x00004000, 0x00006000 },             /* [14:13] BufRelPri = 2h */
++
++      { 0, 0x68, (AMD_FAM10_REV_D | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++        0x00002000, 0x00006000 },             /* [14:13] BufRelPri = 1h */
++
++      { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++        0x00000800, 0x00000800 },             /* [11] RspPassPW = 1 */
+ 
+       /* Errata 281 Workaround */
+       { 0, 0x68, (AMD_DR_B0 | AMD_DR_B1),
+         AMD_PTYPE_SVR, 0x00200000, 0x00600000 },      /* [22:21] DsNpReqLmt0 
= 01b */
+ 
+-      { 0, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 0, 0x84, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
+-      { 0, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 0, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
+-      { 0, 0xC4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 0, 0xC4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
+-      { 0, 0xE4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 0, 0xE4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
+       /* Link Global Retry Control Register */
+-      { 0, 0x150, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 0, 0x150, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00073900, 0x00073F00 },
+ 
+       /*  Errata 351
+@@ -172,13 +282,39 @@ static const struct {
+         0x00000000, 0x00000100 },
+       { 0, 0x18C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00000000, 0x00000100 },
+-      { 0, 0x170, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        0x00000000, 0x00000100 },
+ 
+       /* Link Global Extended Control Register */
+       { 0, 0x16C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00000014, 0x0000003F },     /* [15:13] ForceFullT0 = 0b,
+-                                                               * Set T0Time 
14h per BKDG */
++                                       * Set T0Time 14h per BKDG */
++
++      { 0, 0x170, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++      { 0, 0x174, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++      { 0, 0x178, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++      { 0, 0x17C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++      { 0, 0x180, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++      { 0, 0x184, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++      { 0, 0x188, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++      { 0, 0x18C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000100, 0x00000100 },
++
++      /* Link Global Extended Control Register */
++      { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000014, 0x0000003F },     /* [15:13] ForceFullT0 = 111b,
++                                       * Set T0Time 26h per BKDG */
++
++      { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x7 << 13, 0x7 << 13 },       /* [15:13] ForceFullT0 = 7h */
++
++      { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x26, 0x3f }, /* [5:0] T0Time = 26h */
+ 
+ 
+       /* Function 1 - Map Init */
+@@ -205,10 +341,10 @@ static const struct {
+       /* Function 2 - DRAM Controller */
+ 
+       /* Function 3 - Misc. Control */
+-      { 3, 0x40, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0x40, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00000100, 0x00000100 },     /* [8] MstrAbrtEn */
+ 
+-      { 3, 0x44, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0x44, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x4A30005C, 0x4A30005C },     /* [30] SyncOnDramAdrParErrEn = 1,
+                                          [27] NbMcaToMstCpuEn = 1,
+                                          [25] DisPciCfgCpuErrRsp = 1,
+@@ -220,8 +356,12 @@ static const struct {
+                                          [2] SyncOnUcEccEn = 1 */
+ 
+       /* XBAR buffer settings */
+-      { 3, 0x6C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        0x00018052, 0x700780F7 },
++      { 3, 0x6c, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++        0x00018052, 0x700780f7 },
++
++      /* XBAR buffer settings */
++      { 3, 0x6c, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x10010052, 0x700700f7 },
+ 
+       /* Errata 281 Workaround */
+       { 3, 0x6C, ( AMD_DR_B0 | AMD_DR_B1),
+@@ -233,12 +373,18 @@ static const struct {
+       { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00041153, 0x777777F7 },
+ 
++      { 3, 0x70, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x10171155, 0x777777f7 },
++
+       { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x61221151, 0x777777F7 },
+ 
+       { 3, 0x74, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x00080101, 0x000F7777 },
+ 
++      { 3, 0x74, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00172111, 0x77ff7777 },
++
+       { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00090914, 0x707FFF1F },
+ 
+@@ -246,12 +392,18 @@ static const struct {
+       { 3, 0x7C, ( AMD_DR_B0 | AMD_DR_B1),
+        AMD_PTYPE_SVR, 0x00144514, 0x707FFF1F },
+ 
++      { 3, 0x7C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x040d0f16, 0x07ffff1f },
++
+       { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x00070814, 0x007FFF1F },
+ 
+       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00800756, 0x00F3FFFF },
+ 
++      { 3, 0x140, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00a11755, 0x00f3ffff },
++
+       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x00C37756, 0x00F3FFFF },
+ 
+@@ -263,6 +415,9 @@ static const struct {
+        AMD_PTYPE_SVR, 0x00000001, 0x0000000F },
+               /* [3:0] RspTok = 0001b */
+ 
++      { 3, 0x144, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000028, 0x000000ff },
++
+       { 3, 0x148, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x8000052A, 0xD5FFFFFF },
+ 
+@@ -270,41 +425,53 @@ static const struct {
+       { 3, 0x80, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0xE6002200, 0xFFFFFFFF },
+ 
++      /* ACPI Power State Control Reg1 */
++      { 3, 0x80, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0xe20be200, 0xefefef00 },
++
+       /* ACPI Power State Control Reg2 */
+       { 3, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0xA0E641E6, 0xFFFFFFFF },
+ 
++      /* ACPI Power State Control Reg2 */
++      { 3, 0x84, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x01e200e2, 0xefef00ef },
++
+       { 3, 0xA0, AMD_FAM10_ALL, AMD_PTYPE_MOB | AMD_PTYPE_DSK,
+         0x00000080, 0x00000080 },     /* [7] PSIVidEnable */
+ 
+       { 3, 0xA0, AMD_DR_Bx, AMD_PTYPE_ALL,
+         0x00002800, 0x000003800 },    /* [13:11] PllLockTime = 5 */
+ 
+-      { 3, 0xA0, (AMD_FAM10_ALL & ~(AMD_DR_Bx)), AMD_PTYPE_ALL,
++      { 3, 0xA0, ((AMD_FAM10_ALL | AMD_FAM15_ALL) & ~(AMD_DR_Bx)), 
AMD_PTYPE_ALL,
+         0x00000800, 0x000003800 },    /* [13:11] PllLockTime = 1 */
+ 
+       /* Reported Temp Control Register */
+-      { 3, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00000080, 0x00000080 },     /* [7] TempSlewDnEn = 1 */
+ 
+       /* Clock Power/Timing Control 0 Register */
+-      { 3, 0xD4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0xD4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0xC0000F00, 0xF0000F00 },     /*  [31] NbClkDivApplyAll = 1,
+               [30:28] NbClkDiv = 100b,[11:8] ClkRampHystSel = 1111b */
+ 
+       /* Clock Power/Timing Control 1 Register */
++      { 3, 0xD8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++        0x03000010, 0x0F000070 },     /* [6:4] VSRampTime = 1,
++                                       * [27:24] ReConDel = 3 */
++
++      /* Clock Power/Timing Control 1 Register */
+       { 3, 0xD8, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        0x03000016, 0x0F000077 },     /* [6:4] VSRampTime = 1,
+-              [2:0] VSSlamTime = 6, [27:24] ReConDel = 3 */
++        0x00000006, 0x00000007 },     /* [2:0] VSSlamTime = 6 */
+ 
+ 
+       /* Clock Power/Timing Control 2 Register */
+-      { 3, 0xDC, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0xDC, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00005000, 0x00007000 },     /* [14:12] NbsynPtrAdj = 5 */
+ 
+ 
+       /* Extended NB MCA Config Register */
+-      { 3, 0x180, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0x180, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x007003E2, 0x007003E2 },     /* [22:20] = SyncFloodOn_Err = 7,
+                                          [9] SyncOnUncNbAryEn = 1 ,
+                                          [8] SyncOnProtEn = 1,
+@@ -319,12 +486,17 @@ static const struct {
+         0x00400000, 0x00400000 },
+ 
+       /* L3 Control Register */
+-      { 3, 0x1B8, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0x1b8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00001000, 0x00001000 },     /* [12] = L3PrivReplEn */
+ 
+       /* IBS Control Register */
+-      { 3, 0x1CC, AMD_FAM10_ALL, AMD_PTYPE_ALL,
++      { 3, 0x1cc, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00000100, 0x00000100 },     /* [8] = LvtOffsetVal */
++
++      /* Erratum 619 - Family 15h Bx
++       * System software should set F5x88[14] to 1b. */
++      { 5, 0x88, AMD_OR_B2, AMD_PTYPE_ALL,
++        1 << 14, 1 << 14 },
+ };
+ 
+ 
+@@ -333,7 +505,7 @@ static const struct {
+  */
+ static const struct {
+       u16 htreg;      /* HT Phy Register index */
+-      u32 revision;
++      uint64_t revision;
+       u32 platform;
+       u32 linktype;
+       u32 data;
+@@ -442,38 +614,38 @@ static const struct {
+       { 0x530A, AMD_DR_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
+         0x00004400, 0x00006400 },     /* HT_PHY_DLL_REG */
+ 
+-      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
+         0x00000000, 0x000000FF },     /* Provide clear setting for logical
+                                          completeness */
+ 
+-      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
+         0x00000000, 0x000000FF },     /* Provide clear setting for logical
+                                          completeness */
+ 
+-      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
++      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
+         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
+ 
+-      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
++      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,  
HTPHY_LINKTYPE_HT1,
+         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
+ 
+       /* Link Phy Receiver Loop Filter Registers */
+-      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
+         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
+                                          [21:14] LfcMin = 10h */
+ 
+-      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
+         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
+                                          [21:14] LfcMin = 10h */
+ 
+-      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
++      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
+         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
+                                          [21:14] LfcMin = 08h */
+ 
+-      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
++      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
+         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
+                                          [21:14] LfcMin = 08h */
+ 
+-      { 0xC0, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
++      { 0xC0, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_ALL,
+         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
+                                                                  [20:16] 
RttIndex = 04h */
+ };
+diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
+index 86e3179..e8e0818 100644
+--- a/src/cpu/amd/family_10h-family_15h/fidvid.c
++++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -43,7 +44,7 @@ Fam10 Bios and Kernel Development Guide #31116, rev 3.48, 
April 22, 2010
+ 
+ 3.-  2.4.2.7 dualPlaneOnly(dev)
+ 
+-4.-  2.4.2.8 applyBoostFIDOffset(dev)
++4.-  2.4.2.8 applyBoostFIDOffset(dev, nodeid)
+ 
+ 5.-  enableNbPState1(dev)
+ 
+@@ -142,25 +143,33 @@ static void enable_fid_change(u8 fid)
+       }
+ }
+ 
+-static void applyBoostFIDOffset(  device_t dev ) {
+-  // BKDG 2.4.2.8
+-  // revision E only, but E is apparently not supported yet, therefore 
untested
+-  if ((cpuid_edx(0x80000007) & CPB_MASK)
+-      &&  ((cpuid_ecx(0x80000008) & NC_MASK) ==5) ) {
+-      u32 core =  get_node_core_id_x().coreid;
+-      u32 asymetricBoostThisCore = ((pci_read_config32(dev, 0x10C) >> 
(core*2))) & 3;
+-      msr_t msr =  rdmsr(PS_REG_BASE);
+-      u32 cpuFid = msr.lo & PS_CPU_FID_MASK;
+-      cpuFid = cpuFid + asymetricBoostThisCore;
+-      msr.lo &=   ~PS_CPU_FID_MASK;
+-      msr.lo |= cpuFid ;
+-      wrmsr(PS_REG_BASE , msr);
+-
+-  }
++static void applyBoostFIDOffset(device_t dev, uint32_t nodeid) {
++      // BKDG 2.4.2.8
++      // Fam10h revision E only, but E is apparently not supported yet, 
therefore untested
++      if ((cpuid_edx(0x80000007) & CPB_MASK)
++              &&  ((cpuid_ecx(0x80000008) & NC_MASK) == 5) ) {
++              u32 core =  get_node_core_id_x().coreid;
++              u32 asymetricBoostThisCore = ((pci_read_config32(dev, 0x10C) >> 
(core*2))) & 3;
++              msr_t msr =  rdmsr(PS_REG_BASE);
++              u32 cpuFid = msr.lo & PS_CPU_FID_MASK;
++              cpuFid = cpuFid + asymetricBoostThisCore;
++              msr.lo &=   ~PS_CPU_FID_MASK;
++              msr.lo |= cpuFid ;
++              wrmsr(PS_REG_BASE , msr);
++      } else if (is_fam15h()) {
++              uint32_t dword = pci_read_config32(NODE_PCI(nodeid, 4), 0x15c);
++              uint8_t boost_count = (dword >> 2) & 0x7;
++              if (boost_count > 0) {
++                      /* Enable boost */
++                      dword &= ~0x3;
++                      dword |= 0x1;
++                      pci_write_config32(NODE_PCI(nodeid, 4), 0x15c, dword);
++              }
++      }
+ }
+ 
+ static void enableNbPState1( device_t dev ) {
+-  u32 cpuRev =  mctGetLogicalCPUID(0xFF);
++  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
+   if (cpuRev & AMD_FAM10_C3) {
+     u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
+     if ( nbPState){
+@@ -202,7 +211,7 @@ static u8 setPStateMaxVal( device_t dev ) {
+ static void dualPlaneOnly(  device_t dev ) {
+   // BKDG 2.4.2.7
+ 
+-  u32 cpuRev =  mctGetLogicalCPUID(0xFF);
++  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
+   if ((mctGetProcessorPackageType() ==  AMD_PKGTYPE_AM3_2r2)
+       && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no 
constant for E
+     if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
+@@ -282,12 +291,16 @@ static void 
recalculateVsSlamTimeSettingOnCorePre(device_t dev)
+        */
+ 
+       /* Determine if this is a PVI or SVI system */
+-      dtemp = pci_read_config32(dev, 0xA0);
+-
+-      if (dtemp & PVI_MODE)
+-              pviModeFlag = 1;
+-      else
++      if (is_fam15h()) {
+               pviModeFlag = 0;
++      } else {
++              dtemp = pci_read_config32(dev, 0xa0);
++
++              if (dtemp & PVI_MODE)
++                      pviModeFlag = 1;
++              else
++                      pviModeFlag = 0;
++      }
+ 
+       /* Get P0's voltage */
+         /* MSRC001_00[68:64] are not programmed yet when called from
+@@ -514,59 +527,67 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 
cpuRev) {
+ }
+ 
+ static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 
procPkg) {
+-                /* step 1, chapter 2.4.2.6 of AMD Fam 10 BKDG #31116 Rev 3.48 
22.4.2010 */
+-        u32 dword;
+-      u32 c1= 1;
+-        if (cpuRev & (AMD_DR_Bx)) {
+-            // will coreboot ever enable cache scrubbing ?
+-            // if it does, will it be enough to check the current state
+-            // or should we configure for what we'll set up later ?
+-            dword = pci_read_config32(dev, 0x58);
+-            u32 scrubbingCache = dword &
+-                              ( (0x1F << 16) // DCacheScrub
+-                                | (0x1F << 8) ); // L2Scrub
+-          if (scrubbingCache) {
+-              c1 = 0x80;
+-          } else {
+-              c1 = 0xA0;
+-          }
+-      } else { // rev C or later
+-          // same doubt as cache scrubbing: ok to check current state ?
+-            dword = pci_read_config32(dev, 0xDC);
+-            u32 cacheFlushOnHalt = dword & (7 << 16);
+-            if (!cacheFlushOnHalt) {
+-                     c1 = 0x80;
+-                  }
+-              }
+-              dword = (c1 << 24) | (0xE641E6);
+-      pci_write_config32(dev, 0x84, dword);
+-
+-
+-        /* FIXME: BKDG Table 100 says if the link is at a Gen1
+-frequency and the chipset does not support a 10us minimum LDTSTOP
+-assertion time, then { If ASB2 && SVI then smaf001 = F6h else
+-smaf001=87h. } else ...  I hardly know what it means or how to check
+-it from here, so I bluntly assume it is false and code here the else,
+-which is easier  */
+-
+-        u32 smaf001 = 0xE6;
+-        if (cpuRev & AMD_DR_Bx ) {
+-          smaf001 = 0xA6;
+-        } else {
+-            #if CONFIG_SVI_HIGH_FREQ
+-                if (cpuRev & (AMD_RB_C3 | AMD_DA_C3)) {
+-                     smaf001 = 0xF6;
+-                }
+-            #endif
+-        }
+-        u32 fidvidChange = 0;
+-        if (((cpuRev & AMD_DA_Cx) && (procPkg & AMD_PKGTYPE_S1gX))
+-                  || (cpuRev & AMD_RB_C3) ) {
+-                       fidvidChange=0x0B;
+-        }
+-      dword = (0xE6 << 24) | (fidvidChange << 16)
+-                        | (smaf001 << 8) | 0x81;
+-      pci_write_config32(dev, 0x80, dword);
++      if (is_fam15h()) {
++              /* Family 15h BKDG Rev. 3.14 D18F3x80 recommended settings */
++              pci_write_config32(dev, 0x80, 0xe20be281);
++
++              /* Family 15h BKDG Rev. 3.14 D18F3x84 recommended settings */
++              pci_write_config32(dev, 0x84, 0x01e200e2);
++      } else {
++              /* step 1, chapter 2.4.2.6 of AMD Fam 10 BKDG #31116 Rev 3.48 
22.4.2010 */
++              u32 dword;
++              u32 c1= 1;
++              if (cpuRev & (AMD_DR_Bx)) {
++                      // will coreboot ever enable cache scrubbing ?
++                      // if it does, will it be enough to check the current 
state
++                      // or should we configure for what we'll set up later ?
++                      dword = pci_read_config32(dev, 0x58);
++                      u32 scrubbingCache = dword &
++                                              ( (0x1F << 16) // DCacheScrub
++                                              | (0x1F << 8) ); // L2Scrub
++                      if (scrubbingCache) {
++                              c1 = 0x80;
++                      } else {
++                              c1 = 0xA0;
++                      }
++              } else { // rev C or later
++                      // same doubt as cache scrubbing: ok to check current 
state ?
++                      dword = pci_read_config32(dev, 0xDC);
++                      u32 cacheFlushOnHalt = dword & (7 << 16);
++                      if (!cacheFlushOnHalt) {
++                              c1 = 0x80;
++                      }
++              }
++              dword = (c1 << 24) | (0xE641E6);
++              pci_write_config32(dev, 0x84, dword);
++
++              /* FIXME: BKDG Table 100 says if the link is at a Gen1
++              * frequency and the chipset does not support a 10us minimum 
LDTSTOP
++              * assertion time, then { If ASB2 && SVI then smaf001 = F6h else
++              * smaf001=87h. } else ...  I hardly know what it means or how 
to check
++              * it from here, so I bluntly assume it is false and code here 
the else,
++              * which is easier
++              */
++
++              u32 smaf001 = 0xE6;
++              if (cpuRev & AMD_DR_Bx ) {
++                      smaf001 = 0xA6;
++              } else {
++              #if CONFIG_SVI_HIGH_FREQ
++                      if (cpuRev & (AMD_RB_C3 | AMD_DA_C3)) {
++                              smaf001 = 0xF6;
++                      }
++              #endif
++              }
++              u32 fidvidChange = 0;
++              if (((cpuRev & AMD_DA_Cx) && (procPkg & AMD_PKGTYPE_S1gX))
++                      || (cpuRev & AMD_RB_C3) ) {
++                              fidvidChange=0x0B;
++              }
++              dword = (0xE6 << 24) | (fidvidChange << 16)
++                              | (smaf001 << 8) | 0x81;
++              pci_write_config32(dev, 0x80, dword);
++      }
+ }
+ 
+ static void prep_fid_change(void)
+@@ -583,7 +604,7 @@ static void prep_fid_change(void)
+       for (i = 0; i < nodes; i++) {
+               printk(BIOS_DEBUG, "Prep FID/VID Node:%02x\n", i);
+               dev = NODE_PCI(i, 3);
+-                u32 cpuRev = mctGetLogicalCPUID(0xFF) ;
++                uint64_t cpuRev = mctGetLogicalCPUID(0xFF) ;
+               u8 procPkg =  mctGetProcessorPackageType();
+ 
+               setVSRamp(dev);
+@@ -611,7 +632,7 @@ static void prep_fid_change(void)
+       }
+ }
+ 
+-static void waitCurrentPstate(u32 target_pstate){
++static void waitCurrentPstate(u32 target_pstate) {
+   msr_t initial_msr = rdmsr(TSC_MSR);
+   msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
+   msr_t tsc_msr;
+@@ -644,7 +665,7 @@ static void waitCurrentPstate(u32 target_pstate){
+ 
+   if (pstate_msr.lo != target_pstate) {
+     msr_t limit_msr = rdmsr(0xc0010061);
+-    printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state 
%01x P-state current limit MSRC001_0061=%02x\n", target_pstate, pstate_msr.lo, 
limit_msr.lo);
++    printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state 
%01x P-state current limit MSRC001_0061=%08x %08x\n", target_pstate, 
pstate_msr.lo, limit_msr.hi, limit_msr.lo);
+ 
+     do { // should we just go on instead ?
+       pstate_msr = rdmsr(CUR_PSTATE_MSR);
+@@ -654,6 +675,7 @@ static void waitCurrentPstate(u32 target_pstate){
+ 
+ static void set_pstate(u32 nonBoostedPState) {
+       msr_t msr;
++      uint8_t skip_wait;
+ 
+       // Transition P0 for calling core.
+       msr = rdmsr(0xC0010062);
+@@ -661,12 +683,21 @@ static void set_pstate(u32 nonBoostedPState) {
+       msr.lo = nonBoostedPState;
+       wrmsr(0xC0010062, msr);
+ 
+-      /* Wait for P0 to set. */
+-        waitCurrentPstate(nonBoostedPState);
+-}
+-
+-
++      if (is_fam15h()) {
++              /* Do not wait for the first (even) set of cores to transition 
on Family 15h systems */
++              if ((cpuid_ebx(0x00000001) & 0x01000000))
++                      skip_wait = 0;
++              else
++                      skip_wait = 1;
++      } else {
++              skip_wait = 0;
++      }
+ 
++      if (!skip_wait) {
++              /* Wait for core to transition to P0 */
++              waitCurrentPstate(nonBoostedPState);
++      }
++}
+ 
+ static void UpdateSinglePlaneNbVid(void)
+ {
+@@ -756,11 +787,14 @@ static u32 needs_NB_COF_VID_update(void)
+       u8 nodes;
+       u8 i;
+ 
++      if (is_fam15h())
++              return 0;
++
+       /* If any node has nb_cof_vid_update set all nodes need an update. */
+       nodes = get_nodes();
+       nb_cof_vid_update = 0;
+       for (i = 0; i < nodes; i++) {
+-                u32 cpuRev = mctGetLogicalCPUID(i) ;
++                uint64_t cpuRev = mctGetLogicalCPUID(i);
+                 u32 nbCofVidUpdateDefined = (cpuRev & (AMD_FAM10_LT_D));
+               if (nbCofVidUpdateDefined
+                     && (pci_read_config32(NODE_PCI(i, 3), 0x1FC)
+@@ -784,9 +818,11 @@ static u32 init_fidvid_core(u32 nodeid, u32 coreid)
+       /* Steps 1-6 of BIOS NB COF and VID Configuration
+        * for SVI and Single-Plane PVI Systems. BKDG 2.4.2.9 #31116 rev 3.48
+        */
+-
+       dev = NODE_PCI(nodeid, 3);
+-      pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE;
++      if (is_fam15h())
++              pvimode = 0;
++      else
++              pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE;
+       reg1fc = pci_read_config32(dev, 0x1FC);
+ 
+       if (nb_cof_vid_update) {
+@@ -798,7 +834,7 @@ static u32 init_fidvid_core(u32 nodeid, u32 coreid)
+                       fid_max = fid_max +  ((reg1fc &  
DUAL_PLANE_NB_FID_OFF_MASK ) >>  DUAL_PLANE_NB_FID_SHIFT );
+               }
+               /* write newNbVid to P-state Reg's NbVid always if 
NbVidUpdatedAll=1 */
+-              fixPsNbVidBeforeWR(vid_max, coreid,dev,pvimode);
++              fixPsNbVidBeforeWR(vid_max, coreid, dev, pvimode);
+ 
+               /* fid setup is handled by the BSP at the end. */
+ 
+@@ -818,7 +854,7 @@ static void init_fidvid_ap(u32 apicid, u32 nodeid, u32 
coreid)
+ 
+       printk(BIOS_DEBUG, "FIDVID on AP: %02x\n", apicid);
+ 
+-        send = init_fidvid_core(nodeid,coreid);
++        send = init_fidvid_core(nodeid, coreid);
+       send |= (apicid << 24); // ap apicid
+ 
+       // Send signal to BSP about this AP max fid
+@@ -860,7 +896,8 @@ static void init_fidvid_bsp_stage1(u32 ap_apicid, void *gp)
+       while (--loop > 0) {
+               if (lapic_remote_read(ap_apicid, LAPIC_MSG_REG, &readback) != 0)
+                       continue;
+-              if ((readback & 0x3f) == F10_APSTATE_RESET) {
++              if (((readback & 0x3f) == F10_APSTATE_RESET)
++                      || (is_fam15h() && ((readback & 0x3f) == 
F10_APSTATE_ASLEEP))) {
+                       timeout = 0;
+                       break;  /* target ap is in stage 1 */
+               }
+@@ -948,7 +985,10 @@ static void init_fidvid_stage2(u32 apicid, u32 nodeid)
+       /* If any node has nb_cof_vid_update set all nodes need an update. */
+ 
+       dev = NODE_PCI(nodeid, 3);
+-      pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1;
++      if (is_fam15h())
++              pvimode = 0;
++      else
++              pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1;
+       reg1fc = pci_read_config32(dev, 0x1FC);
+       nbvid = (reg1fc >> 7) & 0x7F;
+       NbVidUpdateAll = (reg1fc >> 1) & 1;
+@@ -969,15 +1009,17 @@ static void init_fidvid_stage2(u32 apicid, u32 nodeid)
+       pci_write_config32(dev, 0xA0, dtemp);
+ 
+         dualPlaneOnly(dev);
+-        applyBoostFIDOffset(dev);
++        applyBoostFIDOffset(dev, nodeid);
+         enableNbPState1(dev);
+ 
+       finalPstateChange();
+ 
+-      /* Set TSC to tick at the P0 ndfid rate */
+-      msr = rdmsr(HWCR);
+-      msr.lo |= 1 << 24;
+-      wrmsr(HWCR, msr);
++      if (!is_fam15h()) {
++              /* Set TSC to tick at the P0 ndfid rate */
++              msr = rdmsr(HWCR);
++              msr.lo |= 1 << 24;
++              wrmsr(HWCR, msr);
++      }
+ }
+ 
+ 
+@@ -1011,8 +1053,7 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes)
+       /* Steps 1-6 of BIOS NB COF and VID Configuration
+        * for SVI and Single-Plane PVI Systems.
+        */
+-
+-      fv.common_fid = init_fidvid_core(0,0);
++      fv.common_fid = init_fidvid_core(0, 0);
+ 
+       print_debug_fv("BSP fid = ", fv.common_fid);
+ 
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index 8de6d25..aced850 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -30,9 +30,12 @@
+ #include <northbridge/amd/amdfam10/raminit_amdmct.c>
+ #include <reset.h>
+ 
++#if IS_ENABLED(CONFIG_SET_FIDVID)
+ static void prep_fid_change(void);
+ static void init_fidvid_stage2(u32 apicid, u32 nodeid);
+-void cpuSetAMDMSR(void);
++#endif
++
++void cpuSetAMDMSR(uint8_t node_id);
+ 
+ #if CONFIG_PCI_IO_CFG_EXT
+ static void set_EnableCf8ExtCfg(void)
+@@ -51,43 +54,38 @@ static void set_EnableCf8ExtCfg(void) { }
+ 
+ typedef void (*process_ap_t) (u32 apicid, void *gp);
+ 
+-//core_range = 0 : all cores
+-//core range = 1 : core 0 only
+-//core range = 2 : cores other than core0
++uint32_t get_boot_apic_id(uint8_t node, uint32_t core) {
++      uint32_t ap_apicid;
+ 
+-static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t 
process_ap,
+-                      void *gp)
+-{
+-      // here assume the OS don't change our apicid
+-      u32 ap_apicid;
++      uint32_t nb_cfg_54;
++      uint32_t siblings;
++      uint32_t cores_found;
+ 
+-      u32 nodes;
+-      u32 siblings;
+-      u32 disable_siblings;
+-      u32 cores_found;
+-      u32 nb_cfg_54;
+-      int i, j;
+-      u32 ApicIdCoreIdSize;
++      uint8_t fam15h = 0;
+       uint8_t rev_gte_d = 0;
+       uint8_t dual_node = 0;
+       uint32_t f3xe8;
++      uint32_t family;
++      uint32_t model;
+ 
+-      /* get_nodes define in ht_wrapper.c */
+-      nodes = get_nodes();
+-
+-      if (!CONFIG_LOGICAL_CPUS ||
+-          read_option(multi_core, 0) != 0) {  // 0 means multi core
+-              disable_siblings = 1;
+-      } else {
+-              disable_siblings = 0;
+-      }
++      uint32_t ApicIdCoreIdSize;
+ 
+       /* Assume that all node are same stepping, otherwise we can use use
+          nb_cfg_54 from bsp for all nodes */
+       nb_cfg_54 = read_nb_cfg_54();
+       f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
+ 
+-      if (cpuid_eax(0x80000001) >= 0x8)
++      family = model = cpuid_eax(0x80000001);
++      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f) {
++              /* Family 15h or later */
++              fam15h = 1;
++              nb_cfg_54 = 1;
++      }
++
++      if ((model >= 0x8) || fam15h)
+               /* Revision D or later */
+               rev_gte_d = 1;
+ 
+@@ -103,10 +101,63 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
+               siblings = 3;   //quad core
+       }
+ 
++      cores_found = get_core_num_in_bsp(node);
++      if (siblings > cores_found)
++              siblings = cores_found;
++
++      if (dual_node) {
++              ap_apicid = 0;
++              if (fam15h) {
++                      ap_apicid |= ((node >> 1) & 0x3) << 5;                  
/* Node ID */
++                      ap_apicid |= ((node & 0x1) * (siblings + 1)) + core;    
/* Core ID */
++              } else {
++                      if (nb_cfg_54) {
++                              ap_apicid |= ((node >> 1) & 0x3) << 4;          
        /* Node ID */
++                              ap_apicid |= ((node & 0x1) * (siblings + 1)) + 
core;    /* Core ID */
++                      } else {
++                              ap_apicid |= node & 0x3;                        
                /* Node ID */
++                              ap_apicid |= (((node & 0x1) * (siblings + 1)) + 
core) << 4;     /* Core ID */
++                      }
++              }
++      } else {
++              if (fam15h) {
++                      ap_apicid = (node * (siblings + 1)) + core;
++              } else {
++                      ap_apicid = node * (nb_cfg_54 ? (siblings + 1) : 1) +
++                                      core * (nb_cfg_54 ? 1 : 64);
++              }
++      }
++
++      return ap_apicid;
++}
++
++//core_range = 0 : all cores
++//core range = 1 : core 0 only
++//core range = 2 : cores other than core0
++
++static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t 
process_ap,
++                      void *gp)
++{
++      // here assume the OS don't change our apicid
++      u32 ap_apicid;
++
++      u32 nodes;
++      u32 disable_siblings;
++      u32 cores_found;
++      int i, j;
++
++      /* get_nodes define in ht_wrapper.c */
++      nodes = get_nodes();
++
++      if (!CONFIG_LOGICAL_CPUS ||
++          read_option(multi_core, 0) != 0) {  // 0 means multi core
++              disable_siblings = 1;
++      } else {
++              disable_siblings = 0;
++      }
++
+       for (i = 0; i < nodes; i++) {
+               cores_found = get_core_num_in_bsp(i);
+-              if (siblings > cores_found)
+-                      siblings = cores_found;
+ 
+               u32 jstart, jend;
+ 
+@@ -123,21 +174,7 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
+               }
+ 
+               for (j = jstart; j <= jend; j++) {
+-                      if (dual_node) {
+-                              ap_apicid = 0;
+-                              if (nb_cfg_54) {
+-                                      ap_apicid |= ((i >> 1) & 0x3) << 4;     
                /* Node ID */
+-                                      ap_apicid |= ((i & 0x1) * (siblings + 
1)) + j;          /* Core ID */
+-                              } else {
+-                                      ap_apicid |= i & 0x3;                   
                /* Node ID */
+-                                      ap_apicid |= (((i & 0x1) * (siblings + 
1)) + j) << 4;   /* Core ID */
+-                              }
+-                      } else {
+-                              ap_apicid =
+-                              i * (nb_cfg_54 ? (siblings + 1) : 1) +
+-                              j * (nb_cfg_54 ? 1 : 64);
+-                      }
+-
++                      ap_apicid = get_boot_apic_id(i, j);
+ 
+ #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET > 0)
+ #if !CONFIG_LIFT_BSP_APIC_ID
+@@ -197,7 +234,7 @@ void print_apicid_nodeid_coreid(u32 apicid, struct 
node_core_id id,
+              apicid, id.nodeid, id.coreid);
+ }
+ 
+-static u32 wait_cpu_state(u32 apicid, u32 state)
++uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2)
+ {
+       u32 readback = 0;
+       u32 timeout = 1;
+@@ -205,7 +242,7 @@ static u32 wait_cpu_state(u32 apicid, u32 state)
+       while (--loop > 0) {
+               if (lapic_remote_read(apicid, LAPIC_MSG_REG, &readback) != 0)
+                       continue;
+-              if ((readback & 0x3f) == state || (readback & 0x3f) == 
F10_APSTATE_RESET) {
++              if ((readback & 0x3f) == state || (readback & 0x3f) == state2 
|| (readback & 0x3f) == F10_APSTATE_RESET) {
+                       timeout = 0;
+                       break;  //target cpu is in stage started
+               }
+@@ -222,7 +259,7 @@ static u32 wait_cpu_state(u32 apicid, u32 state)
+ static void wait_ap_started(u32 ap_apicid, void *gp)
+ {
+       u32 timeout;
+-      timeout = wait_cpu_state(ap_apicid, F10_APSTATE_STARTED);
++      timeout = wait_cpu_state(ap_apicid, F10_APSTATE_STARTED, 
F10_APSTATE_ASLEEP);
+       printk(BIOS_DEBUG, "* AP %02x", ap_apicid);
+       if (timeout) {
+               printk(BIOS_DEBUG, " timed out:%08x\n", timeout);
+@@ -258,16 +295,27 @@ static void enable_apic_ext_id(u32 node)
+       pci_write_config32(NODE_HT(node), 0x68, val);
+ }
+ 
+-static void STOP_CAR_AND_CPU(void)
++static void STOP_CAR_AND_CPU(uint8_t skip_sharedc_config, uint32_t apicid)
+ {
+       msr_t msr;
++      uint32_t family;
++
++      family = amd_fam1x_cpu_family();                // inline
++
++      if (family < 0x6f) {
++              /* Family 10h or earlier */
++
++              /* Disable L2 IC to L3 connection (Only for CAR) */
++              msr = rdmsr(BU_CFG2);
++              msr.lo &= ~(1 << ClLinesToNbDis);
++              wrmsr(BU_CFG2, msr);
++      }
+ 
+-      /* Disable L2 IC to L3 connection (Only for CAR) */
+-      msr = rdmsr(BU_CFG2);
+-      msr.lo &= ~(1 << ClLinesToNbDis);
+-      wrmsr(BU_CFG2, msr);
++      disable_cache_as_ram(skip_sharedc_config);      // inline
++
++      /* Mark the core as sleeping */
++      lapic_write(LAPIC_MSG_REG, (apicid << 24) | F10_APSTATE_ASLEEP);
+ 
+-      disable_cache_as_ram(); // inline
+       /* stop all cores except node0/core0 the bsp .... */
+       stop_this_cpu();
+ }
+@@ -276,6 +324,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
+ {
+       u32 bsp_apicid = 0;
+       u32 apicid;
++      uint8_t set_mtrrs;
+       struct node_core_id id;
+ 
+       /* Please refer to the calculations and explaination in 
cache_as_ram.inc before modifying these values */
+@@ -362,7 +411,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
+                */
+               update_microcode(cpuid_eax(1));
+ 
+-              cpuSetAMDMSR();
++              cpuSetAMDMSR(id.nodeid);
+ 
+ #if CONFIG_SET_FIDVID
+ #if CONFIG_LOGICAL_CPUS && CONFIG_SET_FIDVID_CORE0_ONLY
+@@ -385,10 +434,29 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
+               }
+ #endif
+ 
++              if (is_fam15h()) {
++                      /* core 1 on node 0 is special; to avoid corrupting the
++                       * BSP do not alter MTRRs on that core */
++                      if (apicid == 1)
++                              set_mtrrs = 0;
++                      else
++                              set_mtrrs = !!(apicid & 0x1);
++              } else {
++                      set_mtrrs = 1;
++              }
++
+               /* AP is ready, configure MTRRs and go to sleep */
+-              set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK);
++              if (set_mtrrs)
++                      set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, 
MTRR_TYPE_WRBACK);
+ 
+-              STOP_CAR_AND_CPU();
++              printk(BIOS_DEBUG, "Disabling CAR on AP %02x\n", apicid);
++              if (is_fam15h()) {
++                      /* Only modify the MSRs on the odd cores (the last 
cores to finish booting) */
++                      STOP_CAR_AND_CPU(!set_mtrrs, apicid);
++              } else {
++                      /* Modify MSRs on all cores */
++                      STOP_CAR_AND_CPU(0, apicid);
++              }
+ 
+               printk(BIOS_DEBUG,
+                      "\nAP %02x should be halted but you are reading 
this....\n",
+@@ -496,7 +564,7 @@ static void setup_remote_node(u8 node)
+ }
+ #endif                                /* CONFIG_MAX_PHYSICAL_CPUS > 1 */
+ 
+-static void AMD_Errata281(u8 node, u32 revision, u32 platform)
++static void AMD_Errata281(u8 node, uint64_t revision, u32 platform)
+ {
+       /* Workaround for Transaction Scheduling Conflict in
+        * Northbridge Cross Bar.  Implement XCS Token adjustment
+@@ -794,7 +862,7 @@ static void AMD_SetHtPhyRegister(u8 node, u8 link, u8 
entry)
+       } while (!(val & HTPHY_IS_COMPLETE_MASK));
+ }
+ 
+-void cpuSetAMDMSR(void)
++void cpuSetAMDMSR(uint8_t node_id)
+ {
+       /* This routine loads the CPU with default settings in fam10_msr_default
+        * table . It must be run after Cache-As-RAM has been enabled, and
+@@ -804,7 +872,8 @@ void cpuSetAMDMSR(void)
+        */
+       msr_t msr;
+       u8 i;
+-      u32 revision, platform;
++      u32 platform;
++      uint64_t revision;
+ 
+       printk(BIOS_DEBUG, "cpuSetAMDMSR ");
+ 
+@@ -824,6 +893,49 @@ void cpuSetAMDMSR(void)
+       }
+       AMD_Errata298();
+ 
++      if (revision & AMD_FAM15_ALL) {
++              uint32_t f5x80;
++              uint8_t enabled;
++              uint8_t compute_unit_count = 0;
++              f5x80 = pci_read_config32(NODE_PCI(node_id, 5), 0x80);
++              enabled = f5x80 & 0xf;
++              if (enabled == 0x1)
++                      compute_unit_count = 1;
++              if (enabled == 0x3)
++                      compute_unit_count = 2;
++              if (enabled == 0x7)
++                      compute_unit_count = 3;
++              if (enabled == 0xf)
++                      compute_unit_count = 4;
++              msr = rdmsr(BU_CFG2);
++              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
++              msr.lo |= (((compute_unit_count - 1) & 0x3) << 6);
++              wrmsr(BU_CFG2, msr);
++      }
++
++      /* Revision C0 and above */
++      if (revision & AMD_OR_C0) {
++              uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 
0x1fc);
++              msr = rdmsr(FP_CFG);
++              msr.hi &= ~(0x7 << (42-32));                    /* DiDtCfg4 */
++              msr.hi |= (((f3x1fc >> 17) & 0x7) << (42-32));
++              msr.hi &= ~(0x1 << (41-32));                    /* DiDtCfg5 */
++              msr.hi |= (((f3x1fc >> 22) & 0x1) << (41-32));
++              msr.hi &= ~(0x1 << (40-32));                    /* DiDtCfg3 */
++              msr.hi |= (((f3x1fc >> 16) & 0x1) << (40-32));
++              msr.hi &= ~(0x7 << (32-32));                    /* DiDtCfg1 (1) 
*/
++              msr.hi |= (((f3x1fc >> 11) & 0x7) << (32-32));
++              msr.lo &= ~(0x1f << 27);                        /* DiDtCfg1 (2) 
*/
++              msr.lo |= (((f3x1fc >> 6) & 0x1f) << 27);
++              msr.lo &= ~(0x3 << 25);                         /* DiDtCfg2 */
++              msr.lo |= (((f3x1fc >> 14) & 0x3) << 25);
++              msr.lo &= ~(0x1f << 18);                        /* DiDtCfg0 */
++              msr.lo |= (((f3x1fc >> 1) & 0x1f) << 18);
++              msr.lo &= ~(0x1 << 16);                         /* DiDtMode */
++              msr.lo |= ((f3x1fc & 0x1) << 16);
++              wrmsr(FP_CFG, msr);
++      }
++
+       printk(BIOS_DEBUG, " done\n");
+ }
+ 
+@@ -835,9 +947,10 @@ static void cpuSetAMDPCI(u8 node)
+        * that it is run for the first core on each node
+        */
+       u8 i, j;
+-      u32 revision, platform;
++      u32 platform;
+       u32 val;
+       u8 offset;
++      uint64_t revision;
+ 
+       printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node);
+ 
+@@ -899,6 +1012,7 @@ static void cpuSetAMDPCI(u8 node)
+ }
+ 
+ #ifdef UNUSED_CODE
++/* Clearing the MCA registers is apparently handled in the ramstage CPU 
Function 3 driver */
+ static void cpuInitializeMCA(void)
+ {
+       /* Clears Machine Check Architecture (MCA) registers, which power on
+diff --git a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c 
b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
+index b942c1a..8a61f13 100644
+--- a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
++++ b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
+@@ -39,6 +39,23 @@
+ 
+ #define MCI_STATUS 0x401
+ 
++static inline uint8_t is_fam15h(void)
++{
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      return fam15h;
++}
++
++static volatile uint8_t 
fam15h_startup_flags[MAX_NODES_SUPPORTED][MAX_CORES_SUPPORTED] = {{ 0 }};
++
+ static void model_10xxx_init(device_t dev)
+ {
+       u8 i;
+@@ -47,13 +64,44 @@ static void model_10xxx_init(device_t dev)
+ #if CONFIG_LOGICAL_CPUS
+       u32 siblings;
+ #endif
++      uint8_t delay_start;
+ 
+       id = get_node_core_id(read_nb_cfg_54());        /* nb_cfg_54 can not be 
set */
+       printk(BIOS_DEBUG, "nodeid = %02d, coreid = %02d\n", id.nodeid, 
id.coreid);
+ 
++      if (is_fam15h())
++              delay_start = !!(id.coreid & 0x1);
++      else
++              delay_start = 0;
++
+       /* Turn on caching if we haven't already */
+       x86_enable_cache();
+-      amd_setup_mtrrs();
++
++      if (!delay_start) {
++              /* Initialize all variable MTRRs except the first pair.
++               * This prevents Linux from having to correct an inconsistent
++               * MTRR setup, which would crash Family 15h CPUs due to the
++               * compute unit structure sharing MTRR MSRs between AP cores.
++               */
++              msr.hi = 0x00000000;
++              msr.lo = 0x00000000;
++
++              disable_cache();
++
++              for (i = 0x2; i < 0x10; i++) {
++                      wrmsr(0x00000200 | i, msr);
++              }
++
++              enable_cache();
++
++              /* Set up other MTRRs */
++              amd_setup_mtrrs();
++      } else {
++              while (!fam15h_startup_flags[id.nodeid][id.coreid - 1]) {
++                      /* Wait for CU first core startup */
++              }
++      }
++
+       x86_mtrr_check();
+ 
+       disable_cache();
+@@ -88,17 +136,24 @@ static void model_10xxx_init(device_t dev)
+       printk(BIOS_DEBUG, "siblings = %02d, ", siblings);
+ #endif
+ 
+-      /* DisableCf8ExtCfg */
++      /* Disable Cf8ExtCfg */
+       msr = rdmsr(NB_CFG_MSR);
+       msr.hi &= ~(1 << (46 - 32));
+       wrmsr(NB_CFG_MSR, msr);
+ 
+-      msr = rdmsr(BU_CFG2_MSR);
+-      /* Clear ClLinesToNbDis */
+-      msr.lo &= ~(1 << 15);
+-      /* Clear bit 35 as per Erratum 343 */
+-      msr.hi &= ~(1 << (35-32));
+-      wrmsr(BU_CFG2_MSR, msr);
++      if (is_fam15h()) {
++              msr = rdmsr(BU_CFG3_MSR);
++              /* Set CombineCr0Cd */
++              msr.hi |= (1 << (49-32));
++              wrmsr(BU_CFG3_MSR, msr);
++      } else {
++              msr = rdmsr(BU_CFG2_MSR);
++              /* Clear ClLinesToNbDis */
++              msr.lo &= ~(1 << 15);
++              /* Clear bit 35 as per Erratum 343 */
++              msr.hi &= ~(1 << (35-32));
++              wrmsr(BU_CFG2_MSR, msr);
++      }
+ 
+       if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) {
+               printk(BIOS_DEBUG, "Initializing SMM ASeg memory\n");
+@@ -131,6 +186,7 @@ static void model_10xxx_init(device_t dev)
+       msr.lo |= (1 << 0);
+       wrmsr(HWCR_MSR, msr);
+ 
++      fam15h_startup_flags[id.nodeid][id.coreid] = 1;
+ }
+ 
+ static struct device_operations cpu_dev_ops = {
+@@ -147,15 +203,17 @@ static struct cpu_device_id cpu_table[] = {
+       { X86_VENDOR_AMD, 0x100f22 },
+       { X86_VENDOR_AMD, 0x100f23 },
+       { X86_VENDOR_AMD, 0x100f40 },           /* RB-C0 */
+-      { X86_VENDOR_AMD, 0x100F42 },           /* RB-C2 */
+-      { X86_VENDOR_AMD, 0x100F43 },           /* RB-C3 */
+-      { X86_VENDOR_AMD, 0x100F52 },           /* BL-C2 */
+-      { X86_VENDOR_AMD, 0x100F62 },           /* DA-C2 */
+-      { X86_VENDOR_AMD, 0x100F63 },           /* DA-C3 */
+-      { X86_VENDOR_AMD, 0x100F80 },           /* HY-D0 */
+-      { X86_VENDOR_AMD, 0x100F81 },           /* HY-D1 */
+-      { X86_VENDOR_AMD, 0x100F91 },           /* HY-D1 */
+-      { X86_VENDOR_AMD, 0x100FA0 },           /* PH-E0 */
++      { X86_VENDOR_AMD, 0x100f42 },           /* RB-C2 */
++      { X86_VENDOR_AMD, 0x100f43 },           /* RB-C3 */
++      { X86_VENDOR_AMD, 0x100f52 },           /* BL-C2 */
++      { X86_VENDOR_AMD, 0x100f62 },           /* DA-C2 */
++      { X86_VENDOR_AMD, 0x100f63 },           /* DA-C3 */
++      { X86_VENDOR_AMD, 0x100f80 },           /* HY-D0 */
++      { X86_VENDOR_AMD, 0x100f81 },           /* HY-D1 */
++      { X86_VENDOR_AMD, 0x100f91 },           /* HY-D1 */
++      { X86_VENDOR_AMD, 0x100fa0 },           /* PH-E0 */
++      { X86_VENDOR_AMD, 0x600f12 },           /* OR-B2 */
++      { X86_VENDOR_AMD, 0x600f20 },           /* OR-C0 */
+       { 0, 0 },
+ };
+ 
+diff --git a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c 
b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
+index 98ef08a..84e5514 100644
+--- a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
++++ b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
+@@ -74,8 +74,7 @@ static void write_pstates_for_core(u8 pstate_num, u16 
*pstate_feq, u32 *pstate_p
+               /* Revision C or greater single-link processor */
+               cpuid1 = cpuid(0x80000008);
+               acpigen_write_PSD_package(0, (cpuid1.ecx & 0xff) + 1, SW_ALL);
+-      }
+-      else {
++      } else {
+               /* Find the local APIC ID for the specified core ID */
+               struct device* cpu;
+               int cpu_index = 0;
+@@ -99,7 +98,9 @@ static void write_pstates_for_core(u8 pstate_num, u16 
*pstate_feq, u32 *pstate_p
+ }
+ 
+ /*
+-* For details of this algorithm, please refer to the BDKG 3.62 page 69
++* For details of this algorithm, please refer to:
++* Family 10h BDKG 3.62 page 69
++* Family 15h BDKG 3.14 page 74
+ *
+ * WARNING: The core count algorithm below assumes that all processors
+ * are identical, with the same number of active cores.  While the BKDG
+@@ -149,6 +150,13 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+       uint8_t node_count;
+       uint8_t cores_per_node;
+       uint8_t total_core_count;
++      uint8_t fam15h;
++      uint8_t fam10h_rev_e = 0;
++
++      /* Detect Revision E processors via method used in fidvid.c */
++      if ((cpuid_edx(0x80000007) & CPB_MASK)
++              &&  ((cpuid_ecx(0x80000008) & NC_MASK) == 5))
++                      fam10h_rev_e = 1;
+ 
+       /*
+        * Based on the CPU socket type,cmp_cap and pwr_lmt , get the power 
limit.
+@@ -156,11 +164,17 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+        * cmp_cap : 0x0 SingleCore ; 0x1 DualCore ; 0x2 TripleCore ; 0x3 
QuadCore ; 0x4 QuintupleCore ; 0x5 HexCore
+        */
+       printk(BIOS_INFO, "Pstates algorithm ...\n");
++      fam15h = !!(mctGetLogicalCPUID(0) & AMD_FAM15_ALL);
+       /* Get number of cores */
+-      dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xE8);
+-      cmp_cap = (dtemp & 0x3000) >> 12;
+-      if (mctGetLogicalCPUID(0) & AMD_FAM10_REV_D)    /* revision D */
+-              cmp_cap |= (dtemp & 0x8000) >> 13;
++      if (fam15h) {
++              cmp_cap = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 
5)), 0x84) & 0xff;
++      } else {
++              dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 
0xe8);
++              cmp_cap = (dtemp & 0x3000) >> 12;
++              if (mctGetLogicalCPUID(0) & (AMD_FAM10_REV_D | AMD_FAM15_ALL))  
/* revision D or higher */
++                      cmp_cap |= (dtemp & 0x8000) >> 13;
++      }
++
+       /* Get number of nodes */
+       dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 0)), 0x60);
+       node_count = ((dtemp & 0x70) >> 4) + 1;
+@@ -169,6 +183,14 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+       /* Compute total number of cores installed in system */
+       total_core_count = cores_per_node * node_count;
+ 
++      /* Get number of boost states */
++      uint8_t boost_count = 0;
++      dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 4)), 0x15c);
++      if (fam10h_rev_e)
++              boost_count = (dtemp >> 2) & 0x1;
++      else if (mctGetLogicalCPUID(0) & AMD_FAM15_ALL)
++              boost_count = (dtemp >> 2) & 0x7;
++
+       Pstate_num = 0;
+ 
+       /* See if the CPUID(0x80000007) returned EDX[7]==1b */
+@@ -205,7 +227,7 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+ 
+       /* Get PSmax's index */
+       msr = rdmsr(0xC0010061);
+-      Pstate_max = (uint8_t) ((msr.lo >> PS_MAX_VAL_SHFT) & BIT_MASK_3);
++      Pstate_max = (uint8_t) ((msr.lo >> PS_MAX_VAL_SHFT) & 
((fam15h)?BIT_MASK_7:BIT_MASK_3));
+ 
+       /* Determine if all enabled Pstates have the same fidvid */
+       uint8_t i;
+@@ -219,10 +241,14 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+               }
+       }
+ 
++      /* Family 15h uses slightly different PSmax numbering */
++      if (fam15h)
++              Pstate_max++;
++
+       /* Populate tables with all Pstate information */
+       for (Pstate_num = 0; Pstate_num < Pstate_max; Pstate_num++) {
+               /* Get power state information */
+-              msr = rdmsr(0xC0010064 + Pstate_num);
++              msr = rdmsr(0xC0010064 + Pstate_num + boost_count);
+               cpufid = (msr.lo & 0x3f);
+               cpudid = (msr.lo & 0x1c0) >> 6;
+               cpuvid = (msr.lo & 0xfe00) >> 9;
+@@ -232,12 +258,10 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+               if (pviModeFlag) {
+                       if (cpuvid >= 0x20) {
+                               core_voltage = 7625 - (((cpuvid - 0x20) * 
10000) / 80);
+-                      }
+-                      else {
++                      } else {
+                               core_voltage = 15500 - ((cpuvid * 10000) / 40);
+                       }
+-              }
+-              else {
++              } else {
+                       cpuvid = cpuvid & 0x7f;
+                       if (cpuvid >= 0x7c)
+                               core_voltage = 0;
+diff --git a/src/cpu/amd/family_10h-family_15h/processor_name.c 
b/src/cpu/amd/family_10h-family_15h/processor_name.c
+index 12c45c9..fbd0452 100644
+--- a/src/cpu/amd/family_10h-family_15h/processor_name.c
++++ b/src/cpu/amd/family_10h-family_15h/processor_name.c
+@@ -33,6 +33,10 @@
+ #include <cpu/amd/mtrr.h>
+ #include <cpu/cpu.h>
+ #include <cpu/amd/model_10xxx_rev.h>
++#include <device/device.h>
++#include <device/pci.h>
++#include <device/pnp.h>
++#include <device/pci_ops.h>
+ 
+ /* The maximum length of CPU names is 48 bytes, including the final NULL byte.
+  * If you change these names your BIOS will _NOT_ pass the AMD validation and
+@@ -212,104 +216,138 @@ static int strcpymax(char *dst, const char *src, int 
buflen)
+       return i;
+ }
+ 
++#define NAME_STRING_MAXLEN 48
+ 
+ int init_processor_name(void)
+ {
+-      /* variable names taken from fam10 revision guide for clarity */
+-      u32 BrandId;    /* CPUID Fn8000_0001_EBX */
+-      u8 String1;     /* BrandID[14:11] */
+-      u8 String2;     /* BrandID[3:0] */
+-      u8 Model;       /* BrandID[10:4] */
+-      u8 Pg;          /* BrandID[15] */
+-      u8 PkgTyp;      /* BrandID[31:28] */
+-      u8 NC;          /* CPUID Fn8000_0008_ECX */
+-      const char *processor_name_string = unknown;
+-      char program_string[48];
+-      u32 *p_program_string = (u32 *)program_string;
+       msr_t msr;
+-      int i, j = 0, str2_checkNC = 1;
+-      const struct str_s *str, *str2;
++      ssize_t i;
++      char program_string[NAME_STRING_MAXLEN];
++      u32 *p_program_string = (u32 *)program_string;
++      uint8_t fam15h = 0;
++      uint32_t family;
+ 
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+ 
+-      /* Find out which CPU brand it is */
+-      BrandId = cpuid_ebx(0x80000001);
+-      String1 = (u8)((BrandId >> 11) & 0x0F);
+-      String2 = (u8)((BrandId >> 0) & 0x0F);
+-      Model = (u8)((BrandId >> 4) & 0x7F);
+-      Pg = (u8)((BrandId >> 15) & 0x01);
+-      PkgTyp = (u8)((BrandId >> 28) & 0x0F);
+-      NC = (u8)(cpuid_ecx(0x80000008) & 0xFF);
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
+ 
+       /* null the string */
+       memset(program_string, 0, sizeof(program_string));
+ 
+-      if (!Model) {
+-              processor_name_string = Pg ? thermal : sample;
+-              goto done;
+-      }
+-
+-      switch (PkgTyp) {
+-      case 0:         /* F1207 */
+-              str = String1_socket_F;
+-              str2 = String2_socket_F;
+-              str2_checkNC = 0;
+-              break;
+-      case 1:         /* AM2 */
+-              str = String1_socket_AM2;
+-              str2 = String2_socket_AM2;
+-              break;
+-      case 3:         /* G34 */
+-              str = String1_socket_G34;
+-              str2 = String2_socket_G34;
+-              str2_checkNC = 0;
+-              break;
+-      case 5:         /* C32 */
+-              str = String1_socket_C32;
+-              str2 = String2_socket_C32;
+-              break;
+-      default:
+-              goto done;
+-      }
++      if (fam15h) {
++              /* Family 15h or later */
++              uint32_t dword;
++              device_t cpu_fn5_dev = dev_find_slot(0, PCI_DEVFN(0x18, 5));
++              pci_write_config32(cpu_fn5_dev, 0x194, 0);
++              dword = pci_read_config32(cpu_fn5_dev, 0x198);
++              if (dword == 0) {
++                      strcpymax(program_string, sample, 
sizeof(program_string));
++              } else {
++                      /* Assemble the string from PCI configuration register 
contents */
++                      for (i = 0; i < 12; i++) {
++                              pci_write_config32(cpu_fn5_dev, 0x194, i);
++                              p_program_string[i] = 
pci_read_config32(cpu_fn5_dev, 0x198);
++                      }
++
++                      /* Correctly place the null terminator */
++                      for (i = (NAME_STRING_MAXLEN - 2); i > 0; i--) {
++                              if (program_string[i] != 0x20)
++                                      break;
++                      }
++                      program_string[i + 1] = 0;
++              }
++      } else {
++              /* variable names taken from fam10 revision guide for clarity */
++              u32 BrandId;    /* CPUID Fn8000_0001_EBX */
++              u8 String1;     /* BrandID[14:11] */
++              u8 String2;     /* BrandID[3:0] */
++              u8 Model;       /* BrandID[10:4] */
++              u8 Pg;          /* BrandID[15] */
++              u8 PkgTyp;      /* BrandID[31:28] */
++              u8 NC;          /* CPUID Fn8000_0008_ECX */
++              const char *processor_name_string = unknown;
++              int j = 0, str2_checkNC = 1;
++              const struct str_s *str, *str2;
++
++              /* Find out which CPU brand it is */
++              BrandId = cpuid_ebx(0x80000001);
++              String1 = (u8)((BrandId >> 11) & 0x0F);
++              String2 = (u8)((BrandId >> 0) & 0x0F);
++              Model = (u8)((BrandId >> 4) & 0x7F);
++              Pg = (u8)((BrandId >> 15) & 0x01);
++              PkgTyp = (u8)((BrandId >> 28) & 0x0F);
++              NC = (u8)(cpuid_ecx(0x80000008) & 0xFF);
++
++              if (!Model) {
++                      processor_name_string = Pg ? thermal : sample;
++                      goto done;
++              }
+ 
+-      /* String1 */
+-      for (i = 0; str[i].value; i++) {
+-              if ((str[i].Pg == Pg) &&
+-                  (str[i].NC == NC) &&
+-                  (str[i].String == String1)) {
+-                      processor_name_string = str[i].value;
++              switch (PkgTyp) {
++              case 0:         /* F1207 */
++                      str = String1_socket_F;
++                      str2 = String2_socket_F;
++                      str2_checkNC = 0;
++                      break;
++              case 1:         /* AM2 */
++                      str = String1_socket_AM2;
++                      str2 = String2_socket_AM2;
++                      break;
++              case 3:         /* G34 */
++                      str = String1_socket_G34;
++                      str2 = String2_socket_G34;
++                      str2_checkNC = 0;
++                      break;
++              case 5:         /* C32 */
++                      str = String1_socket_C32;
++                      str2 = String2_socket_C32;
+                       break;
++              default:
++                      goto done;
+               }
+-      }
+ 
+-      if (!str[i].value)
+-              goto done;
++              /* String1 */
++              for (i = 0; str[i].value; i++) {
++                      if ((str[i].Pg == Pg) &&
++                      (str[i].NC == NC) &&
++                      (str[i].String == String1)) {
++                              processor_name_string = str[i].value;
++                              break;
++                      }
++              }
+ 
+-      j = strcpymax(program_string, processor_name_string,
+-                    sizeof(program_string));
++              if (!str[i].value)
++                      goto done;
+ 
+-      /* Translate Model from 01-99 to ASCII and put it on the end.
+-       * Numbers less than 10 should include a leading zero, e.g., 09.*/
+-      if (Model < 100 && j < sizeof(program_string) - 2) {
+-              program_string[j++] = (Model / 10) + '0';
+-              program_string[j++] = (Model % 10) + '0';
+-      }
++              j = strcpymax(program_string, processor_name_string,
++                      sizeof(program_string));
+ 
+-      processor_name_string = unknown2;
+-
+-      /* String 2 */
+-      for(i = 0; str2[i].value; i++) {
+-              if ((str2[i].Pg == Pg) &&
+-                  ((str2[i].NC == NC) || !str2_checkNC) &&
+-                  (str2[i].String == String2)) {
+-                      processor_name_string = str2[i].value;
+-                      break;
++              /* Translate Model from 01-99 to ASCII and put it on the end.
++              * Numbers less than 10 should include a leading zero, e.g., 
09.*/
++              if (Model < 100 && j < sizeof(program_string) - 2) {
++                      program_string[j++] = (Model / 10) + '0';
++                      program_string[j++] = (Model % 10) + '0';
+               }
+-      }
+ 
++              processor_name_string = unknown2;
++
++              /* String 2 */
++              for(i = 0; str2[i].value; i++) {
++                      if ((str2[i].Pg == Pg) &&
++                      ((str2[i].NC == NC) || !str2_checkNC) &&
++                      (str2[i].String == String2)) {
++                              processor_name_string = str2[i].value;
++                              break;
++                      }
++              }
+ 
+-done:
+-      strcpymax(&program_string[j], processor_name_string,
+-                sizeof(program_string) - j);
++      done:
++              strcpymax(&program_string[j], processor_name_string,
++                      sizeof(program_string) - j);
++      }
+ 
+       printk(BIOS_DEBUG, "CPU model: %s\n", program_string);
+ 
+diff --git a/src/cpu/amd/family_10h-family_15h/update_microcode.c 
b/src/cpu/amd/family_10h-family_15h/update_microcode.c
+index 51aca35..3b2f5dd 100644
+--- a/src/cpu/amd/family_10h-family_15h/update_microcode.c
++++ b/src/cpu/amd/family_10h-family_15h/update_microcode.c
+@@ -28,6 +28,7 @@ struct id_mapping {
+ 
+ static u16 get_equivalent_processor_rev_id(u32 orig_id) {
+       static const struct id_mapping id_mapping_table[] = {
++              /* Family 10h */
+               { 0x100f00, 0x1000 },
+               { 0x100f01, 0x1000 },
+               { 0x100f02, 0x1000 },
+@@ -42,8 +43,13 @@ static u16 get_equivalent_processor_rev_id(u32 orig_id) {
+               { 0x100f62, 0x1062 }, /* DA-C2 */
+               { 0x100f63, 0x1043 }, /* DA-C3 */
+               { 0x100f81, 0x1081 }, /* HY-D1 */
++              { 0x100f91, 0x1081 }, /* HY-D1 */
+               { 0x100fa0, 0x10A0 }, /* PH-E0 */
+ 
++              /* Family 15h */
++              { 0x600f12, 0x6012 }, /* OR-B2 */
++              { 0x600f20, 0x6020 }, /* OR-C0 */
++
+               /* Array terminator */
+               { 0xffffff, 0x0000 },
+       };
+diff --git a/src/cpu/amd/model_fxx/init_cpus.c 
b/src/cpu/amd/model_fxx/init_cpus.c
+index 12d3a95..3960c03 100644
+--- a/src/cpu/amd/model_fxx/init_cpus.c
++++ b/src/cpu/amd/model_fxx/init_cpus.c
+@@ -190,7 +190,7 @@ void allow_all_aps_stop(u32 bsp_apicid)
+ 
+ static void STOP_CAR_AND_CPU(void)
+ {
+-      disable_cache_as_ram(); // inline
++      disable_cache_as_ram(0);        // inline
+       /* stop all cores except node0/core0 the bsp .... */
+       stop_this_cpu();
+ }
+diff --git a/src/cpu/amd/quadcore/quadcore.c b/src/cpu/amd/quadcore/quadcore.c
+index 9c21e94..8a9b5ed 100644
+--- a/src/cpu/amd/quadcore/quadcore.c
++++ b/src/cpu/amd/quadcore/quadcore.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -26,16 +27,41 @@
+ 
+ #include "cpu/amd/quadcore/quadcore_id.c"
+ 
++/* get_boot_apic_id and wait_cpu_state located in init_cpus.c */
++uint32_t get_boot_apic_id(uint8_t node, uint32_t core);
++uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2);
++
++static inline uint8_t is_fam15h(void)
++{
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      return fam15h;
++}
++
+ static u32 get_core_num_in_bsp(u32 nodeid)
+ {
+       u32 dword;
+-      dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
+-      dword >>= 12;
+-      /* Bit 15 is CmpCap[2] since Revision D. */
+-      if ((cpuid_ecx(0x80000008) & 0xff) > 3)
+-          dword = ((dword & 8) >> 1) | (dword & 3);
+-      else
+-          dword &= 3;
++      if (is_fam15h()) {
++              /* Family 15h moved CmpCap to F5x84 [7:0] */
++              dword = pci_read_config32(NODE_PCI(nodeid, 5), 0x84);
++              dword &= 0xff;
++      } else {
++              dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
++              dword >>= 12;
++              /* Bit 15 is CmpCap[2] since Revision D. */
++              if ((cpuid_ecx(0x80000008) & 0xff) > 3)
++              dword = ((dword & 8) >> 1) | (dword & 3);
++              else
++              dword &= 3;
++      }
+       return dword;
+ }
+ 
+@@ -50,28 +76,68 @@ static u8 set_apicid_cpuid_lo(void)
+       return 1;
+ }
+ 
+-static void real_start_other_core(u32 nodeid, u32 cores)
++static void real_start_other_core(uint32_t nodeid, uint32_t cores)
+ {
+-      u32 dword, i;
++      ssize_t i;
++      uint32_t dword;
+ 
+       printk(BIOS_DEBUG, "Start other core - nodeid: %02x  cores: %02x\n", 
nodeid, cores);
+ 
+       /* set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4
+          accesses and error logging to core0 */
+       dword = pci_read_config32(NODE_PCI(nodeid, 3), 0x44);
+-      dword |= 1 << 27;       // NbMcaToMstCpuEn bit
++      dword |= 1 << 30;       /* SyncFloodOnDramAdrParErr=1 */
++      dword |= 1 << 27;       /* NbMcaToMstCpuEn=1 */
++      dword |= 1 << 21;       /* SyncFloodOnAnyUcErr=1 */
++      dword |= 1 << 20;       /* SyncFloodOnWDT=1 */
++      dword |= 1 << 2;        /* SyncFloodOnDramUcEcc=1 */
+       pci_write_config32(NODE_PCI(nodeid, 3), 0x44, dword);
+-      // set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
+-      dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
+-      dword |= 1 << 5;
+-      pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);
+-
+-      if(cores > 1) {
+-              dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
+-              for (i = 0; i < cores - 1; i++) {
+-                      dword |= 1 << i;
++      if (is_fam15h()) {
++              uint32_t core_activation_flags = 0;
++              uint32_t active_cores = 0;
++
++              /* Set PCI_DEV(0, 0x18+nodeid, 0), 0x1dc bits 7:1 to start 
cores */
++              dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x1dc);
++              for (i = 1; i < cores + 1; i++) {
++                      core_activation_flags |= 1 << i;
++              }
++
++              /* Start the first core of each compute unit */
++              active_cores |= core_activation_flags & 0x55;
++              pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword | 
active_cores);
++
++              /* Each core shares a single set of MTRR registers with
++               * another core in the same compute unit, therefore, it
++               * is important that one core in each CU starts in advance
++               * of the other in order to avoid one core stomping all over
++               * the other core's settings.
++               */
++
++              /* Wait for the first core of each compute unit to start... */
++              uint32_t timeout;
++              for (i = 1; i < cores + 1; i++) {
++                      if (!(i & 0x1)) {
++                              uint32_t ap_apicid = get_boot_apic_id(nodeid, 
i);
++                              timeout = wait_cpu_state(ap_apicid, 
F10_APSTATE_ASLEEP, F10_APSTATE_ASLEEP);
++                      }
++              }
++
++              /* Start the second core of each compute unit */
++              active_cores |= core_activation_flags & 0xaa;
++              pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword | 
active_cores);
++      } else {
++              // set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
++              dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
++              dword |= 1 << 5;
++              pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);
++
++              if (cores > 1) {
++                      dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
++                      for (i = 0; i < cores - 1; i++) {
++                              dword |= 1 << i;
++                      }
++                      pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
+               }
+-              pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
+       }
+ }
+ 
+@@ -91,10 +157,9 @@ static void start_other_cores(void)
+ 
+       for (nodeid = 0; nodeid < nodes; nodeid++) {
+               u32 cores = get_core_num_in_bsp(nodeid);
+-              printk(BIOS_DEBUG, "init node: %02x  cores: %02x \n", nodeid, 
cores);
++              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1 \n", 
nodeid, cores);
+               if (cores > 0) {
+                       real_start_other_core(nodeid, cores);
+               }
+       }
+-
+ }
+diff --git a/src/cpu/amd/quadcore/quadcore_id.c 
b/src/cpu/amd/quadcore/quadcore_id.c
+index c5921de..c0537b3 100644
+--- a/src/cpu/amd/quadcore/quadcore_id.c
++++ b/src/cpu/amd/quadcore/quadcore_id.c
+@@ -43,9 +43,12 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
+ {
+       struct node_core_id id;
+       uint8_t apicid;
++      uint8_t fam15h = 0;
+       uint8_t rev_gte_d = 0;
+       uint8_t dual_node = 0;
+       uint32_t f3xe8;
++      uint32_t family;
++      uint32_t model;
+ 
+ #ifdef __PRE_RAM__
+       f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
+@@ -53,7 +56,17 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
+       f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
+ #endif
+ 
+-      if (cpuid_eax(0x80000001) >= 0x8)
++      family = model = cpuid_eax(0x80000001);
++      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f) {
++              /* Family 15h or later */
++              fam15h = 1;
++              nb_cfg_54 = 1;
++      }
++
++      if ((model >= 0x8) || fam15h)
+               /* Revision D or later */
+               rev_gte_d = 1;
+ 
+@@ -67,7 +80,13 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
+        */
+       apicid = (cpuid_ebx(1) >> 24) & 0xff;
+       if( nb_cfg_54) {
+-              if (rev_gte_d && dual_node) {
++              if (fam15h && dual_node) {
++                      id.coreid = apicid & 0x1f;
++                      id.nodeid = (apicid & 0x60) >> 5;
++              } else if (fam15h && !dual_node) {
++                      id.coreid = apicid & 0xf;
++                      id.nodeid = (apicid & 0x70) >> 4;
++              } else if (rev_gte_d && dual_node) {
+                       id.coreid = apicid & 0xf;
+                       id.nodeid = (apicid & 0x30) >> 4;
+               } else if (rev_gte_d && !dual_node) {
+@@ -90,7 +109,25 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
+               }
+       }
+ 
+-      if (rev_gte_d && dual_node) {
++      if (fam15h && dual_node) {
++              /* Coreboot expects each separate processor die to be on a 
different nodeid.
++               * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
++               */
++              uint32_t f5x84;
++              uint8_t core_count;
++
++#ifdef __PRE_RAM__
++              f5x84 = pci_read_config32(NODE_PCI(0, 5), 0x84);
++#else
++              f5x84 = pci_read_config32(get_node_pci(0, 5), 0x84);
++#endif
++              core_count = (f5x84 & 0xff) + 1;
++              id.nodeid = id.nodeid * 2;
++              if (id.coreid >= core_count) {
++                      id.nodeid += 1;
++                      id.coreid = id.coreid - core_count;
++              }
++      } else if (rev_gte_d && dual_node) {
+               /* Coreboot expects each separate processor die to be on a 
different nodeid.
+                * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
+                */
+diff --git a/src/include/cpu/amd/model_10xxx_msr.h 
b/src/include/cpu/amd/model_10xxx_msr.h
+index 6c7dece..7d78e2d 100644
+--- a/src/include/cpu/amd/model_10xxx_msr.h
++++ b/src/include/cpu/amd/model_10xxx_msr.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -32,7 +33,13 @@
+ #define IC_CFG_MSR                    0xC0011021
+ #define DC_CFG_MSR                    0xC0011022
+ #define BU_CFG_MSR                    0xC0011023
++#define FP_CFG_MSR                    0xC0011028
++#define DE_CFG_MSR                    0xC0011029
+ #define BU_CFG2_MSR                   0xC001102A
++#define BU_CFG3_MSR                   0xC001102B
++#define EX_CFG_MSR                    0xC001102C
++#define LS_CFG2_MSR                   0xC001102D
++#define IBS_OP_DATA3_MSR              0xC0011037
+ 
+ #define CPU_ID_FEATURES_MSR           0xC0011004
+ #define CPU_ID_HYPER_EXT_FEATURES     0xC001100d
+diff --git a/src/mainboard/advansus/a785e-i/romstage.c 
b/src/mainboard/advansus/a785e-i/romstage.c
+index 4c2b38a..ab717fd 100644
+--- a/src/mainboard/advansus/a785e-i/romstage.c
++++ b/src/mainboard/advansus/a785e-i/romstage.c
+@@ -131,7 +131,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/amd/bimini_fam10/romstage.c 
b/src/mainboard/amd/bimini_fam10/romstage.c
+index e2bd351..5e2cf82 100644
+--- a/src/mainboard/amd/bimini_fam10/romstage.c
++++ b/src/mainboard/amd/bimini_fam10/romstage.c
+@@ -123,7 +123,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/amd/mahogany_fam10/romstage.c 
b/src/mainboard/amd/mahogany_fam10/romstage.c
+index 74bc9d5..025a8bb 100644
+--- a/src/mainboard/amd/mahogany_fam10/romstage.c
++++ b/src/mainboard/amd/mahogany_fam10/romstage.c
+@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c 
b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
+index 20d46e6..5063439 100644
+--- a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
++++ b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
+@@ -231,7 +231,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/amd/tilapia_fam10/romstage.c 
b/src/mainboard/amd/tilapia_fam10/romstage.c
+index 89100b1..e37bc08 100644
+--- a/src/mainboard/amd/tilapia_fam10/romstage.c
++++ b/src/mainboard/amd/tilapia_fam10/romstage.c
+@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/asus/kfsn4-dre/romstage.c 
b/src/mainboard/asus/kfsn4-dre/romstage.c
+index 5d1f5a6..dd5c7dc 100644
+--- a/src/mainboard/asus/kfsn4-dre/romstage.c
++++ b/src/mainboard/asus/kfsn4-dre/romstage.c
+@@ -245,7 +245,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index a3f3310..a58fd0f 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -354,7 +354,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+@@ -512,4 +512,4 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 **List)
+ {
+       return 0;
+-}
+\ No newline at end of file
++}
+diff --git a/src/mainboard/asus/m4a78-em/romstage.c 
b/src/mainboard/asus/m4a78-em/romstage.c
+index 82f30d9..82b96bf 100644
+--- a/src/mainboard/asus/m4a78-em/romstage.c
++++ b/src/mainboard/asus/m4a78-em/romstage.c
+@@ -127,7 +127,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/asus/m4a785-m/romstage.c 
b/src/mainboard/asus/m4a785-m/romstage.c
+index 780bf81..30975fa 100644
+--- a/src/mainboard/asus/m4a785-m/romstage.c
++++ b/src/mainboard/asus/m4a785-m/romstage.c
+@@ -127,7 +127,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/asus/m5a88-v/romstage.c 
b/src/mainboard/asus/m5a88-v/romstage.c
+index 38761a6..4edaba2 100644
+--- a/src/mainboard/asus/m5a88-v/romstage.c
++++ b/src/mainboard/asus/m5a88-v/romstage.c
+@@ -128,7 +128,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/avalue/eax-785e/romstage.c 
b/src/mainboard/avalue/eax-785e/romstage.c
+index 764a5c6..447012b 100644
+--- a/src/mainboard/avalue/eax-785e/romstage.c
++++ b/src/mainboard/avalue/eax-785e/romstage.c
+@@ -132,7 +132,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/gigabyte/ma785gm/romstage.c 
b/src/mainboard/gigabyte/ma785gm/romstage.c
+index db4e449..444e59d 100644
+--- a/src/mainboard/gigabyte/ma785gm/romstage.c
++++ b/src/mainboard/gigabyte/ma785gm/romstage.c
+@@ -122,7 +122,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/gigabyte/ma785gmt/romstage.c 
b/src/mainboard/gigabyte/ma785gmt/romstage.c
+index 4ce7c58..705d7c5 100644
+--- a/src/mainboard/gigabyte/ma785gmt/romstage.c
++++ b/src/mainboard/gigabyte/ma785gmt/romstage.c
+@@ -122,7 +122,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/gigabyte/ma78gm/romstage.c 
b/src/mainboard/gigabyte/ma78gm/romstage.c
+index d2a0b95..5d21801 100644
+--- a/src/mainboard/gigabyte/ma78gm/romstage.c
++++ b/src/mainboard/gigabyte/ma78gm/romstage.c
+@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/hp/dl165_g6_fam10/romstage.c 
b/src/mainboard/hp/dl165_g6_fam10/romstage.c
+index 97e60d5..26c0bb9 100644
+--- a/src/mainboard/hp/dl165_g6_fam10/romstage.c
++++ b/src/mainboard/hp/dl165_g6_fam10/romstage.c
+@@ -137,7 +137,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/iei/kino-780am2-fam10/romstage.c 
b/src/mainboard/iei/kino-780am2-fam10/romstage.c
+index edbae3a..321eea6 100644
+--- a/src/mainboard/iei/kino-780am2-fam10/romstage.c
++++ b/src/mainboard/iei/kino-780am2-fam10/romstage.c
+@@ -125,7 +125,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/jetway/pa78vm5/romstage.c 
b/src/mainboard/jetway/pa78vm5/romstage.c
+index 16bb089..93dd2ce 100644
+--- a/src/mainboard/jetway/pa78vm5/romstage.c
++++ b/src/mainboard/jetway/pa78vm5/romstage.c
+@@ -130,7 +130,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/msi/ms9652_fam10/romstage.c 
b/src/mainboard/msi/ms9652_fam10/romstage.c
+index 4ea3306..5da971f 100644
+--- a/src/mainboard/msi/ms9652_fam10/romstage.c
++++ b/src/mainboard/msi/ms9652_fam10/romstage.c
+@@ -150,7 +150,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/supermicro/h8dmr_fam10/romstage.c 
b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
+index c224dbc..1425546 100644
+--- a/src/mainboard/supermicro/h8dmr_fam10/romstage.c
++++ b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
+@@ -146,7 +146,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/supermicro/h8qme_fam10/romstage.c 
b/src/mainboard/supermicro/h8qme_fam10/romstage.c
+index 0f9445b..4721eba 100644
+--- a/src/mainboard/supermicro/h8qme_fam10/romstage.c
++++ b/src/mainboard/supermicro/h8qme_fam10/romstage.c
+@@ -214,7 +214,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/mainboard/supermicro/h8scm_fam10/romstage.c 
b/src/mainboard/supermicro/h8scm_fam10/romstage.c
+index 4ea14fe..858aca0 100644
+--- a/src/mainboard/supermicro/h8scm_fam10/romstage.c
++++ b/src/mainboard/supermicro/h8scm_fam10/romstage.c
+@@ -136,7 +136,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       /* TODO: The Kernel must support 12 processor, otherwise the interrupt
+diff --git a/src/mainboard/tyan/s2912_fam10/romstage.c 
b/src/mainboard/tyan/s2912_fam10/romstage.c
+index 0030619..cdf51b1 100644
+--- a/src/mainboard/tyan/s2912_fam10/romstage.c
++++ b/src/mainboard/tyan/s2912_fam10/romstage.c
+@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       post_code(0x33);
+ 
+-      cpuSetAMDMSR();
++      cpuSetAMDMSR(0);
+       post_code(0x34);
+ 
+       amd_ht_init(sysinfo);
+diff --git a/src/northbridge/amd/amdfam10/Kconfig 
b/src/northbridge/amd/amdfam10/Kconfig
+index ada5b9f..cb0d109 100644
+--- a/src/northbridge/amd/amdfam10/Kconfig
++++ b/src/northbridge/amd/amdfam10/Kconfig
+@@ -96,7 +96,7 @@ endif
+ if HAVE_ACPI_RESUME
+       config S3_DATA_SIZE
+               int
+-              default 16384
++              default 32768
+ endif
+ 
+ if DIMM_DDR2
+diff --git a/src/northbridge/amd/amdfam10/Makefile.inc 
b/src/northbridge/amd/amdfam10/Makefile.inc
+index b4097b4..4098dce 100644
+--- a/src/northbridge/amd/amdfam10/Makefile.inc
++++ b/src/northbridge/amd/amdfam10/Makefile.inc
+@@ -2,6 +2,8 @@ ifeq ($(CONFIG_NORTHBRIDGE_AMD_AMDFAM10),y)
+ 
+ ramstage-y += northbridge.c
+ ramstage-y += misc_control.c
++ramstage-y += link_control.c
++ramstage-y += nb_control.c
+ romstage-y += amdfam10_util.c
+ ramstage-y += amdfam10_util.c
+ 
+diff --git a/src/northbridge/amd/amdfam10/amdfam10.h 
b/src/northbridge/amd/amdfam10/amdfam10.h
+index a1e08a0..b724394 100644
+--- a/src/northbridge/amd/amdfam10/amdfam10.h
++++ b/src/northbridge/amd/amdfam10/amdfam10.h
+@@ -962,9 +962,12 @@ that are corresponding to 0x01, 0x02, 0x03, 0x05, 0x06, 
0x07
+ 
+ #define LAPIC_MSG_REG 0x380
+ #define F10_APSTATE_STARTED 0x13  // start of AP execution
+-#define F10_APSTATE_STOPPED 0x14  // allow AP to stop
++#define F10_APSTATE_ASLEEP  0x14  // AP sleeping
++#define F10_APSTATE_STOPPED 0x15  // allow AP to stop
+ #define F10_APSTATE_RESET   0x01  // waiting for warm reset
+ 
++#define MAX_CORES_SUPPORTED 128
++
+ #include "nums.h"
+ 
+ #ifdef __PRE_RAM__
+@@ -1038,7 +1041,6 @@ struct sys_info {
+ 
+       struct MCTStatStruc MCTstat;
+       struct DCTStatStruc DCTstatA[NODE_NUMS];
+-
+ } __attribute__((packed));
+ 
+ #ifdef __PRE_RAM__
+diff --git a/src/northbridge/amd/amdfam10/amdfam10_util.c 
b/src/northbridge/amd/amdfam10/amdfam10_util.c
+index 423bb73..a4045bdf 100644
+--- a/src/northbridge/amd/amdfam10/amdfam10_util.c
++++ b/src/northbridge/amd/amdfam10/amdfam10_util.c
+@@ -34,14 +34,14 @@ u32 Get_NB32(u32 dev, u32 reg)
+ }
+ #endif
+ 
+-u32 mctGetLogicalCPUID(u32 Node)
++uint64_t mctGetLogicalCPUID(u32 Node)
+ {
+       /* Converts the CPUID to a logical ID MASK that is used to check
+        CPU version support versions */
+       u32 dev;
+       u32 val, valx;
+       u32 family, model, stepping;
+-      u32 ret;
++      uint64_t ret;
+ 
+       if (Node == 0xFF) { /* current node */
+               val = cpuid_eax(0x80000001);
+@@ -100,9 +100,16 @@ u32 mctGetLogicalCPUID(u32 Node)
+       case 0x100a0:
+               ret = AMD_PH_E0;
+               break;
++      case 0x15012:
++      case 0x1501f:
++              ret = AMD_OR_B2;
++              break;
++      case 0x15020:
++              ret = AMD_OR_C0;
++              break;
+       default:
+               /* FIXME: mabe we should die() here. */
+-              printk(BIOS_ERR, "FIXME! CPU Version unknown or not supported! 
\n");
++              printk(BIOS_ERR, "FIXME! CPU Version unknown or not supported! 
%08x\n", valx);
+               ret = 0;
+       }
+ 
+diff --git a/src/northbridge/amd/amdfam10/link_control.c 
b/src/northbridge/amd/amdfam10/link_control.c
+new file mode 100644
+index 0000000..1091ef4
+--- /dev/null
++++ b/src/northbridge/amd/amdfam10/link_control.c
+@@ -0,0 +1,86 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
++ */
++
++/* Configure various power control registers, including processor
++ * boost support.
++ */
++
++#include <console/console.h>
++#include <device/device.h>
++#include <device/pci.h>
++#include <device/pci_ids.h>
++#include <device/pci_ops.h>
++#include <pc80/mc146818rtc.h>
++#include <lib.h>
++#include <cpu/amd/model_10xxx_rev.h>
++
++#include "amdfam10.h"
++
++static inline uint8_t is_fam15h(void)
++{
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      return fam15h;
++}
++
++static void nb_control_init(struct device *dev)
++{
++      uint32_t dword;
++
++      printk(BIOS_DEBUG, "NB: Function 4 Link Control.. ");
++
++      if (is_fam15h()) {
++              /* Enable APM */
++              dword = pci_read_config32(dev, 0x15c);
++              dword |= (0x1 << 7);                    /* ApmMasterEn = 1 */
++              pci_write_config32(dev, 0x15c, dword);
++      }
++
++      printk(BIOS_DEBUG, "done.\n");
++}
++
++
++static struct device_operations mcf4_ops  = {
++      .read_resources   = pci_dev_read_resources,
++      .set_resources    = pci_dev_set_resources,
++      .enable_resources = pci_dev_enable_resources,
++      .init             = nb_control_init,
++      .scan_bus         = 0,
++      .ops_pci          = 0,
++};
++
++static const struct pci_driver mcf4_driver_fam10 __pci_driver = {
++      .ops    = &mcf4_ops,
++      .vendor = PCI_VENDOR_ID_AMD,
++      .device = 0x1204,
++};
++
++static const struct pci_driver mcf4_driver_fam15 __pci_driver = {
++      .ops    = &mcf4_ops,
++      .vendor = PCI_VENDOR_ID_AMD,
++      .device = 0x1604,
++};
+\ No newline at end of file
+diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
+index 90a4db1..8777e8f 100644
+--- a/src/northbridge/amd/amdfam10/misc_control.c
++++ b/src/northbridge/amd/amdfam10/misc_control.c
+@@ -4,6 +4,7 @@
+  * Copyright (C) 2003 by Eric Biederman
+  * Copyright (C) Stefan Reinauer
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -152,3 +153,9 @@ static const struct pci_driver mcf3_driver __pci_driver = {
+       .vendor = PCI_VENDOR_ID_AMD,
+       .device = 0x1203,
+ };
++
++static const struct pci_driver mcf3_driver_fam15 __pci_driver = {
++      .ops    = &mcf3_ops,
++      .vendor = PCI_VENDOR_ID_AMD,
++      .device = 0x1603,
++};
+diff --git a/src/northbridge/amd/amdfam10/nb_control.c 
b/src/northbridge/amd/amdfam10/nb_control.c
+new file mode 100644
+index 0000000..f95b6f8
+--- /dev/null
++++ b/src/northbridge/amd/amdfam10/nb_control.c
+@@ -0,0 +1,85 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,  MA 02110-1301 USA
++ */
++
++/* Configure various power control registers, including processor boost
++ * and TDP monitoring support.
++ */
++
++#include <console/console.h>
++#include <device/device.h>
++#include <device/pci.h>
++#include <device/pci_ids.h>
++#include <device/pci_ops.h>
++#include <pc80/mc146818rtc.h>
++#include <lib.h>
++#include <cpu/amd/model_10xxx_rev.h>
++
++#include "amdfam10.h"
++
++static void nb_control_init(struct device *dev)
++{
++      uint32_t dword;
++      uint32_t f5x80;
++      uint8_t cu_enabled;
++      uint8_t compute_unit_count = 0;
++
++      printk(BIOS_DEBUG, "NB: Function 5 Northbridge Control.. ");
++
++      /* Determine the number of active compute units on this node */
++      f5x80 = pci_read_config32(dev, 0x80);
++      cu_enabled = f5x80 & 0xf;
++      if (cu_enabled == 0x1)
++              compute_unit_count = 1;
++      if (cu_enabled == 0x3)
++              compute_unit_count = 2;
++      if (cu_enabled == 0x7)
++              compute_unit_count = 3;
++      if (cu_enabled == 0xf)
++              compute_unit_count = 4;
++
++      /* Configure Processor TDP Running Average */
++      dword = pci_read_config32(dev, 0xe0);
++      dword &= ~0xf;                          /* RunAvgRange = 0x9 */
++      dword |= 0x9;
++      pci_write_config32(dev, 0xe0, dword);
++
++      /* Configure northbridge P-states */
++      dword = pci_read_config32(dev, 0xe0);
++      dword &= ~(0x7 << 9);                   /* NbPstateThreshold = 
compute_unit_count */
++      dword |= (compute_unit_count & 0x7) << 9;
++      pci_write_config32(dev, 0xe0, dword);
++
++      printk(BIOS_DEBUG, "done.\n");
++}
++
++
++static struct device_operations mcf5_ops  = {
++      .read_resources   = pci_dev_read_resources,
++      .set_resources    = pci_dev_set_resources,
++      .enable_resources = pci_dev_enable_resources,
++      .init             = nb_control_init,
++      .scan_bus         = 0,
++      .ops_pci          = 0,
++};
++
++static const struct pci_driver mcf5_driver_fam15 __pci_driver = {
++      .ops    = &mcf5_ops,
++      .vendor = PCI_VENDOR_ID_AMD,
++      .device = 0x1605,
++};
+\ No newline at end of file
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index fb3b2f7..fcf85a7 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -81,6 +81,21 @@ device_t get_node_pci(u32 nodeid, u32 fn)
+ #endif
+ }
+ 
++static inline uint8_t is_fam15h(void)
++{
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      return fam15h;
++}
++
+ static void get_fx_devs(void)
+ {
+       int i;
+@@ -202,7 +217,7 @@ static void amd_g34_fixup(struct bus *link, device_t dev)
+               /* Revision D or later */
+               rev_gte_d = 1;
+ 
+-      if (rev_gte_d) {
++      if (rev_gte_d || is_fam15h()) {
+               f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
+ 
+               /* Check for dual node capability */
+@@ -215,6 +230,15 @@ static void amd_g34_fixup(struct bus *link, device_t dev)
+                       */
+                       f3xe8 = pci_read_config32(get_node_pci(nodeid, 3), 
0xe8);
+                       uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 
30);
++                      uint8_t defective_link_number_1;
++                      uint8_t defective_link_number_2;
++                      if (is_fam15h()) {
++                              defective_link_number_1 = 4;    /* Link 0 
Sublink 1 */
++                              defective_link_number_2 = 7;    /* Link 3 
Sublink 1 */
++                      } else {
++                              defective_link_number_1 = 6;    /* Link 2 
Sublink 1 */
++                              defective_link_number_2 = 5;    /* Link 1 
Sublink 1 */
++                      }
+                       if (internal_node_number == 0) {
+                               /* Node 0 */
+                               if (link->link_num == 6)        /* Link 2 
Sublink 1 */
+@@ -314,6 +338,46 @@ static void amdfam10_scan_chains(device_t dev)
+ {
+       struct bus *link;
+ 
++#if CONFIG_CPU_AMD_SOCKET_G34_NON_AGESA
++      if (is_fam15h()) {
++              uint8_t current_link_number = 0;
++
++              for (link = dev->link_list; link; link = link->next) {
++                      /* The following links have changed position in Fam15h 
G34 processors:
++                       * Fam10  Fam15
++                       * Node 0
++                       * L3 --> L1
++                       * L0 --> L3
++                       * L1 --> L2
++                       * L2 --> L0
++                       * Node 1
++                       * L0 --> L0
++                       * L1 --> L3
++                       * L2 --> L1
++                       * L3 --> L2
++                       */
++                      if (link->link_num == 0)
++                              link->link_num = 3;
++                      else if (link->link_num == 1)
++                              link->link_num = 2;
++                      else if (link->link_num == 2)
++                              link->link_num = 0;
++                      else if (link->link_num == 3)
++                              link->link_num = 1;
++                      else if (link->link_num == 5)
++                              link->link_num = 7;
++                      else if (link->link_num == 6)
++                              link->link_num = 5;
++                      else if (link->link_num == 7)
++                              link->link_num = 6;
++
++                      current_link_number++;
++                      if (current_link_number > 3)
++                              current_link_number = 0;
++              }
++      }
++#endif
++
+       /* Do sb ht chain at first, in case s2885 put sb chain (8131/8111) on 
link2, but put 8151 on link0 */
+       trim_ht_chain(dev);
+ 
+@@ -620,13 +684,21 @@ static const struct pci_driver mcf0_driver __pci_driver 
= {
+       .device = 0x1200,
+ };
+ 
++
+ static void amdfam10_nb_init(void *chip_info)
+ {
+       relocate_sb_ht_chain();
+ }
+ 
++static const struct pci_driver mcf0_driver_fam15 __pci_driver = {
++      .ops    = &northbridge_operations,
++      .vendor = PCI_VENDOR_ID_AMD,
++      .device = 0x1600,
++};
++
++
+ struct chip_operations northbridge_amd_amdfam10_ops = {
+-      CHIP_NAME("AMD FAM10 Northbridge")
++      CHIP_NAME("AMD Family 10h/15h Northbridge")
+       .enable_dev = 0,
+       .init = amdfam10_nb_init,
+ };
+@@ -950,38 +1022,61 @@ static int amdfam10_get_smbios_data16(int* count, int 
handle, unsigned long *cur
+ 
+ static uint16_t amdmct_mct_speed_enum_to_mhz(uint8_t speed)
+ {
+-      if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
+-              switch (speed) {
+-                      case 1:
+-                              return 200;
+-                      case 2:
+-                              return 266;
+-                      case 3:
+-                              return 333;
+-                      case 4:
+-                              return 400;
+-                      case 5:
+-                              return 533;
+-                      default:
+-                              return 0;
+-              }
+-      } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
+-              switch (speed) {
+-                      case 3:
+-                              return 333;
+-                      case 4:
+-                              return 400;
+-                      case 5:
+-                              return 533;
+-                      case 6:
+-                              return 667;
+-                      case 7:
+-                              return 800;
+-                      default:
+-                              return 0;
++      if (is_fam15h()) {
++              if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++                      switch (speed) {
++                              case 0x4:
++                                      return 333;
++                              case 0x6:
++                                      return 400;
++                              case 0xa:
++                                      return 533;
++                              case 0xe:
++                                      return 667;
++                              case 0x12:
++                                      return 800;
++                              case 0x16:
++                                      return 933;
++                              default:
++                                      return 0;
++                      }
++              } else {
++                      return 0;
+               }
+       } else {
+-              return 0;
++              if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
++                      switch (speed) {
++                              case 1:
++                                      return 200;
++                              case 2:
++                                      return 266;
++                              case 3:
++                                      return 333;
++                              case 4:
++                                      return 400;
++                              case 5:
++                                      return 533;
++                              default:
++                                      return 0;
++                      }
++              } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++                      switch (speed) {
++                              case 3:
++                                      return 333;
++                              case 4:
++                                      return 400;
++                              case 5:
++                                      return 533;
++                              case 6:
++                                      return 667;
++                              case 7:
++                                      return 800;
++                              default:
++                                      return 0;
++                      }
++              } else {
++                      return 0;
++              }
+       }
+ }
+ 
+@@ -1076,6 +1171,8 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
+ #if IS_ENABLED(CONFIG_DIMM_DDR3)
+                                       /* Find the maximum and minimum 
supported voltages */
+                                       uint8_t supported_voltages = 
mem_info->dct_stat[node].DimmSupportedVoltages[slot];
++                                      uint8_t configured_voltage = 
mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
++
+                                       if (supported_voltages & 0x8)
+                                               t->minimum_voltage = 1150;
+                                       else if (supported_voltages & 0x4)
+@@ -1094,7 +1191,14 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
+                                       else if (supported_voltages & 0x8)
+                                               t->maximum_voltage = 1150;
+ 
+-                                      t->configured_voltage = 
mem_info->dct_stat[node].DimmConfiguredVoltage[slot];
++                                      if (configured_voltage & 0x8)
++                                              t->configured_voltage = 1150;
++                                      else if (configured_voltage & 0x4)
++                                              t->configured_voltage = 1250;
++                                      else if (configured_voltage & 0x2)
++                                              t->configured_voltage = 1350;
++                                      else if (configured_voltage & 0x1)
++                                              t->configured_voltage = 1500;
+ #endif
+                               }
+                               t->memory_error_information_handle = 0xFFFE;    
/* no error information handle available */
+@@ -1233,12 +1337,14 @@ static void cpu_bus_scan(device_t dev)
+ #if CONFIG_CBB
+       device_t pci_domain;
+ #endif
++      int nvram = 0;
+       int i,j;
+       int nodes;
+       unsigned nb_cfg_54;
+       unsigned siblings;
+       int cores_found;
+       int disable_siblings;
++      uint8_t disable_cu_siblings = 0;
+       unsigned ApicIdCoreIdSize;
+ 
+       nb_cfg_54 = 0;
+@@ -1325,14 +1431,23 @@ static void cpu_bus_scan(device_t dev)
+       /* Always use the devicetree node with lapic_id 0 for BSP. */
+       remap_bsp_lapic(cpu_bus);
+ 
++      if (get_option(&nvram, "compute_unit_siblings") == CB_SUCCESS)
++              disable_cu_siblings = !!nvram;
++
++      if (disable_cu_siblings)
++              printk(BIOS_DEBUG, "Disabling siblings on each compute unit as 
requested\n");
++
+       for(i = 0; i < nodes; i++) {
+               device_t cdb_dev;
+               unsigned busn, devn;
+               struct bus *pbus;
+ 
++              uint8_t fam15h = 0;
+               uint8_t rev_gte_d = 0;
+               uint8_t dual_node = 0;
+               uint32_t f3xe8;
++              uint32_t family;
++              uint32_t model;
+ 
+               busn = CONFIG_CBB;
+               devn = CONFIG_CDB+i;
+@@ -1372,7 +1487,16 @@ static void cpu_bus_scan(device_t dev)
+ 
+               f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
+ 
+-              if (cpuid_eax(0x80000001) >= 0x8)
++              family = model = cpuid_eax(0x80000001);
++              model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++
++              if (is_fam15h()) {
++                      /* Family 15h or later */
++                      fam15h = 1;
++                      nb_cfg_54 = 1;
++              }
++
++              if ((model >= 0x8) || fam15h)
+                       /* Revision D or later */
+                       rev_gte_d = 1;
+ 
+@@ -1382,13 +1506,20 @@ static void cpu_bus_scan(device_t dev)
+                               dual_node = 1;
+ 
+               cores_found = 0; // one core
+-              cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
++              if (fam15h)
++                      cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 5));
++              else
++                      cdb_dev = dev_find_slot(busn, PCI_DEVFN(devn, 3));
+               int enable_node = cdb_dev && cdb_dev->enabled;
+               if (enable_node) {
+-                      j = pci_read_config32(cdb_dev, 0xe8);
+-                      cores_found = (j >> 12) & 3; // dev is func 3
+-                      if (siblings > 3)
+-                              cores_found |= (j >> 13) & 4;
++                      if (fam15h) {
++                              cores_found = pci_read_config32(cdb_dev, 0x84) 
& 0xff;
++                      } else {
++                              j = pci_read_config32(cdb_dev, 0xe8);
++                              cores_found = (j >> 12) & 3; // dev is func 3
++                              if (siblings > 3)
++                                      cores_found |= (j >> 13) & 4;
++                      }
+                       printk(BIOS_DEBUG, "  %s siblings=%d\n", 
dev_path(cdb_dev), cores_found);
+               }
+ 
+@@ -1408,15 +1539,24 @@ static void cpu_bus_scan(device_t dev)
+ 
+                       if (dual_node) {
+                               apic_id = 0;
+-                              if (nb_cfg_54) {
+-                                      apic_id |= ((i >> 1) & 0x3) << 4;       
                /* Node ID */
++                              if (fam15h) {
++                                      apic_id |= ((i >> 1) & 0x3) << 5;       
                /* Node ID */
+                                       apic_id |= ((i & 0x1) * (siblings + 1)) 
+ j;            /* Core ID */
+                               } else {
+-                                      apic_id |= i & 0x3;                     
                /* Node ID */
+-                                      apic_id |= (((i & 0x1) * (siblings + 
1)) + j) << 4;     /* Core ID */
++                                      if (nb_cfg_54) {
++                                              apic_id |= ((i >> 1) & 0x3) << 
4;                       /* Node ID */
++                                              apic_id |= ((i & 0x1) * 
(siblings + 1)) + j;            /* Core ID */
++                                      } else {
++                                              apic_id |= i & 0x3;             
                        /* Node ID */
++                                              apic_id |= (((i & 0x1) * 
(siblings + 1)) + j) << 4;     /* Core ID */
++                                      }
+                               }
+                       } else {
+-                              apic_id = i * (nb_cfg_54?(siblings+1):1) + j * 
(nb_cfg_54?1:64); // ?
++                              if (fam15h) {
++                                      apic_id = (i * (siblings + 1)) + j;
++                              } else {
++                                      apic_id = i * 
(nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:64); // ?
++                              }
+                       }
+ 
+ #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET>0)
+@@ -1426,6 +1566,9 @@ static void cpu_bus_scan(device_t dev)
+                               }
+                       }
+ #endif
++                      if (disable_cu_siblings && (j & 0x1))
++                              continue;
++
+                       device_t cpu = add_cpu_device(cpu_bus, apic_id, 
enable_node);
+                       if (cpu)
+                               amd_cpu_topology(cpu, i, j);
+@@ -1484,6 +1627,6 @@ static void root_complex_enable_dev(struct device *dev)
+ }
+ 
+ struct chip_operations northbridge_amd_amdfam10_root_complex_ops = {
+-      CHIP_NAME("AMD FAM10 Root Complex")
++      CHIP_NAME("AMD Family 10h/15h Root Complex")
+       .enable_dev = root_complex_enable_dev,
+ };
+diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+index 5068e7a..cae228f 100644
+--- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
++++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+@@ -44,8 +44,120 @@ static  void print_tf(const char *func, const char *strval)
+ #endif
+ }
+ 
+-static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t registered, uint16_t 
freq)
++static inline void fam15h_switch_dct(uint32_t dev, uint8_t dct)
+ {
++      uint32_t dword;
++
++      dword = Get_NB32(dev, 0x10c);
++      dword &= ~0x1;
++      dword |= (dct & 0x1);
++      Set_NB32(dev, 0x10c, dword);
++}
++
++static inline void fam15h_switch_nb_pstate_config_reg(uint32_t dev, uint8_t 
nb_pstate)
++{
++      uint32_t dword;
++
++      dword = Get_NB32(dev, 0x10c);
++      dword &= ~(0x3 << 4);
++      dword |= (nb_pstate & 0x3) << 4;
++      Set_NB32(dev, 0x10c, dword);
++}
++
++static inline uint32_t Get_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg)
++{
++      if (is_fam15h()) {
++              /* Obtain address of function 0x1 */
++              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
++              fam15h_switch_dct(dev_map, dct);
++              return Get_NB32(dev, reg);
++      } else {
++              return Get_NB32(dev, (0x100 * dct) + reg);
++      }
++}
++
++static inline void Set_NB32_DCT(uint32_t dev, uint8_t dct, uint32_t reg, 
uint32_t val)
++{
++      if (is_fam15h()) {
++              /* Obtain address of function 0x1 */
++              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
++              fam15h_switch_dct(dev_map, dct);
++              Set_NB32(dev, reg, val);
++      } else {
++              Set_NB32(dev, (0x100 * dct) + reg, val);
++      }
++}
++
++static inline uint32_t Get_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, 
uint8_t nb_pstate, uint32_t reg)
++{
++      if (is_fam15h()) {
++              /* Obtain address of function 0x1 */
++              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
++              fam15h_switch_dct(dev_map, dct);
++              fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate);
++              return Get_NB32(dev, reg);
++      } else {
++              return Get_NB32(dev, (0x100 * dct) + reg);
++      }
++}
++
++static inline void Set_NB32_DCT_NBPstate(uint32_t dev, uint8_t dct, uint8_t 
nb_pstate, uint32_t reg, uint32_t val)
++{
++      if (is_fam15h()) {
++              /* Obtain address of function 0x1 */
++              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
++              fam15h_switch_dct(dev_map, dct);
++              fam15h_switch_nb_pstate_config_reg(dev_map, nb_pstate);
++              Set_NB32(dev, reg, val);
++      } else {
++              Set_NB32(dev, (0x100 * dct) + reg, val);
++      }
++}
++
++static inline uint32_t Get_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, 
uint32_t index_reg, uint32_t index)
++{
++      if (is_fam15h()) {
++              /* Obtain address of function 0x1 */
++              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
++              fam15h_switch_dct(dev_map, dct);
++              return Get_NB32_index_wait(dev, index_reg, index);
++      } else {
++              return Get_NB32_index_wait(dev, (0x100 * dct) + index_reg, 
index);
++      }
++}
++
++static inline void Set_NB32_index_wait_DCT(uint32_t dev, uint8_t dct, 
uint32_t index_reg, uint32_t index, uint32_t data)
++{
++      if (is_fam15h()) {
++              /* Obtain address of function 0x1 */
++              uint32_t dev_map = (dev & (~(0x7 << 12))) | (0x1 << 12);
++              fam15h_switch_dct(dev_map, dct);
++              Set_NB32_index_wait(dev, index_reg, index, data);
++      } else {
++              Set_NB32_index_wait(dev, (0x100 * dct) + index_reg, index, 
data);
++      }
++}
++
++static uint16_t voltage_index_to_mv(uint8_t index)
++{
++      if (index & 0x8)
++              return 1150;
++      if (index & 0x4)
++              return 1250;
++      else if (index & 0x2)
++              return 1350;
++      else
++              return 1500;
++}
++
++static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t highest_rank_count, 
uint8_t registered, uint8_t voltage, uint16_t freq)
++{
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
+       /* Return limited maximum RAM frequency */
+       if (IS_ENABLED(CONFIG_DIMM_DDR2)) {
+               if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
+@@ -68,34 +180,178 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t 
registered, uint16_t freq
+                       }
+               }
+       } else if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
+-              if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
+-                      /* K10 BKDG Rev. 3.62 Table 34 */
+-                      if (count > 2) {
+-                              /* Limit to DDR3-800 */
+-                              if (freq > 400) {
+-                                      freq = 400;
+-                                      print_tf(__func__, ": More than 2 
registered DIMMs on channel; limiting to DDR3-800\n");
++              if (voltage == 0) {
++                      printk(BIOS_DEBUG, "%s: WARNING: Mainboard DDR3 voltage 
unknown, assuming 1.5V!\n", __func__);
++                      voltage = 0x1;
++              }
++
++              if (is_fam15h()) {
++                      if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
++                              /* Fam15h BKDG Rev. 3.14 Table 27 */
++                              if (voltage & 0x4) {
++                                      /* 1.25V */
++                                      if (count > 1) {
++                                              if (highest_rank_count > 1) {
++                                                      /* Limit to DDR3-1066 */
++                                                      if (freq > 533) {
++                                                              freq = 533;
++                                                              
printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting 
to DDR3-1066\n", __func__, voltage_index_to_mv(voltage));
++                                                      }
++                                              } else {
++                                                      /* Limit to DDR3-1333 */
++                                                      if (freq > 666) {
++                                                              freq = 666;
++                                                              
printk(BIOS_DEBUG, "%s: More than 1 registered DIMM on %dmV channel; limiting 
to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
++                                                      }
++                                              }
++                                      } else {
++                                              /* Limit to DDR3-1333 */
++                                              if (freq > 666) {
++                                                      freq = 666;
++                                                      printk(BIOS_DEBUG, "%s: 
1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
++                                              }
++                                      }
++                              } else if (voltage & 0x2) {
++                                      /* 1.35V */
++                                      if (count > 1) {
++                                              /* Limit to DDR3-1333 */
++                                              if (freq > 666) {
++                                                      freq = 666;
++                                                      printk(BIOS_DEBUG, "%s: 
More than 1 registered DIMM on %dmV channel; limiting to DDR3-1333\n", 
__func__, voltage_index_to_mv(voltage));
++                                              }
++                                      } else {
++                                              /* Limit to DDR3-1600 */
++                                              if (freq > 800) {
++                                                      freq = 800;
++                                                      printk(BIOS_DEBUG, "%s: 
1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, 
voltage_index_to_mv(voltage));
++                                              }
++                                      }
++                              } else if (voltage & 0x1) {
++                                      /* 1.50V */
++                                      if (count > 1) {
++                                              /* Limit to DDR3-1600 */
++                                              if (freq > 800) {
++                                                      freq = 800;
++                                                      printk(BIOS_DEBUG, "%s: 
More than 1 registered DIMM on %dmV channel; limiting to DDR3-1600\n", 
__func__, voltage_index_to_mv(voltage));
++                                              }
++                                      } else {
++                                              /* Limit to DDR3-1866 */
++                                              if (freq > 933) {
++                                                      freq = 933;
++                                                      printk(BIOS_DEBUG, "%s: 
1 registered DIMM on %dmV channel; limiting to DDR3-1866\n", __func__, 
voltage_index_to_mv(voltage));
++                                              }
++                                      }
++                              }
++                      } else {
++                              /* Fam15h BKDG Rev. 3.14 Table 26 */
++                              if (voltage & 0x4) {
++                                      /* 1.25V */
++                                      if (count > 1) {
++                                              if (highest_rank_count > 1) {
++                                                      /* Limit to DDR3-1066 */
++                                                      if (freq > 533) {
++                                                              freq = 533;
++                                                              
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1066\n", __func__, voltage_index_to_mv(voltage));
++                                                      }
++                                              } else {
++                                                      /* Limit to DDR3-1333 */
++                                                      if (freq > 666) {
++                                                              freq = 666;
++                                                              
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
++                                                      }
++                                              }
++                                      } else {
++                                              /* Limit to DDR3-1333 */
++                                              if (freq > 666) {
++                                                      freq = 666;
++                                                      printk(BIOS_DEBUG, "%s: 
1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
++                                              }
++                                      }
++                              } else if (voltage & 0x2) {
++                                      /* 1.35V */
++                                      if (MaxDimmsInstallable > 1) {
++                                              /* Limit to DDR3-1333 */
++                                              if (freq > 666) {
++                                                      freq = 666;
++                                                      printk(BIOS_DEBUG, "%s: 
More than 1 unbuffered DIMM on %dmV channel; limiting to DDR3-1333\n", 
__func__, voltage_index_to_mv(voltage));
++                                              }
++                                      } else {
++                                              /* Limit to DDR3-1600 */
++                                              if (freq > 800) {
++                                                      freq = 800;
++                                                      printk(BIOS_DEBUG, "%s: 
1 unbuffered DIMM on %dmV channel; limiting to DDR3-1600\n", __func__, 
voltage_index_to_mv(voltage));
++                                              }
++                                      }
++                              } else if (voltage & 0x1) {
++                                      if (MaxDimmsInstallable == 1) {
++                                              if (count > 1) {
++                                                      /* Limit to DDR3-1600 */
++                                                      if (freq > 800) {
++                                                              freq = 800;
++                                                              
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
++                                                      }
++                                              } else {
++                                                      /* Limit to DDR3-1866 */
++                                                      if (freq > 933) {
++                                                              freq = 933;
++                                                              
printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to 
DDR3-1866\n", __func__, voltage_index_to_mv(voltage));
++                                                      }
++                                              }
++                                      } else {
++                                              if (count > 1) {
++                                                      if (highest_rank_count 
> 1) {
++                                                              /* Limit to 
DDR3-1333 */
++                                                              if (freq > 666) 
{
++                                                                      freq = 
666;
++                                                                      
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1333\n", __func__, voltage_index_to_mv(voltage));
++                                                              }
++                                                      } else {
++                                                              /* Limit to 
DDR3-1600 */
++                                                              if (freq > 800) 
{
++                                                                      freq = 
800;
++                                                                      
printk(BIOS_DEBUG, "%s: More than 1 unbuffered DIMM on %dmV channel; limiting 
to DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
++                                                              }
++                                                      }
++                                              } else {
++                                                      /* Limit to DDR3-1600 */
++                                                      if (freq > 800) {
++                                                              freq = 800;
++                                                              
printk(BIOS_DEBUG, "%s: 1 unbuffered DIMM on %dmV channel; limiting to 
DDR3-1600\n", __func__, voltage_index_to_mv(voltage));
++                                                      }
++                                              }
++                                      }
+                               }
+-                      } else if (count == 2) {
+-                              /* Limit to DDR3-1066 */
+-                              if (freq > 533) {
+-                                      freq = 533;
+-                                      print_tf(__func__, ": 2 registered 
DIMMs on channel; limiting to DDR3-1066\n");
++                      }
++              } else {
++                      if (IS_ENABLED(CONFIG_DIMM_REGISTERED) && registered) {
++                              /* K10 BKDG Rev. 3.62 Table 34 */
++                              if (count > 2) {
++                                      /* Limit to DDR3-800 */
++                                      if (freq > 400) {
++                                              freq = 400;
++                                              printk(BIOS_DEBUG, "%s: More 
than 2 registered DIMMs on %dmV channel; limiting to DDR3-800\n", __func__, 
voltage_index_to_mv(voltage));
++                                      }
++                              } else if (count == 2) {
++                                      /* Limit to DDR3-1066 */
++                                      if (freq > 533) {
++                                              freq = 533;
++                                              printk(BIOS_DEBUG, "%s: 2 
registered DIMMs on %dmV channel; limiting to DDR3-1066\n", __func__, 
voltage_index_to_mv(voltage));
++                                      }
++                              } else {
++                                      /* Limit to DDR3-1333 */
++                                      if (freq > 666) {
++                                              freq = 666;
++                                              printk(BIOS_DEBUG, "%s: 1 
registered DIMM on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
++                                      }
+                               }
+                       } else {
++                              /* K10 BKDG Rev. 3.62 Table 33 */
+                               /* Limit to DDR3-1333 */
+                               if (freq > 666) {
+                                       freq = 666;
+-                                      print_tf(__func__, ": 1 registered DIMM 
on channel; limiting to DDR3-1333\n");
++                                      printk(BIOS_DEBUG, "%s: unbuffered 
DIMMs on %dmV channel; limiting to DDR3-1333\n", __func__, 
voltage_index_to_mv(voltage));
+                               }
+                       }
+-              } else {
+-                      /* K10 BKDG Rev. 3.62 Table 33 */
+-                      /* Limit to DDR3-1333 */
+-                      if (freq > 666) {
+-                              freq = 666;
+-                              print_tf(__func__, ": unbuffered DIMMs on 
channel; limiting to DDR3-1333\n");
+-                      }
+               }
+       }
+ 
+@@ -225,11 +481,13 @@ void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 
node)
+ 
+ }
+ 
++#if IS_ENABLED(CONFIG_SET_FIDVID)
+ static u8 mctGetProcessorPackageType(void) {
+       /* FIXME: I guess this belongs wherever mctGetLogicalCPUID ends up ? */
+-     u32 BrandId = cpuid_ebx(0x80000001);
+-     return (u8)((BrandId >> 28) & 0x0F);
++      u32 BrandId = cpuid_ebx(0x80000001);
++      return (u8)((BrandId >> 28) & 0x0F);
+ }
++#endif
+ 
+ static void raminit_amdmct(struct sys_info *sysinfo)
+ {
+diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
+index 97f9db8..8f9177f 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.c
++++ b/src/northbridge/amd/amdht/h3ncmn.c
+@@ -43,6 +43,7 @@
+ #define CPU_HTNB_FUNC_04              4
+ #define CPU_ADDR_FUNC_01              1
+ #define CPU_NB_FUNC_03                        3
++#define CPU_NB_FUNC_05                        5
+ 
+ /* Function 0 registers */
+ #define REG_ROUTE0_0X40               0x40
+@@ -70,6 +71,7 @@
+ #define REG_NB_CPUID_3XFC             0xFC
+ #define REG_NB_LINK_XCS_TOKEN0_3X148  0x148
+ #define REG_NB_DOWNCORE_3X190         0x190
++#define REG_NB_CAPABILITY_5X84                0x84
+ 
+ /* Function 4 registers */
+ 
+@@ -555,9 +557,10 @@ static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge 
*nb)
+                               15, 12, &temp);
+ 
+       /* bits[15,13,12] specify the cores */
+-      /* Support Downcoring */
+       temp = ((temp & 8) >> 1) + (temp & 3);
+       cores = temp + 1;
++
++      /* Support Downcoring */
+       AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
+                                       makePCIBusFromNode(node),
+                                       makePCIDeviceFromNode(node),
+@@ -576,6 +579,56 @@ static u8 fam10GetNumCoresOnNode(u8 node, cNorthBridge 
*nb)
+ 
+ 
/***************************************************************************//**
+  *
++ * static u8
++ * fam15GetNumCoresOnNode(u8 node, cNorthBridge *nb)
++ *
++ *  Description:
++ *    Return the number of cores (1 based count) on node.
++ *
++ *  Parameters:
++ *    @param[in]  node      = the node that will be examined
++ *    @param[in] *nb = this northbridge
++ *    @return    = the number of cores
++ *
++ *
++ */
++static u8 fam15GetNumCoresOnNode(u8 node, cNorthBridge *nb)
++{
++      u32 temp, leveling, cores;
++      u8 i;
++
++      ASSERT((node < nb->maxNodes));
++      /* Read CmpCap [7:0] */
++      AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
++                              makePCIBusFromNode(node),
++                              makePCIDeviceFromNode(node),
++                              CPU_NB_FUNC_05,
++                              REG_NB_CAPABILITY_5X84),
++                              7, 0, &temp);
++
++      /* bits[7:0] specify the cores */
++      temp = temp & 0xff;
++      cores = temp + 1;
++
++      /* Support Downcoring */
++      AmdPCIReadBits (MAKE_SBDFO(makePCISegmentFromNode(node),
++                                      makePCIBusFromNode(node),
++                                      makePCIDeviceFromNode(node),
++                                      CPU_NB_FUNC_03,
++                                      REG_NB_DOWNCORE_3X190),
++                                      31, 0, &leveling);
++      for (i=0; i<cores; i++)
++      {
++              if (leveling & ((u32) 1 << i))
++              {
++                      temp--;
++              }
++      }
++      return (u8)(temp+1);
++}
++
++/***************************************************************************//**
++ *
+  * static void
+  * setTotalNodesAndCores(u8 node, u8 totalNodes, u8 totalCores, cNorthBridge 
*nb)
+  *
+@@ -854,6 +907,69 @@ static BOOL fam10IsCapable(u8 node, sMainData *pDat, 
cNorthBridge *nb)
+ 
+ 
/***************************************************************************//**
+  *
++ * static BOOL
++ * fam15IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
++ *
++ *  Description:
++ *    Get node capability and update the minimum supported system capability.
++ *    Return whether the current configuration exceeds the capability.
++ *
++ *  Parameters:
++ *    @param[in]  node   = the node
++ *    @param[in,out] *pDat = sysMpCap (updated) and NodesDiscovered
++ *    @param[in] *nb   = this northbridge
++ *    @return             true: system is capable of current config.
++ *                       false: system is not capable of current config.
++ *
++ * 
---------------------------------------------------------------------------------------
++ */
++static BOOL fam15IsCapable(u8 node, sMainData *pDat, cNorthBridge *nb)
++{
++#ifndef HT_BUILD_NC_ONLY
++      u32 temp;
++      u8 maxNodes;
++
++      ASSERT(node < nb->maxNodes);
++
++      AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
++                              makePCIBusFromNode(node),
++                              makePCIDeviceFromNode(node),
++                              CPU_NB_FUNC_03,
++                              REG_NB_CAPABILITY_3XE8),
++                              18, 16, &temp);
++
++      if (temp != 0)
++      {
++              maxNodes = (1 << (~temp & 0x3));  /* That is, 1, 2, 4, or 8 */
++      }
++      else
++      {
++              /* Check if CPU package is dual node */
++              AmdPCIReadBits(MAKE_SBDFO(makePCISegmentFromNode(node),
++                                      makePCIBusFromNode(node),
++                                      makePCIDeviceFromNode(node),
++                                      CPU_NB_FUNC_03,
++                                      REG_NB_CAPABILITY_3XE8),
++                                      29, 29, &temp);
++              if (temp)
++                      maxNodes = 4;
++              else
++                      maxNodes = 8;
++      }
++
++      if (pDat->sysMpCap > maxNodes)
++      {
++              pDat->sysMpCap = maxNodes;
++      }
++      /* Note since sysMpCap is one based and NodesDiscovered is zero based, 
equal is false */
++      return (pDat->sysMpCap > pDat->NodesDiscovered);
++#else
++      return 1;
++#endif
++}
++
++/***************************************************************************//**
++ *
+  * static void
+  * fam0fStopLink(u8 currentNode, u8 currentLink, cNorthBridge *nb)
+  *
+@@ -2068,6 +2184,49 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
+       u32 match;
+       u32 extFam, baseFam, model;
+ 
++      cNorthBridge fam15 =
++      {
++#ifdef HT_BUILD_NC_ONLY
++              8,
++              1,
++              12,
++#else
++              8,
++              8,
++              64,
++#endif /* HT_BUILD_NC_ONLY*/
++              writeRoutingTable,
++              writeNodeID,
++              readDefLnk,
++              enableRoutingTables,
++              verifyLinkIsCoherent,
++              readTrueLinkFailStatus,
++              readToken,
++              writeToken,
++              fam15GetNumCoresOnNode,
++              setTotalNodesAndCores,
++              limitNodes,
++              writeFullRoutingTable,
++              isCompatible,
++              fam15IsCapable,
++              (void (*)(u8, u8, cNorthBridge*))commonVoid,
++              (BOOL (*)(u8, u8, sMainData*, cNorthBridge*))commonReturnFalse,
++              readSbLink,
++              verifyLinkIsNonCoherent,
++              ht3SetCFGAddrMap,
++              convertBitsToWidth,
++              convertWidthToBits,
++              fam10NorthBridgeFreqMask,
++              gatherLinkData,
++              setLinkData,
++              ht3WriteTrafficDistribution,
++              fam10BufferOptimizations,
++              0x00000001,
++              0x00000200,
++              18,
++              0x00000f06
++      };
++
+       cNorthBridge fam10 =
+       {
+ #ifdef HT_BUILD_NC_ONLY
+@@ -2175,8 +2334,14 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
+                       7, 4, &model);
+       match = (u32)((baseFam << 8) | extFam);
+ 
+-      /* Test each in turn looking for a match.       Init the struct if 
found */
+-      if (match == fam10.compatibleKey)
++      /* Test each in turn looking for a match.
++       * Initialize the struct if found.
++       */
++      if (match == fam15.compatibleKey)
++      {
++              Amdmemcpy((void *)nb, (const void *)&fam15, (u32) 
sizeof(cNorthBridge));
++      }
++      else if (match == fam10.compatibleKey)
+       {
+               Amdmemcpy((void *)nb, (const void *)&fam10, (u32) 
sizeof(cNorthBridge));
+       }
+diff --git a/src/northbridge/amd/amdht/ht_wrapper.c 
b/src/northbridge/amd/amdht/ht_wrapper.c
+index 389b1b1..c0ccc69 100644
+--- a/src/northbridge/amd/amdht/ht_wrapper.c
++++ b/src/northbridge/amd/amdht/ht_wrapper.c
+@@ -174,16 +174,22 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
+       printk(BIOS_DEBUG, "amd_ht_fixup()\n");
+       if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX)) {
+               uint8_t rev_gte_d = 0;
++              uint8_t fam15h = 0;
+               uint8_t dual_node = 0;
+               uint32_t f3xe8;
+               uint32_t family;
+               uint32_t model;
+ 
+               family = model = cpuid_eax(0x80000001);
+-              model = ((model & 0xf0000) >> 16) | ((model & 0xf0) >> 4);
++              model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++              family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+ 
+-              if (model >= 0x8)
+-                      /* Revision D or later */
++              if (family >= 0x6f)
++                      /* Family 15h or later */
++                      fam15h = 1;
++
++              if ((model >= 0x8) || fam15h)
++                      /* Family 10h Revision D or later */
+                       rev_gte_d = 1;
+ 
+               if (rev_gte_d) {
+@@ -195,7 +201,8 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
+ 
+                       if (dual_node) {
+                               /* Each G34 processor contains a defective HT 
link.
+-                              * See the BKDG Rev 3.62 section 2.7.1.5 for 
details.
++                              * See the Family 10h BKDG Rev 3.62 section 
2.7.1.5 for details
++                              * For Family 15h see the BKDG Rev. 3.14 section 
2.12.1.5 for details.
+                               */
+                               uint8_t node;
+                               uint8_t node_count = get_nodes();
+@@ -205,46 +212,46 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
+                                       uint8_t internal_node_number = ((f3xe8 
& 0xc0000000) >> 30);
+                                       printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link\n", node, 
internal_node_number);
+                                       if (internal_node_number == 0) {
+-                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xd8) & 0x1;
++                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0x98:0xd8) & 0x1;
+                                               if (package_link_3_connected) {
+                                                       /* Set WidthIn and 
WidthOut to 0 */
+-                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xc4);
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4);
+                                                       dword &= ~0x77000000;
+-                                                      
pci_write_config32(NODE_PCI(node, 0), 0xc4, dword);
++                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4, dword);
+                                                       /* Set Ganged to 1 */
+-                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x178);
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178);
+                                                       dword |= 0x00000001;
+-                                                      
pci_write_config32(NODE_PCI(node, 0), 0x178, dword);
++                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178, dword);
+                                               } else {
+                                                       /* Set ConnDly to 1 */
+                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
+                                                       dword |= 0x00000100;
+                                                       
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
+                                                       /* Set TransOff and 
EndOfChain to 1 */
+-                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xc4);
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4);
+                                                       dword |= 0x000000c0;
+-                                                      
pci_write_config32(NODE_PCI(node, 4), 0xc4, dword);
++                                                      
pci_write_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4, dword);
+                                               }
+                                       } else if (internal_node_number == 1) {
+-                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 0xb8) & 0x1;
++                                              uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0xf8:0xb8) & 0x1;
+                                               if (package_link_3_connected) {
+                                                       /* Set WidthIn and 
WidthOut to 0 */
+-                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0xa4);
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4);
+                                                       dword &= ~0x77000000;
+-                                                      
pci_write_config32(NODE_PCI(node, 0), 0xa4, dword);
++                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4, dword);
+                                                       /* Set Ganged to 1 */
+-                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), 0x174);
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174);
+                                                       dword |= 0x00000001;
+-                                                      
pci_write_config32(NODE_PCI(node, 0), 0x174, dword);
++                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174, dword);
+                                               } else {
+                                                       /* Set ConnDly to 1 */
+                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
+                                                       dword |= 0x00000100;
+                                                       
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
+                                                       /* Set TransOff and 
EndOfChain to 1 */
+-                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), 0xa4);
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4);
+                                                       dword |= 0x000000c0;
+-                                                      
pci_write_config32(NODE_PCI(node, 4), 0xa4, dword);
++                                                      
pci_write_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4, dword);
+                                               }
+                                       }
+                               }
+diff --git a/src/northbridge/amd/amdmct/amddefs.h 
b/src/northbridge/amd/amdmct/amddefs.h
+index 117fea5..20a77d3 100644
+--- a/src/northbridge/amd/amdmct/amddefs.h
++++ b/src/northbridge/amd/amdmct/amddefs.h
+@@ -20,33 +20,35 @@
+ /* FIXME: this file should be moved to include/cpu/amd/amddefs.h */
+ 
+ /* Public Revisions - USE THESE VERSIONS TO MAKE COMPARE WITH CPULOGICALID 
RETURN VALUE*/
+-#define       AMD_SAFEMODE    0x80000000      /* Unknown future revision - 
SAFE MODE */
+-#define       AMD_NPT_F0      0x00000001      /* F0 stepping */
+-#define       AMD_NPT_F1      0x00000002      /* F1 stepping */
+-#define       AMD_NPT_F2C     0x00000004
+-#define       AMD_NPT_F2D     0x00000008
+-#define       AMD_NPT_F2E     0x00000010      /* F2 stepping E */
+-#define       AMD_NPT_F2G     0x00000020      /* F2 stepping G */
+-#define       AMD_NPT_F2J     0x00000040
+-#define       AMD_NPT_F2K     0x00000080
+-#define       AMD_NPT_F3L     0x00000100      /* F3 Stepping */
+-#define       AMD_NPT_G0A     0x00000200      /* G0 stepping */
+-#define       AMD_NPT_G1B     0x00000400      /* G1 stepping */
+-#define       AMD_DR_A0A      0x00010000      /* Barcelona A0 */
+-#define       AMD_DR_A1B      0x00020000      /* Barcelona A1 */
+-#define       AMD_DR_A2       0x00040000      /* Barcelona A2 */
+-#define       AMD_DR_B0       0x00080000      /* Barcelona B0 */
+-#define       AMD_DR_B1       0x00100000      /* Barcelona B1 */
+-#define       AMD_DR_B2       0x00200000      /* Barcelona B2 */
+-#define       AMD_DR_BA       0x00400000      /* Barcelona BA */
+-#define       AMD_DR_B3       0x00800000      /* Barcelona B3 */
+-#define       AMD_RB_C2       0x01000000      /* Shanghai C2 */
+-#define       AMD_DA_C2       0x02000000      /* XXXX C2 */
+-#define       AMD_HY_D0       0x04000000      /* Istanbul D0 */
+-#define       AMD_RB_C3       0x08000000      /* ??? C3 */
+-#define       AMD_DA_C3       0x10000000      /* XXXX C3 */
+-#define       AMD_HY_D1       0x20000000      /* Istanbul D1 */
+-#define       AMD_PH_E0       0x40000000      /* Phenom II X4 X6 */
++#define       AMD_SAFEMODE    0x8000000000000000      /* Unknown future 
revision - SAFE MODE */
++#define       AMD_NPT_F0      0x0000000000000001      /* F0 stepping */
++#define       AMD_NPT_F1      0x0000000000000002      /* F1 stepping */
++#define       AMD_NPT_F2C     0x0000000000000004
++#define       AMD_NPT_F2D     0x0000000000000008
++#define       AMD_NPT_F2E     0x0000000000000010      /* F2 stepping E */
++#define       AMD_NPT_F2G     0x0000000000000020      /* F2 stepping G */
++#define       AMD_NPT_F2J     0x0000000000000040
++#define       AMD_NPT_F2K     0x0000000000000080
++#define       AMD_NPT_F3L     0x0000000000000100      /* F3 Stepping */
++#define       AMD_NPT_G0A     0x0000000000000200      /* G0 stepping */
++#define       AMD_NPT_G1B     0x0000000000000400      /* G1 stepping */
++#define       AMD_DR_A0A      0x0000000000010000      /* Barcelona A0 */
++#define       AMD_DR_A1B      0x0000000000020000      /* Barcelona A1 */
++#define       AMD_DR_A2       0x0000000000040000      /* Barcelona A2 */
++#define       AMD_DR_B0       0x0000000000080000      /* Barcelona B0 */
++#define       AMD_DR_B1       0x0000000000100000      /* Barcelona B1 */
++#define       AMD_DR_B2       0x0000000000200000      /* Barcelona B2 */
++#define       AMD_DR_BA       0x0000000000400000      /* Barcelona BA */
++#define       AMD_DR_B3       0x0000000000800000      /* Barcelona B3 */
++#define       AMD_RB_C2       0x0000000001000000      /* Shanghai C2 */
++#define       AMD_DA_C2       0x0000000002000000      /* XXXX C2 */
++#define       AMD_HY_D0       0x0000000004000000      /* Istanbul D0 */
++#define       AMD_RB_C3       0x0000000008000000      /* ??? C3 */
++#define       AMD_DA_C3       0x0000000010000000      /* XXXX C3 */
++#define       AMD_HY_D1       0x0000000020000000      /* Istanbul D1 */
++#define       AMD_PH_E0       0x0000000040000000      /* Phenom II X4 X6 */
++#define       AMD_OR_B2       0x0000000080000000      /* Interlagos */
++#define       AMD_OR_C0       0x0000000100000000      /* Abu Dhabi */
+ 
+ /*
+  * Groups - Create as many as you wish, from the above public values
+@@ -76,6 +78,7 @@
+ #define       AMD_DRBH_Cx     (AMD_DR_Cx | AMD_HY_D0 )
+ #define       AMD_DRBA23_RBC2 (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 )
+ #define       AMD_DR_DAC2_OR_C3       (AMD_DA_C2 | AMD_DA_C3 | AMD_RB_C3)
++#define       AMD_FAM15_ALL   (AMD_OR_B2 | AMD_OR_C0)
+ 
+ /*
+  *  Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH 
CPUPLATFORMTYPE RETURN VALUE
+@@ -122,23 +125,34 @@
+  */
+ #define CPUID_EXT_PM          0x80000007
+ #define CPUID_MODEL           1
+-#define MCG_CAP               0x00000179
++#define MCG_CAP                       0x00000179
+       #define MCG_CTL_P       8
+-#define MC0_CTL               0x00000400
+-#define MC0_STA               MC0_CTL + 1
+-#define FS_Base               0xC0000100
++#define MC0_CTL                       0x00000400
++#define MC0_STA                       (MC0_CTL + 1)
++#define MC4_MISC0             0x00000413
++#define MC4_MISC1             0xC0000408
++#define MC4_MISC2             0xC0000409
++#define FS_Base                       0xC0000100
+ #define SYSCFG                        0xC0010010
+ #define HWCR                  0xC0010015
+ #define NB_CFG                        0xC001001F
+ #define FidVidStatus          0xC0010042
++#define MC1_CTL_MASK          0xC0010045
+ #define MC4_CTL_MASK          0xC0010048
+ #define OSVW_ID_Length                0xC0010140
+ #define OSVW_Status           0xC0010141
+ #define CPUIDFEATURES         0xC0011004
+ #define LS_CFG                        0xC0011020
++#define IC_CFG                        0xC0011021
+ #define DC_CFG                        0xC0011022
+ #define BU_CFG                        0xC0011023
+-#define BU_CFG2               0xC001102A
++#define FP_CFG                        0xC0011028
++#define DE_CFG                        0xC0011029
++#define BU_CFG2                       0xC001102A
++#define BU_CFG3                       0xC001102B
++#define EX_CFG                        0xC001102C
++#define LS_CFG2                       0xC001102D
++#define IBS_OP_DATA3          0xC0011037
+ 
+ /*
+  * Processor package types
+diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c 
b/src/northbridge/amd/amdmct/mct/mct_d.c
+index 88910e2..be0af65 100644
+--- a/src/northbridge/amd/amdmct/mct/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct/mct_d.c
+@@ -2189,6 +2189,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                                       
pDCTstat->DimmManufacturerID[i] |= ((uint64_t)mctRead_SPD(smbaddr, 
SPD_MANID_START + k)) << (k * 8);
+                                               for (k = 0; k < 
SPD_PARTN_LENGTH; k++)
+                                                       
pDCTstat->DimmPartNumber[i][k] = mctRead_SPD(smbaddr, SPD_PARTN_START + k);
++                                              
pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
+                                               pDCTstat->DimmRevisionNumber[i] 
= 0;
+                                               for (k = 0; k < 2; k++)
+                                                       
pDCTstat->DimmRevisionNumber[i] |= ((uint16_t)mctRead_SPD(smbaddr, 
SPD_REVNO_START + k)) << (k * 8);
+@@ -2206,8 +2207,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                       if (byte & JED_REGADCMSK) {
+                                               RegDIMMPresent |= 1 << i;
+                                               pDCTstat->DimmRegistered[i] = 1;
+-                                      }
+-                                      else {
++                                      } else {
+                                               pDCTstat->DimmRegistered[i] = 0;
+                                       }
+                                       /* Check ECC capable */
+diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h 
b/src/northbridge/amd/amdmct/mct/mct_d.h
+index 132bdc9..6b6194d 100644
+--- a/src/northbridge/amd/amdmct/mct/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct/mct_d.h
+@@ -434,7 +434,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+               /* CH A byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
+               /* CH B byte lane 0 - 7 minimum filtered window  passing DQS 
delay value*/
+               /* CH B byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
+-      u32 LogicalCPUID;       /* The logical CPUID of the node*/
++      uint64_t LogicalCPUID;  /* The logical CPUID of the node*/
+       u16 HostBiosSrvc1;      /* Word sized general purpose field for use by 
host BIOS.  Scratch space.*/
+       u32 HostBiosSrvc2;      /* Dword sized general purpose field for use by 
host BIOS.  Scratch space.*/
+       u16 DimmQRPresent;      /* QuadRank DIMM present?*/
+@@ -529,7 +529,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+       uint8_t DimmRegistered[MAX_DIMMS_SUPPORTED];
+ 
+       uint64_t DimmManufacturerID[MAX_DIMMS_SUPPORTED];
+-      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH];
++      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
+       uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
+       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
+ } __attribute__((packed));
+@@ -598,17 +598,18 @@ struct DCTStatStruc {            /* A per Node 
structure*/
+                                           266=266MHz (DDR533)
+                                           333=333MHz (DDR667)
+                                           400=400MHz (DDR800)*/
+-#define NV_ECC_CAP            4       /* Bus ECC capable (1-bits)
++#define NV_MIN_MEMCLK         4       /* Minimum platform demonstrated 
Memclock (10-bits) */
++#define NV_ECC_CAP            5       /* Bus ECC capable (1-bits)
+                                           0=Platform not capable
+                                           1=Platform is capable*/
+-#define NV_4RANKType          5       /* Quad Rank DIMM slot type (2-bits)
++#define NV_4RANKType          6       /* Quad Rank DIMM slot type (2-bits)
+                                           0=Normal
+                                           1=R4 (4-Rank Registered DIMMs in 
AMD server configuration)
+                                           2=S4 (Unbuffered SO-DIMMs)*/
+-#define NV_BYPMAX             6       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
++#define NV_BYPMAX             7       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
+                                           4=4 times bypass (normal for 
non-UMA systems)
+                                           7=7 times bypass (normal for UMA 
systems)*/
+-#define NV_RDWRQBYP           7       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
++#define NV_RDWRQBYP           8       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
+                                           2=8 times (normal for non-UMA 
systems)
+                                           3=16 times (normal for UMA 
systems)*/
+ 
+@@ -671,8 +672,9 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+ #define NV_ECCRedir           54      /* Dram ECC Redirection enable*/
+ #define NV_DramBKScrub                55      /* Dram ECC Background Scrubber 
CTL*/
+ #define NV_L2BKScrub          56      /* L2 ECC Background Scrubber CTL*/
+-#define NV_DCBKScrub          57      /* DCache ECC Background Scrubber CTL*/
+-#define NV_CS_SpareCTL                58      /* Chip Select Spare Control 
bit 0:
++#define NV_L3BKScrub          57      /* L3 ECC Background Scrubber CTL*/
++#define NV_DCBKScrub          58      /* DCache ECC Background Scrubber CTL*/
++#define NV_CS_SpareCTL                59      /* Chip Select Spare Control 
bit 0:
+                                              0=disable Spare
+                                              1=enable Spare */
+                                       /* Chip Select Spare Control bit 1-4:
+@@ -712,7 +714,7 @@ u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
+ u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 
RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
+ void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+-u32 mctGetLogicalCPUID(u32 Node);
++uint64_t mctGetLogicalCPUID(u32 Node);
+ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA, u8 Pass);
+ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+diff --git a/src/northbridge/amd/amdmct/mct/mctpro_d.c 
b/src/northbridge/amd/amdmct/mct/mctpro_d.c
+index c332357..fe56201 100644
+--- a/src/northbridge/amd/amdmct/mct/mctpro_d.c
++++ b/src/northbridge/amd/amdmct/mct/mctpro_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -23,7 +24,7 @@ void EarlySampleSupport_D(void)
+ 
+ u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val)
+ {
+-      u32 tmp;
++      uint64_t tmp;
+       tmp = pDCTstat->LogicalCPUID;
+       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+               val &= 0x0FFFFFFF;
+@@ -42,7 +43,7 @@ u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val)
+        * ( F2x[1, 0]8C[1:0] > 00b).  Silicon Status: Fixed in Rev B
+        * FIXME: check if this is still required.
+        */
+-      u32 tmp;
++      uint64_t tmp;
+       tmp = pDCTstat->LogicalCPUID;
+       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+               if(!(val & (3<<12) ))
+@@ -54,7 +55,7 @@ u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val)
+ 
+ void mct_ForceAutoPrecharge_D(struct DCTStatStruc *pDCTstat, u32 dct)
+ {
+-      u32 tmp;
++      uint64_t tmp;
+       u32 reg;
+       u32 reg_off;
+       u32 dev;
+@@ -96,7 +97,7 @@ void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,
+        * FIXME: check this.
+        */
+ 
+-      u32 tmp;
++      uint64_t tmp;
+       u32 dev;
+       u32 reg;
+       u32 val;
+@@ -143,10 +144,9 @@ void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc 
*pMCTstat,
+       u32 index;
+       u32 reg;
+       u32 val;
+-      u32 tmp;
++      uint64_t tmp;
+       u32 Channel;
+ 
+-
+       tmp = pDCTstat->LogicalCPUID;
+       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+ 
+@@ -206,7 +206,7 @@ u32 Modify_D3CMP(struct DCTStatStruc *pDCTstat, u32 dct, 
u32 value)
+       u32 index_reg;
+       u32 index;
+       u32 val;
+-      u32 tmp;
++      uint64_t tmp;
+ 
+       tmp = pDCTstat->LogicalCPUID;
+       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+@@ -237,7 +237,7 @@ void SyncSetting(struct DCTStatStruc *pDCTstat)
+        * Silicon Status: Fix TBD
+        */
+ 
+-      u32 tmp;
++      uint64_t tmp;
+       tmp = pDCTstat->LogicalCPUID;
+       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+               pDCTstat->CH_ODC_CTL[1] = pDCTstat->CH_ODC_CTL[0];
+@@ -278,7 +278,7 @@ u32 CheckNBCOFAutoPrechg(struct DCTStatStruc *pDCTstat, 
u32 dct)
+ 
+ void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct)
+ {
+-      u32 tmp;
++      uint64_t tmp;
+       u32 Speed;
+       u32 ch, ch_start, ch_end;
+       u32 index_reg;
+@@ -286,7 +286,6 @@ void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, 
u32 dct)
+       u32 dev;
+       u32 val;
+ 
+-
+       tmp = pDCTstat->LogicalCPUID;
+       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+               Speed = pDCTstat->Speed;
+@@ -331,7 +330,7 @@ static u8 mct_checkFenceHoleAdjust_D(struct MCTStatStruc 
*pMCTstat,
+                               u8 ChipSel,  u8 *result)
+ {
+       u8 ByteLane;
+-      u32 tmp;
++      uint64_t tmp;
+ 
+       tmp = pDCTstat->LogicalCPUID;
+       if ((tmp == AMD_DR_A0A) || (tmp == AMD_DR_A1B) || (tmp == AMD_DR_A2)) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 12dfff1..74066b1 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -75,6 +75,8 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+ static u16 Get_Fk_D(u8 k);
+ static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i);
++static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat);
+ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+ static void mct_DramInit(struct MCTStatStruc *pMCTstat,
+@@ -105,11 +107,11 @@ static void Get_TrwtTO(struct MCTStatStruc *pMCTstat,
+ static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat);
+ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
+-                                      u32 dev, u32 index_reg);
++                                      u32 dev, uint8_t dct, u32 index_reg);
+ static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat, u8 dct,
+                                       u32 dev, u32 index_reg);
+ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
+-                              u32 dev, u32 index_reg, u32 index);
++                              u32 dev, uint8_t dct, u32 index_reg, u32 index);
+ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat, u8 dct,
+@@ -128,6 +130,8 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
++static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat, u8 dct);
+ static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+ static u32 mct_NodePresent_D(void);
+@@ -138,7 +142,9 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc 
*pMCTstat,
+ static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat);
++                                      struct DCTStatStruc *pDCTstat, u8 dct);
++static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat, u8 dct);
+ void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat);
+ static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
+@@ -158,6 +164,10 @@ static u32 mct_DisDllShutdownSR(struct MCTStatStruc 
*pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 
DramConfigLo, u8 dct);
+ static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
++static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat);
++void SetTargetFreq(struct MCTStatStruc *pMCTstat,
++                                        struct DCTStatStruc *pDCTstat);
+ 
+ static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u32 MrsChipSel);
+@@ -165,7 +175,8 @@ static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc 
*pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dimm);
+ static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 
misc2);
+ static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat);
+-static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA);
++static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Pass);
+ static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+ static void SyncSetting(struct DCTStatStruc *pDCTstat);
+@@ -173,6 +184,12 @@ static u8 crcCheck(u8 smbaddr);
+ static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
+ static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
+ 
++static void read_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay,
++                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
++
++static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay,
++                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
++
+ /*See mctAutoInitMCT header for index relationships to CL and T*/
+ static const u16 Table_F_k[]  = {00,200,266,333,400,533 };
+ static const u8 Tab_BankAddr[]        = 
{0x3F,0x01,0x09,0x3F,0x3F,0x11,0x0A,0x19,0x12,0x1A,0x21,0x22,0x23};
+@@ -223,6 +240,936 @@ static const u8 Table_Comp_Rise_Slew_15x[] = {7, 7, 3, 
2, 0xFF};
+ static const u8 Table_Comp_Fall_Slew_20x[] = {7, 5, 3, 2, 0xFF};
+ static const u8 Table_Comp_Fall_Slew_15x[] = {7, 7, 5, 3, 0xFF};
+ 
++static uint8_t dct_ddr_voltage_index(struct DCTStatStruc *pDCTstat, uint8_t 
dct)
++{
++      uint8_t dimm;
++      uint8_t ddr_voltage_index = 0;
++
++      /* Find current DDR supply voltage for this DCT */
++      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
++              if (pDCTstat->DIMMValidDCT[dct] & (1 << dimm))
++                      ddr_voltage_index |= 
pDCTstat->DimmConfiguredVoltage[dimm];
++      }
++      if (ddr_voltage_index > 0x7) {
++              printk(BIOS_DEBUG, "%s: Insufficient DDR supply voltage 
indicated!  Configuring processor for 1.25V operation, but this attempt may 
fail...\n", __func__);
++              ddr_voltage_index = 0x4;
++      }
++      if (ddr_voltage_index == 0x0) {
++              printk(BIOS_DEBUG, "%s: No DDR supply voltage indicated!  
Configuring processor for 1.5V operation, but this attempt may fail...\n", 
__func__);
++              ddr_voltage_index = 0x1;
++      }
++
++      return ddr_voltage_index;
++}
++
++static uint16_t fam15h_mhz_to_memclk_config(uint16_t freq)
++{
++      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
++      uint16_t iter;
++
++      /* Compute the index value for the given frequency */
++      for (iter = 0; iter <= 0x16; iter++) {
++              if (fam15h_freq_tab[iter] == freq)
++                      break;
++      }
++      if (fam15h_freq_tab[iter] == freq)
++              freq = iter;
++      if (freq == 0)
++              freq = 0x4;
++
++      return freq;
++}
++
++static uint16_t fam10h_mhz_to_memclk_config(uint16_t freq)
++{
++      uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
++      uint16_t iter;
++
++      /* Compute the index value for the given frequency */
++      for (iter = 0; iter <= 0x6; iter++) {
++              if (fam10h_freq_tab[iter] == freq)
++                      break;
++      }
++      if (fam10h_freq_tab[iter] == freq)
++              freq = iter;
++      if (freq == 0)
++              freq = 0x3;
++
++      return freq;
++}
++
++static uint16_t mhz_to_memclk_config(uint16_t freq)
++{
++      if (is_fam15h())
++              return fam15h_mhz_to_memclk_config(freq);
++      else
++              return fam10h_mhz_to_memclk_config(freq) + 1;
++}
++
++static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t drive_strength)
++{
++      uint8_t lrdimm = 0;
++      uint8_t package_type;
++      uint8_t ddr_voltage_index;
++      uint32_t calibration_code = 0;
++      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++      if (!lrdimm) {
++              /* Not an LRDIMM */
++              if ((package_type == PT_M2) || (package_type == PT_GR)) {
++                      /* Socket AM3 or G34 */
++                      if (ddr_voltage_index & 0x4) {
++                              /* 1.25V */
++                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 43 */
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xb6d;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x924;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x6db;
++                              } else if ((MemClkFreq == 0xa) || (MemClkFreq 
== 0xe)) {
++                                      /* DDR3-1066 - DDR3-1333 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xdb6;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x924;
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0xfff;
++                              }
++                      }
++                      else if (ddr_voltage_index & 0x2) {
++                              /* 1.35V */
++                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 42 */
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x924;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x492;
++                              } else if ((MemClkFreq == 0xa) || (MemClkFreq 
== 0xe)) {
++                                      /* DDR3-1066 - DDR3-1333 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xdb6;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xbd6;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x6db;
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0xdb6;
++                              }
++                      }
++                      else if (ddr_voltage_index & 0x1) {
++                              /* 1.5V */
++                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 41 */
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xb6d;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x492;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x492;
++                              } else if ((MemClkFreq == 0xa) || (MemClkFreq 
== 0xe)) {
++                                      /* DDR3-1066 - DDR3-1333 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x924;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x6db;
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0xb6d;
++                              }
++                      }
++              }
++              else if (package_type == PT_C3) {
++                      /* Socket C32 */
++                      if (ddr_voltage_index & 0x4) {
++                              /* 1.25V */
++                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 46 */
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xb6d;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x924;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x6db;
++                              } else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xdb6;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x924;
++                              } else if (MemClkFreq == 0xe) {
++                                      /* DDR3-1333 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xb6d;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x492;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x492;
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0xfff;
++                              }
++                      }
++                      else if (ddr_voltage_index & 0x2) {
++                              /* 1.35V */
++                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 45 */
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x924;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x492;
++                              } else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xdb6;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xb6d;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x6db;
++                              } else if (MemClkFreq == 0xe) {
++                                      /* DDR3-1333 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x924;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x492;
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0xdb6;
++                              }
++                      }
++                      else if (ddr_voltage_index & 0x1) {
++                              /* 1.5V */
++                              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 44 */
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xb6d;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x492;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x492;
++                              } else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x924;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x6db;
++                              } else if (MemClkFreq == 0xe) {
++                                      /* DDR3-1333 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xb6d;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0x6db;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0x492;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0x492;
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
++                                      if (drive_strength == 0x0)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x1)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x2)
++                                              calibration_code = 0xfff;
++                                      else if (drive_strength == 0x3)
++                                              calibration_code = 0xb6d;
++                              }
++                      }
++              }
++      } else {
++              /* LRDIMM */
++
++              /* TODO
++               * Implement LRDIMM support
++               * See Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Tables 47 - 49
++               */
++      }
++
++      return calibration_code;
++}
++
++static uint32_t fam15h_phy_predriver_cmd_addr_calibration_code(struct 
DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength)
++{
++      uint8_t ddr_voltage_index;
++      uint32_t calibration_code = 0;
++      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
++
++      if (ddr_voltage_index & 0x4) {
++              /* 1.25V */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 52 */
++              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
++                      /* DDR3-667 - DDR3-800 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x492;
++              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
++                      /* DDR3-1066 - DDR3-1333 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xdad;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x6db;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x492;
++              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
++                      /* DDR3-1600 - DDR3-1866 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xdad;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xb64;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xb64;
++              }
++      }
++      else if (ddr_voltage_index & 0x2) {
++              /* 1.35V */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 51 */
++              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
++                      /* DDR3-667 - DDR3-800 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x492;
++              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
++                      /* DDR3-1066 - DDR3-1333 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0x6db;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x6db;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x6db;
++              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
++                      /* DDR3-1600 - DDR3-1866 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xb6d;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xb6d;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x924;
++              }
++      }
++      else if (ddr_voltage_index & 0x1) {
++              /* 1.5V */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 50 */
++              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
++                      /* DDR3-667 - DDR3-800 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x492;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x492;
++              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
++                      /* DDR3-1066 - DDR3-1333 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0x6db;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0x6db;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x6db;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x6db;
++              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
++                      /* DDR3-1600 - DDR3-1866 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xb6d;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xb6d;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xb6d;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xb6d;
++              }
++      }
++
++      return calibration_code;
++}
++
++static uint32_t fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t drive_strength)
++{
++      uint8_t ddr_voltage_index;
++      uint32_t calibration_code = 0;
++      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
++
++      if (ddr_voltage_index & 0x4) {
++              /* 1.25V */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 55 */
++              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
++                      /* DDR3-667 - DDR3-800 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xdad;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xdad;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x924;
++              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
++                      /* DDR3-1066 - DDR3-1333 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xff6;
++              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
++                      /* DDR3-1600 - DDR3-1866 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xff6;
++              }
++      }
++      else if (ddr_voltage_index & 0x2) {
++              /* 1.35V */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 54 */
++              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
++                      /* DDR3-667 - DDR3-800 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xdad;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xdad;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x924;
++              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
++                      /* DDR3-1066 - DDR3-1333 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xdad;
++              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
++                      /* DDR3-1600 - DDR3-1866 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xdad;
++              }
++      }
++      else if (ddr_voltage_index & 0x1) {
++              /* 1.5V */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 53 */
++              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
++                      /* DDR3-667 - DDR3-800 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0x924;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0x924;
++              } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
++                      /* DDR3-1066 - DDR3-1333 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xb6d;
++              } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) {
++                      /* DDR3-1600 - DDR3-1866 */
++                      if (drive_strength == 0x0)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x1)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x2)
++                              calibration_code = 0xff6;
++                      else if (drive_strength == 0x3)
++                              calibration_code = 0xff6;
++              }
++      }
++
++      return calibration_code;
++}
++
++static uint32_t fam15h_output_driver_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
++{
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      uint8_t package_type;
++      uint32_t calibration_code = 0;
++
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      /* Obtain number of DIMMs on channel */
++      uint8_t dimm_count = pDCTstat->MAdimms[dct];
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++
++      if (package_type == PT_GR) {
++              /* Socket G34 */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
++              if (MaxDimmsInstallable == 1) {
++                      if (MemClkFreq == 0x4) {
++                              /* DDR3-667 */
++                              calibration_code = 0x00112222;
++                      }
++                      else if (MemClkFreq == 0x6) {
++                              /* DDR3-800 */
++                              calibration_code = 0x10112222;
++                      }
++                      else if (MemClkFreq == 0xa) {
++                              /* DDR3-1066 */
++                              calibration_code = 0x20112222;
++                      }
++                      else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) {
++                              /* DDR3-1333 - DDR3-1600 */
++                              calibration_code = 0x30112222;
++                      }
++                      else if (MemClkFreq == 0x16) {
++                              /* DDR3-1866 */
++                              calibration_code = 0x30332222;
++                      }
++              } else if (MaxDimmsInstallable == 2) {
++                      if (dimm_count == 1) {
++                              /* 1 DIMM detected */
++                              if (MemClkFreq == 0x4) {
++                                      /* DDR3-667 */
++                                      calibration_code = 0x00112222;
++                              }
++                              else if (MemClkFreq == 0x6) {
++                                      /* DDR3-800 */
++                                      calibration_code = 0x10112222;
++                              }
++                              else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      calibration_code = 0x20112222;
++                              }
++                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
++                                      /* DDR3-1333 - DDR3-1600 */
++                                      calibration_code = 0x30112222;
++                              }
++                      } else if (dimm_count == 2) {
++                              /* 2 DIMMs detected */
++                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                              if (MemClkFreq == 0x4) {
++                                      /* DDR3-667 */
++                                      calibration_code = 0x10222222;
++                              }
++                              else if (MemClkFreq == 0x6) {
++                                      /* DDR3-800 */
++                                      calibration_code = 0x20222222;
++                              }
++                              else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      calibration_code = 0x30222222;
++                              }
++                              else if (MemClkFreq == 0xe) {
++                                      /* DDR3-1333 */
++                                      calibration_code = 0x30222222;
++                              }
++                              else if (MemClkFreq == 0x12) {
++                                      /* DDR3-1600 */
++                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
++                                              calibration_code = 0x30222222;
++                                      else
++                                              calibration_code = 0x30112222;
++                              }
++                      }
++              } else if (MaxDimmsInstallable == 3) {
++                      /* TODO
++                       * 3 DIMM/channel support unimplemented
++                       */
++              }
++      } else {
++              /* TODO
++               * Other socket support unimplemented
++               */
++      }
++
++      return calibration_code;
++}
++
++static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
++{
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      uint8_t package_type;
++      uint32_t calibration_code = 0;
++
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      /* Obtain number of DIMMs on channel */
++      uint8_t dimm_count = pDCTstat->MAdimms[dct];
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++
++      if (package_type == PT_GR) {
++              /* Socket G34 */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
++              if (MaxDimmsInstallable == 1) {
++                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                      if (MemClkFreq == 0x4) {
++                              /* DDR3-667 */
++                              if (rank_count_dimm0 == 1)
++                                      calibration_code = 0x00000000;
++                              else
++                                      calibration_code = 0x003b0000;
++                      } else if (MemClkFreq == 0x6) {
++                              /* DDR3-800 */
++                              if (rank_count_dimm0 == 1)
++                                      calibration_code = 0x00000000;
++                              else
++                                      calibration_code = 0x003b0000;
++                      } else if (MemClkFreq == 0xa) {
++                              /* DDR3-1066 */
++                              calibration_code = 0x00383837;
++                      } else if (MemClkFreq == 0xe) {
++                              /* DDR3-1333 */
++                              calibration_code = 0x00363635;
++                      } else if (MemClkFreq == 0x12) {
++                              /* DDR3-1600 */
++                              if (rank_count_dimm0 == 1)
++                                      calibration_code = 0x00353533;
++                              else
++                                      calibration_code = 0x00003533;
++                      } else if (MemClkFreq == 0x16) {
++                              /* DDR3-1866 */
++                              calibration_code = 0x00333330;
++                      }
++              } else if (MaxDimmsInstallable == 2) {
++                      if (dimm_count == 1) {
++                              /* 1 DIMM detected */
++                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                              if (MemClkFreq == 0x4) {
++                                      /* DDR3-667 */
++                                      if (rank_count_dimm0 == 1)
++                                              calibration_code = 0x00000000;
++                                      else
++                                              calibration_code = 0x003b0000;
++                              } else if (MemClkFreq == 0x6) {
++                                      /* DDR3-800 */
++                                      if (rank_count_dimm0 == 1)
++                                              calibration_code = 0x00000000;
++                                      else
++                                              calibration_code = 0x003b0000;
++                              } else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      calibration_code = 0x00383837;
++                              } else if (MemClkFreq == 0xe) {
++                                      /* DDR3-1333 */
++                                      calibration_code = 0x00363635;
++                              } else if (MemClkFreq == 0x12) {
++                                      /* DDR3-1600 */
++                                      if (rank_count_dimm0 == 1)
++                                              calibration_code = 0x00353533;
++                                      else
++                                              calibration_code = 0x00003533;
++                              }
++                      } else if (dimm_count == 2) {
++                              /* 2 DIMMs detected */
++                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                              if (MemClkFreq == 0x4) {
++                                      /* DDR3-667 */
++                                      calibration_code = 0x00390039;
++                              } else if (MemClkFreq == 0x6) {
++                                      /* DDR3-800 */
++                                      calibration_code = 0x00390039;
++                              } else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      calibration_code = 0x003a3a3a;
++                              } else if (MemClkFreq == 0xe) {
++                                      /* DDR3-1333 */
++                                      calibration_code = 0x00003939;
++                              } else if (MemClkFreq == 0x12) {
++                                      /* DDR3-1600 */
++                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
++                                              calibration_code = 0x00003738;
++                              }
++                      }
++              } else if (MaxDimmsInstallable == 3) {
++                      /* TODO
++                       * 3 DIMM/channel support unimplemented
++                       */
++              }
++      } else {
++              /* TODO
++               * Other socket support unimplemented
++               */
++      }
++
++      return calibration_code;
++}
++
++static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t 
dct)
++{
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      uint8_t package_type;
++      uint32_t slow_access = 0;
++
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      /* Obtain number of DIMMs on channel */
++      uint8_t dimm_count = pDCTstat->MAdimms[dct];
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++
++      if (package_type == PT_GR) {
++              /* Socket G34 */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
++              if (MaxDimmsInstallable == 1) {
++                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                      if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
++                              || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) {
++                              /* DDR3-667 - DDR3-1333 */
++                              slow_access = 0;
++                      } else if ((MemClkFreq == 0x12) || (MemClkFreq == 
0x16)) {
++                              /* DDR3-1600 - DDR3-1866 */
++                              if (rank_count_dimm0 == 1)
++                                      slow_access = 0;
++                              else
++                                      slow_access = 1;
++                      }
++              } else if (MaxDimmsInstallable == 2) {
++                      if (dimm_count == 1) {
++                              /* 1 DIMM detected */
++                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
++                                      || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
++                                      /* DDR3-667 - DDR3-1333 */
++                                      slow_access = 0;
++                              }
++                              else if (MemClkFreq == 0x12) {
++                                      /* DDR3-1600 */
++                                      if (rank_count_dimm0 == 1)
++                                              slow_access = 0;
++                                      else
++                                              slow_access = 1;
++                              }
++                      } else if (dimm_count == 2) {
++                              /* 2 DIMMs detected */
++                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
++                                      || (MemClkFreq == 0xa)) {
++                                      /* DDR3-667 - DDR3-1066 */
++                                      slow_access = 0;
++                              }
++                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
++                                      /* DDR3-1333 - DDR3-1600 */
++                                      slow_access = 1;
++                              }
++                      }
++              } else if (MaxDimmsInstallable == 3) {
++                      /* TODO
++                       * 3 DIMM/channel support unimplemented
++                       */
++              }
++      } else {
++              /* TODO
++               * Other socket support unimplemented
++               */
++      }
++
++      return slow_access;
++}
++
++static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, u8 dct)
++{
++      uint32_t dev;
++      uint32_t reg;
++      uint32_t dword;
++
++      uint8_t enable_slow_access_mode = 0;
++      dev = pDCTstat->dev_dct;
++
++      if (is_fam15h()) {
++              if (pDCTstat->_2Tmode)
++                      enable_slow_access_mode = 1;
++      } else {
++              if (pDCTstat->_2Tmode == 2)
++                      enable_slow_access_mode = 1;
++      }
++
++      reg = 0x94;                             /* DRAM Configuration High */
++      dword = Get_NB32_DCT(dev, dct, reg);
++      if (enable_slow_access_mode)
++              dword |= (0x1 << 20);           /* Set 2T CMD mode */
++      else
++              dword &= ~(0x1 << 20);          /* Clear 2T CMD mode */
++      Set_NB32_DCT(dev, dct, reg, dword);
++}
++
++static void precise_ndelay_fam15(struct MCTStatStruc *pMCTstat, uint32_t 
nanoseconds) {
++      msr_t tsc_msr;
++      uint64_t cycle_count = (((uint64_t)pMCTstat->TSCFreq) * nanoseconds) / 
1000;
++      uint64_t start_timestamp;
++      uint64_t current_timestamp;
++
++      tsc_msr = rdmsr(0x00000010);
++      start_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo;
++        do {
++              tsc_msr = rdmsr(0x00000010);
++              current_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo;
++        } while ((current_timestamp - start_timestamp) < cycle_count);
++}
++
++static void precise_memclk_delay_fam15(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, uint8_t dct, uint32_t clocks) {
++      uint16_t memclk_freq;
++      uint32_t delay_ns;
++      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
++
++      memclk_freq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      delay_ns = (((uint64_t)clocks * 1000) / fam15h_freq_tab[memclk_freq]);
++      precise_ndelay_fam15(pMCTstat, delay_ns);
++}
++
+ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+ {
+@@ -277,10 +1224,26 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
+ restartinit:
+       mctInitMemGPIOs_A_D();          /* Set any required GPIOs*/
+       if (s3resume) {
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_En_Fam15\n");
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
++
++                      mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
++              }
++
+ #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
+               restore_mct_information_from_nvram();
+ #endif
++
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
++
++                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
++              }
+       } else {
+               NodesWmem = 0;
+               node_sys_base = 0;
+@@ -297,15 +1260,15 @@ restartinit:
+                       pDCTstat->dev_map = PA_MAP(Node);
+                       pDCTstat->dev_dct = PA_DCT(Node);
+                       pDCTstat->dev_nbmisc = PA_NBMISC(Node);
++                      pDCTstat->dev_link = PA_LINK(Node);
++                      pDCTstat->dev_nbctl = PA_NBCTL(Node);
+                       pDCTstat->NodeSysBase = node_sys_base;
+ 
+                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node 
%d\n", Node);
+                       mct_init(pMCTstat, pDCTstat);
+                       mctNodeIDDebugPort_D();
+                       pDCTstat->NodePresent = NodePresent_D(Node);
+-                      if (pDCTstat->NodePresent) {            /* See if Node 
is there*/
+-                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
clear_legacy_Mode\n");
+-                              clear_legacy_Mode(pMCTstat, pDCTstat);
++                      if (pDCTstat->NodePresent) {
+                               pDCTstat->LogicalCPUID = 
mctGetLogicalCPUID_D(Node);
+ 
+                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_InitialMCT_D\n");
+@@ -314,6 +1277,26 @@ restartinit:
+                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
+                               mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
+ 
++                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_preInitDCT\n");
++                              mct_preInitDCT(pMCTstat, pDCTstat);
++                      }
++                      node_sys_base = pDCTstat->NodeSysBase;
++                      node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
++              }
++
++#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
++              DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
++#endif
++
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
++
++                      if (pDCTstat->NodePresent) {
++                              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
++                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
++
+                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_initDCT\n");
+                               mct_initDCT(pMCTstat, pDCTstat);
+                               if (pDCTstat->ErrCode == SC_FatalErr) {
+@@ -321,20 +1304,13 @@ restartinit:
+                               } else if (pDCTstat->ErrCode < SC_StopError) {
+                                       NodesWmem++;
+                               }
+-                      }       /* if Node present */
+-                      node_sys_base = pDCTstat->NodeSysBase;
+-                      node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
++                      }
+               }
+               if (NodesWmem == 0) {
+                       printk(BIOS_DEBUG, "No Nodes?!\n");
+                       goto fatalexit;
+               }
+ 
+-#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
+-              DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
+-#endif
+-
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n");
+               SyncDCTsReady_D(pMCTstat, pDCTstatA);   /* Make sure DCTs are 
ready for accesses.*/
+ 
+@@ -355,7 +1331,6 @@ restartinit:
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+               mct_OtherTiming(pMCTstat, pDCTstatA);
+ 
+-
+               if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 
1st pass of DIMM spare enabled*/
+                       goto restartinit;
+               }
+@@ -369,6 +1344,14 @@ restartinit:
+                       MCTMemClr_D(pMCTstat,pDCTstatA);
+               }
+ 
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
++
++                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
++              }
++
+               mct_FinalMCT_D(pMCTstat, pDCTstatA);
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: 
%x\n", pMCTstat->GStatus);
+       }
+@@ -408,6 +1391,425 @@ static u8 ReconfigureDIMMspare_D(struct MCTStatStruc 
*pMCTstat,
+       return ret;
+ }
+ 
++/* Enable or disable phy-assisted training mode
++ * Phy-assisted training mode applies to the follow DRAM training procedures:
++ * Write Levelization Training (2.10.5.8.1)
++ * DQS Receiver Enable Training (2.10.5.8.2)
++ */
++static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
++                      struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t 
enable)
++{
++      uint8_t index;
++      uint32_t dword;
++      uint32_t index_reg = 0x98;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      if (enable) {
++              /* Enable training mode */
++              dword = Get_NB32_DCT(dev, dct, 0x78);                   /* DRAM 
Control */
++              dword &= ~(0x1 << 17);                                  /* 
AddrCmdTriEn = 0 */
++              Set_NB32_DCT(dev, dct, 0x78, dword);                    /* DRAM 
Control */
++
++              dword = Get_NB32_DCT(dev, dct, 0x8c);                   /* DRAM 
Timing High */
++              dword |= (0x1 << 18);                                   /* 
DisAutoRefresh = 1 */
++              Set_NB32_DCT(dev, dct, 0x8c, dword);                    /* DRAM 
Timing High */
++
++              dword = Get_NB32_DCT(dev, dct, 0x94);                   /* DRAM 
Configuration High */
++              dword &= ~(0xf << 24);                                  /* 
DcqBypassMax = 0 */
++              dword &= ~(0x1 << 22);                                  /* 
BankSwizzleMode = 0 */
++              dword &= ~(0x1 << 15);                                  /* 
PowerDownEn = 0 */
++              dword &= ~(0x3 << 10);                                  /* 
ZqcsInterval = 0 */
++              Set_NB32_DCT(dev, dct, 0x94, dword);                    /* DRAM 
Configuration High */
++
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d);
++              dword &= ~(0xf << 16);                                  /* 
RxMaxDurDllNoLock = 0 */
++              dword &= ~(0xf);                                        /* 
TxMaxDurDllNoLock = 0 */
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword);
++
++              for (index = 0; index < 0x9; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0010 | (index << 8));
++                      dword &= ~(0x1 << 12);                          /* 
EnRxPadStandby = 0 */
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 
| (index << 8), dword);
++              }
++
++              dword = Get_NB32_DCT(dev, dct, 0xa4);                   /* DRAM 
Controller Temperature Throttle */
++              dword &= ~(0x1 << 11);                                  /* 
BwCapEn = 0 */
++              dword &= ~(0x1 << 8);                                   /* 
ODTSEn = 0 */
++              Set_NB32_DCT(dev, dct, 0xa4, dword);                    /* DRAM 
Controller Temperature Throttle */
++
++              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* DRAM 
Controller Select Low */
++              dword &= ~(0x1 << 2);                                   /* 
DctSelIntLvEn = 0 */
++              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
++
++              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58);  /* 
Scrub Rate Control */
++              dword &= ~(0x1f << 24);                                 /* 
L3Scrub = 0 */
++              dword &= ~(0x1f);                                       /* 
DramScrub = 0 */
++              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* 
Scrub Rate Control */
++
++              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM 
Scrub Address Low */
++              dword &= ~(0x1);                                        /* 
ScrubReDirEn = 0 */
++              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM 
Scrub Address Low */
++
++              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 
Control 1 */
++              dword |= (0x1 << 4);                                    /* 
L3ScrbRedirDis = 1 */
++              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 
Control 1 */
++
++              /* Fam15h BKDG section 2.10.5.5.1 */
++              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
++              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0xb */
++              dword |= (0xb << 24);
++              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = 0xb */
++              dword |= (0xb << 16);
++              dword &= ~(0xf);                                        /* 
TrdrdDd = 0xb */
++              dword |= 0xb;
++              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
++
++              /* Fam15h BKDG section 2.10.5.5.2 */
++              dword = Get_NB32_DCT(dev, dct, 0x214);                  /* DRAM 
Timing 4 */
++              dword &= ~(0xf << 16);                                  /* 
TwrwrSdSc = 0xb */
++              dword |= (0xb << 16);
++              dword &= ~(0xf << 8);                                   /* 
TwrwrSdDc = 0xb */
++              dword |= (0xb << 8);
++              dword &= ~(0xf);                                        /* 
TwrwrDd = 0xb */
++              dword |= 0xb;
++              Set_NB32_DCT(dev, dct, 0x214, dword);                   /* DRAM 
Timing 4 */
++
++              /* Fam15h BKDG section 2.10.5.5.3 */
++              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
++              dword &= ~(0xf << 8);                                   /* 
Twrrd = 0xb */
++              dword |= (0xb << 8);
++              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
++
++              /* Fam15h BKDG section 2.10.5.5.4 */
++              dword = Get_NB32_DCT(dev, dct, 0x21c);                  /* DRAM 
Timing 6 */
++              dword &= ~(0x1f << 8);                                  /* 
TrwtTO = 0x16 */
++              dword |= (0x16 << 8);
++              dword &= ~(0x1f << 16);                                 /* 
TrwtWB = TrwtTO + 1 */
++              dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
++              Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
++      } else {
++              /* Disable training mode */
++              uint8_t lane;
++              uint8_t dimm;
++              uint8_t receiver;
++              uint8_t max_lane;
++              uint8_t ecc_enabled;
++              uint8_t x4_present = 0;
++              uint8_t x8_present = 0;
++              uint8_t memclk_index;
++              uint8_t interleave_channels = 0;
++              uint8_t redirect_ecc_scrub = 0;
++              uint16_t trdrdsddc;
++              uint16_t trdrddd;
++              uint16_t cdd_trdrddd;
++              uint16_t twrwrsddc;
++              uint16_t twrwrdd;
++              uint16_t cdd_twrwrdd;
++              uint16_t twrrd;
++              uint16_t trwtto;
++              uint8_t first_dimm;
++              uint16_t delay;
++              uint16_t delay2;
++              uint8_t read_odt_delay;
++              uint8_t write_odt_delay;
++              uint16_t difference;
++              uint16_t current_total_delay_1[MAX_BYTE_LANES];
++              uint16_t current_total_delay_2[MAX_BYTE_LANES];
++
++              /* FIXME
++               * This should be platform configurable
++               */
++              uint8_t dimm_event_l_pin_support = 0;
++
++              ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs);
++              if (ecc_enabled)
++                      max_lane = 9;
++              else
++                      max_lane = 8;
++
++              if (pDCTstat->Dimmx4Present & ((dct)?0xaa:0x55))
++                      x4_present = 1;
++              if (pDCTstat->Dimmx8Present & ((dct)?0xaa:0x55))
++                      x8_present = 1;
++              memclk_index = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
++
++              if (pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1] && 
mctGet_NVbits(NV_Unganged))
++                      interleave_channels = 1;
++
++              if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
++                      redirect_ecc_scrub = 1;
++
++              dword = (Get_NB32_DCT(dev, dct, 0x240) >> 4) & 0xf;
++              if (dword > 6)
++                      read_odt_delay = dword - 6;
++              else
++                      read_odt_delay = 0;
++
++              dword = Get_NB32_DCT(dev, dct, 0x240);
++              delay = (dword >> 4) & 0xf;
++              if (delay > 6)
++                      read_odt_delay = delay - 6;
++              else
++                      read_odt_delay = 0;
++              delay = (dword >> 12) & 0x7;
++              if (delay > 6)
++                      write_odt_delay = delay - 6;
++              else
++                      write_odt_delay = 0;
++
++              /* TODO:
++               * Adjust trdrdsddc if four-rank DIMMs are installed per
++               * section 2.10.5.5.1 of the Family 15h BKDG.
++               * cdd_trdrdsddc will also need to be calculated in that 
process.
++               */
++              trdrdsddc = 3;
++
++              /* Calculate the Critical Delay Difference for TrdrdDd */
++              cdd_trdrddd = 0;
++              first_dimm = 1;
++              for (receiver = 0; receiver < 8; receiver += 2) {
++                      dimm = (receiver >> 1);
++
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
++                              continue;
++
++                      
read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, 
dimm, index_reg);
++
++                      if (first_dimm) {
++                              memcpy(current_total_delay_1, 
current_total_delay_2, sizeof(current_total_delay_1));
++                              first_dimm = 0;
++                      }
++
++                      for (lane = 0; lane < max_lane; lane++) {
++                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
++                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
++                              else
++                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
++
++                              if (difference > cdd_trdrddd)
++                                      cdd_trdrddd = difference;
++                      }
++              }
++
++              /* Convert the difference to MEMCLKs */
++              cdd_trdrddd = (((cdd_trdrddd >> 5) & 0x1f) + 1) / 2;
++
++              /* Calculate Trdrddd */
++              delay = (read_odt_delay + 3) * 2;
++              delay2 = cdd_trdrddd + 7;
++              if (delay2 > delay)
++                      delay = delay2;
++              trdrddd = (delay + 1) / 2;      /* + 1 is equivalent to ceiling 
function here */
++              if (trdrdsddc > trdrddd)
++                      trdrddd = trdrdsddc;
++
++              /* TODO:
++               * Adjust twrwrsddc if four-rank DIMMs are installed per
++               * section 2.10.5.5.1 of the Family 15h BKDG.
++               * cdd_twrwrsddc will also need to be calculated in that 
process.
++               */
++              twrwrsddc = 4;
++
++              /* Calculate the Critical Delay Difference for TwrwrDd */
++              cdd_twrwrdd = 0;
++              first_dimm = 1;
++              for (receiver = 0; receiver < 8; receiver += 2) {
++                      dimm = (receiver >> 1);
++
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
++                              continue;
++
++                      
read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, 
index_reg);
++
++                      if (first_dimm) {
++                              memcpy(current_total_delay_1, 
current_total_delay_2, sizeof(current_total_delay_1));
++                              first_dimm = 0;
++                      }
++
++                      for (lane = 0; lane < max_lane; lane++) {
++                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
++                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
++                              else
++                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
++
++                              if (difference > cdd_twrwrdd)
++                                      cdd_twrwrdd = difference;
++                      }
++              }
++
++              /* Convert the difference to MEMCLKs */
++              cdd_twrwrdd = (((cdd_twrwrdd >> 5) & 0x1f) + 1) / 2;
++
++              /* Calculate Twrwrdd */
++              delay = (write_odt_delay + 3) * 2;
++              delay2 = cdd_twrwrdd + 7;
++              if (delay2 > delay)
++                      delay = delay2;
++              twrwrdd = (delay + 1) / 2;      /* + 1 is equivalent to ceiling 
function here */
++              if (twrwrsddc > twrwrdd)
++                      twrwrdd = twrwrsddc;
++
++              dword = Get_NB32_DCT(dev, dct, 0x78);                   /* DRAM 
Control */
++              dword |= (0x1 << 17);                                   /* 
AddrCmdTriEn = 1 */
++              Set_NB32_DCT(dev, dct, 0x78, dword);                    /* DRAM 
Control */
++
++              dword = Get_NB32_DCT(dev, dct, 0x8c);                   /* DRAM 
Timing High */
++              dword &= ~(0x1 << 18);                                  /* 
DisAutoRefresh = 0 */
++              Set_NB32_DCT(dev, dct, 0x8c, dword);                    /* DRAM 
Timing High */
++
++              dword = Get_NB32_DCT(dev, dct, 0x94);                   /* DRAM 
Configuration High */
++              dword |= (0xf << 24);                                   /* 
DcqBypassMax = 0xf */
++              dword |= (0x1 << 22);                                   /* 
BankSwizzleMode = 1 */
++              dword |= (0x1 << 15);                                   /* 
PowerDownEn = 1 */
++              dword &= ~(0x3 << 10);                                  /* 
ZqcsInterval = 0x2 */
++              dword |= (0x2 << 10);
++              Set_NB32_DCT(dev, dct, 0x94, dword);                    /* DRAM 
Configuration High */
++
++              if (x4_present && x8_present) {
++                      /* Mixed channel of 4x and 8x DIMMs */
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d);
++                      dword &= ~(0x3 << 24);                                  
/* RxDLLWakeupTime = 0 */
++                      dword &= ~(0x7 << 20);                                  
/* RxCPUpdPeriod = 0 */
++                      dword &= ~(0xf << 16);                                  
/* RxMaxDurDllNoLock = 0 */
++                      dword &= ~(0x3 << 8);                                   
/* TxDLLWakeupTime = 0 */
++                      dword &= ~(0x7 << 4);                                   
/* TxCPUpdPeriod = 0 */
++                      dword &= ~(0xf);                                        
/* TxMaxDurDllNoLock = 0 */
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d, dword);
++              } else {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d);
++                      dword &= ~(0x3 << 24);                                  
/* RxDLLWakeupTime = 3 */
++                      dword |= (0x3 << 24);
++                      dword &= ~(0x7 << 20);                                  
/* RxCPUpdPeriod = 3 */
++                      dword |= (0x3 << 20);
++                      dword &= ~(0xf << 16);                                  
/* RxMaxDurDllNoLock = 7 */
++                      dword |= (0x7 << 16);
++                      dword &= ~(0x3 << 8);                                   
/* TxDLLWakeupTime = 3 */
++                      dword |= (0x3 << 8);
++                      dword &= ~(0x7 << 4);                                   
/* TxCPUpdPeriod = 3 */
++                      dword |= (0x3 << 4);
++                      dword &= ~(0xf);                                        
/* TxMaxDurDllNoLock = 7 */
++                      dword |= 0x7;
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0000000d, dword);
++              }
++
++              if ((memclk_index <= 0x12) && (x4_present != x8_present)) {
++                      /* MemClkFreq <= 800MHz
++                       * Not a mixed channel of x4 and x8 DIMMs
++                       */
++                      for (index = 0; index < 0x9; index++) {
++                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0010 | (index << 8));
++                              dword |= (0x1 << 12);                           
/* EnRxPadStandby = 1 */
++                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0010 | (index << 8), dword);
++                      }
++              } else {
++                      for (index = 0; index < 0x9; index++) {
++                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0010 | (index << 8));
++                              dword &= ~(0x1 << 12);                          
/* EnRxPadStandby = 0 */
++                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0010 | (index << 8), dword);
++                      }
++              }
++
++              /* TODO
++               * Calculate Twrrd per section 2.10.5.5.3 of the Family 15h BKDG
++               */
++              twrrd = 0xb;
++
++              /* TODO
++               * Calculate TrwtTO per section 2.10.5.5.4 of the Family 15h 
BKDG
++               */
++              trwtto = 0x16;
++
++              dword = Get_NB32_DCT(dev, dct, 0xa4);                   /* DRAM 
Controller Temperature Throttle */
++              dword &= ~(0x1 << 11);                                  /* 
BwCapEn = 0 */
++              dword &= ~(0x1 << 8);                                   /* 
ODTSEn = dimm_event_l_pin_support */
++              dword |= (dimm_event_l_pin_support & 0x1) << 8;
++              Set_NB32_DCT(dev, dct, 0xa4, dword);                    /* DRAM 
Controller Temperature Throttle */
++
++              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* DRAM 
Controller Select Low */
++              dword &= ~(0x1 << 2);                                   /* 
DctSelIntLvEn = interleave_channels */
++              dword |= (interleave_channels & 0x1) << 2;
++              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
++
++              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58);  /* 
Scrub Rate Control */
++              dword &= ~(0x1f << 24);                                 /* 
L3Scrub = NV_L3BKScrub */
++              dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
++              dword &= ~(0x1f);                                       /* 
DramScrub = NV_DramBKScrub */
++              dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f;
++              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* 
Scrub Rate Control */
++
++              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM 
Scrub Address Low */
++              dword &= ~(0x1);                                        /* 
ScrubReDirEn = redirect_ecc_scrub */
++              dword |= redirect_ecc_scrub & 0x1;
++              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM 
Scrub Address Low */
++
++              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 
Control 1 */
++              dword &= ~(0x1 << 4);                                   /* 
L3ScrbRedirDis = 0 */
++              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 
Control 1 */
++
++              /* FIXME
++               * The BKDG-recommended settings cause memory corruption on the 
ASUS KGPE-D16.
++               * Investigate and fix...
++               */
++#if 0
++              /* Fam15h BKDG section 2.10.5.5.1 */
++              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
++              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0x1 */
++              dword |= (0x1 << 24);
++              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = trdrdsddc */
++              dword |= ((trdrdsddc & 0xf) << 16);
++              dword &= ~(0xf);                                        /* 
TrdrdDd = trdrddd */
++              dword |= (trdrddd & 0xf);
++              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
++#endif
++
++              /* Fam15h BKDG section 2.10.5.5.2 */
++              dword = Get_NB32_DCT(dev, dct, 0x214);                  /* DRAM 
Timing 4 */
++              dword &= ~(0xf << 16);                                  /* 
TwrwrSdSc = 0x1 */
++              dword |= (0x1 << 16);
++              dword &= ~(0xf << 8);                                   /* 
TwrwrSdDc = twrwrsddc */
++              dword |= ((twrwrsddc & 0xf) << 8);
++              dword &= ~(0xf);                                        /* 
TwrwrDd = twrwrdd */
++              dword |= (twrwrdd & 0xf);
++              Set_NB32_DCT(dev, dct, 0x214, dword);                   /* DRAM 
Timing 4 */
++
++              /* Fam15h BKDG section 2.10.5.5.3 */
++              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
++              dword &= ~(0xf << 8);                                   /* 
Twrrd = twrrd */
++              dword |= ((twrrd & 0xf) << 8);
++              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
++
++              /* Fam15h BKDG section 2.10.5.5.4 */
++              dword = Get_NB32_DCT(dev, dct, 0x21c);                  /* DRAM 
Timing 6 */
++              dword &= ~(0x1f << 8);                                  /* 
TrwtTO = trwtto */
++              dword |= ((trwtto & 0x1f) << 8);
++              dword &= ~(0x1f << 16);                                 /* 
TrwtWB = TrwtTO + 1 */
++              dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
++              Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
++
++              /* Enable prefetchers */
++              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* 
Memory Controller Configuration High */
++              dword &= ~(0x1 << 13);                                  /* 
PrefIoDis = 0 */
++              dword &= ~(0x1 << 12);                                  /* 
PrefCpuDis = 0 */
++              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* 
Memory Controller Configuration High */
++      }
++}
++
++static void exit_training_mode_fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstatA)
++{
++      uint8_t node;
++      uint8_t dct;
++
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              struct DCTStatStruc *pDCTstat;
++              pDCTstat = pDCTstatA + node;
++
++              if (pDCTstat->NodePresent)
++                      for (dct = 0; dct < 2; dct++)
++                              fam15EnableTrainingMode(pMCTstat, pDCTstat, 
dct, 0);
++      }
++}
++
+ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA)
+ {
+@@ -424,6 +1826,20 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
+       phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
+ 
++      if (is_fam15h()) {
++              uint8_t Node;
++              struct DCTStatStruc *pDCTstat;
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      pDCTstat = pDCTstatA + Node;
++                      if (pDCTstat->NodePresent) {
++                              if (pDCTstat->DIMMValidDCT[0])
++                                      InitPhyCompensation(pMCTstat, pDCTstat, 
0);
++                              if (pDCTstat->DIMMValidDCT[1])
++                                      InitPhyCompensation(pMCTstat, pDCTstat, 
1);
++                      }
++              }
++      }
++
+       if (nv_DQSTrainCTL) {
+               mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
+               /* TODO: should be in mctHookBeforeAnyTraining */
+@@ -431,16 +1847,35 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+               _WRMSR(0x26D, 0x04040404, 0x04040404);
+               _WRMSR(0x26E, 0x04040404, 0x04040404);
+               _WRMSR(0x26F, 0x04040404, 0x04040404);
+-              mct_WriteLevelization_HW(pMCTstat, pDCTstatA);
++              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
+ 
+-              TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
++              if (is_fam15h()) {
++                      /* Receiver Enable Training Pass 1 */
++                      TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
++              }
+ 
+-              mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
++              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass);
++
++              if (is_fam15h()) {
++                      /* Receiver Enable Training Pass 2 */
++                      // TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass);
++
++                      /* TODO:
++                       * Determine why running TrainReceiverEn_D in SecondPass
++                       * mode yields less stable training values than when run
++                       * in FirstPass mode as in the HACK below.
++                       */
++                      TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
++              } else {
++                      TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass);
++              }
+ 
+-              /* Second Pass never used for Barcelona! */
+-              /* TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass); */
++              mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
+ 
+-              mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
++              if (is_fam15h())
++                      exit_training_mode_fam15(pMCTstat, pDCTstatA);
++              else
++                      mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
+ 
+               /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+               mctHookAfterAnyTraining();
+@@ -476,7 +1911,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
+                       for (Channel = 0;Channel < 2; Channel++) {
+                               /* there are four receiver pairs,
+                                  loosely associated with chipselects.*/
+-                              index_reg = 0x98 + Channel * 0x100;
++                              index_reg = 0x98;
+                               for (Receiver = 0; Receiver < 8; Receiver += 2) 
{
+                                       /* Set Receiver Enable Values */
+                                       mct_SetRcvrEnDly_D(pDCTstat,
+@@ -492,7 +1927,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
+                                               txdqs = 
pDCTstat->CH_D_B_TxDqs[Channel][Receiver >> 1][ByteLane];
+                                               index = 
Table_DQSRcvEn_Offset[ByteLane >> 1];
+                                               index += (Receiver >> 1) * 3 + 
0x10 + 0x20; /* Addl_Index */
+-                                              val = Get_NB32_index_wait(dev, 
0x98 + 0x100*Channel, index);
++                                              val = 
Get_NB32_index_wait_DCT(dev, Channel, 0x98, index);
+                                               if (ByteLane & 1) { /* odd byte 
lane */
+                                                       val &= ~(0xFF << 16);
+                                                       val |= txdqs << 16;
+@@ -500,7 +1935,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
+                                                       val &= ~0xFF;
+                                                       val |= txdqs;
+                                               }
+-                                              Set_NB32_index_wait(dev, 0x98 + 
0x100*Channel, index, val);
++                                              Set_NB32_index_wait_DCT(dev, 
Channel, 0x98, index, val);
+                                       }
+                               }
+                       }
+@@ -510,7 +1945,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
+ 
+                       for (Channel = 0; Channel < 2; Channel++) {
+                               u8 *p;
+-                              index_reg = 0x98 + Channel * 0x100;
++                              index_reg = 0x98;
+ 
+                               /* NOTE:
+                                * when 400, 533, 667, it will support 
dimm0/1/2/3,
+@@ -525,7 +1960,7 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
+                                       if (DIMM == 0) {
+                                               index = 0;      /* CHA Write 
Data Timing Low */
+                                       } else {
+-                                              if (pDCTstat->Speed >= 4) {
++                                              if (pDCTstat->Speed >= 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+                                                       index = 0x100 * DIMM;
+                                               } else {
+                                                       break;
+@@ -534,23 +1969,23 @@ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc 
*pMCTstat,
+                                       for (Dir = 0; Dir < 2; Dir++) {/* RD/WR 
*/
+                                               p = 
pDCTstat->CH_D_DIR_B_DQS[Channel][DIMM][Dir];
+                                               val = stream_to_int(p); /* CHA 
Read Data Timing High */
+-                                              Set_NB32_index_wait(dev, 
index_reg, index+1, val);
++                                              Set_NB32_index_wait_DCT(dev, 
Channel, index_reg, index+1, val);
+                                               val = stream_to_int(p+4); /* 
CHA Write Data Timing High */
+-                                              Set_NB32_index_wait(dev, 
index_reg, index+2, val);
++                                              Set_NB32_index_wait_DCT(dev, 
Channel, index_reg, index+2, val);
+                                               val = *(p+8); /* CHA Write ECC 
Timing */
+-                                              Set_NB32_index_wait(dev, 
index_reg, index+3, val);
++                                              Set_NB32_index_wait_DCT(dev, 
Channel, index_reg, index+3, val);
+                                               index += 4;
+                                       }
+                               }
+                       }
+ 
+                       for (Channel = 0; Channel<2; Channel++) {
+-                              reg = 0x78 + Channel * 0x100;
+-                              val = Get_NB32(dev, reg);
++                              reg = 0x78;
++                              val = Get_NB32_DCT(dev, Channel, reg);
+                               val &= ~(0x3ff<<22);
+                               val |= ((u32) pDCTstat->CH_MaxRdLat[Channel] << 
22);
+                               val &= ~(1<<DqsRcvEnTrain);
+-                              Set_NB32(dev, reg, val);        /* program 
MaxRdLatency to correspond with current delay*/
++                              Set_NB32_DCT(dev, Channel, reg, val);   /* 
program MaxRdLatency to correspond with current delay*/
+                       }
+               }
+       }
+@@ -812,49 +2247,70 @@ finish:
+       return ret;
+ }
+ 
+-static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
++static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
+ {
+       /*
+-       * Initialize DRAM on single Athlon 64/Opteron Node.
++       * Run DCT pre-initialization tasks
+        */
+-      u8 stopDCTflag;
+-      u32 val;
++      uint32_t dword;
+ 
++      /* Reset DCT registers */
+       ClearDCT_D(pMCTstat, pDCTstat, dct);
+-      stopDCTflag = 1;                /*preload flag with 'disable' */
+-      /* enable DDR3 support */
+-      val = Get_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100);
+-      val |= 1 << Ddr3Mode;
+-      Set_NB32(pDCTstat->dev_dct, 0x94 + dct * 0x100, val);
++      pDCTstat->stopDCT = 1;          /*preload flag with 'disable' */
++
++      if (!is_fam15h()) {
++              /* Enable DDR3 support */
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
++              dword |= 1 << Ddr3Mode;
++              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
++      }
++
++      /* Read the SPD information into the data structures */
+       if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
+               printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_DIMMPresence Done\n");
+-              if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
+-                      printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth 
Done\n");
+-                      if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
+-                              printk(BIOS_DEBUG, "\t\tDCTInit_D: 
AutoCycTiming_D Done\n");
+-                              if (AutoConfig_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
+-                                      printk(BIOS_DEBUG, "\t\tDCTInit_D: 
AutoConfig_D Done\n");
+-                                      if (PlatformSpec_D(pMCTstat, pDCTstat, 
dct) < SC_StopError) {
+-                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: PlatformSpec_D Done\n");
+-                                              stopDCTflag = 0;
+-                                              if (!(pMCTstat->GStatus & (1 << 
GSB_EnDIMMSpareNW))) {
+-                                                      printk(BIOS_DEBUG, 
"\t\tDCTInit_D: StartupDCT_D\n");
+-                                                      StartupDCT_D(pMCTstat, 
pDCTstat, dct);   /*yeaahhh! */
+-                                              }
++      }
++}
++
++static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
++{
++      /*
++       * Initialize DRAM on single Athlon 64/Opteron Node.
++       */
++      uint32_t dword;
++
++      if (!is_fam15h()) {
++              /* (Re)-enable DDR3 support */
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
++              dword |= 1 << Ddr3Mode;
++              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
++      }
++
++      if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) {
++              printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
++              if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
++                      printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D 
Done\n");
++                      if (AutoConfig_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
++                              printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D 
Done\n");
++                              if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
++                                      printk(BIOS_DEBUG, "\t\tDCTInit_D: 
PlatformSpec_D Done\n");
++                                      pDCTstat->stopDCT = 0;
++                                      if (!(pMCTstat->GStatus & (1 << 
GSB_EnDIMMSpareNW))) {
++                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: StartupDCT_D\n");
++                                              StartupDCT_D(pMCTstat, 
pDCTstat, dct);   /*yeaahhh! */
+                                       }
+                               }
+                       }
+               }
+       }
+ 
+-      if (stopDCTflag) {
+-              u32 reg_off = dct * 0x100;
+-              val = 1<<DisDramInterface;
+-              Set_NB32(pDCTstat->dev_dct, reg_off+0x94, val);
+-              /*To maximize power savings when DisDramInterface=1b,
+-                all of the MemClkDis bits should also be set.*/
+-              val = 0xFF000000;
+-              Set_NB32(pDCTstat->dev_dct, reg_off+0x88, val);
++      if (pDCTstat->stopDCT) {
++              dword = 1 << DisDramInterface;
++              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
++
++              /* To maximize power savings when DisDramInterface=1b,
++               * all of the MemClkDis bits should also be set.
++               */
++              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x88, 0xff000000);
+       } else {
+               mct_EnDllShutdownSR(pMCTstat, pDCTstat, dct);
+       }
+@@ -876,20 +2332,24 @@ static void SyncDCTsReady_D(struct MCTStatStruc 
*pMCTstat,
+               pDCTstat = pDCTstatA + Node;
+               mct_SyncDCTsReady(pDCTstat);
+       }
+-      /* v6.1.3 */
+-      /* re-enable phy compensation engine when dram init is completed on all 
nodes. */
+-      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+-              struct DCTStatStruc *pDCTstat;
+-              pDCTstat = pDCTstatA + Node;
+-              if (pDCTstat->NodePresent) {
+-                      if (pDCTstat->DIMMValidDCT[0] > 0 || 
pDCTstat->DIMMValidDCT[1] > 0) {
+-                              /* re-enable phy compensation engine when dram 
init on both DCTs is completed. */
+-                              val = Get_NB32_index_wait(pDCTstat->dev_dct, 
0x98, 0x8);
+-                              val &= ~(1 << DisAutoComp);
+-                              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 
0x8, val);
++
++      if (!is_fam15h()) {
++              /* v6.1.3 */
++              /* re-enable phy compensation engine when dram init is 
completed on all nodes. */
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
++                      if (pDCTstat->NodePresent) {
++                              if (pDCTstat->DIMMValidDCT[0] > 0 || 
pDCTstat->DIMMValidDCT[1] > 0) {
++                                      /* re-enable phy compensation engine 
when dram init on both DCTs is completed. */
++                                      val = 
Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8);
++                                      val &= ~(1 << DisAutoComp);
++                                      Set_NB32_index_wait(pDCTstat->dev_dct, 
0x98, 0x8, val);
++                              }
+                       }
+               }
+       }
++
+       /* wait 750us before any memory access can be made. */
+       mct_Wait(15000);
+ }
+@@ -911,10 +2371,9 @@ static void StartupDCT_D(struct MCTStatStruc *pMCTstat,
+        */
+       u32 val;
+       u32 dev;
+-      u32 reg_off = dct * 0x100;
+ 
+       dev = pDCTstat->dev_dct;
+-      val = Get_NB32(dev, 0x94 + reg_off);
++      val = Get_NB32_DCT(dev, dct, 0x94);
+       if (val & (1<<MemClkFreqVal)) {
+               mctHookBeforeDramInit();        /* generalized Hook */
+               if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)))
+@@ -929,23 +2388,23 @@ static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
+ {
+       u32 reg_end;
+       u32 dev = pDCTstat->dev_dct;
+-      u32 reg = 0x40 + 0x100 * dct;
++      u32 reg = 0x40;
+       u32 val = 0;
+ 
+       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+-              reg_end = 0x78 + 0x100 * dct;
++              reg_end = 0x78;
+       } else {
+-              reg_end = 0xA4 + 0x100 * dct;
++              reg_end = 0xA4;
+       }
+ 
+       while(reg < reg_end) {
+               if ((reg & 0xFF) == 0x90) {
+                       if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+-                              val = Get_NB32(dev, reg); /* get DRAMConfigLow 
*/
++                              val = Get_NB32_DCT(dev, dct, reg); /* get 
DRAMConfigLow */
+                               val |= 0x08000000; /* preserve value of 
DisDllShutdownSR for only Rev.D */
+                       }
+               }
+-              Set_NB32(dev, reg, val);
++              Set_NB32_DCT(dev, dct, reg, val);
+               val = 0;
+               reg += 4;
+       }
+@@ -964,6 +2423,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+       u16 Trp, Trrd, Trcd, Tras, Trc;
+       u8 Trfc[4];
+       u16 Tfaw;
++      u16 Tcwl;       /* Fam15h only */
+       u32 DramTimingLo, DramTimingHi;
+       u8 tCK16x;
+       u16 Twtr;
+@@ -972,10 +2432,11 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+       u8 byte;
+       u32 dword;
+       u32 dev;
+-      u32 reg_off;
+       u32 val;
+       u16 smbaddr;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       /* Gather all DIMM mini-max values for cycle timing data */
+       Trp = 0;
+       Trrd = 0;
+@@ -1188,88 +2649,164 @@ static void SPD2ndTiming(struct MCTStatStruc 
*pMCTstat,
+ 
+       mctAdjustAutoCycTmg_D();
+ 
++      if (is_fam15h()) {
++              /* Compute Tcwl (Fam15h BKDG v3.14 Table 203) */
++              if (pDCTstat->Speed <= 0x6)
++                      Tcwl = 0x5;
++              else if (pDCTstat->Speed == 0xa)
++                      Tcwl = 0x6;
++              else if (pDCTstat->Speed == 0xe)
++                      Tcwl = 0x7;
++              else if (pDCTstat->Speed == 0x12)
++                      Tcwl = 0x8;
++              else if (pDCTstat->Speed == 0x16)
++                      Tcwl = 0x9;
++              else
++                      Tcwl = 0x5;     /* Power-on default */
++      }
++
+       /* Program DRAM Timing values */
+-      DramTimingLo = 0;       /* Dram Timing Low init */
+-      val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
+-      DramTimingLo |= val;
++      if (is_fam15h()) {
++              dev = pDCTstat->dev_dct;
+ 
+-      val = pDCTstat->Trcd - Bias_TrcdT;
+-      DramTimingLo |= val<<4;
++              dword = Get_NB32_DCT(dev, dct, 0x8c);                           
/* DRAM Timing High */
++              val = 2;                                                        
/* Tref = 7.8us */
++              dword &= ~(0x3 << 16);
++              dword |= (val & 0x3) << 16;
++              Set_NB32_DCT(dev, dct, 0x8c, dword);                            
/* DRAM Timing High */
++
++              dword = Get_NB32_DCT(dev, dct, 0x200);                          
/* DRAM Timing 0 */
++              dword &= ~(0x3f1f1f1f);
++              dword |= ((pDCTstat->Tras + 0xf) & 0x3f) << 24;                 
/* Tras */
++              dword |= ((pDCTstat->Trp + 0x5) & 0x1f) << 16;                  
/* Trp */
++              dword |= ((pDCTstat->Trcd + 0x5) & 0x1f) << 8;                  
/* Trcd */
++              dword |= (pDCTstat->CASL & 0x1f);                               
/* Tcl */
++              Set_NB32_DCT(dev, dct, 0x200, dword);                           
/* DRAM Timing 0 */
++
++              dword = Get_NB32_DCT(dev, dct, 0x204);                          
/* DRAM Timing 1 */
++              dword &= ~(0x0f3f0f3f);
++              dword |= ((pDCTstat->Trtp + 0x4) & 0xf) << 24;                  
/* Trtp */
++              if (pDCTstat->Tfaw != 0)
++                      dword |= ((((pDCTstat->Tfaw - 0x1) * 2) + 0x10) & 0x3f) 
<< 16;  /* FourActWindow */
++              dword |= ((pDCTstat->Trrd + 0x4) & 0xf) << 8;                   
/* Trrd */
++              dword |= ((pDCTstat->Trc + 0xb) & 0x3f);                        
/* Trc */
++              Set_NB32_DCT(dev, dct, 0x204, dword);                           
/* DRAM Timing 1 */
++
++              dword = Get_NB32_DCT(dev, dct, 0x208);                          
/* DRAM Timing 2 */
++              dword &= ~(0x07070707);
++              dword |= (pDCTstat->Trfc[3] & 0x7) << 24;                       
/* Trfc3 */
++              dword |= (pDCTstat->Trfc[2] & 0x7) << 16;                       
/* Trfc2 */
++              dword |= (pDCTstat->Trfc[1] & 0x7) << 8;                        
/* Trfc1 */
++              dword |= (pDCTstat->Trfc[0] & 0x7);                             
/* Trfc0 */
++              Set_NB32_DCT(dev, dct, 0x208, dword);                           
/* DRAM Timing 2 */
++
++              dword = Get_NB32_DCT(dev, dct, 0x20c);                          
/* DRAM Timing 3 */
++              dword &= ~(0x00000f00);
++              dword |= ((pDCTstat->Twtr + 0x4) & 0xf) << 8;                   
/* Twtr */
++              dword &= ~(0x0000001f);
++              dword |= (Tcwl & 0x1f);                                         
/* Tcwl */
++              Set_NB32_DCT(dev, dct, 0x20c, dword);                           
/* DRAM Timing 3 */
++
++              dword = Get_NB32_DCT(dev, dct, 0x22c);                          
/* DRAM Timing 10 */
++              dword &= ~(0x0000001f);
++              dword |= ((pDCTstat->Twr + 0x4) & 0x1f);                        
/* Twr */
++              Set_NB32_DCT(dev, dct, 0x22c, dword);                           
/* DRAM Timing 10 */
++
++              if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
++                      /* Enable phy-assisted training mode */
++                      fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 1);
++              }
+ 
+-      val = pDCTstat->Trp - Bias_TrpT;
+-      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+-      DramTimingLo |= val<<7;
++              /* Other setup (not training specific) */
++              dword = Get_NB32_DCT(dev, dct, 0x90);                           
/* DRAM Configuration Low */
++              dword &= ~(0x1 << 23);                                          
/* ForceAutoPchg = 0 */
++              dword &= ~(0x1 << 20);                                          
/* DynPageCloseEn = 0 */
++              Set_NB32_DCT(dev, dct, 0x90, dword);                            
/* DRAM Configuration Low */
+ 
+-      val = pDCTstat->Trtp - Bias_TrtpT;
+-      DramTimingLo |= val<<10;
++              Set_NB32_DCT(dev, dct, 0x228, 0x14141414);                      
/* DRAM Timing 9 */
++      } else {
++              DramTimingLo = 0;       /* Dram Timing Low init */
++              val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */
++              DramTimingLo |= val;
+ 
+-      val = pDCTstat->Tras - Bias_TrasT;
+-      DramTimingLo |= val<<12;
++              val = pDCTstat->Trcd - Bias_TrcdT;
++              DramTimingLo |= val<<4;
+ 
+-      val = pDCTstat->Trc - Bias_TrcT;
+-      DramTimingLo |= val<<16;
++              val = pDCTstat->Trp - Bias_TrpT;
++              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
++              DramTimingLo |= val<<7;
+ 
+-      val = pDCTstat->Trrd - Bias_TrrdT;
+-      DramTimingLo |= val<<22;
++              val = pDCTstat->Trtp - Bias_TrtpT;
++              DramTimingLo |= val<<10;
+ 
+-      DramTimingHi = 0;       /* Dram Timing High init */
+-      val = pDCTstat->Twtr - Bias_TwtrT;
+-      DramTimingHi |= val<<8;
++              val = pDCTstat->Tras - Bias_TrasT;
++              DramTimingLo |= val<<12;
+ 
+-      val = 2;
+-      DramTimingHi |= val<<16;
++              val = pDCTstat->Trc - Bias_TrcT;
++              DramTimingLo |= val<<16;
+ 
+-      val = 0;
+-      for (i=4;i>0;i--) {
+-              val <<= 3;
+-              val |= Trfc[i-1];
+-      }
+-      DramTimingHi |= val << 20;
++              val = pDCTstat->Trrd - Bias_TrrdT;
++              DramTimingLo |= val<<22;
+ 
+-      dev = pDCTstat->dev_dct;
+-      reg_off = 0x100 * dct;
+-      /* Twr */
+-      val = pDCTstat->Twr;
+-      if (val == 10)
+-              val = 9;
+-      else if (val == 12)
+-              val = 10;
+-      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+-      val -= Bias_TwrT;
+-      val <<= 4;
+-      dword = Get_NB32(dev, 0x84 + reg_off);
+-      dword &= ~0x70;
+-      dword |= val;
+-      Set_NB32(dev, 0x84 + reg_off, dword);
++              DramTimingHi = 0;       /* Dram Timing High init */
++              val = pDCTstat->Twtr - Bias_TwtrT;
++              DramTimingHi |= val<<8;
+ 
+-      /* Tfaw */
+-      val = pDCTstat->Tfaw;
+-      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
+-      val -= Bias_TfawT;
+-      val >>= 1;
+-      val <<= 28;
+-      dword = Get_NB32(dev, 0x94 + reg_off);
+-      dword &= ~0xf0000000;
+-      dword |= val;
+-      Set_NB32(dev, 0x94 + reg_off, dword);
+-
+-      /* dev = pDCTstat->dev_dct; */
+-      /* reg_off = 0x100 * dct; */
+-
+-      if (pDCTstat->Speed > 4) {
+-              val = Get_NB32(dev, 0x88 + reg_off);
+-              val &= 0xFF000000;
+-              DramTimingLo |= val;
+-      }
+-      Set_NB32(dev, 0x88 + reg_off, DramTimingLo);    /*DCT Timing Low*/
++              val = 2;                /* Tref = 7.8us */
++              DramTimingHi |= val<<16;
++
++              val = 0;
++              for (i=4;i>0;i--) {
++                      val <<= 3;
++                      val |= Trfc[i-1];
++              }
++              DramTimingHi |= val << 20;
++
++              dev = pDCTstat->dev_dct;
++              /* Twr */
++              val = pDCTstat->Twr;
++              if (val == 10)
++                      val = 9;
++              else if (val == 12)
++                      val = 10;
++              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
++              val -= Bias_TwrT;
++              val <<= 4;
++              dword = Get_NB32_DCT(dev, dct, 0x84);
++              dword &= ~0x70;
++              dword |= val;
++              Set_NB32_DCT(dev, dct, 0x84, dword);
++
++              /* Tfaw */
++              val = pDCTstat->Tfaw;
++              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
++              val -= Bias_TfawT;
++              val >>= 1;
++              val <<= 28;
++              dword = Get_NB32_DCT(dev, dct, 0x94);
++              dword &= ~0xf0000000;
++              dword |= val;
++              Set_NB32_DCT(dev, dct, 0x94, dword);
++
++              /* dev = pDCTstat->dev_dct; */
++
++              if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
++                      val = Get_NB32_DCT(dev, dct, 0x88);
++                      val &= 0xFF000000;
++                      DramTimingLo |= val;
++              }
++              Set_NB32_DCT(dev, dct, 0x88, DramTimingLo);     /*DCT Timing 
Low*/
+ 
+-      if (pDCTstat->Speed > 4) {
+-              DramTimingHi |= 1 << DisAutoRefresh;
++              if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
++                      DramTimingHi |= 1 << DisAutoRefresh;
++              }
++              DramTimingHi |= 0x000018FF;
++              Set_NB32_DCT(dev, dct, 0x8c, DramTimingHi);     /*DCT Timing 
Hi*/
+       }
+-      DramTimingHi |= 0x000018FF;
+-      Set_NB32(dev, 0x8c + reg_off, DramTimingHi);    /*DCT Timing Hi*/
+ 
+       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+@@ -1303,6 +2840,8 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+        * timing mode is 'Auto'.
+        */
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       /* Get primary timing (CAS Latency and Cycle Time) */
+       if (pDCTstat->Speed == 0) {
+               mctGet_MaxLoadFreq(pDCTstat);
+@@ -1312,6 +2851,7 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+ 
+               /* Go get best T and CL as specified by DIMM mfgs. and OEM */
+               SPDGetTCL_D(pMCTstat, pDCTstat, dct);
++
+               /* skip callback mctForce800to1067_D */
+               pDCTstat->Speed = pDCTstat->DIMMAutoSpeed;
+               pDCTstat->CASL = pDCTstat->DIMMCASL;
+@@ -1344,7 +2884,10 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
+       u16 word;
+ 
+       /* Get CPU Si Revision defined limit (NPT) */
+-      proposedFreq = 800;      /* Rev F0 programmable max memclock is */
++      if (is_fam15h())
++              proposedFreq = 933;
++      else
++              proposedFreq = 800;      /* Rev F0 programmable max memclock is 
*/
+ 
+       /*Get User defined limit if  "limit" mode */
+       if ( mctGet_NVbits(NV_MCTUSRTMGMODE) == 1) {
+@@ -1381,6 +2924,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+       u16 tCKmin16x;
+       u16 tCKproposed16x;
+       u8 CLactual, CLdesired, CLT_Fail;
++      uint16_t min_frequency_tck16x;
+ 
+       u8 smbaddr, byte = 0, bytex = 0;
+ 
+@@ -1390,6 +2934,17 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+       tCKmin16x = 0;
+       CLT_Fail = 0;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
++      if (is_fam15h()) {
++              uint16_t minimum_frequency_mhz = mctGet_NVbits(NV_MIN_MEMCLK);
++              if (minimum_frequency_mhz == 0)
++                      minimum_frequency_mhz = 333;
++              min_frequency_tck16x = 16000 / minimum_frequency_mhz;
++      } else {
++              min_frequency_tck16x = 40;
++      }
++
+       for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
+               if (pDCTstat->DIMMValid & (1 << i)) {
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
+@@ -1419,27 +2974,44 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+                               tCKmin16x = byte * MTB16x;
+               }
+       }
+-      /* calculate tCKproposed16x */
++      /* calculate tCKproposed16x (proposed clock period in ns * 16) */
+       tCKproposed16x =  16000 / pDCTstat->PresetmaxFreq;
+       if (tCKmin16x > tCKproposed16x)
+               tCKproposed16x = tCKmin16x;
+ 
+-      /* mctHookTwo1333DimmOverride(); */
+-      /* For UDIMM, if there are two DDR3-1333 on the same channel,
+-         downgrade DDR speed to 1066. */
+-
+       /* TODO: get user manual tCK16x(Freq.) and overwrite current 
tCKproposed16x if manual. */
+-      if (tCKproposed16x == 20)
+-              pDCTstat->TargetFreq = 7;
+-      else if (tCKproposed16x <= 24) {
+-              pDCTstat->TargetFreq = 6;
+-              tCKproposed16x = 24;
+-      } else if (tCKproposed16x <= 30) {
+-              pDCTstat->TargetFreq = 5;
+-              tCKproposed16x = 30;
++      if (is_fam15h()) {
++              if (tCKproposed16x == 17)
++                      pDCTstat->TargetFreq = 0x16;
++              else if (tCKproposed16x <= 20) {
++                      pDCTstat->TargetFreq = 0x12;
++                      tCKproposed16x = 20;
++              } else if (tCKproposed16x <= 24) {
++                      pDCTstat->TargetFreq = 0xe;
++                      tCKproposed16x = 24;
++              } else if (tCKproposed16x <= 30) {
++                      pDCTstat->TargetFreq = 0xa;
++                      tCKproposed16x = 30;
++              } else if (tCKproposed16x <= 40) {
++                      pDCTstat->TargetFreq = 0x6;
++                      tCKproposed16x = 40;
++              } else {
++                      pDCTstat->TargetFreq = 0x4;
++                      tCKproposed16x = 48;
++              }
+       } else {
+-              pDCTstat->TargetFreq = 4;
+-              tCKproposed16x = 40;
++              if (tCKproposed16x == 20)
++                      pDCTstat->TargetFreq = 7;
++              else if (tCKproposed16x <= 24) {
++                      pDCTstat->TargetFreq = 6;
++                      tCKproposed16x = 24;
++              } else if (tCKproposed16x <= 30) {
++                      pDCTstat->TargetFreq = 5;
++                      tCKproposed16x = 30;
++              } else {
++                      pDCTstat->TargetFreq = 4;
++                      tCKproposed16x = 40;
++              }
+       }
+       /* Running through this loop twice:
+          - First time find tCL at target frequency
+@@ -1478,27 +3050,42 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+               /* get CL and T */
+               if (!CLT_Fail) {
+                       bytex = CLactual;
+-                      if (tCKproposed16x == 20)
+-                              byte = 7;
+-                      else if (tCKproposed16x == 24)
+-                              byte = 6;
+-                      else if (tCKproposed16x == 30)
+-                              byte = 5;
+-                      else
+-                              byte = 4;
++                      if (is_fam15h()) {
++                              if (tCKproposed16x == 17)
++                                      byte = 0x16;
++                              else if (tCKproposed16x == 20)
++                                      byte = 0x12;
++                              else if (tCKproposed16x == 24)
++                                      byte = 0xe;
++                              else if (tCKproposed16x == 30)
++                                      byte = 0xa;
++                              else if (tCKproposed16x == 40)
++                                      byte = 0x6;
++                              else
++                                      byte = 0x4;
++                      } else {
++                              if (tCKproposed16x == 20)
++                                      byte = 7;
++                              else if (tCKproposed16x == 24)
++                                      byte = 6;
++                              else if (tCKproposed16x == 30)
++                                      byte = 5;
++                              else
++                                      byte = 4;
++                      }
+               } else {
+                       /* mctHookManualCLOverride */
+                       /* TODO: */
+               }
+ 
+-              if (tCKproposed16x != 40) {
++              if (tCKproposed16x != min_frequency_tck16x) {
+                       if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
+                               pDCTstat->DIMMAutoSpeed = byte;
+                               pDCTstat->DIMMCASL = bytex;
+                               break;
+                       } else {
+                               pDCTstat->TargetCASL = bytex;
+-                              tCKproposed16x = 40;
++                              tCKproposed16x = min_frequency_tck16x;
+                       }
+               } else {
+                       pDCTstat->DIMMAutoSpeed = byte;
+@@ -1519,29 +3106,21 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+ static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 dev;
+-      u32 reg;
+-      u32 val;
++      if (!is_fam15h()) {
++              mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
+ 
+-      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
++              if (pDCTstat->GangedMode == 1) {
++                      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
++                      mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
++              }
+ 
+-      if (pDCTstat->GangedMode == 1) {
+-              mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
+-              mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
+-      }
++              set_2t_configuration(pMCTstat, pDCTstat, dct);
+ 
+-      if ( pDCTstat->_2Tmode == 2) {
+-              dev = pDCTstat->dev_dct;
+-              reg = 0x94 + 0x100 * dct; /* Dram Configuration Hi */
+-              val = Get_NB32(dev, reg);
+-              val |= 1 << 20;                /* 2T CMD mode */
+-              Set_NB32(dev, reg, val);
++              mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
++              mct_PlatformSpec(pMCTstat, pDCTstat, dct);
++              if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
++                      InitPhyCompensation(pMCTstat, pDCTstat, dct);
+       }
+-
+-      mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
+-      mct_PlatformSpec(pMCTstat, pDCTstat, dct);
+-      if (pDCTstat->DIMMAutoSpeed == 4)
+-              InitPhyCompensation(pMCTstat, pDCTstat, dct);
+       mctHookAfterPSCfg();
+ 
+       return pDCTstat->ErrCode;
+@@ -1553,11 +3132,11 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+       u32 DramControl, DramTimingLo, Status;
+       u32 DramConfigLo, DramConfigHi, DramConfigMisc, DramConfigMisc2;
+       u32 val;
+-      u32 reg_off;
+       u32 dev;
+       u16 word;
+       u32 dword;
+       u8 byte;
++      uint32_t offset;
+ 
+       DramConfigLo = 0;
+       DramConfigHi = 0;
+@@ -1577,12 +3156,10 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+       Status = pDCTstat->Status;
+ 
+       dev = pDCTstat->dev_dct;
+-      reg_off = 0x100 * dct;
+-
+ 
+       /* Build Dram Control Register Value */
+-      DramConfigMisc2 = Get_NB32 (dev, 0xA8 + reg_off);       /* Dram 
Control*/
+-      DramControl = Get_NB32 (dev, 0x78 + reg_off);           /* Dram 
Control*/
++      DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xA8);         /* Dram 
Control*/
++      DramControl = Get_NB32_DCT(dev, dct, 0x78);             /* Dram 
Control*/
+ 
+       /* FIXME: Skip mct_checkForDxSupport */
+       /* REV_CALL mct_DoRdPtrInit if not Dx */
+@@ -1624,8 +3201,12 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+       DramConfigLo = mct_DisDllShutdownSR(pMCTstat, pDCTstat, DramConfigLo, 
dct);
+ 
+       /* Build Dram Config Hi Register Value */
++      if (is_fam15h())
++              offset = 0x0;
++      else
++              offset = 0x1;
+       dword = pDCTstat->Speed;
+-      DramConfigHi |= dword - 1;      /* get MemClk encoding */
++      DramConfigHi |= dword - offset; /* get MemClk encoding */
+       DramConfigHi |= 1 << MemClkFreqVal;
+ 
+       if (Status & (1 << SB_Registered))
+@@ -1658,7 +3239,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+               val = 0x0f; /* recommended setting (default) */
+       DramConfigHi |= val << 24;
+ 
+-      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx))
++      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx | 
AMD_FAM15_ALL))
+               DramConfigHi |= 1 << DcqArbBypassEn;
+ 
+       /* Build MemClkDis Value from Dram Timing Lo and
+@@ -1669,7 +3250,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+           NV_AllMemClks <>0 AND SB_DiagClks ==0 */
+ 
+       /* Dram Timing Low (owns Clock Enable bits) */
+-      DramTimingLo = Get_NB32(dev, 0x88 + reg_off);
++      DramTimingLo = Get_NB32_DCT(dev, dct, 0x88);
+       if (mctGet_NVbits(NV_AllMemClks) == 0) {
+               /* Special Jedec SPD diagnostic bit - "enable all clocks" */
+               if (!(pDCTstat->Status & (1<<SB_DiagClks))) {
+@@ -1700,28 +3281,34 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+                               }
+                               dword++ ;
+                       }
++                      DramTimingLo &= ~(0xff << 24);
+                       DramTimingLo |= byte << 24;
+               }
+       }
+ 
+-      printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %x\n", DramControl);
+-      printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %x\n", DramTimingLo);
+-      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %x\n", 
DramConfigMisc);
+-      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %x\n", 
DramConfigMisc2);
+-      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo: %x\n", DramConfigLo);
+-      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi: %x\n", DramConfigHi);
++      printk(BIOS_DEBUG, "AutoConfig_D: DramControl:     %08x\n", 
DramControl);
++      printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo:    %08x\n", 
DramTimingLo);
++      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc:  %08x\n", 
DramConfigMisc);
++      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %08x\n", 
DramConfigMisc2);
++      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo:    %08x\n", 
DramConfigLo);
++      printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi:    %08x\n", 
DramConfigHi);
+ 
+       /* Write Values to the registers */
+-      Set_NB32(dev, 0x78 + reg_off, DramControl);
+-      Set_NB32(dev, 0x88 + reg_off, DramTimingLo);
+-      Set_NB32(dev, 0xA0 + reg_off, DramConfigMisc);
++      Set_NB32_DCT(dev, dct, 0x78, DramControl);
++      Set_NB32_DCT(dev, dct, 0x88, DramTimingLo);
++      Set_NB32_DCT(dev, dct, 0xa0, DramConfigMisc);
+       DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, 
DramConfigMisc2);
+-      Set_NB32(dev, 0xA8 + reg_off, DramConfigMisc2);
+-      Set_NB32(dev, 0x90 + reg_off, DramConfigLo);
++      Set_NB32_DCT(dev, dct, 0xa8, DramConfigMisc2);
++      Set_NB32_DCT(dev, dct, 0x90, DramConfigLo);
+       ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
+-      dword = Get_NB32(dev, 0x94 + reg_off);
++
++      if (is_fam15h())
++              InitDDRPhy(pMCTstat, pDCTstat, dct);
++
++      /* Write the DRAM Configuration High register, including memory 
frequency change */
++      dword = Get_NB32_DCT(dev, dct, 0x94);
+       DramConfigHi |= dword;
+-      mct_SetDramConfigHi_D(pDCTstat, dct, DramConfigHi);
++      mct_SetDramConfigHi_D(pMCTstat, pDCTstat, dct, DramConfigHi);
+       mct_EarlyArbEn_D(pMCTstat, pDCTstat, dct);
+       mctHookAfterAutoCfg();
+ 
+@@ -1731,6 +3318,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+       printk(BIOS_DEBUG, "AutoConfig: ErrStatus %x\n", pDCTstat->ErrStatus);
+       printk(BIOS_DEBUG, "AutoConfig: ErrCode %x\n", pDCTstat->ErrCode);
+       printk(BIOS_DEBUG, "AutoConfig: Done\n\n");
++
+ AutoConfig_exit:
+       return pDCTstat->ErrCode;
+ }
+@@ -1748,14 +3336,12 @@ static void SPDSetBanks_D(struct MCTStatStruc 
*pMCTstat,
+       u32 val;
+       u32 reg;
+       u32 dev;
+-      u32 reg_off;
+       u8 byte;
+       u16 word;
+       u32 dword;
+       u16 smbaddr;
+ 
+       dev = pDCTstat->dev_dct;
+-      reg_off = 0x100 * dct;
+ 
+       BankAddrReg = 0;
+       for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel+=2) {
+@@ -1820,10 +3406,10 @@ static void SPDSetBanks_D(struct MCTStatStruc 
*pMCTstat,
+                               /*set ChipSelect population indicator odd bits*/
+                               pDCTstat->CSPresent |= 1 << (ChipSel + 1);
+ 
+-                      reg = 0x60+(ChipSel<<1) + reg_off;      /*Dram CS Mask 
Register */
++                      reg = 0x60+(ChipSel<<1);        /*Dram CS Mask Register 
*/
+                       val = csMask;
+                       val &= 0x1FF83FE0;      /* Mask out reserved bits.*/
+-                      Set_NB32(dev, reg, val);
++                      Set_NB32_DCT(dev, dct, reg, val);
+               } else {
+                       if (pDCTstat->DIMMSPDCSE & (1<<ChipSel))
+                               pDCTstat->CSTestFail |= (1<<ChipSel);
+@@ -1847,8 +3433,8 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+       if (!pDCTstat->CSPresent)
+               pDCTstat->ErrCode = SC_StopError;
+ 
+-      reg = 0x80 + reg_off;           /* Bank Addressing Register */
+-      Set_NB32(dev, reg, BankAddrReg);
++      reg = 0x80;             /* Bank Addressing Register */
++      Set_NB32_DCT(dev, dct, reg, BankAddrReg);
+ 
+       pDCTstat->CSPresent_DCT[dct] = pDCTstat->CSPresent;
+       /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
+@@ -1933,11 +3519,9 @@ static void StitchMemory_D(struct MCTStatStruc 
*pMCTstat,
+       u16 word;
+       u32 dev;
+       u32 reg;
+-      u32 reg_off;
+       u32 val;
+ 
+       dev = pDCTstat->dev_dct;
+-      reg_off = 0x100 * dct;
+ 
+       _DSpareEn = 0;
+ 
+@@ -1974,11 +3558,11 @@ static void StitchMemory_D(struct MCTStatStruc 
*pMCTstat,
+               BiggestBank = 0;
+               for (q = 0; q < MAX_CS_SUPPORTED; q++) { /* from DIMMS to CS */
+                       if (pDCTstat->CSPresent & (1 << q)) {  /* bank present? 
*/
+-                              reg  = 0x40 + (q << 2) + reg_off;  /* Base[q] 
reg.*/
+-                              val = Get_NB32(dev, reg);
++                              reg  = 0x40 + (q << 2);  /* Base[q] reg.*/
++                              val = Get_NB32_DCT(dev, dct, reg);
+                               if (!(val & 3)) {       /* 
(CSEnable|Spare==1)bank is enabled already? */
+-                                      reg = 0x60 + (q << 1) + reg_off; 
/*Mask[q] reg.*/
+-                                      val = Get_NB32(dev, reg);
++                                      reg = 0x60 + (q << 1); /*Mask[q] reg.*/
++                                      val = Get_NB32_DCT(dev, dct, reg);
+                                       val >>= 19;
+                                       val++;
+                                       val <<= 19;
+@@ -1994,7 +3578,7 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+               if (BiggestBank !=0) {
+                       curcsBase = nxtcsBase;          /* curcsBase=nxtcsBase*/
+                       /* DRAM CS Base b Address Register offset */
+-                      reg = 0x40 + (b << 2) + reg_off;
++                      reg = 0x40 + (b << 2);
+                       if (_DSpareEn) {
+                               BiggestBank = 0;
+                               val = 1 << Spare;       /* Spare Enable*/
+@@ -2013,7 +3597,7 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+                                       }
+                               }
+                       }
+-                      Set_NB32(dev, reg, val);
++                      Set_NB32_DCT(dev, dct, reg, val);
+                       if (_DSpareEn)
+                               _DSpareEn = 0;
+                       else
+@@ -2024,9 +3608,9 @@ static void StitchMemory_D(struct MCTStatStruc *pMCTstat,
+               /* bank present but disabled?*/
+               if ( pDCTstat->CSTestFail & (1 << p)) {
+                       /* DRAM CS Base b Address Register offset */
+-                      reg = (p << 2) + 0x40 + reg_off;
++                      reg = (p << 2) + 0x40;
+                       val = 1 << TestFail;
+-                      Set_NB32(dev, reg, val);
++                      Set_NB32_DCT(dev, dct, reg, val);
+               }
+       }
+ 
+@@ -2064,7 +3648,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+       u16 i, j, k;
+       u8 smbaddr;
+       u8 SPDCtrl;
+-      u16 RegDIMMPresent, MaxDimms;
++      u16 RegDIMMPresent, LRDIMMPresent, MaxDimms;
+       u8 devwidth;
+       u16 DimmSlots;
+       u8 byte = 0, bytex;
+@@ -2077,6 +3661,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+       SPDCtrl = mctGet_NVbits(NV_SPDCHK_RESTRT);
+ 
+       RegDIMMPresent = 0;
++      LRDIMMPresent = 0;
+       pDCTstat->DimmQRPresent = 0;
+ 
+       for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
+@@ -2115,6 +3700,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                               pDCTstat->DimmManufacturerID[i] 
|= ((uint64_t)mctRead_SPD(smbaddr, SPD_MANID_START + k)) << (k * 8);
+                                       for (k = 0; k < SPD_PARTN_LENGTH; k++)
+                                               pDCTstat->DimmPartNumber[i][k] 
= mctRead_SPD(smbaddr, SPD_PARTN_START + k);
++                                      
pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
+                                       pDCTstat->DimmRevisionNumber[i] = 0;
+                                       for (k = 0; k < 2; k++)
+                                               pDCTstat->DimmRevisionNumber[i] 
|= ((uint16_t)mctRead_SPD(smbaddr, SPD_REVNO_START + k)) << (k * 8);
+@@ -2138,6 +3724,12 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                               } else {
+                                       pDCTstat->DimmRegistered[i] = 0;
+                               }
++                              if (byte == JED_LRDIMM) {
++                                      LRDIMMPresent |= 1 << i;
++                                      pDCTstat->DimmLoadReduced[i] = 1;
++                              } else {
++                                      pDCTstat->DimmLoadReduced[i] = 0;
++                              }
+                               /* Check ECC capable */
+                               byte = mctRead_SPD(smbaddr, SPD_BusWidth);
+                               if (byte & JED_ECC) {
+@@ -2221,6 +3813,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+       printk(BIOS_DEBUG, "\t DIMMPresence: DIMMValid=%x\n", 
pDCTstat->DIMMValid);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DIMMPresent=%x\n", 
pDCTstat->DIMMPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: RegDIMMPresent=%x\n", 
RegDIMMPresent);
++      printk(BIOS_DEBUG, "\t DIMMPresence: LRDIMMPresent=%x\n", 
LRDIMMPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DimmECCPresent=%x\n", 
pDCTstat->DimmECCPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: DimmPARPresent=%x\n", 
pDCTstat->DimmPARPresent);
+       printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx4Present=%x\n", 
pDCTstat->Dimmx4Present);
+@@ -2247,6 +3840,16 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                               pDCTstat->Status |= 1<<SB_Registered;
+                       }
+               }
++              if (LRDIMMPresent != 0) {
++                      if ((LRDIMMPresent ^ pDCTstat->DIMMValid) !=0) {
++                              /* module type DIMM mismatch (reg'ed, 
unbuffered) */
++                              pDCTstat->ErrStatus |= 1<<SB_DimmMismatchM;
++                              pDCTstat->ErrCode = SC_StopError;
++                      } else{
++                              /* all DIMMs are registered */
++                              pDCTstat->Status |= 1<<SB_LoadReduced;
++                      }
++              }
+               if (pDCTstat->DimmECCPresent != 0) {
+                       if ((pDCTstat->DimmECCPresent ^ pDCTstat->DIMMValid )== 
0) {
+                               /* all DIMMs are ECC capable */
+@@ -2284,6 +3887,26 @@ static u8 Get_DIMMAddress_D(struct DCTStatStruc 
*pDCTstat, u8 i)
+       return p[i];
+ }
+ 
++static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      u8 err_code;
++
++      /* Preconfigure DCT0 */
++      DCTPreInit_D(pMCTstat, pDCTstat, 0);
++
++      /* Configure DCT1 if unganged and enabled*/
++      if (!pDCTstat->GangedMode) {
++              if (pDCTstat->DIMMValidDCT[1] > 0) {
++                      err_code = pDCTstat->ErrCode;           /* save DCT0 
errors */
++                      pDCTstat->ErrCode = 0;
++                      DCTPreInit_D(pMCTstat, pDCTstat, 1);
++                      if (pDCTstat->ErrCode == 2)             /* DCT1 is not 
Running */
++                              pDCTstat->ErrCode = err_code;   /* Using DCT0 
Error code to update pDCTstat.ErrCode */
++              }
++      }
++}
++
+ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+ {
+@@ -2295,7 +3918,7 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+       if (pDCTstat->ErrCode == SC_FatalErr) {
+               /* Do nothing goto exitDCTInit; any fatal errors? */
+       } else {
+-              /* Configure DCT1 if unganged and enabled*/
++              /* Configure DCT1 if unganged and enabled */
+               if (!pDCTstat->GangedMode) {
+                       if (pDCTstat->DIMMValidDCT[1] > 0) {
+                               err_code = pDCTstat->ErrCode;           /* save 
DCT0 errors */
+@@ -2305,17 +3928,21 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+                                       pDCTstat->ErrCode = err_code;   /* 
Using DCT0 Error code to update pDCTstat.ErrCode */
+                       } else {
+                               val = 1 << DisDramInterface;
+-                              Set_NB32(pDCTstat->dev_dct, 0x100 + 0x94, val);
++                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
++
++                              /* To maximize power savings when 
DisDramInterface=1b,
++                               * all of the MemClkDis bits should also be set.
++                               */
++                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x88, 
0xff000000);
+                       }
+               }
+       }
+-/* exitDCTInit: */
+ }
+ 
+ static void mct_DramInit(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat);
++      mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat, dct);
+       mct_DramInit_Sw_D(pMCTstat, pDCTstat, dct);
+       /* mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct); */
+ }
+@@ -2343,7 +3970,8 @@ static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
+               if (byte)
+                       pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO); /* Set 
temp. to avoid setting of ganged mode */
+ 
+-              if (!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) {
++              if ((!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) && 
(pDCTstat->LogicalCPUID & AMD_FAM10_ALL)) {
++                      /* Ganged channel mode not supported on Family 15h or 
higher */
+                       pDCTstat->GangedMode = 1;
+                       /* valid 128-bit mode population. */
+                       pDCTstat->Status |= 1 << SB_128bitmode;
+@@ -2387,10 +4015,8 @@ void Set_NB32_index(u32 dev, u32 index_reg, u32 index, 
u32 data)
+ 
+ u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index)
+ {
+-
+       u32 dword;
+ 
+-
+       index &= ~(1 << DctAccessWrite);
+       Set_NB32(dev, index_reg, index);
+       do {
+@@ -2405,7 +4031,6 @@ void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 
index, u32 data)
+ {
+       u32 dword;
+ 
+-
+       Set_NB32(dev, index_reg + 0x4, data);
+       index |= (1 << DctAccessWrite);
+       Set_NB32(dev, index_reg, index);
+@@ -2420,16 +4045,17 @@ static u8 mct_BeforePlatformSpec(struct MCTStatStruc 
*pMCTstat,
+ {
+       /* mct_checkForCxDxSupport_D */
+       if (pDCTstat->LogicalCPUID & AMD_DR_GT_Bx) {
++              /* Family 10h Errata 322: Address and Command Fine Delay Values 
May Be Incorrect */
+               /* 1. Write 00000000h to F2x[1,0]9C_xD08E000 */
+-              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 0x100, 
0x0D08E000, 0);
++              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D08E000, 0);
+               /* 2. If DRAM Configuration Register[MemClkFreq] 
(F2x[1,0]94[2:0]) is
+                  greater than or equal to 011b (DDR-800 and higher),
+                  then write 00000080h to F2x[1,0]9C_xD02E001,
+                  else write 00000090h to F2x[1,0]9C_xD02E001. */
+-              if (pDCTstat->Speed >= 4)
+-                      Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 
0x100, 0xD02E001, 0x80);
++              if (pDCTstat->Speed >= 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D02E001, 0x80);
+               else
+-                      Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + dct * 
0x100, 0xD02E001, 0x90);
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D02E001, 0x90);
+       }
+       return pDCTstat->ErrCode;
+ }
+@@ -2455,9 +4081,9 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+               i_end = dct + 1;
+       }
+       for (i=i_start; i<i_end; i++) {
+-              index_reg = 0x98 + (i * 0x100);
+-              Set_NB32_index_wait(dev, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
+-              Set_NB32_index_wait(dev, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
++              index_reg = 0x98;
++              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
++              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
+       }
+ 
+       return pDCTstat->ErrCode;
+@@ -2511,14 +4137,14 @@ static u8 mct_SPDCalcWidth(struct MCTStatStruc 
*pMCTstat,
+       }
+ 
+       if (pDCTstat->DIMMValidDCT[0] == 0) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94);
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+               val |= 1 << DisDramInterface;
+-              Set_NB32(pDCTstat->dev_dct, 0x94, val);
++              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
+       }
+       if (pDCTstat->DIMMValidDCT[1] == 0) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+               val |= 1 << DisDramInterface;
+-              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
++              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
+       }
+ 
+       printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
+@@ -2648,21 +4274,20 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+       u32 reg;
+-      u32 reg_off = 0x100 * dct;
+       u32 val;
+       u32 dword;
+       u32 dev = pDCTstat->dev_dct;
+ 
+-      Get_DqsRcvEnGross_Diff(pDCTstat, dev, 0x98 + reg_off);
+-      Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98 + reg_off);
++      Get_DqsRcvEnGross_Diff(pDCTstat, dev, dct, 0x98);
++      Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98);
+       Get_Trdrd(pMCTstat, pDCTstat, dct);
+       Get_Twrwr(pMCTstat, pDCTstat, dct);
+       Get_Twrrd(pMCTstat, pDCTstat, dct);
+       Get_TrwtTO(pMCTstat, pDCTstat, dct);
+       Get_TrwtWB(pMCTstat, pDCTstat);
+ 
+-      reg = 0x8C + reg_off;           /* Dram Timing Hi */
+-      val = Get_NB32(dev, reg);
++      reg = 0x8C;             /* Dram Timing Hi */
++      val = Get_NB32_DCT(dev, dct, reg);
+       val &= 0xffff0300;
+       dword = pDCTstat->TrwtTO;
+       val |= dword << 4;
+@@ -2674,10 +4299,10 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
+       val |= dword << 14;
+       dword = pDCTstat->TrwtWB;
+       val |= dword;
+-      Set_NB32(dev, reg, val);
++      Set_NB32_DCT(dev, dct, reg, val);
+ 
+-      reg = 0x78 + reg_off;
+-      val = Get_NB32(dev, reg);
++      reg = 0x78;
++      val = Get_NB32_DCT(dev, dct, reg);
+       val &= 0xFFFFC0FF;
+       dword = pDCTstat->Twrrd >> 2;
+       val |= dword << 8;
+@@ -2685,7 +4310,7 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
+       val |= dword << 10;
+       dword = pDCTstat->Trdrd >> 2;
+       val |= dword << 12;
+-      Set_NB32(dev, reg, val);
++      Set_NB32_DCT(dev, dct, reg, val);
+ }
+ 
+ static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+@@ -2755,18 +4380,17 @@ static void Get_TrwtWB(struct MCTStatStruc *pMCTstat,
+ static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+                          struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 reg_off =  0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val1, val2;
+ 
+-      val1 = Get_NB32(dev, reg_off + 0x88) & 0xF;
+-      val2 = (Get_NB32(dev, reg_off + 0x84) >> 20) & 7;
++      val1 = Get_NB32_DCT(dev, dct, 0x88) & 0xF;
++      val2 = (Get_NB32_DCT(dev, dct, 0x84) >> 20) & 7;
+ 
+       return val1 - val2;
+ }
+ 
+ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat,
+-                                      u32 dev, u32 index_reg)
++                                      u32 dev, uint8_t dct, u32 index_reg)
+ {
+       u8 Smallest, Largest;
+       u32 val;
+@@ -2776,12 +4400,12 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
+          DqsRcvEnGrossDelay of any other DIMM is equal to the Critical
+          Gross Delay Difference (CGDD) */
+       /* DqsRcvEn byte 1,0 */
+-      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x10);
++      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x10);
+       Largest = val & 0xFF;
+       Smallest = (val >> 8) & 0xFF;
+ 
+       /* DqsRcvEn byte 3,2 */
+-      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x11);
++      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x11);
+       byte = val & 0xFF;
+       bytex = (val >> 8) & 0xFF;
+       if (bytex < Smallest)
+@@ -2790,7 +4414,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
+               Largest = byte;
+ 
+       /* DqsRcvEn byte 5,4 */
+-      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x20);
++      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x20);
+       byte = val & 0xFF;
+       bytex = (val >> 8) & 0xFF;
+       if (bytex < Smallest)
+@@ -2799,7 +4423,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
+               Largest = byte;
+ 
+       /* DqsRcvEn byte 7,6 */
+-      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x21);
++      val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x21);
+       byte = val & 0xFF;
+       bytex = (val >> 8) & 0xFF;
+       if (bytex < Smallest)
+@@ -2809,7 +4433,7 @@ static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc 
*pDCTstat,
+ 
+       if (pDCTstat->DimmECCPresent> 0) {
+               /*DqsRcvEn Ecc */
+-              val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, index_reg, 0x12);
++              val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 
0x12);
+               byte = val & 0xFF;
+               bytex = (val >> 8) & 0xFF;
+               if (bytex < Smallest)
+@@ -2873,7 +4497,7 @@ static void Get_WrDatGross_Diff(struct DCTStatStruc 
*pDCTstat,
+ }
+ 
+ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat,
+-                                      u32 dev, u32 index_reg,
++                                      u32 dev, uint8_t dct, u32 index_reg,
+                                       u32 index)
+ {
+       u8 Smallest, Largest;
+@@ -2891,7 +4515,7 @@ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
+ 
+       for (i=0; i < 8; i+=2) {
+               if ( pDCTstat->DIMMValid & (1 << i)) {
+-                      val = Get_NB32_index_wait(dev, index_reg, index);
++                      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
index);
+                       val &= 0x00E000E0;
+                       byte = (val >> 5) & 0xFF;
+                       if (byte < Smallest)
+@@ -2929,7 +4553,7 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
+       Smallest = 3;
+       Largest = 0;
+       for (i=0; i < 2; i++) {
+-              val = Get_NB32_index_wait(dev, index_reg, index);
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+               val &= 0x60606060;
+               val >>= 5;
+               for (j=0; j < 4; j++) {
+@@ -2945,7 +4569,7 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
+ 
+       if (pDCTstat->DimmECCPresent > 0) {
+               index++;
+-              val = Get_NB32_index_wait(dev, index_reg, index);
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+               val &= 0x00000060;
+               val >>= 5;
+               byte = val & 0xFF;
+@@ -2965,25 +4589,30 @@ static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc 
*pDCTstat,
+ static void mct_PhyController_Config(struct MCTStatStruc *pMCTstat,
+                                    struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 index_reg = 0x98 + 0x100 * dct;
++      uint8_t index;
++      uint32_t dword;
++      u32 index_reg = 0x98;
+       u32 dev = pDCTstat->dev_dct;
+-      u32 val;
+ 
+-      if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3)) {
++      if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3 | 
AMD_FAM15_ALL)) {
+               if (pDCTstat->Dimmx4Present == 0) {
+-                      /* Set bit7 RxDqsUDllPowerDown  to register F2x[1, 
0]98_x0D0F0F13 for power saving */
+-                      val = Get_NB32_index_wait(dev, index_reg, 0x0D0F0F13); 
/* Agesa v3 v6 might be wrong here. */
+-                      val |= 1 << 7; /* BIOS should set this bit when x4 
DIMMs are not present */
+-                      Set_NB32_index_wait(dev, index_reg, 0x0D0F0F13, val);
++                      /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 
0]98_x0D0F0F13 for
++                       * additional power saving when x4 DIMMs are not 
present.
++                       */
++                      for (index = 0; index < 0x9; index++) {
++                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0013 | (index << 8));
++                              dword |= (0x1 << 7);                            
/* RxDqsUDllPowerDown = 1 */
++                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0013 | (index << 8), dword);
++                      }
+               }
+       }
+ 
+-      if (pDCTstat->LogicalCPUID & AMD_DR_DAC2_OR_C3) {
++      if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_FAM15_ALL)) {
+               if (pDCTstat->DimmECCPresent == 0) {
+                       /* Set bit4 PwrDn to register F2x[1, 0]98_x0D0F0830 for 
power saving */
+-                      val = Get_NB32_index_wait(dev, index_reg, 0x0D0F0830);
+-                      val |= 1 << 4; /* BIOS should set this bit if ECC DIMMs 
are not present */
+-                      Set_NB32_index_wait(dev, index_reg, 0x0D0F0830, val);
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0830);
++                      dword |= 1 << 4; /* BIOS should set this bit if ECC 
DIMMs are not present */
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0830, dword);
+               }
+       }
+ 
+@@ -3024,21 +4653,61 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
+                               val &= ~(1 << 12);
+ 
+                       val &= 0x0FFFFFFF;
+-                      switch (pDCTstat->Speed) {
+-                      case 4:
+-                              val |= 0x50000000; /* 5 for DDR800 */
+-                              break;
+-                      case 5:
+-                              val |= 0x60000000; /* 6 for DDR1066 */
+-                              break;
+-                      case 6:
+-                              val |= 0x80000000; /* 8 for DDR800 */
+-                              break;
+-                      default:
+-                              val |= 0x90000000; /* 9 for DDR1600 */
+-                              break;
++                      if (!is_fam15h()) {
++                              switch (pDCTstat->Speed) {
++                              case 4:
++                                      val |= 0x50000000; /* 5 for DDR800 */
++                                      break;
++                              case 5:
++                                      val |= 0x60000000; /* 6 for DDR1066 */
++                                      break;
++                              case 6:
++                                      val |= 0x80000000; /* 8 for DDR800 */
++                                      break;
++                              default:
++                                      val |= 0x90000000; /* 9 for DDR1600 */
++                                      break;
++                              }
+                       }
+                       Set_NB32(pDCTstat->dev_dct, 0x1B0, val);
++
++                      if (is_fam15h()) {
++                              uint8_t wm1;
++                              uint8_t wm2;
++
++                              switch (pDCTstat->Speed) {
++                              case 0x4:
++                                      wm1 = 0x3;
++                                      wm2 = 0x4;
++                                      break;
++                              case 0x6:
++                                      wm1 = 0x3;
++                                      wm2 = 0x5;
++                                      break;
++                              case 0xa:
++                                      wm1 = 0x4;
++                                      wm2 = 0x6;
++                                      break;
++                              case 0xe:
++                                      wm1 = 0x5;
++                                      wm2 = 0x8;
++                                      break;
++                              case 0x12:
++                                      wm1 = 0x6;
++                                      wm2 = 0x9;
++                                      break;
++                              default:
++                                      wm1 = 0x7;
++                                      wm2 = 0xa;
++                                      break;
++                              }
++
++                              val = Get_NB32(pDCTstat->dev_dct, 0x1B4);
++                              val &= ~(0x3ff);
++                              val |= ((wm2 & 0x1f) << 5);
++                              val |= (wm1 & 0x1f);
++                              Set_NB32(pDCTstat->dev_dct, 0x1B4, val);
++                      }
+               }
+       }
+ 
+@@ -3055,16 +4724,103 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
+       }
+ }
+ 
++void mct_ForceNBPState0_En_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      /* Force the NB P-state to P0 */
++      uint32_t dword;
++      uint32_t dword2;
++
++      dword = Get_NB32(pDCTstat->dev_nbctl, 0x174);
++      if (!(dword & 0x1)) {
++              dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
++              pDCTstat->SwNbPstateLoDis = (dword >> 14) & 0x1;
++              pDCTstat->NbPstateDisOnP0 = (dword >> 13) & 0x1;
++              pDCTstat->NbPstateThreshold = (dword >> 9) & 0x7;
++              pDCTstat->NbPstateHi = (dword >> 6) & 0x3;
++              dword &= ~(0x1 << 14);          /* SwNbPstateLoDis = 0 */
++              dword &= ~(0x1 << 13);          /* NbPstateDisOnP0 = 0 */
++              dword &= ~(0x7 << 9);           /* NbPstateThreshold = 0 */
++              dword &= ~(0x3 << 3);           /* NbPstateLo = NbPstateMaxVal 
*/
++              dword |= ((dword & 0x3) << 3);
++              Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
++
++              /* Wait until CurNbPState == NbPstateLo */
++              do {
++                      dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174);
++              } while (((dword2 << 19) & 0x7) != (dword & 0x3));
++
++              dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
++              dword &= ~(0x3 << 6);           /* NbPstateHi = 0 */
++              dword |= (0x3 << 14);           /* SwNbPstateLoDis = 1 */
++              Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
++
++              /* Wait until CurNbPState == 0 */
++              do {
++                      dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174);
++              } while (((dword2 << 19) & 0x7) != 0);
++      }
++}
++
++void mct_ForceNBPState0_Dis_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      /* Restore normal NB P-state functionailty */
++      uint32_t dword;
++
++      dword = Get_NB32(pDCTstat->dev_nbctl, 0x174);
++      if (!(dword & 0x1)) {
++              dword = Get_NB32(pDCTstat->dev_nbctl, 0x170);
++              dword &= ~(0x1 << 14);                                  /* 
SwNbPstateLoDis*/
++              dword |= ((pDCTstat->SwNbPstateLoDis & 0x1) << 14);
++              dword &= ~(0x1 << 13);                                  /* 
NbPstateDisOnP0 */
++              dword |= ((pDCTstat->NbPstateDisOnP0 & 0x1) << 13);
++              dword &= ~(0x7 << 9);                                   /* 
NbPstateThreshold */
++              dword |= ((pDCTstat->NbPstateThreshold & 0x7) << 9);
++              dword &= ~(0x3 << 6);                                   /* 
NbPstateHi */
++              dword |= ((pDCTstat->NbPstateHi & 0x3) << 3);
++              Set_NB32(pDCTstat->dev_nbctl, 0x170, dword);
++      }
++}
++
+ static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat)
+ {
+-      mct_SetClToNB_D(pMCTstat, pDCTstat);
+-      mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
++      if (is_fam15h()) {
++              msr_t p0_state_msr;
++              uint8_t cpu_fid;
++              uint8_t cpu_did;
++              uint32_t cpu_divisor;
++              uint8_t boost_states;
++
++              /* Retrieve the number of boost states */
++              boost_states = (Get_NB32(pDCTstat->dev_link, 0x15c) >> 2) & 0x7;
++
++              /* Retrieve and store the TSC frequency (P0 COF) */
++              p0_state_msr = rdmsr(0xc0010064 + boost_states);
++              cpu_fid = p0_state_msr.lo & 0x3f;
++              cpu_did = (p0_state_msr.lo >> 6) & 0x7;
++              cpu_divisor = (0x1 << cpu_did);
++              pMCTstat->TSCFreq = (100 * (cpu_fid + 0x10)) / cpu_divisor;
++
++              mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
++      } else {
++              /* K10 BKDG v3.62 section 2.8.9.2 */
++              printk(BIOS_DEBUG, "mct_InitialMCT_D: clear_legacy_Mode\n");
++              clear_legacy_Mode(pMCTstat, pDCTstat);
++
++              /* Northbridge configuration */
++              mct_SetClToNB_D(pMCTstat, pDCTstat);
++              mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat);
++      }
+ }
+ 
+ static u32 mct_NodePresent_D(void)
+ {
+       u32 val;
+-      val = 0x12001022;
++      if (is_fam15h())
++              val = 0x16001022;
++      else
++              val = 0x12001022;
+       return val;
+ }
+ 
+@@ -3097,14 +4853,13 @@ static void clear_legacy_Mode(struct MCTStatStruc 
*pMCTstat,
+ 
+       /* Clear Legacy BIOS Mode bit */
+       reg = 0x94;
+-      val = Get_NB32(dev, reg);
++      val = Get_NB32_DCT(dev, 0, reg);
+       val &= ~(1<<LegacyBiosMode);
+-      Set_NB32(dev, reg, val);
++      Set_NB32_DCT(dev, 0, reg, val);
+ 
+-      reg = 0x94 + 0x100;
+-      val = Get_NB32(dev, reg);
++      val = Get_NB32_DCT(dev, 1, reg);
+       val &= ~(1<<LegacyBiosMode);
+-      Set_NB32(dev, reg, val);
++      Set_NB32_DCT(dev, 1, reg, val);
+ }
+ 
+ static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat,
+@@ -3171,7 +4926,7 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
+ {
+       u32 val;
+       u32 dev = pDCTstat->dev_dct;
+-      u32 index_reg = 0x98 + 0x100 * dct;
++      u32 index_reg = 0x98;
+       u32 index;
+       u16 word;
+ 
+@@ -3186,9 +4941,9 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
+       }
+       word = (~word) & 0xFF;
+       index  = 0x0c;
+-      val = Get_NB32_index_wait(dev, index_reg, index);
++      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+       val |= word;
+-      Set_NB32_index_wait(dev, index_reg, index, val);
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+ }
+ 
+ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+@@ -3196,7 +4951,7 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+ {
+       u32 val;
+       u32 dev;
+-      u32 index_reg = 0x98 + 0x100 * dct;
++      u32 index_reg = 0x98;
+       u32 index;
+       u16 word;
+ 
+@@ -3208,14 +4963,14 @@ static void SetCKETriState(struct MCTStatStruc 
*pMCTstat,
+       word = pDCTstat->CSPresent;
+ 
+       index  = 0x0c;
+-      val = Get_NB32_index_wait(dev, index_reg, index);
++      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+       if ((word & 0x55) == 0)
+               val |= 1 << 12;
+ 
+       if ((word & 0xAA) == 0)
+               val |= 1 << 13;
+ 
+-      Set_NB32_index_wait(dev, index_reg, index, val);
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+ }
+ 
+ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+@@ -3223,7 +4978,7 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+ {
+       u32 val;
+       u32 dev;
+-      u32 index_reg = 0x98 + 0x100 * dct;
++      u32 index_reg = 0x98;
+       u8 cs;
+       u32 index;
+       u8 odt;
+@@ -3257,86 +5012,281 @@ static void SetODTTriState(struct MCTStatStruc 
*pMCTstat,
+       }
+ 
+       index  = 0x0C;
+-      val = Get_NB32_index_wait(dev, index_reg, index);
++      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+       val |= ((odt & 0xFF) << 8);     /* set bits 11:8 ODTTriState[3:0] */
+-      Set_NB32_index_wait(dev, index_reg, index, val);
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
++
++}
++
++/* Family 15h */
++static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat, u8 dct)
++{
++      uint8_t index;
++      uint32_t dword;
++      uint8_t ddr_voltage_index;
++      uint8_t amd_voltage_level_index = 0;
++      uint32_t index_reg = 0x98;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
+ 
++      /* Find current DDR supply voltage for this DCT */
++      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
++
++      /* Fam15h BKDG v3.14 section 2.10.5.3
++       * The remainder of the Phy Initialization algorithm picks up in 
phyAssistedMemFnceTraining
++       */
++      for (dct = 0; dct < 2; dct++) {
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 
0x80000000);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 
0x00000118);
++
++              /* Program desired VDDIO level */
++              if (ddr_voltage_index & 0x4) {
++                      /* 1.25V */
++                      amd_voltage_level_index = 0x2;
++              } else if (ddr_voltage_index & 0x2) {
++                      /* 1.35V */
++                      amd_voltage_level_index = 0x1;
++              } else if (ddr_voltage_index & 0x1) {
++                      /* 1.50V */
++                      amd_voltage_level_index = 0x0;
++              }
++
++              /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */
++              for (index = 0; index < 0x9; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f001f | (index << 8));
++                      dword &= ~(0x3 << 3);
++                      dword |= (amd_voltage_level_index << 3);
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f 
| (index << 8), dword);
++              }
++
++              /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */
++              for (index = 0; index < 0x3; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f201f | (index << 8));
++                      dword &= ~(0x3 << 3);
++                      dword |= (amd_voltage_level_index << 3);
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f 
| (index << 8), dword);
++              }
++              for (index = 0; index < 0x2; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f801f | (index << 8));
++                      dword &= ~(0x3 << 3);
++                      dword |= (amd_voltage_level_index << 3);
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f 
| (index << 8), dword);
++              }
++              for (index = 0; index < 0x1; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc01f | (index << 8));
++                      dword &= ~(0x3 << 3);
++                      dword |= (amd_voltage_level_index << 3);
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f 
| (index << 8), dword);
++              }
++
++              /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f4009);
++              dword &= ~(0x0000c00c);
++              dword |= (amd_voltage_level_index << 14);
++              dword |= (amd_voltage_level_index << 2);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f4009, dword);
++      }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static void InitPhyCompensation(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+       u8 i;
+-      u32 index_reg = 0x98 + 0x100 * dct;
++      u32 index_reg = 0x98;
+       u32 dev = pDCTstat->dev_dct;
+-      u32 val;
+       u32 valx = 0;
+-      u32 dword;
++      uint8_t index;
++      uint32_t dword;
+       const u8 *p;
+ 
+-      val = Get_NB32_index_wait(dev, index_reg, 0x00);
+-      dword = 0;
+-      for (i=0; i < 6; i++) {
+-              switch (i) {
+-                      case 0:
+-                      case 4:
+-                              p = Table_Comp_Rise_Slew_15x;
+-                              valx = p[(val >> 16) & 3];
+-                              break;
+-                      case 1:
+-                      case 5:
+-                              p = Table_Comp_Fall_Slew_15x;
+-                              valx = p[(val >> 16) & 3];
+-                              break;
+-                      case 2:
+-                              p = Table_Comp_Rise_Slew_20x;
+-                              valx = p[(val >> 8) & 3];
+-                              break;
+-                      case 3:
+-                              p = Table_Comp_Fall_Slew_20x;
+-                              valx = p[(val >> 8) & 3];
+-                              break;
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
++      if (is_fam15h()) {
++              /* Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 
2.10.5.3.4 */
++              uint32_t tx_pre;
++              uint32_t drive_strength;
++
++              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
++              dword |= (0x3 << 13);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
++
++              /* Determine TxPreP/TxPreN for data lanes (Stage 1) */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
++              drive_strength = (dword >> 20) & 0x7;   /* DqsDrvStren */
++              tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, 
drive_strength);
++
++              /* Program TxPreP/TxPreN for data lanes (Stage 1) */
++              for (index = 0; index < 0x9; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0006 | (index << 8));
++                      dword &= ~(0xfff);
++                      dword |= tx_pre;
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0006 
| (index << 8), dword);
++              }
+ 
++              /* Determine TxPreP/TxPreN for data lanes (Stage 2) */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
++              drive_strength = (dword >> 16) & 0x7;   /* DataDrvStren */
++              tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, 
drive_strength);
++
++              /* Program TxPreP/TxPreN for data lanes (Stage 2) */
++              for (index = 0; index < 0x9; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f000a | (index << 8));
++                      dword &= ~(0xfff);
++                      dword |= tx_pre;
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000a 
| (index << 8), dword);
++              }
++              for (index = 0; index < 0x9; index++) {
++                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0002 | (index << 8));
++                      dword &= ~(0xfff);
++                      dword |= (0x8000 | tx_pre);
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0002 
| (index << 8), dword);
+               }
+-              dword |= valx << (5 * i);
+-      }
+ 
+-      /* Override/Exception */
+-      if (!pDCTstat->GangedMode) {
+-              i = 0; /* use i for the dct setting required */
+-              if (pDCTstat->MAdimms[0] < 4)
+-                      i = 1;
+-              if (((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) && 
(pDCTstat->MAdimms[i] == 4)) {
+-                      dword &= 0xF18FFF18;
+-                      index_reg = 0x98;       /* force dct = 0 */
++              /* Determine TxPreP/TxPreN for command/address lines (Stage 1) 
*/
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
++              drive_strength = (dword >> 4) & 0x7;    /* CsOdtDrvStren */
++              tx_pre = 
fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
++
++              /* Program TxPreP/TxPreN for command/address lines (Stage 1) */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8006);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8006, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f800a);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f800a, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8002);
++              dword &= ~(0xfff);
++              dword |= (0x8000 | tx_pre);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8002, dword);
++
++              /* Determine TxPreP/TxPreN for command/address lines (Stage 2) 
*/
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
++              drive_strength = (dword >> 8) & 0x7;    /* AddrCmdDrvStren */
++              tx_pre = 
fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
++
++              /* Program TxPreP/TxPreN for command/address lines (Stage 2) */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8106);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8106, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f810a);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f810a, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc006);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc006, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc00a);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00a, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc00e);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00e, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc012);
++              dword &= ~(0xfff);
++              dword |= tx_pre;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc012, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f8102);
++              dword &= ~(0xfff);
++              dword |= (0x8000 | tx_pre);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8102, dword);
++
++              /* Determine TxPreP/TxPreN for command/address lines (Stage 3) 
*/
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
++              drive_strength = (dword >> 0) & 0x7;    /* CkeDrvStren */
++              tx_pre = 
fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength);
++
++              /* Program TxPreP/TxPreN for command/address lines (Stage 3) */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc002);
++              dword &= ~(0xfff);
++              dword |= (0x8000 | tx_pre);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc002, dword);
++
++              /* Determine TxPreP/TxPreN for clock lines */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
++              drive_strength = (dword >> 12) & 0x7;   /* ClkDrvStren */
++              tx_pre = fam15h_phy_predriver_clk_calibration_code(pDCTstat, 
dct, drive_strength);
++
++              /* Program TxPreP/TxPreN for clock lines */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f2002);
++              dword &= ~(0xfff);
++              dword |= (0x8000 | tx_pre);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2002, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f2102);
++              dword &= ~(0xfff);
++              dword |= (0x8000 | tx_pre);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2102, dword);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f2202);
++              dword &= ~(0xfff);
++              dword |= (0x8000 | tx_pre);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2202, dword);
++      } else {
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00);
++              dword = 0;
++              for (i=0; i < 6; i++) {
++                      switch (i) {
++                              case 0:
++                              case 4:
++                                      p = Table_Comp_Rise_Slew_15x;
++                                      valx = p[(dword >> 16) & 3];
++                                      break;
++                              case 1:
++                              case 5:
++                                      p = Table_Comp_Fall_Slew_15x;
++                                      valx = p[(dword >> 16) & 3];
++                                      break;
++                              case 2:
++                                      p = Table_Comp_Rise_Slew_20x;
++                                      valx = p[(dword >> 8) & 3];
++                                      break;
++                              case 3:
++                                      p = Table_Comp_Fall_Slew_20x;
++                                      valx = p[(dword >> 8) & 3];
++                                      break;
++                      }
++                      dword |= valx << (5 * i);
+               }
++
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0a, dword);
+       }
+ 
+-      Set_NB32_index_wait(dev, index_reg, 0x0a, dword);
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 reg;
+-      u32 val;
+-      u32 dev = pDCTstat->dev_dct;
+-
+-      /* GhEnhancement #18429 modified by askar: For low NB CLK :
+-       * Memclk ratio, the DCT may need to arbitrate early to avoid
+-       * unnecessary bubbles.
+-       * bit 19 of F2x[1,0]78 Dram  Control Register, set this bit only when
+-       * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 (inclusive)
+-       */
+-      reg = 0x78 + 0x100 * dct;
+-      val = Get_NB32(dev, reg);
+-
+-      if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
+-              val |= (1 << EarlyArbEn);
+-      else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
+-              val |= (1 << EarlyArbEn);
+-
+-      Set_NB32(dev, reg, val);
++      if (!is_fam15h()) {
++              u32 reg;
++              u32 val;
++              u32 dev = pDCTstat->dev_dct;
++
++              /* GhEnhancement #18429 modified by askar: For low NB CLK :
++              * Memclk ratio, the DCT may need to arbitrate early to avoid
++              * unnecessary bubbles.
++              * bit 19 of F2x[1,0]78 Dram  Control Register, set this bit 
only when
++              * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 
(inclusive)
++              */
++              reg = 0x78;
++              val = Get_NB32_DCT(dev, dct, reg);
++
++              if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
++                      val |= (1 << EarlyArbEn);
++              else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat))
++                      val |= (1 << EarlyArbEn);
++
++              Set_NB32_DCT(dev, dct, reg, val);
++      }
+ }
+ 
+ static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
+@@ -3359,9 +5309,9 @@ static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc 
*pMCTstat,
+               NbDid |= 1;
+ 
+       reg = 0x94;
+-      val = Get_NB32(dev, reg);
++      val = Get_NB32_DCT(dev, 0, reg);
+       if (!(val & (1 << MemClkFreqVal)))
+-              val = Get_NB32(dev, reg + 0x100);       /* get the DCT1 value */
++              val = Get_NB32_DCT(dev, 1, reg);        /* get the DCT1 value */
+ 
+       val &= 0x07;
+       val += 3;
+@@ -3430,28 +5380,204 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat)
++                                      struct DCTStatStruc *pDCTstat, u8 dct)
++{
++      mct_ProgramODT_D(pMCTstat, pDCTstat, dct);
++}
++
++static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+       u8 i;
+-      u32 reg_off, dword;
++      u32 dword;
+       u32 dev = pDCTstat->dev_dct;
+ 
+-      if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      if (is_fam15h()) {
++              /* Obtain number of DIMMs on channel */
++              uint8_t dimm_count = pDCTstat->MAdimms[dct];
++              uint8_t rank_count_dimm0;
++              uint8_t rank_count_dimm1;
++              uint32_t odt_pattern_0;
++              uint32_t odt_pattern_1;
++              uint32_t odt_pattern_2;
++              uint32_t odt_pattern_3;
++              uint8_t write_odt_duration;
++              uint8_t read_odt_duration;
++              uint8_t write_odt_delay;
++              uint8_t read_odt_delay;
++
++              /* Select appropriate ODT pattern for installed DIMMs
++               * Refer to the Fam15h BKDG Rev. 3.14, page 149 onwards
++               */
++              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED]) {
++                      if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      if (rank_count_dimm1 == 1) {
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x00020000;
++                                      } else if (rank_count_dimm1 == 2) {
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x08020000;
++                                      } else if (rank_count_dimm1 == 4) {
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x020a0000;
++                                              odt_pattern_3 = 0x080a0000;
++                                      } else {
++                                              /* Fallback */
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x08020000;
++                                      }
++                              } else {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x01010202;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x09030603;
++                                      } else if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 == 4)) {
++                                              odt_pattern_0 = 0x01010000;
++                                              odt_pattern_1 = 0x01010a0a;
++                                              odt_pattern_2 = 0x01090000;
++                                              odt_pattern_3 = 0x01030e0b;
++                                      } else if ((rank_count_dimm0 == 4) && 
(rank_count_dimm1 < 4)) {
++                                              odt_pattern_0 = 0x00000202;
++                                              odt_pattern_1 = 0x05050202;
++                                              odt_pattern_2 = 0x00000206;
++                                              odt_pattern_3 = 0x0d070203;
++                                      } else if ((rank_count_dimm0 == 4) && 
(rank_count_dimm1 == 4)) {
++                                              odt_pattern_0 = 0x05050a0a;
++                                              odt_pattern_1 = 0x05050a0a;
++                                              odt_pattern_2 = 0x050d0a0e;
++                                              odt_pattern_3 = 0x05070a0b;
++                                      } else {
++                                              /* Fallback */
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x00000000;
++                                      }
++                              }
++                      } else {
++                              /* FIXME
++                               * 3 DIMMs per channel UNIMPLEMENTED
++                               */
++                              odt_pattern_0 = 0x00000000;
++                              odt_pattern_1 = 0x00000000;
++                              odt_pattern_2 = 0x00000000;
++                              odt_pattern_3 = 0x00000000;
++                      }
++              } else if 
(pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
++                      /* TODO
++                       * Load reduced dimms UNIMPLEMENTED
++                       */
++                      odt_pattern_0 = 0x00000000;
++                      odt_pattern_1 = 0x00000000;
++                      odt_pattern_2 = 0x00000000;
++                      odt_pattern_3 = 0x00000000;
++              } else {
++                      if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      if (rank_count_dimm1 == 1) {
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x00020000;
++                                      } else if (rank_count_dimm1 == 2) {
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x08020000;
++                                      } else {
++                                              /* Fallback */
++                                              odt_pattern_0 = 0x00000000;
++                                              odt_pattern_1 = 0x00000000;
++                                              odt_pattern_2 = 0x00000000;
++                                              odt_pattern_3 = 0x08020000;
++                                      }
++                              } else {
++                                      /* 2 DIMMs detected */
++                                      odt_pattern_0 = 0x00000000;
++                                      odt_pattern_1 = 0x01010202;
++                                      odt_pattern_2 = 0x00000000;
++                                      odt_pattern_3 = 0x09030603;
++                              }
++                      } else {
++                              /* FIXME
++                               * 3 DIMMs per channel UNIMPLEMENTED
++                               */
++                              odt_pattern_0 = 0x00000000;
++                              odt_pattern_1 = 0x00000000;
++                              odt_pattern_2 = 0x00000000;
++                              odt_pattern_3 = 0x00000000;
++                      }
++              }
++
++              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
++                      /* TODO
++                       * Load reduced dimms UNIMPLEMENTED
++                       */
++                      write_odt_duration = 0x0;
++                      read_odt_duration = 0x0;
++                      write_odt_delay = 0x0;
++                      read_odt_delay = 0x0;
++              } else {
++                      uint8_t tcl;
++                      uint8_t tcwl;
++                      tcl = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
++                      tcwl = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
++
++                      write_odt_duration = 0x6;
++                      read_odt_duration = 0x6;
++                      write_odt_delay = 0x0;
++                      if (tcl > tcwl)
++                              read_odt_delay = tcl - tcwl;
++                      else
++                              read_odt_delay = 0x0;
++              }
++
++              /* Program ODT pattern */
++              Set_NB32_DCT(dev, dct, 0x230, odt_pattern_1);
++              Set_NB32_DCT(dev, dct, 0x234, odt_pattern_0);
++              Set_NB32_DCT(dev, dct, 0x238, odt_pattern_3);
++              Set_NB32_DCT(dev, dct, 0x23c, odt_pattern_2);
++              dword = Get_NB32_DCT(dev, dct, 0x240);
++              dword &= ~(0x7 << 12);                          /* 
WrOdtOnDuration = write_odt_duration */
++              dword |= (write_odt_duration & 0x7) << 12;
++              dword &= ~(0x7 << 8);                           /* 
WrOdtTrnOnDly = write_odt_delay */
++              dword |= (write_odt_delay & 0x7) << 8;
++              dword &= ~(0xf << 4);                           /* 
RdOdtOnDuration = read_odt_duration */
++              dword |= (read_odt_duration & 0xf) << 4;
++              dword &= ~(0xf);                                /* 
RdOdtTrnOnDly = read_odt_delay */
++              dword |= (read_odt_delay & 0xf);
++              Set_NB32_DCT(dev, dct, 0x240, dword);
++      } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+               if (pDCTstat->Speed == 3)
+                       dword = 0x00000800;
+               else
+                       dword = 0x00000000;
+               for (i=0; i < 2; i++) {
+-                      reg_off = 0x100 * i;
+-                      Set_NB32(dev,  0x98 + reg_off, 0x0D000030);
+-                      Set_NB32(dev,  0x9C + reg_off, dword);
+-                      Set_NB32(dev,  0x98 + reg_off, 0x4D040F30);
+-
+-                      /* FIXME
+-                       * Mainboards need to be able to specify the maximum 
number of DIMMs installable per channel
+-                       * For now assume a maximum of 2 DIMMs per channel can 
be installed
+-                       */
+-                      uint8_t MaxDimmsInstallable = 2;
++                      Set_NB32_DCT(dev, i, 0x98, 0x0D000030);
++                      Set_NB32_DCT(dev, i, 0x9C, dword);
++                      Set_NB32_DCT(dev, i, 0x98, 0x4D040F30);
+ 
+                       /* Obtain number of DIMMs on channel */
+                       uint8_t dimm_count = pDCTstat->MAdimms[i];
+@@ -3463,7 +5589,7 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
+                       uint32_t odt_pattern_3;
+ 
+                       /* Select appropriate ODT pattern for installed DIMMs
+-                       * Refer to the BKDG Rev. 3.62, page 120 onwards
++                       * Refer to the Fam10h BKDG Rev. 3.62, page 120 onwards
+                        */
+                       if 
(pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) {
+                               if (MaxDimmsInstallable == 2) {
+@@ -3574,10 +5700,10 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
+                       }
+ 
+                       /* Program ODT pattern */
+-                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x180, 
odt_pattern_1);
+-                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x181, 
odt_pattern_0);
+-                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x182, 
odt_pattern_3);
+-                      Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x183, 
odt_pattern_2);
++                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x180, 
odt_pattern_1);
++                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, 
odt_pattern_0);
++                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, 
odt_pattern_3);
++                      Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, 
odt_pattern_2);
+               }
+       }
+ }
+@@ -3585,34 +5711,32 @@ static void mct_BeforeDramInit_Prod_D(struct 
MCTStatStruc *pMCTstat,
+ static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct, val;
+ 
+       /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
+       if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) {
+-              Set_NB32(dev,  0x9C + reg_off, 0x1C);
+-              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE006);
+-              Set_NB32(dev,  0x9C + reg_off, 0x13D);
+-              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE007);
++              Set_NB32_DCT(dev, dct, 0x9C, 0x1C);
++              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006);
++              Set_NB32_DCT(dev, dct, 0x9C, 0x13D);
++              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007);
+ 
+-              val = Get_NB32(dev, 0x90 + reg_off);
++              val = Get_NB32_DCT(dev, dct, 0x90);
+               val &= ~(1 << 27/* DisDllShutdownSR */);
+-              Set_NB32(dev, 0x90 + reg_off, val);
++              Set_NB32_DCT(dev, dct, 0x90, val);
+       }
+ }
+ 
+ static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 
DramConfigLo, u8 dct)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+ 
+       /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */
+       if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) {
+-              Set_NB32(dev,  0x9C + reg_off, 0x7D0);
+-              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE006);
+-              Set_NB32(dev,  0x9C + reg_off, 0x190);
+-              Set_NB32(dev,  0x98 + reg_off, 0x4D0FE007);
++              Set_NB32_DCT(dev, dct, 0x9C, 0x7D0);
++              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006);
++              Set_NB32_DCT(dev, dct, 0x9C, 0x190);
++              Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007);
+ 
+               DramConfigLo |=  /* DisDllShutdownSR */ 1 << 27;
+       }
+@@ -3704,52 +5828,61 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+                               DramMRS |= 1 << 23;
+               }
+       }
+-      /*
+-       DRAM MRS Register
+-       DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7)
+-      */
+-      DramMRS |= 1 << 2;
+-      /* Dram nominal termination: */
+-      byte = pDCTstat->MAdimms[dct];
+-      if (!(pDCTstat->Status & (1 << SB_Registered))) {
+-              DramMRS |= 1 << 7; /* 60 ohms */
+-              if (byte & 2) {
+-                      if (pDCTstat->Speed < 6)
+-                              DramMRS |= 1 << 8; /* 40 ohms */
+-                      else
+-                              DramMRS |= 1 << 9; /* 30 ohms */
++
++      if (is_fam15h()) {
++              DramMRS |= (0x1 << 23);         /* PchgPDModeSel = 1 */
++      } else {
++              /*
++              DRAM MRS Register
++              DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = 
Rzq/7)
++              */
++              DramMRS |= 1 << 2;
++              /* Dram nominal termination: */
++              byte = pDCTstat->MAdimms[dct];
++              if (!(pDCTstat->Status & (1 << SB_Registered))) {
++                      DramMRS |= 1 << 7; /* 60 ohms */
++                      if (byte & 2) {
++                              if (pDCTstat->Speed < 6)
++                                      DramMRS |= 1 << 8; /* 40 ohms */
++                              else
++                                      DramMRS |= 1 << 9; /* 30 ohms */
++                      }
+               }
+-      }
+-      /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
+-      if (!(pDCTstat->Status & (1 << SB_Registered))) {
+-              if (byte >= 2) {
+-                      if (pDCTstat->Speed == 7)
+-                              DramMRS |= 1 << 10;
+-                      else
+-                              DramMRS |= 1 << 11;
++              /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */
++              if (!(pDCTstat->Status & (1 << SB_Registered))) {
++                      if (byte >= 2) {
++                              if (pDCTstat->Speed == 7)
++                                      DramMRS |= 1 << 10;
++                              else
++                                      DramMRS |= 1 << 11;
++                      }
++              } else {
++                      DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, 
byte);
+               }
+-      } else {
+-              DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, byte);
++
++              /* Qoff=0, output buffers enabled */
++              /* Tcwl */
++              DramMRS |= (pDCTstat->Speed - 4) << 20;
++              /* ASR=1, auto self refresh */
++              /* SRT=0 */
++              DramMRS |= 1 << 18;
+       }
+ 
+       /* burst length control */
+       if (pDCTstat->Status & (1 << SB_128bitmode))
+               DramMRS |= 1 << 1;
+-      /* Qoff=0, output buffers enabled */
+-      /* Tcwl */
+-      DramMRS |= (pDCTstat->Speed - 4) << 20;
+-      /* ASR=1, auto self refresh */
+-      /* SRT=0 */
+-      DramMRS |= 1 << 18;
+-
+-      dword = Get_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84);
+-      dword &= ~0x00FC2F8F;
++
++      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
++      if (is_fam15h())
++              dword &= ~0x00800003;
++      else
++              dword &= ~0x00fc2f8f;
+       dword |= DramMRS;
+-      Set_NB32(pDCTstat->dev_dct, 0x100 * dct + 0x84, dword);
++      Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword);
+ }
+ 
+-void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct,
+-                              u32 DramConfigHi)
++void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, u32 dct, u32 
DramConfigHi)
+ {
+       /* Bug#15114: Comp. update interrupted by Freq. change can cause
+        * subsequent update to be invalid during any MemClk frequency change:
+@@ -3778,45 +5911,86 @@ void mct_SetDramConfigHi_D(struct DCTStatStruc 
*pDCTstat, u32 dct,
+        */
+ 
+       u32 dev = pDCTstat->dev_dct;
+-      u32 index_reg = 0x98 + 0x100 * dct;
++      u32 index_reg = 0x98;
+       u32 index;
+ 
+-      u32 val;
++      uint32_t dword;
++
++      if (is_fam15h()) {
++              /* Initial setup for frequency change
++               * 9C_x0000_0004 must be configured before MemClkFreqVal is set
++               */
+ 
+-      index = 0x08;
+-      val = Get_NB32_index_wait(dev, index_reg, index);
+-      if (!(val & (1 << DisAutoComp)))
+-              Set_NB32_index_wait(dev, index_reg, index, val | (1 << 
DisAutoComp));
++              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0x190 */
++              dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
index_reg, 0x0d0fe006);
++              dword &= ~(0x0000ffff);
++              dword |= 0x00000190;
++              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 
0x0d0fe006, dword);
+ 
+-      mct_Wait(100);
++              dword = Get_NB32_DCT(dev, dct, 0x94);
++              dword &= ~(1 << MemClkFreqVal);
++              Set_NB32_DCT(dev, dct, 0x94, dword);
+ 
+-      Set_NB32(dev, 0x94 + 0x100 * dct, DramConfigHi);
++              dword = DramConfigHi;
++              dword &= ~(1 << MemClkFreqVal);
++              Set_NB32_DCT(dev, dct, 0x94, dword);
++
++              mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct);
++              set_2t_configuration(pMCTstat, pDCTstat, dct);
++              mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct);
++              mct_PlatformSpec(pMCTstat, pDCTstat, dct);
++      } else {
++              index = 0x08;
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
++              if (!(dword & (1 << DisAutoComp)))
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, 
dword | (1 << DisAutoComp));
++
++              mct_Wait(100);
++      }
++
++      /* Program the DRAM Configuration High register */
++      Set_NB32_DCT(dev, dct, 0x94, DramConfigHi);
++
++      if (is_fam15h()) {
++              /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
++              do {
++                      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94);
++              } while (dword & (1 << FreqChgInProg));
++
++              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0xf */
++              dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
index_reg, 0x0d0fe006);
++              dword &= ~(0x0000ffff);
++              dword |= 0x0000000f;
++              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 
0x0d0fe006, dword);
++      }
+ }
+ 
+ static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA)
+ {
+-      u8 Node;
+-      struct DCTStatStruc *pDCTstat;
++      if (!is_fam15h()) {
++              u8 Node;
++              struct DCTStatStruc *pDCTstat;
+ 
+-      /* Errata 178
+-       *
+-       * Bug#15115: Uncertainty In The Sync Chain Leads To Setup Violations
+-       *            In TX FIFO
+-       * Solution: BIOS should program DRAM Control Register[RdPtrInit] =
+-       *            5h, (F2x[1, 0]78[3:0] = 5h).
+-       * Silicon Status: Fixed In Rev B0
+-       *
+-       * Bug#15880: Determine validity of reset settings for DDR PHY timing.
+-       * Solution: At least, set WrDqs fine delay to be 0 for DDR3 training.
+-       */
+-      for (Node = 0; Node < 8; Node++) {
+-              pDCTstat = pDCTstatA + Node;
++              /* Errata 178
++               *
++               * Bug#15115: Uncertainty In The Sync Chain Leads To Setup 
Violations
++               *            In TX FIFO
++               * Solution: BIOS should program DRAM Control 
Register[RdPtrInit] =
++               *            5h, (F2x[1, 0]78[3:0] = 5h).
++               * Silicon Status: Fixed In Rev B0
++               *
++               * Bug#15880: Determine validity of reset settings for DDR PHY 
timing.
++               * Solution: At least, set WrDqs fine delay to be 0 for DDR3 
training.
++               */
++              for (Node = 0; Node < 8; Node++) {
++                      pDCTstat = pDCTstatA + Node;
+ 
+-              if (pDCTstat->NodePresent) {
+-                      mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
+-                      mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
+-                      mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
++                      if (pDCTstat->NodePresent) {
++                              mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */
++                              mct_ResetDLL_D(pMCTstat, pDCTstat, 0);
++                              mct_ResetDLL_D(pMCTstat, pDCTstat, 1);
++                      }
+               }
+       }
+ }
+@@ -3827,7 +6001,6 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat,
+ {
+       u8 Receiver;
+       u32 dev = pDCTstat->dev_dct;
+-      u32 reg_off = 0x100 * dct;
+       u32 addr;
+       u32 lo, hi;
+       u8 wrap32dis = 0;
+@@ -3838,6 +6011,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc 
*pMCTstat,
+               return;
+       }
+ 
++      /* Skip reset DLL for Family 15h */
++      if (is_fam15h()) {
++              return;
++      }
++
+       addr = HWCR;
+       _RDMSR(addr, &lo, &hi);
+       if(lo & (1<<17)) {              /* save the old value */
+@@ -3857,11 +6035,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc 
*pMCTstat,
+                               mct_Read1LTestPattern_D(pMCTstat, pDCTstat, 
addr);      /* cache fills */
+ 
+                               /* Write 0000_8000h to register 
F2x[1,0]9C_xD080F0C */
+-                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00008000);
++                              Set_NB32_index_wait_DCT(dev, dct, 0x98, 
0xD080F0C, 0x00008000);
+                               mct_Wait(80); /* wait >= 300ns */
+ 
+                               /* Write 0000_0000h to register 
F2x[1,0]9C_xD080F0C */
+-                              Set_NB32_index_wait(dev, 0x98 + reg_off, 
0xD080F0C, 0x00000000);
++                              Set_NB32_index_wait_DCT(dev, dct, 0x98, 
0xD080F0C, 0x00000000);
+                               mct_Wait(800); /* wait >= 2us */
+                               break;
+                       }
+@@ -3901,39 +6079,39 @@ static void mct_EnableDatIntlv_D(struct MCTStatStruc 
*pMCTstat,
+ static void SetDllSpeedUp_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 val;
+-      u32 dev = pDCTstat->dev_dct;
+-      u32 reg_off = 0x100 * dct;
+-
+-      if (pDCTstat->Speed >= 7) { /* DDR1600 and above */
+-              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F10 */
+-              Set_NB32(dev, reg_off + 0x98, 0x0D080F10);
+-              val = Get_NB32(dev, reg_off + 0x9C);
+-              val |= 1 < 13;
+-              Set_NB32(dev, reg_off + 0x9C, val);
+-              Set_NB32(dev, reg_off + 0x98, 0x4D080F10);
+-
+-              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F11 */
+-              Set_NB32(dev, reg_off + 0x98, 0x0D080F11);
+-              val = Get_NB32(dev, reg_off + 0x9C);
+-              val |= 1 < 13;
+-              Set_NB32(dev, reg_off + 0x9C, val);
+-              Set_NB32(dev, reg_off + 0x98, 0x4D080F11);
+-
+-              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D088F30 */
+-              Set_NB32(dev, reg_off + 0x98, 0x0D088F30);
+-              val = Get_NB32(dev, reg_off + 0x9C);
+-              val |= 1 < 13;
+-              Set_NB32(dev, reg_off + 0x9C, val);
+-              Set_NB32(dev, reg_off + 0x98, 0x4D088F30);
+-
+-              /* Set bit13 PowerDown to register F2x[1, 0]98_x0D08CF30 */
+-              Set_NB32(dev, reg_off + 0x98, 0x0D08CF30);
+-              val = Get_NB32(dev, reg_off + 0x9C);
+-              val |= 1 < 13;
+-              Set_NB32(dev, reg_off + 0x9C, val);
+-              Set_NB32(dev, reg_off + 0x98, 0x4D08CF30);
+-
++      if (!is_fam15h()) {
++              u32 val;
++              u32 dev = pDCTstat->dev_dct;
++
++              if (pDCTstat->Speed >= mhz_to_memclk_config(800)) { /* DDR1600 
and above */
++                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D080F10 */
++                      Set_NB32_DCT(dev, dct, 0x98, 0x0D080F10);
++                      val = Get_NB32_DCT(dev, dct, 0x9C);
++                      val |= 1 < 13;
++                      Set_NB32_DCT(dev, dct, 0x9C, val);
++                      Set_NB32_DCT(dev, dct, 0x98, 0x4D080F10);
++
++                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D080F11 */
++                      Set_NB32_DCT(dev, dct, 0x98, 0x0D080F11);
++                      val = Get_NB32_DCT(dev, dct, 0x9C);
++                      val |= 1 < 13;
++                      Set_NB32_DCT(dev, dct, 0x9C, val);
++                      Set_NB32_DCT(dev, dct, 0x98, 0x4D080F11);
++
++                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D088F30 */
++                      Set_NB32_DCT(dev, dct, 0x98, 0x0D088F30);
++                      val = Get_NB32_DCT(dev, dct, 0x9C);
++                      val |= 1 < 13;
++                      Set_NB32_DCT(dev, dct, 0x9C, val);
++                      Set_NB32_DCT(dev, dct, 0x98, 0x4D088F30);
++
++                      /* Set bit13 PowerDown to register F2x[1, 
0]98_x0D08CF30 */
++                      Set_NB32_DCT(dev, dct, 0x98, 0x0D08CF30);
++                      val = Get_NB32_DCT(dev, dct, 0x9C);
++                      val |= 1 < 13;
++                      Set_NB32_DCT(dev, dct, 0x9C, val);
++                      Set_NB32_DCT(dev, dct, 0x98, 0x4D08CF30);
++              }
+       }
+ }
+ 
+@@ -3961,7 +6139,6 @@ static void SyncSetting(struct DCTStatStruc *pDCTstat)
+ static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) {
+ 
+       u32 val;
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+ 
+       if (pDCTstat->LogicalCPUID & (AMD_DR_B2 | AMD_DR_B3)) {
+@@ -3969,16 +6146,16 @@ static void AfterDramInit_D(struct DCTStatStruc 
*pDCTstat, u8 dct) {
+               val = Get_NB32(dev, 0x110);
+               if (!(val & (1 << DramEnabled))) {
+                       /* If 50 us expires while DramEnable =0 then do the 
following */
+-                      val = Get_NB32(dev, 0x90 + reg_off);
++                      val = Get_NB32_DCT(dev, dct, 0x90);
+                       val &= ~(1 << Width128);                /* Program 
Width128 = 0 */
+-                      Set_NB32(dev, 0x90 + reg_off, val);
++                      Set_NB32_DCT(dev, dct, 0x90, val);
+ 
+-                      val = Get_NB32_index_wait(dev, 0x98 + reg_off, 0x05);   
/* Perform dummy CSR read to F2x09C_x05 */
++                      val = Get_NB32_index_wait_DCT(dev, dct, 0x98, 0x05);    
/* Perform dummy CSR read to F2x09C_x05 */
+ 
+                       if (pDCTstat->GangedMode) {
+-                              val = Get_NB32(dev, 0x90 + reg_off);
++                              val = Get_NB32_DCT(dev, dct, 0x90);
+                               val |= 1 << Width128;           /* Program 
Width128 = 0 */
+-                              Set_NB32(dev, 0x90 + reg_off, val);
++                              Set_NB32_DCT(dev, dct, 0x90, val);
+                       }
+               }
+       }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index a947c2d..50fbff7 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -76,6 +76,8 @@
+ /* #define PA_EXT_DCTADDL (((00 << 3)+5) << 8) */     /*Node x DCT function, 
Additional Registers PCI Address bits [15:0]*/
+ 
+ #define PA_NBMISC(Node)       ((((0x18+Node) << 3)+3) << 12)  /*Node 0 Misc 
PCI Address bits [15:0]*/
++#define PA_LINK(Node) ((((0x18+Node) << 3)+4) << 12)  /*Node 0 Link Control 
bits [15:0]*/
++#define PA_NBCTL(Node)        ((((0x18+Node) << 3)+5) << 12)  /*Node 0 NB 
Control PCI Address bits [15:0]*/
+ /* #define PA_NBDEVOP (((00 << 3)+3) << 8) */  /*Node 0 Misc PCI Address bits 
[15:0]*/
+ 
+ #define DCC_EN                1               /* X:2:0x94[19]*/
+@@ -129,7 +131,7 @@
+ #define X4Dimm                        12      /* func 2, offset 90h, bit 12*/
+ #define UnBuffDimm            16      /* func 2, offset 90h, bit 16*/
+ #define DimmEcEn              19      /* func 2, offset 90h, bit 19*/
+-#define MemClkFreqVal         3       /* func 2, offset 94h, bit 3*/
++#define MemClkFreqVal         ((is_fam15h())?7:3)     /* func 2, offset 94h, 
bit 3 or 7*/
+ #define RDqsEn                        12      /* func 2, offset 94h, bit 12*/
+ #define DisDramInterface      14      /* func 2, offset 94h, bit 14*/
+ #define PowerDownEn           15      /* func 2, offset 94h, bit 15*/
+@@ -204,6 +206,7 @@
+       #define JED_PROBEMSK    0x40    /*Analysis Probe installed*/
+       #define JED_RDIMM       0x1     /* RDIMM */
+       #define JED_MiniRDIMM   0x5     /* Mini-RDIMM */
++      #define JED_LRDIMM      0xb     /* Load-reduced DIMM */
+ #define SPD_Density   4               /* Bank address bits,SDRAM capacity */
+ #define SPD_Addressing        5               /* Row/Column address bits */
+ #define SPD_Voltage   6               /* Supported voltage bitfield */
+@@ -297,6 +300,7 @@ struct MCTStatStruc {
+                                     of sub 4GB dram hole for HW remapping.*/
+       u32 Sub4GCacheTop;      /* If not zero, the 32-bit top of cacheable 
memory.*/
+       u32 SysLimit;           /* LIMIT[39:8] (system address)*/
++      uint32_t TSCFreq;
+ } __attribute__((packed));
+ 
+ 
/*=============================================================================
+@@ -320,7 +324,8 @@ struct MCTStatStruc {
+ 
+ struct DCTStatStruc {         /* A per Node structure*/
+ /* DCTStatStruct_F -  start */
+-      u8 Node_ID;             /* Node ID of current controller*/
++      u8 Node_ID;             /* Node ID of current controller */
++      uint8_t stopDCT;        /* Set if the DCT will be stopped */
+       u8 ErrCode;             /* Current error condition of Node
+               0= no error
+               1= Variance Error, DCT is running but not in an optimal 
configuration.
+@@ -464,7 +469,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+               /* CH A byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
+               /* CH B byte lane 0 - 7 minimum filtered window  passing DQS 
delay value*/
+               /* CH B byte lane 0 - 7 maximum filtered window  passing DQS 
delay value*/
+-      u32 LogicalCPUID;       /* The logical CPUID of the node*/
++      uint64_t LogicalCPUID;  /* The logical CPUID of the node*/
+       u16 HostBiosSrvc1;      /* Word sized general purpose field for use by 
host BIOS.  Scratch space.*/
+       u32 HostBiosSrvc2;      /* Dword sized general purpose field for use by 
host BIOS.  Scratch space.*/
+       u16 DimmQRPresent;      /* QuadRank DIMM present?*/
+@@ -558,12 +563,20 @@ struct DCTStatStruc {            /* A per Node 
structure*/
+       u8 ClToNB_flag; /* is used to restore ClLinesToNbDis bit after memory */
+       u32 NodeSysBase;        /* for channel interleave usage */
+ 
++      /* Fam15h specific backup variables */
++      uint8_t SwNbPstateLoDis;
++      uint8_t NbPstateDisOnP0;
++      uint8_t NbPstateThreshold;
++      uint8_t NbPstateHi;
++
+ /* New for LB Support */
+       u8 NodePresent;
+       u32 dev_host;
+       u32 dev_map;
+       u32 dev_dct;
+       u32 dev_nbmisc;
++      u32 dev_link;
++      u32 dev_nbctl;
+       u8 TargetFreq;
+       u8 TargetCASL;
+       u8 CtrlWrd3;
+@@ -596,9 +609,10 @@ struct DCTStatStruc {             /* A per Node 
structure*/
+       uint8_t DimmBanks[MAX_DIMMS_SUPPORTED];
+       uint8_t DimmWidth[MAX_DIMMS_SUPPORTED];
+       uint8_t DimmRegistered[MAX_DIMMS_SUPPORTED];
++      uint8_t DimmLoadReduced[MAX_DIMMS_SUPPORTED];
+ 
+       uint64_t DimmManufacturerID[MAX_DIMMS_SUPPORTED];
+-      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH];
++      char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
+       uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
+       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
+ } __attribute__((packed));
+@@ -701,7 +715,64 @@ struct amd_s3_persistent_mct_channel_data {
+       /* Other (1 dword) */
+       uint32_t f3x58;
+ 
+-      /* TOTAL: 250 dwords */
++      /* Family 15h-specific registers (90 dwords) */
++      uint32_t f2x200;
++      uint32_t f2x204;
++      uint32_t f2x208;
++      uint32_t f2x20c;
++      uint32_t f2x210[4];                     /* [nb pstate] */
++      uint32_t f2x214;
++      uint32_t f2x218;
++      uint32_t f2x21c;
++      uint32_t f2x22c;
++      uint32_t f2x230;
++      uint32_t f2x234;
++      uint32_t f2x238;
++      uint32_t f2x23c;
++      uint32_t f2x240;
++      uint32_t f2x9cx0d0fe003;
++      uint32_t f2x9cx0d0fe013;
++      uint32_t f2x9cx0d0f0_8_0_1f[9];         /* [lane]*/
++      uint32_t f2x9cx0d0f201f;
++      uint32_t f2x9cx0d0f211f;
++      uint32_t f2x9cx0d0f221f;
++      uint32_t f2x9cx0d0f801f;
++      uint32_t f2x9cx0d0f811f;
++      uint32_t f2x9cx0d0f821f;
++      uint32_t f2x9cx0d0fc01f;
++      uint32_t f2x9cx0d0fc11f;
++      uint32_t f2x9cx0d0fc21f;
++      uint32_t f2x9cx0d0f4009;
++      uint32_t f2x9cx0d0f0_8_0_02[9];         /* [lane]*/
++      uint32_t f2x9cx0d0f0_8_0_06[9];         /* [lane]*/
++      uint32_t f2x9cx0d0f0_8_0_0a[9];         /* [lane]*/
++      uint32_t f2x9cx0d0f2002;
++      uint32_t f2x9cx0d0f2102;
++      uint32_t f2x9cx0d0f2202;
++      uint32_t f2x9cx0d0f8002;
++      uint32_t f2x9cx0d0f8006;
++      uint32_t f2x9cx0d0f800a;
++      uint32_t f2x9cx0d0f8102;
++      uint32_t f2x9cx0d0f8106;
++      uint32_t f2x9cx0d0f810a;
++      uint32_t f2x9cx0d0fc002;
++      uint32_t f2x9cx0d0fc006;
++      uint32_t f2x9cx0d0fc00a;
++      uint32_t f2x9cx0d0fc00e;
++      uint32_t f2x9cx0d0fc012;
++      uint32_t f2x9cx0d0f2031;
++      uint32_t f2x9cx0d0f2131;
++      uint32_t f2x9cx0d0f2231;
++      uint32_t f2x9cx0d0f8031;
++      uint32_t f2x9cx0d0f8131;
++      uint32_t f2x9cx0d0f8231;
++      uint32_t f2x9cx0d0fc031;
++      uint32_t f2x9cx0d0fc131;
++      uint32_t f2x9cx0d0fc231;
++      uint32_t f2x9cx0d0f0_0_f_31[9];         /* [lane] */
++      uint32_t f2x9cx0d0f8021;
++
++      /* TOTAL: 340 dwords */
+ } __attribute__((packed));
+ 
+ struct amd_s3_persistent_node_data {
+@@ -746,18 +817,19 @@ struct amd_s3_persistent_data {
+       Local Configuration Status (DCTStatStruc.Status[31:0])
+ 
===============================================================================*/
+ #define SB_Registered         0       /* All DIMMs are Registered*/
+-#define SB_ECCDIMMs           1       /* All banks ECC capable*/
+-#define SB_PARDIMMs           2       /* All banks Addr/CMD Parity capable*/
+-#define SB_DiagClks           3       /* Jedec ALL slots clock enable diag 
mode*/
+-#define SB_128bitmode         4       /* DCT in 128-bit mode operation*/
+-#define SB_64MuxedMode                5       /* DCT in 64-bit mux'ed mode.*/
+-#define SB_2TMode             6       /* 2T CMD timing mode is enabled.*/
+-#define SB_SWNodeHole         7       /* Remapping of Node Base on this Node 
to create a gap.*/
+-#define SB_HWHole             8       /* Memory Hole created on this Node 
using HW remapping.*/
+-#define SB_Over400MHz         9       /* DCT freq >= 400MHz flag*/
+-#define SB_DQSPos_Pass2       10      /* Using for TrainDQSPos DIMM0/1, when 
freq>=400MHz*/
+-#define SB_DQSRcvLimit                11      /* Using for DQSRcvEnTrain to 
know we have reached to upper bound.*/
+-#define SB_ExtConfig          12      /* Indicator the default setting for 
extend PCI configuration support*/
++#define SB_LoadReduced                1       /* All DIMMs are Load-Reduced*/
++#define SB_ECCDIMMs           2       /* All banks ECC capable*/
++#define SB_PARDIMMs           3       /* All banks Addr/CMD Parity capable*/
++#define SB_DiagClks           4       /* Jedec ALL slots clock enable diag 
mode*/
++#define SB_128bitmode         5       /* DCT in 128-bit mode operation*/
++#define SB_64MuxedMode                6       /* DCT in 64-bit mux'ed mode.*/
++#define SB_2TMode             7       /* 2T CMD timing mode is enabled.*/
++#define SB_SWNodeHole         8       /* Remapping of Node Base on this Node 
to create a gap.*/
++#define SB_HWHole             9       /* Memory Hole created on this Node 
using HW remapping.*/
++#define SB_Over400MHz         10      /* DCT freq >= 400MHz flag*/
++#define SB_DQSPos_Pass2               11      /* Using for TrainDQSPos 
DIMM0/1, when freq>=400MHz*/
++#define SB_DQSRcvLimit                12      /* Using for DQSRcvEnTrain to 
know we have reached to upper bound.*/
++#define SB_ExtConfig          13      /* Indicator the default setting for 
extend PCI configuration support*/
+ 
+ 
+ 
/*===============================================================================
+@@ -775,17 +847,18 @@ struct amd_s3_persistent_data {
+                                           266=266MHz (DDR533)
+                                           333=333MHz (DDR667)
+                                           400=400MHz (DDR800)*/
+-#define NV_ECC_CAP            4       /* Bus ECC capable (1-bits)
++#define NV_MIN_MEMCLK         4       /* Minimum platform demonstrated 
Memclock (10-bits) */
++#define NV_ECC_CAP            5       /* Bus ECC capable (1-bits)
+                                           0=Platform not capable
+                                           1=Platform is capable*/
+-#define NV_4RANKType          5       /* Quad Rank DIMM slot type (2-bits)
++#define NV_4RANKType          6       /* Quad Rank DIMM slot type (2-bits)
+                                           0=Normal
+                                           1=R4 (4-Rank Registered DIMMs in 
AMD server configuration)
+                                           2=S4 (Unbuffered SO-DIMMs)*/
+-#define NV_BYPMAX             6       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
++#define NV_BYPMAX             7       /* Value to set DcqBypassMax field (See 
Function 2, Offset 94h, [27:24] of BKDG for field definition).
+                                           4=4 times bypass (normal for 
non-UMA systems)
+                                           7=7 times bypass (normal for UMA 
systems)*/
+-#define NV_RDWRQBYP           7       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
++#define NV_RDWRQBYP           8       /* Value to set RdWrQByp field (See 
Function 2, Offset A0h, [3:2] of BKDG for field definition).
+                                           2=8 times (normal for non-UMA 
systems)
+                                           3=16 times (normal for UMA 
systems)*/
+ 
+@@ -848,8 +921,9 @@ struct amd_s3_persistent_data {
+ #define NV_ECCRedir           54      /* Dram ECC Redirection enable*/
+ #define NV_DramBKScrub                55      /* Dram ECC Background Scrubber 
CTL*/
+ #define NV_L2BKScrub          56      /* L2 ECC Background Scrubber CTL*/
+-#define NV_DCBKScrub          57      /* DCache ECC Background Scrubber CTL*/
+-#define NV_CS_SpareCTL                58      /* Chip Select Spare Control 
bit 0:
++#define NV_L3BKScrub          57      /* L3 ECC Background Scrubber CTL*/
++#define NV_DCBKScrub          58      /* DCache ECC Background Scrubber CTL*/
++#define NV_CS_SpareCTL                59      /* Chip Select Spare Control 
bit 0:
+                                              0=disable Spare
+                                              1=enable Spare */
+                                       /* Chip Select Spare Control bit 1-4:
+@@ -900,10 +974,12 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u16 RcvrEnDly, u8 FinalVa
+ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel);
+ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u32 dct);
+ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
+-void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct, u32 
DramConfigHi);
++void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u32 dct, u32 DramConfigHi);
+ void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct);
+ void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
+ void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
++void mct_ForceNBPState0_En_Fam15(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
++void mct_ForceNBPState0_Dis_Fam15(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 Pass);
+ void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 _DisableDramECC);
+ u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
+index c40ea1a..f6aa755 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
+@@ -98,6 +98,15 @@ static u32 bsf(u32 x)
+ 
+ u32 SetUpperFSbase(u32 addr_hi);
+ 
++static void proc_MFENCE(void)
++{
++      __asm__ volatile (
++              "outb %%al, $0xed\n\t"  /* _EXECFENCE */
++              "mfence\n\t"
++              :::"memory"
++      );
++}
++
+ static void proc_CLFLUSH(u32 addr_hi)
+ {
+       SetUpperFSbase(addr_hi);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
+index 126642b..3df262b 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -17,6 +18,8 @@
+  * Foundation, Inc.
+  */
+ 
++/* AM3/ASB2/C32/G34 DDR3 */
++
+ static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
+                               u32 *AddrTmgCTL, u32 *ODC_CTL,
+                               u8 *CMDmode);
+@@ -24,17 +27,23 @@ static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 
MAAload,
+ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+                        struct DCTStatStruc *pDCTstat, u32 dct)
+ {
+-      Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
+-                              pDCTstat->MAload[dct],
+-                              &(pDCTstat->CH_ADDR_TMG[dct]), 
&(pDCTstat->CH_ODC_CTL[dct]),
+-                              &pDCTstat->_2Tmode);
++      if (is_fam15h()) {
++              pDCTstat->CH_ADDR_TMG[dct] = 
fam15h_address_timing_compensation_code(pDCTstat, dct);
++              pDCTstat->CH_ODC_CTL[dct] = 
fam15h_output_driver_compensation_code(pDCTstat, dct);
++              pDCTstat->_2Tmode = fam15h_slow_access_mode(pDCTstat, dct);
++      } else {
++              Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
++                                      pDCTstat->MAload[dct],
++                                      &(pDCTstat->CH_ADDR_TMG[dct]), 
&(pDCTstat->CH_ODC_CTL[dct]),
++                                      &pDCTstat->_2Tmode);
++
++              pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;        /* 60ohms */
++      }
+ 
+       pDCTstat->CH_EccDQSLike[0]  = 0x0403;
+       pDCTstat->CH_EccDQSScale[0] = 0x70;
+       pDCTstat->CH_EccDQSLike[1]  = 0x0403;
+       pDCTstat->CH_EccDQSScale[1] = 0x70;
+-
+-      pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;        /* 60ohms */
+ }
+ 
+ /*
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
+index f1fd7a5..a1cdfa6 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -35,7 +36,6 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+ 
+       u32 dev;
+       u32 reg;
+-      u32 reg_off;
+       u32 val;
+       u32 val_lo, val_hi;
+ 
+@@ -44,16 +44,15 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+       EnChipSels = 0;
+ 
+       dev = pDCTstat->dev_dct;
+-      reg_off = 0x100 * dct;
+ 
+       ChipSel = 0;            /* Find out if current configuration is capable 
*/
+       while (DoIntlv && (ChipSel < MAX_CS_SUPPORTED)) {
+-              reg = 0x40+(ChipSel<<2) + reg_off;      /* Dram CS Base 0 */
+-              val = Get_NB32(dev, reg);
++              reg = 0x40+(ChipSel<<2);        /* Dram CS Base 0 */
++              val = Get_NB32_DCT(dev, dct, reg);
+               if ( val & (1<<CSEnable)) {
+                       EnChipSels++;
+-                      reg = 0x60+((ChipSel>>1)<<2)+reg_off; /*Dram CS Mask 0 
*/
+-                      val = Get_NB32(dev, reg);
++                      reg = 0x60+((ChipSel>>1)<<2); /*Dram CS Mask 0 */
++                      val = Get_NB32_DCT(dev, dct, reg);
+                       val >>= 19;
+                       val &= 0x3ff;
+                       val++;
+@@ -63,8 +62,8 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+                               /*If mask sizes not same then skip */
+                               if (val != MemSize)
+                                       break;
+-                      reg = 0x80 + reg_off;           /*Dram Bank Addressing 
*/
+-                      val = Get_NB32(dev, reg);
++                      reg = 0x80;             /*Dram Bank Addressing */
++                      val = Get_NB32_DCT(dev, dct, reg);
+                       val >>= (ChipSel>>1)<<2;
+                       val &= 0x0f;
+                       if(EnChipSels == 1)
+@@ -103,8 +102,8 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+               BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask);
+ 
+               for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) {
+-                      reg = 0x40+(ChipSel<<2) + reg_off;      /*Dram CS Base 
0 */
+-                      val = Get_NB32(dev, reg);
++                      reg = 0x40+(ChipSel<<2);        /*Dram CS Base 0 */
++                      val = Get_NB32_DCT(dev, dct, reg);
+                       if (val & 3) {
+                               val_lo = val & AddrLoMask;
+                               val_hi = val & AddrHiMask;
+@@ -114,13 +113,13 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+                               val_hi >>= BitDelta;
+                               val |= val_lo;
+                               val |= val_hi;
+-                              Set_NB32(dev, reg, val);
++                              Set_NB32_DCT(dev, dct, reg, val);
+ 
+                               if(ChipSel & 1)
+                                       continue;
+ 
+-                              reg = 0x60 + ((ChipSel>>1)<<2) + reg_off; 
/*Dram CS Mask 0 */
+-                              val = Get_NB32(dev, reg);
++                              reg = 0x60 + ((ChipSel>>1)<<2); /*Dram CS Mask 
0 */
++                              val = Get_NB32_DCT(dev, dct, reg);
+                               val_lo = val & AddrLoMask;
+                               val_hi = val & AddrHiMask;
+                               val &= AddrLoMaskN;
+@@ -129,7 +128,7 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+                               val_hi >>= BitDelta;
+                               val |= val_lo;
+                               val |= val_hi;
+-                              Set_NB32(dev, reg, val);
++                              Set_NB32_DCT(dev, dct, reg, val);
+                       }
+               }
+       }       /* DoIntlv */
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index cc2f43a..740edae 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -18,6 +18,12 @@
+  * Foundation, Inc.
+  */
+ 
++static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay,
++                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
++
++static void read_read_dqs_timing_control_registers(uint16_t* 
current_total_delay,
++                      uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
++
+ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u16 like,
+                               u8 scale, u8 ChipSel);
+@@ -37,7 +43,7 @@ static void FlushDQSTestPattern_D(struct DCTStatStruc 
*pDCTstat,
+                                       u32 addr_lo);
+ static void SetTargetWTIO_D(u32 TestAddr);
+ static void ResetTargetWTIO_D(void);
+-void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index);
++void ResetDCTWrPtr_D(u32 dev, uint8_t dct, u32 index_reg, u32 index);
+ u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat,
+@@ -54,6 +60,7 @@ static void proc_IOCLFLUSH_D(u32 addr_hi);
+ static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, u8 ChipSel);
+ 
+ #define DQS_TRAIN_DEBUG 0
++// #define PRINT_PASS_FAIL_BITMAPS 1
+ 
+ static void print_debug_dqs(const char *str, u32 val, u8 level)
+ {
+@@ -198,18 +205,20 @@ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
+               pDCTstat = pDCTstatA + Node;
+ 
+               if (pDCTstat->DCTSysLimit) {
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x78);
+-                      val |= 1 <<DqsRcvEnTrain;
+-                      Set_NB32(pDCTstat->dev_dct, 0x78, val);
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x78 + 0x100);
+-                      val |= 1 <<DqsRcvEnTrain;
+-                      Set_NB32(pDCTstat->dev_dct, 0x78 + 0x100, val);
++                      if (!is_fam15h()) {
++                              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x78);
++                              val |= 1 <<DqsRcvEnTrain;
++                              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x78, val);
++                              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x78);
++                              val |= 1 <<DqsRcvEnTrain;
++                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x78, val);
++                      }
+                       mct_TrainRcvrEn_D(pMCTstat, pDCTstat, Pass);
+               }
+       }
+ }
+ 
+-static void SetEccDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
++static void SetEccDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
+ {
+       u8 channel;
+@@ -268,68 +277,150 @@ static void CalcEccDQSPos_D(struct MCTStatStruc 
*pMCTstat,
+       pDCTstat->DQSDelay = (u8)DQSDelay;
+ }
+ 
+-static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
++static void read_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
++{
++      uint32_t dword;
++      uint32_t mask;
++
++      if (is_fam15h())
++              mask = 0xff;
++      else
++              mask = 0x7f;
++
++      /* Lanes 0 - 3 */
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8));
++      delay[3] = (dword >> 24) & mask;
++      delay[2] = (dword >> 16) & mask;
++      delay[1] = (dword >> 8) & mask;
++      delay[0] = dword & mask;
++
++      /* Lanes 4 - 7 */
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8));
++      delay[7] = (dword >> 24) & mask;
++      delay[6] = (dword >> 16) & mask;
++      delay[5] = (dword >> 8) & mask;
++      delay[4] = dword & mask;
++
++      /* Lane 8 (ECC) */
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8));
++      delay[8] = dword & mask;
++}
++
++static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+ {
+       uint32_t dword;
++      uint32_t mask;
++
++      if (is_fam15h())
++              mask = 0xff;
++      else
++              mask = 0x7f;
+ 
+       /* Lanes 0 - 3 */
+-      dword = Get_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8));
+-      dword &= ~0x7f7f7f7f;
+-      dword |= (delay[3] & 0x7f) << 24;
+-      dword |= (delay[2] & 0x7f) << 16;
+-      dword |= (delay[1] & 0x7f) << 8;
+-      dword |= delay[0] & 0x7f;
+-      Set_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8), dword);
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8));
++      dword &= ~(mask << 24);
++      dword &= ~(mask << 16);
++      dword &= ~(mask << 8);
++      dword &= ~mask;
++      dword |= (delay[3] & mask) << 24;
++      dword |= (delay[2] & mask) << 16;
++      dword |= (delay[1] & mask) << 8;
++      dword |= delay[0] & mask;
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x1 | (dimm << 8), dword);
+ 
+       /* Lanes 4 - 7 */
+-      dword = Get_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8));
+-      dword &= ~0x7f7f7f7f;
+-      dword |= (delay[7] & 0x7f) << 24;
+-      dword |= (delay[6] & 0x7f) << 16;
+-      dword |= (delay[5] & 0x7f) << 8;
+-      dword |= delay[4] & 0x7f;
+-      Set_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8), dword);
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8));
++      dword &= ~(mask << 24);
++      dword &= ~(mask << 16);
++      dword &= ~(mask << 8);
++      dword &= ~mask;
++      dword |= (delay[7] & mask) << 24;
++      dword |= (delay[6] & mask) << 16;
++      dword |= (delay[5] & mask) << 8;
++      dword |= delay[4] & mask;
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x2 | (dimm << 8), dword);
+ 
+       /* Lane 8 (ECC) */
+-      dword = Get_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8));
+-      dword &= ~0x0000007f;
+-      dword |= delay[8] & 0x7f;
+-      Set_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8), dword);
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8));
++      dword &= ~mask;
++      dword |= delay[8] & mask;
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x3 | (dimm << 8), dword);
+ }
+ 
+-static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dimm, uint32_t index_reg)
++static void read_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
+ {
+       uint32_t dword;
++      uint32_t mask;
++
++      if (is_fam15h())
++              mask = 0x3e;
++      else
++              mask = 0x3f;
+ 
+       /* Lanes 0 - 3 */
+-      dword = Get_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8));
+-      dword &= ~0x3f3f3f3f;
+-      dword |= (delay[3] & 0x3f) << 24;
+-      dword |= (delay[2] & 0x3f) << 16;
+-      dword |= (delay[1] & 0x3f) << 8;
+-      dword |= delay[0] & 0x3f;
+-      Set_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8), dword);
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
++      delay[3] = (dword >> 24) & mask;
++      delay[2] = (dword >> 16) & mask;
++      delay[1] = (dword >> 8) & mask;
++      delay[0] = dword & mask;
+ 
+       /* Lanes 4 - 7 */
+-      dword = Get_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8));
+-      dword &= ~0x3f3f3f3f;
+-      dword |= (delay[7] & 0x3f) << 24;
+-      dword |= (delay[6] & 0x3f) << 16;
+-      dword |= (delay[5] & 0x3f) << 8;
+-      dword |= delay[4] & 0x3f;
+-      Set_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8), dword);
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
++      delay[7] = (dword >> 24) & mask;
++      delay[6] = (dword >> 16) & mask;
++      delay[5] = (dword >> 8) & mask;
++      delay[4] = dword & mask;
+ 
+       /* Lane 8 (ECC) */
+-      dword = Get_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8));
+-      dword &= ~0x0000003f;
+-      dword |= delay[8] & 0x3f;
+-      Set_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8), dword);
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
++      delay[8] = dword & mask;
++}
++
++static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t 
dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
++{
++      uint32_t dword;
++      uint32_t mask;
++
++      if (is_fam15h())
++              mask = 0x3e;
++      else
++              mask = 0x3f;
++
++      /* Lanes 0 - 3 */
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
++      dword &= ~(mask << 24);
++      dword &= ~(mask << 16);
++      dword &= ~(mask << 8);
++      dword &= ~mask;
++      dword |= (delay[3] & mask) << 24;
++      dword |= (delay[2] & mask) << 16;
++      dword |= (delay[1] & mask) << 8;
++      dword |= delay[0] & mask;
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8), dword);
++
++      /* Lanes 4 - 7 */
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
++      dword &= ~(mask << 24);
++      dword &= ~(mask << 16);
++      dword &= ~(mask << 8);
++      dword &= ~mask;
++      dword |= (delay[7] & mask) << 24;
++      dword |= (delay[6] & mask) << 16;
++      dword |= (delay[5] & mask) << 8;
++      dword |= delay[4] & mask;
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8), dword);
++
++      /* Lane 8 (ECC) */
++      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
++      dword &= ~mask;
++      dword |= delay[8] & mask;
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8), dword);
+ }
+ 
+ /* DQS Position Training
+  * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.3
+  */
+-static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat,
++static void TrainDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+ {
+       u32 Errors;
+@@ -406,7 +497,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+               if (pDCTstat->DIMMValidDCT[Channel] == 0)       /* 
mct_BeforeTrainDQSRdWrPos_D */
+                       continue;
+ 
+-              index_reg = 0x98 + 0x100 * Channel;
++              index_reg = 0x98;
+ 
+               dual_rank = 0;
+               Receiver = mct_InitReceiver_D(pDCTstat, Channel);
+@@ -462,7 +553,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+                                       break;
+ 
+                               /* Commit the current Write Data Timing 
settings to the hardware registers */
+-                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
++                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
+ 
+                               /* Write the DRAM training pattern to the base 
test address */
+                               WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
+@@ -479,7 +570,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+                                                       
current_read_dqs_delay[lane] = test_read_dqs_delay;
+ 
+                                       /* Commit the current Read DQS Timing 
Control settings to the hardware registers */
+-                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
++                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
+ 
+                                       /* Initialize test result variable */
+                                       bytelane_test_results = 0xff;
+@@ -545,7 +636,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+                                               passing_dqs_delay_found[lane] = 
1;
+ 
+                                               /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
+-                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
++                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
+ 
+                                               /* Exit the DRAM Write Data 
Timing Loop */
+                                               
write_dqs_delay_stepping_done[lane] = 1;
+@@ -579,7 +670,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+                                       current_write_dqs_delay[lane] = 
test_write_dqs_delay;
+ 
+                               /* Commit the current Write Data Timing 
settings to the hardware registers */
+-                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
++                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
+ 
+                               /* Write the DRAM training pattern to the base 
test address */
+                               WriteDQSTestPattern_D(pMCTstat, pDCTstat, 
TestAddr << 8);
+@@ -674,7 +765,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+                                               current_read_dqs_delay[lane] = 
(best_pos + (best_count / 2));
+ 
+                                               /* Commit the current Read DQS 
Timing Control settings to the hardware registers */
+-                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 
1), index_reg);
++                                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
+ 
+                                               /* Save the final Read DQS 
Timing Control settings for later use */
+                                               
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_READDIR][lane] = 
current_read_dqs_delay[lane];
+@@ -717,7 +808,7 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+                                               current_write_dqs_delay[lane] = 
(best_pos + (best_count / 2));
+ 
+                                               /* Commit the current Write 
Data Timing settings to the hardware registers */
+-                                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver 
>> 1), index_reg);
++                                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, Channel, 
(Receiver >> 1), index_reg);
+ 
+                                               /* Save the final Write Data 
Timing settings for later use */
+                                               
pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_WRITEDIR][lane] = 
current_write_dqs_delay[lane];
+@@ -787,6 +878,831 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc 
*pMCTstat,
+       printk(BIOS_DEBUG, "TrainDQSRdWrPos: Done\n\n");
+ }
+ 
++/* Calcuate and set MaxRdLatency
++ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.5
++ */
++static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct)
++{
++      uint8_t dimm;
++      uint8_t lane;
++      uint32_t dword;
++      uint32_t dword2;
++      uint32_t max_delay;
++      uint8_t mem_clk = 0;
++      uint8_t nb_pstate;
++      uint32_t nb_clk;
++      uint32_t p = 0;
++      uint32_t n = 0;
++      uint32_t t = 0;
++      uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
++      uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
++
++      uint32_t index_reg = 0x98;
++      uint32_t dev = pDCTstat->dev_dct;
++      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
++
++      /* P is specified in PhyCLKs (1/2 MEMCLKs) */
++      for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
++              /* 2.10.5.8.5 (2) */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000004);
++              if ((!(dword & (0x1 << 21))) && (!(dword & (0x1 << 13))) && 
(!(dword & (0x1 << 5))))
++                      p += 1;
++              else
++                      p += 2;
++
++              /* 2.10.5.8.5 (3) */
++              dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210) & 
0xf;        /* Retrieve RdPtrInit */
++              p += (9 - dword);
++
++              /* 2.10.5.8.5 (4) */
++              p += 5;
++
++              /* 2.10.5.8.5 (5) */
++              dword = Get_NB32_DCT(dev, dct, 0xa8);
++              dword2 = Get_NB32_DCT(dev, dct, 0x90);
++              if ((!(dword & (0x1 << 5))) && (!(dword2 & (0x1 << 16))))
++                      p += 2;
++
++              /* 2.10.5.8.5 (6) */
++              dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;   /* Retrieve Tcl 
*/
++              p += (2 * (dword - 1));
++
++              /* 2.10.5.8.5 (7) */
++              max_delay = 0;
++              for (dimm = 0; dimm < 4; dimm++) {
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
dimm * 2))
++                              continue;
++
++                      
read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
++                      
read_read_dqs_timing_control_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
++                      for (lane = 0; lane < MAX_BYTE_LANES; lane++)
++                              if ((current_phy_phase_delay[lane] + 
current_read_dqs_delay[lane]) > max_delay)
++                                      max_delay = 
(current_phy_phase_delay[lane] + current_read_dqs_delay[lane]);
++              }
++              p += (max_delay >> 5);
++
++              /* 2.10.5.8.5 (8) */
++              p += 5;
++
++              /* 2.10.5.8.5 (9) */
++              t += 800;
++
++              /* 2.10.5.8.5 (10) */
++              mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
++              dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 
4)));               /* Retrieve NbDid, NbFid */
++              nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) 
& 0x1)?2:1);
++              n = (((((uint64_t)p * 
1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + 
((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
++
++              /* 2.10.5.8.5 (11) */
++              n -= 1;
++
++              /* 2.10.5.8.5 (12) */
++              dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210);
++              dword &= ~(0x3ff << 22);
++              dword |= (((n - 1) & 0x3ff) << 22);
++              Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
++
++              /* Save result for later use */
++              pDCTstat->CH_MaxRdLat[dct] = n;
++      }
++}
++
++static void start_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver)
++{
++      uint32_t dword;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      /* 2.10.5.7.1.1
++       * It appears that the DCT only supports 8-beat burst length mode,
++       * so do nothing here...
++       */
++
++      /* Wait for CmdSendInProg == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x250);
++      } while (dword & (0x1 << 12));
++
++      /* Set CmdTestEnable = 1 */
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword |= (0x1 << 2);
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      /* 2.10.5.8.6.1.1 Send Activate Command (Target A) */
++      dword = Get_NB32_DCT(dev, dct, 0x28c);
++      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
++      dword |= ((0x1 << Receiver) << 22);
++      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
++      dword &= ~(0x3ffff);                            /* CmdAddress = 0 */
++      dword |= (0x1 << 31);                           /* SendActCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x28c, dword);
++
++      /* Wait for SendActCmd == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x28c);
++      } while (dword & (0x1 << 31));
++
++      /* Wait 75 MEMCLKs. */
++      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
++
++      /* 2.10.5.8.6.1.1 Send Activate Command (Target B) */
++      dword = Get_NB32_DCT(dev, dct, 0x28c);
++      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
++      dword |= ((0x1 << Receiver) << 22);
++      dword &= ~(0x7 << 19);                          /* CmdBank = 1 */
++      dword |= (0x1 << 19);
++      dword &= ~(0x3ffff);                            /* CmdAddress = 0 */
++      dword |= (0x1 << 31);                           /* SendActCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x28c, dword);
++
++      /* Wait for SendActCmd == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x28c);
++      } while (dword & (0x1 << 31));
++
++      /* Wait 75 MEMCLKs. */
++      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
++}
++
++static void stop_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver)
++{
++      uint32_t dword;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      /* 2.10.5.8.6.1.1 Send Precharge Command */
++      /* Wait 25 MEMCLKs. */
++      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
++
++      dword = Get_NB32_DCT(dev, dct, 0x28c);
++      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
++      dword |= ((0x1 << Receiver) << 22);
++      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
++      dword &= ~(0x3ffff);                            /* CmdAddress = 0x400 */
++      dword |= 0x400;
++      dword |= (0x1 << 30);                           /* SendPchgCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x28c, dword);
++
++      /* Wait for SendPchgCmd == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x28c);
++      } while (dword & (0x1 << 30));
++
++      /* Wait 25 MEMCLKs. */
++      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
++
++      /* Set CmdTestEnable = 0 */
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword &= ~(0x1 << 2);
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++}
++
++static void read_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
++{
++      uint32_t dword;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      start_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, 
Receiver);
++
++      /* 2.10.5.8.6.1.2 */
++      /* Configure DQMask */
++      if (lane < 4) {
++              Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
++              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++      } else if (lane < 8) {
++              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
++              Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
++      } else {
++              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
++              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++      }
++
++      dword = Get_NB32_DCT(dev, dct, 0x27c);
++      dword &= ~(0xff);                               /* EccMask = 0 */
++      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
++              dword |= 0xff;                          /* EccMask = 0xff */
++      Set_NB32_DCT(dev, dct, 0x27c, dword);
++
++      dword = Get_NB32_DCT(dev, dct, 0x270);
++      dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
++//    dword |= (0x55555);
++      dword |= (0x44443);                             /* Use AGESA seed */
++      Set_NB32_DCT(dev, dct, 0x270, dword);
++
++      /* 2.10.5.8.4 */
++      dword = Get_NB32_DCT(dev, dct, 0x260);
++      dword &= ~(0x1fffff);                           /* CmdCount = 256 */
++      dword |= 256;
++      Set_NB32_DCT(dev, dct, 0x260, dword);
++
++      /* Configure Target A */
++      dword = Get_NB32_DCT(dev, dct, 0x254);
++      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
++      dword |= (Receiver & 0x7) << 24;
++      dword &= ~(0x7 << 21);                          /* TgtBank = 0 */
++      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
++      Set_NB32_DCT(dev, dct, 0x254, dword);
++
++      /* Configure Target B */
++      dword = Get_NB32_DCT(dev, dct, 0x258);
++      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
++      dword |= (Receiver & 0x7) << 24;
++      dword &= ~(0x7 << 21);                          /* TgtBank = 1 */
++      dword |= (0x1 << 21);
++      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
++      Set_NB32_DCT(dev, dct, 0x258, dword);
++
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
++      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
++      dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
++      dword |= (0x1 << 8);
++      dword &= ~(0x7 << 5);                           /* CmdType = 0 (Read) */
++      dword |= (0x1 << 11);                           /* SendCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x250);
++      } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
++
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword &= ~(0x1 << 11);                          /* SendCmd = 0 */
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      stop_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
++}
++
++static void write_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
++{
++      uint32_t dword;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      start_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, 
Receiver);
++
++      /* 2.10.5.8.6.1.2 */
++      /* Configure DQMask */
++      if (lane < 4) {
++              Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
++              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++      } else if (lane < 8) {
++              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
++              Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
++      } else {
++              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
++              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++      }
++
++      dword = Get_NB32_DCT(dev, dct, 0x27c);
++      dword &= ~(0xff);                               /* EccMask = 0 */
++      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
++              dword |= 0xff;                          /* EccMask = 0xff */
++      Set_NB32_DCT(dev, dct, 0x27c, dword);
++
++      dword = Get_NB32_DCT(dev, dct, 0x270);
++      dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
++//    dword |= (0x55555);
++      dword |= (0x44443);                             /* Use AGESA seed */
++      Set_NB32_DCT(dev, dct, 0x270, dword);
++
++      /* 2.10.5.8.4 */
++      dword = Get_NB32_DCT(dev, dct, 0x260);
++      dword &= ~(0x1fffff);                           /* CmdCount = 256 */
++      dword |= 256;
++      Set_NB32_DCT(dev, dct, 0x260, dword);
++
++      /* Configure Target A */
++      dword = Get_NB32_DCT(dev, dct, 0x254);
++      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
++      dword |= (Receiver & 0x7) << 24;
++      dword &= ~(0x7 << 21);                          /* TgtBank = 0 */
++      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
++      Set_NB32_DCT(dev, dct, 0x254, dword);
++
++      /* Configure Target B */
++      dword = Get_NB32_DCT(dev, dct, 0x258);
++      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
++      dword |= (Receiver & 0x7) << 24;
++      dword &= ~(0x7 << 21);                          /* TgtBank = 1 */
++      dword |= (0x1 << 21);
++      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
++      Set_NB32_DCT(dev, dct, 0x258, dword);
++
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
++      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
++      dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
++      dword |= (0x1 << 8);
++      dword &= ~(0x7 << 5);                           /* CmdType = 1 (Write) 
*/
++      dword |= (0x1 << 5);
++      dword |= (0x1 << 11);                           /* SendCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x250);
++      } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
++
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword &= ~(0x1 << 11);                          /* SendCmd = 0 */
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      stop_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver);
++}
++
++/* DQS Position Training
++ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.4
++ */
++static uint8_t TrainDQSRdWrPos_D_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t receiver_start, uint8_t receiver_end, uint8_t lane_start, uint8_t 
lane_end)
++{
++      uint8_t dimm;
++      uint8_t lane;
++      uint32_t dword;
++      uint32_t Errors;
++      uint8_t Receiver;
++      uint8_t dual_rank;
++      uint8_t write_iter;
++      uint8_t read_iter;
++      uint16_t initial_write_dqs_delay[MAX_BYTE_LANES];
++      uint16_t initial_read_dqs_delay[MAX_BYTE_LANES];
++      uint16_t initial_write_data_timing[MAX_BYTE_LANES];
++      uint16_t current_write_data_delay[MAX_BYTE_LANES];
++      uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
++      uint16_t current_write_dqs_delay[MAX_BYTE_LANES];
++      uint8_t passing_dqs_delay_found[MAX_BYTE_LANES];
++      uint8_t dqs_results_array[2][(lane_end - lane_start)][32][32];          
/* [rank][lane][write step][read step] */
++
++      uint8_t last_pos = 0;
++      uint8_t cur_count = 0;
++      uint8_t best_pos = 0;
++      uint8_t best_count = 0;
++
++      uint32_t index_reg = 0x98;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      /* Calculate and program MaxRdLatency */
++      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct);
++
++      Errors = 0;
++      dual_rank = 0;
++      Receiver = mct_InitReceiver_D(pDCTstat, dct);
++      if (receiver_start > Receiver)
++              Receiver = receiver_start;
++
++      /* There are four receiver pairs, loosely associated with chipselects.
++       * This is essentially looping over each DIMM.
++       */
++      for (; Receiver < receiver_end; Receiver += 2) {
++              dimm = (Receiver >> 1);
++              if ((Receiver & 0x1) == 0) {
++                      /* Even rank of DIMM */
++                      if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
Receiver+1))
++                              dual_rank = 1;
++                      else
++                              dual_rank = 0;
++              }
++
++              if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver)) {
++                      continue;
++              }
++
++              /* Initialize variables */
++              for (lane = lane_start; lane < lane_end; lane++) {
++                      passing_dqs_delay_found[lane] = 0;
++              }
++              memset(dqs_results_array, 0, sizeof(dqs_results_array));
++
++              /* Read initial read / write DQS delays */
++              
read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, 
dimm, index_reg);
++              read_dqs_read_data_timing_registers(initial_read_dqs_delay, 
dev, dct, dimm, index_reg);
++
++              /* Read current settings of other (previously trained) lanes */
++              read_dqs_write_data_timing_registers(initial_write_data_timing, 
dev, dct, dimm, index_reg);
++              memcpy(current_write_data_delay, initial_write_data_timing, 
sizeof(current_write_data_delay));
++
++              for (lane = lane_start; lane < lane_end; lane++) {
++                      /* 2.10.5.8.4 (2)
++                       * For each Write Data Delay value from Write DQS Delay 
to Write DQS Delay + 1 UI
++                       */
++                      for (current_write_data_delay[lane] = 
initial_write_dqs_delay[lane]; current_write_data_delay[lane] < 
(initial_write_dqs_delay[lane] + 0x20); current_write_data_delay[lane]++) {
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 16 
current_write_data_delay[lane] ", current_write_data_delay[lane], 6);
++
++                              /* 2.10.5.8.4 (2 A)
++                               * Commit the current Write Data Timing 
settings to the hardware registers
++                               */
++                              
write_dqs_write_data_timing_registers(current_write_data_delay, dev, dct, dimm, 
index_reg);
++
++                              /* 2.10.5.8.4 (2 B)
++                               * Write the DRAM training pattern to the test 
address
++                               */
++                              write_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, dct, Receiver, lane);
++
++                              /* Read current settings of other (previously 
trained) lanes */
++                              
read_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
++
++                              /* 2.10.5.8.4 (2 C)
++                               * For each Read DQS Delay value from 0 to 1 UI
++                               */
++                              for (current_read_dqs_delay[lane] = 0; 
current_read_dqs_delay[lane] < 0x40; current_read_dqs_delay[lane] += 2) {
++                                      
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 current_read_dqs_delay[lane] ", 
current_read_dqs_delay[lane], 6);
++
++                                      /* 2.10.5.8.4 (2 A i)
++                                       * Commit the current Read DQS Timing 
Control settings to the hardware registers
++                                       */
++                                      
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
++
++                                      /* 2.10.5.8.4 (2 A ii)
++                                       * Read the DRAM training pattern from 
the test address
++                                       */
++                                      
read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane);
++
++                                      /* 2.10.5.8.4 (2 A iii)
++                                       * Record pass / fail status
++                                       */
++                                      dword = Get_NB32_DCT(dev, dct, 0x268) & 
0x3ffff;
++                                      if (dword & (0x3 << (lane * 2)))
++                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 0;    /* 
Fail */
++                                      else
++                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 1;    /* 
Pass */
++                              }
++                      }
++
++                      if (dual_rank && (Receiver & 0x1)) {
++                              /* Overlay the previous rank test results with 
the current rank */
++                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
++                                      for (read_iter = 0; read_iter < 32; 
read_iter++) {
++                                              if ((dqs_results_array[0][lane 
- lane_start][write_iter][read_iter])
++                                                      && 
(dqs_results_array[1][lane - lane_start][write_iter][read_iter]))
++                                                      
dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 1;
++                                              else
++                                                      
dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 0;
++                                      }
++                              }
++                      }
++
++                      /* Determine location and length of longest consecutive 
string of read passing values
++                       * Output is stored in best_pos and best_count
++                       */
++                      last_pos = 0;
++                      cur_count = 0;
++                      best_pos = 0;
++                      best_count = 0;
++                      for (write_iter = 0; write_iter < 32; write_iter++) {
++                              for (read_iter = 0; read_iter < 32; 
read_iter++) {
++                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 31)) {
++                                              /* Pass */
++                                              cur_count++;
++                                      } else {
++                                              /* Failure or end of loop */
++                                              if (cur_count > best_count) {
++                                                      best_count = cur_count;
++                                                      best_pos = last_pos;
++                                              }
++                                              cur_count = 0;
++                                              last_pos = read_iter;
++                                      }
++                              }
++                              last_pos = 0;
++                      }
++
++                      if (best_count > 2) {
++                              /* Restore current settings of other 
(previously trained) lanes to the active array */
++                              memcpy(current_read_dqs_delay, 
initial_read_dqs_delay, sizeof(current_read_dqs_delay));
++
++                              /* Program the Read DQS Timing Control register 
with the center of the passing window */
++                              current_read_dqs_delay[lane] = ((best_pos << 1) 
+ ((best_count << 1) / 2));
++                              passing_dqs_delay_found[lane] = 1;
++
++                              /* Commit the current Read DQS Timing Control 
settings to the hardware registers */
++                              
write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
++
++                              /* Save the final Read DQS Timing Control 
settings for later use */
++                              pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 
1][DQS_READDIR][lane] = current_read_dqs_delay[lane];
++
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 
largest read passing region ", best_count, 4);
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 
largest read passing region start ", best_pos, 4);
++                      } else {
++                              /* Reprogram the Read DQS Timing Control 
register with the original settings */
++                              
write_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, 
index_reg);
++                      }
++
++                      /* Determine location and length of longest consecutive 
string of write passing values
++                       * Output is stored in best_pos and best_count
++                       */
++                      last_pos = 0;
++                      cur_count = 0;
++                      best_pos = 0;
++                      best_count = 0;
++                      for (read_iter = 0; read_iter < 32; read_iter++) {
++                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
++                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (write_iter < 31)) {
++                                              /* Pass */
++                                              cur_count++;
++                                      } else {
++                                              /* Failure or end of loop */
++                                              if (cur_count > best_count) {
++                                                      best_count = cur_count;
++                                                      best_pos = last_pos;
++                                              }
++                                              cur_count = 0;
++                                              last_pos = write_iter;
++                                      }
++                              }
++                              last_pos = 0;
++                      }
++
++                      if (best_count > 2) {
++                              /* Restore current settings of other 
(previously trained) lanes to the active array */
++                              memcpy(current_write_dqs_delay, 
initial_write_data_timing, sizeof(current_write_data_delay));
++
++                              /* Program the Write DQS Timing Control 
register with the optimal region within the passing window */
++                              if (pDCTstat->Status & (1 << SB_LoadReduced))
++                                      current_write_dqs_delay[lane] = 
((best_pos + initial_write_dqs_delay[lane]) + (best_count / 3));
++                              else
++                                      current_write_dqs_delay[lane] = 
((best_pos + initial_write_dqs_delay[lane]) + (best_count / 2));
++                              passing_dqs_delay_found[lane] = 1;
++
++                              /* Commit the current Write DQS Timing Control 
settings to the hardware registers */
++                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, 
index_reg);
++
++                              /* Save the final Write Data Timing settings 
for later use */
++                              pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 
1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane];
++
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 
largest write passing region ", best_count, 4);
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 
largest write passing region start ", best_pos, 4);
++                      } else {
++                              /* Reprogram the Write DQS Timing Control 
register with the original settings */
++                              
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, 
index_reg);
++                      }
++              }
++
++#ifdef PRINT_PASS_FAIL_BITMAPS
++              for (lane = lane_start; lane < lane_end; lane++) {
++                      for (read_iter = 0; read_iter < 32; read_iter++) {
++                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
++                                      if (dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter])
++                                              printk(BIOS_DEBUG, "+");
++                                      else
++                                              printk(BIOS_DEBUG, ".");
++                              }
++                              printk(BIOS_DEBUG, "\n");
++                      }
++                      printk(BIOS_DEBUG, "\n\n");
++              }
++#endif
++
++              /* Flag failure(s) if present */
++              for (lane = lane_start; lane < lane_end; lane++) {
++                      if (!passing_dqs_delay_found[lane]) {
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 121 
Unable to find passing region for lane ", lane, 2);
++
++                              /* Flag absence of passing window */
++                              Errors |= 1 << SB_NODQSPOS;
++                      }
++              }
++
++              pDCTstat->TrainErrors |= Errors;
++              pDCTstat->ErrStatus |= Errors;
++
++#if DQS_TRAIN_DEBUG > 0
++              {
++                      u8 val;
++                      u8 i;
++                      u8 ChannelDTD, ReceiverDTD, Dir;
++                      u8 *p;
++
++                      for (Dir = 0; Dir < 2; Dir++) {
++                              if (Dir == 1) {
++                                      printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS WR:\n");
++                              } else {
++                                      printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS RD:\n");
++                              }
++                              for (ChannelDTD = 0; ChannelDTD < 2; 
ChannelDTD++) {
++                                      printk(BIOS_DEBUG, "Channel: %02x\n", 
ChannelDTD);
++                                      for (ReceiverDTD = 0; ReceiverDTD < 
MAX_CS_SUPPORTED; ReceiverDTD += 2) {
++                                              printk(BIOS_DEBUG, 
"\t\tReceiver: %02x:", ReceiverDTD);
++                                              p = 
pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
++                                              for (i=0;i<8; i++) {
++                                                      val  = p[i];
++                                                      printk(BIOS_DEBUG, " 
%02x", val);
++                                              }
++                                              printk(BIOS_DEBUG, "\n");
++                                      }
++                              }
++                      }
++
++              }
++#endif
++      }
++
++      /* Return 1 on success, 0 on failure */
++      return !Errors;
++}
++
++/* DQS Receiver Enable Cycle Training
++ * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.3
++ */
++static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      u32 Errors;
++      u8 Receiver;
++      u8 _DisableDramECC = 0;
++      u8 _Wrap32Dis = 0, _SSE2 = 0;
++
++      u32 addr;
++      u32 cr4;
++      u32 lo, hi;
++
++      uint8_t dct;
++      uint8_t prev;
++      uint8_t dimm;
++      uint8_t lane;
++      uint32_t dword;
++      uint32_t rx_en_offset;
++      uint16_t initial_phy_phase_delay[MAX_BYTE_LANES];
++      uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
++      uint8_t dqs_results_array[1024];
++
++      uint16_t ren_step = 0x40;
++      uint32_t index_reg = 0x98;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      print_debug_dqs("\nTrainDQSReceiverEnCyc: Node_ID ", pDCTstat->Node_ID, 
0);
++      cr4 = read_cr4();
++      if (cr4 & (1<<9)) {
++              _SSE2 = 1;
++      }
++      cr4 |= (1<<9);          /* OSFXSR enable SSE2 */
++      write_cr4(cr4);
++
++      addr = HWCR;
++      _RDMSR(addr, &lo, &hi);
++      if (lo & (1<<17)) {
++              _Wrap32Dis = 1;
++      }
++      lo |= (1<<17);          /* HWCR.wrap32dis */
++      _WRMSR(addr, lo, hi);   /* allow 64-bit memory references in real mode 
*/
++
++      /* Disable ECC correction of reads on the dram bus. */
++      _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
++
++      Errors = 0;
++
++      for (dct = 0; dct < 2; dct++) {
++              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
++              dword &= ~(0x3 << 13);
++              dword |= (0x1 << 13);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
++      }
++
++      for (dct = 0; dct < 2; dct++) {
++              /* 2.10.5.6 */
++              fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 1);
++
++              /* 2.10.5.8.3 */
++              Receiver = mct_InitReceiver_D(pDCTstat, dct);
++
++              /* There are four receiver pairs, loosely associated with 
chipselects.
++               * This is essentially looping over each DIMM.
++               */
++              for (; Receiver < 8; Receiver += 2) {
++                      dimm = (Receiver >> 1);
++
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
Receiver)) {
++                              continue;
++                      }
++
++                      /* 2.10.5.8.3 (2) */
++                      
read_dqs_receiver_enable_control_registers(initial_phy_phase_delay, dev, dct, 
dimm, index_reg);
++
++                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                              /* Initialize variables */
++                              memset(dqs_results_array, 0, 
sizeof(dqs_results_array));
++
++                              /* 2.10.5.8.3 (1) */
++                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0030 | (lane << 8));
++                              dword |= (0x1 << 8);                            
                                /* BlockRxDqsLock = 1 */
++                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0030 | (lane << 8), dword);
++
++                              /* 2.10.5.8.3 (3) */
++                              rx_en_offset = (initial_phy_phase_delay[lane] + 
0x10) % 0x40;
++
++                              /* 2.10.5.8.3 (4) */
++                              for (current_phy_phase_delay[lane] = 
rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; 
current_phy_phase_delay[lane] += ren_step) {
++                                      /* 2.10.5.8.3 (4 A) */
++                                      
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
++
++                                      /* Calculate and program MaxRdLatency */
++                                      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, 
pDCTstat, dct);
++
++                                      /* 2.10.5.8.3 (4 B) */
++                                      
dqs_results_array[current_phy_phase_delay[lane]] = 
TrainDQSRdWrPos_D_Fam15(pMCTstat, pDCTstat, dct, Receiver, Receiver + 2, lane, 
lane + 1);
++                              }
++
++#ifdef PRINT_PASS_FAIL_BITMAPS
++                              uint16_t iter;
++                              for (iter = 0; iter < 0x3ff; iter++) {
++                                      if (dqs_results_array[iter])
++                                              printk(BIOS_DEBUG, "+");
++                                      else
++                                              printk(BIOS_DEBUG, ".");
++                              }
++                              printk(BIOS_DEBUG, "\n");
++#endif
++
++                              /* 2.10.5.8.3 (5) */
++                              prev = 0;
++                              for (current_phy_phase_delay[lane] = 
rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; 
current_phy_phase_delay[lane] += ren_step) {
++                                      if 
((dqs_results_array[current_phy_phase_delay[lane]] == 0) && (prev == 1)) {
++                                              /* Restore last known good 
delay */
++                                              current_phy_phase_delay[lane] 
-= ren_step;
++
++                                              /* 2.10.5.8.3 (5 A B) */
++                                              current_phy_phase_delay[lane] 
-= 0x10;
++
++                                              /* Update hardware registers 
with final values */
++                                              
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
++                                              break;
++                                      }
++                                      prev = 
dqs_results_array[current_phy_phase_delay[lane]];
++                              }
++
++                              /* 2.10.5.8.3 (6) */
++                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0030 | (lane << 8));
++                              dword &= ~(0x1 << 8);                           
                                /* BlockRxDqsLock = 0 */
++                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0030 | (lane << 8), dword);
++                      }
++
++#if DQS_TRAIN_DEBUG > 0
++                      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc_D_Fam15 DQS 
receiver enable timing: ");
++                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                              printk(BIOS_DEBUG, " %03x", 
current_phy_phase_delay[lane]);
++                      }
++                      printk(BIOS_DEBUG, "\n");
++#endif
++              }
++      }
++
++      pDCTstat->TrainErrors |= Errors;
++      pDCTstat->ErrStatus |= Errors;
++
++#if DQS_TRAIN_DEBUG > 0
++      {
++              u8 val;
++              u8 i;
++              u8 ChannelDTD, ReceiverDTD, Dir;
++              u8 *p;
++
++              for (Dir = 0; Dir < 2; Dir++) {
++                      if (Dir == 1) {
++                              printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS WR:\n");
++                      } else {
++                              printk(BIOS_DEBUG, "TrainDQSRdWrPos: 
CH_D_DIR_B_DQS RD:\n");
++                      }
++                      for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
++                              printk(BIOS_DEBUG, "Channel: %02x\n", 
ChannelDTD);
++                              for (ReceiverDTD = 0; ReceiverDTD < 
MAX_CS_SUPPORTED; ReceiverDTD += 2) {
++                                      printk(BIOS_DEBUG, "\t\tReceiver: 
%02x:", ReceiverDTD);
++                                      p = 
pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir];
++                                      for (i=0;i<8; i++) {
++                                              val  = p[i];
++                                              printk(BIOS_DEBUG, " %02x", 
val);
++                                      }
++                                      printk(BIOS_DEBUG, "\n");
++                              }
++                      }
++              }
++
++      }
++#endif
++      if (_DisableDramECC) {
++              mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
++      }
++      if (!_Wrap32Dis) {
++              addr = HWCR;
++              _RDMSR(addr, &lo, &hi);
++              lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
++              _WRMSR(addr, lo, hi);
++      }
++      if (!_SSE2){
++              cr4 = read_cr4();
++              cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
++              write_cr4(cr4);
++      }
++
++      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: Status %x\n", 
pDCTstat->Status);
++      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: TrainErrors %x\n", 
pDCTstat->TrainErrors);
++      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: ErrStatus %x\n", 
pDCTstat->ErrStatus);
++      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: ErrCode %x\n", 
pDCTstat->ErrCode);
++      printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc: Done\n\n");
++}
++
+ static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u32 *buffer)
+ {
+@@ -869,18 +1785,17 @@ static u8 ChipSelPresent_D(struct MCTStatStruc 
*pMCTstat,
+       u32 val;
+       u32 reg;
+       u32 dev = pDCTstat->dev_dct;
+-      u32 reg_off;
++      uint8_t dct = 0;
+       u8 ret = 0;
+ 
+-      if (!pDCTstat->GangedMode) {
+-              reg_off = 0x100 * Channel;
+-      } else {
+-              reg_off = 0;
+-      }
++      if (!pDCTstat->GangedMode)
++              dct = Channel;
++      else
++              dct = 0;
+ 
+       if (ChipSel < MAX_CS_SUPPORTED){
+-              reg = 0x40 + (ChipSel << 2) + reg_off;
+-              val = Get_NB32(dev, reg);
++              reg = 0x40 + (ChipSel << 2);
++              val = Get_NB32_DCT(dev, dct, reg);
+               if (val & ( 1 << 0))
+                       ret = 1;
+       }
+@@ -1085,12 +2000,12 @@ u32 SetUpperFSbase(u32 addr_hi)
+       return addr_hi << 8;
+ }
+ 
+-void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index)
++void ResetDCTWrPtr_D(u32 dev, uint8_t dct, u32 index_reg, u32 index)
+ {
+       u32 val;
+ 
+-      val = Get_NB32_index_wait(dev, index_reg, index);
+-      Set_NB32_index_wait(dev, index_reg, index, val);
++      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+ }
+ 
+ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
+@@ -1103,9 +2018,13 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat,
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               if (pDCTstat->DCTSysLimit) {
+-                      TrainDQSRdWrPos_D(pMCTstat, pDCTstat);
+-                      for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel 
+= 2) {
+-                              SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel);
++                      if (is_fam15h()) {
++                              TrainDQSReceiverEnCyc_D_Fam15(pMCTstat, 
pDCTstat);
++                      } else {
++                              TrainDQSRdWrPos_D_Fam10(pMCTstat, pDCTstat);
++                              for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; 
ChipSel += 2) {
++                                      SetEccDQSRdWrPos_D_Fam10(pMCTstat, 
pDCTstat, ChipSel);
++                              }
+                       }
+               }
+       }
+@@ -1126,19 +2045,18 @@ u8 mct_DisableDimmEccEn_D(struct MCTStatStruc 
*pMCTstat,
+ 
+       dev = pDCTstat->dev_dct;
+       reg = 0x90;
+-      val = Get_NB32(dev, reg);
++      val = Get_NB32_DCT(dev, 0, reg);
+       if (val & (1<<DimmEcEn)) {
+               _DisableDramECC |= 0x01;
+               val &= ~(1<<DimmEcEn);
+-              Set_NB32(dev, reg, val);
++              Set_NB32_DCT(dev, 0, reg, val);
+       }
+       if (!pDCTstat->GangedMode) {
+-              reg = 0x190;
+-              val = Get_NB32(dev, reg);
++              val = Get_NB32_DCT(dev, 1, reg);
+               if (val & (1<<DimmEcEn)) {
+                       _DisableDramECC |= 0x02;
+                       val &= ~(1<<DimmEcEn);
+-                      Set_NB32(dev, reg, val);
++                      Set_NB32_DCT(dev, 1, reg, val);
+               }
+       }
+       return _DisableDramECC;
+@@ -1157,15 +2075,14 @@ void mct_EnableDimmEccEn_D(struct MCTStatStruc 
*pMCTstat,
+ 
+       if ((_DisableDramECC & 0x01) == 0x01) {
+               reg = 0x90;
+-              val = Get_NB32(dev, reg);
++              val = Get_NB32_DCT(dev, 0, reg);
+               val |= (1<<DimmEcEn);
+-              Set_NB32(dev, reg, val);
++              Set_NB32_DCT(dev, 0, reg, val);
+       }
+       if ((_DisableDramECC & 0x02) == 0x02) {
+-              reg = 0x190;
+-              val = Get_NB32(dev, reg);
++              val = Get_NB32_DCT(dev, 1, reg);
+               val |= (1<<DimmEcEn);
+-              Set_NB32(dev, reg, val);
++              Set_NB32_DCT(dev, 1, reg, val);
+       }
+ }
+ 
+@@ -1177,7 +2094,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
+ {
+       u8 ByteLane;
+       u32 val;
+-      u32 index_reg = 0x98 + 0x100 * pDCTstat->Channel;
++      u32 index_reg = 0x98;
+       u8 shift;
+       u32 dqs_delay = (u32)pDCTstat->DQSDelay;
+       u32 dev = pDCTstat->dev_dct;
+@@ -1205,7 +2122,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
+ 
+               index += (ChipSel>>1) << 8;
+ 
+-              val = Get_NB32_index_wait(dev, index_reg, index);
++              val = Get_NB32_index_wait_DCT(dev, pDCTstat->Channel, 
index_reg, index);
+               if (ByteLane < 8) {
+                       if (pDCTstat->Direction == DQS_WRITEDIR) {
+                               dqs_delay += 
pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][ChipSel>>1][ByteLane];
+@@ -1215,7 +2132,7 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc 
*pMCTstat,
+               }
+               val &= ~(0x7f << shift);
+               val |= (dqs_delay << shift);
+-              Set_NB32_index_wait(dev, index_reg, index, val);
++              Set_NB32_index_wait_DCT(dev, pDCTstat->Channel, index_reg, 
index, val);
+       }
+ }
+ 
+@@ -1241,7 +2158,7 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
+                               u8 Channel, u8 receiver, u8 *valid)
+ {
+       u32 val;
+-      u32 reg_off = 0;
++      uint8_t dct = 0;
+       u32 reg;
+       u32 dword;
+       u32 dev = pDCTstat->dev_dct;
+@@ -1250,12 +2167,12 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat,
+ 
+ 
+       if (!pDCTstat->GangedMode) {
+-              reg_off = 0x100 * Channel;
++              dct = Channel;
+       }
+ 
+       /* get the local base addr of the chipselect */
+-      reg = 0x40 + (receiver << 2) + reg_off;
+-      val = Get_NB32(dev, reg);
++      reg = 0x40 + (receiver << 2);
++      val = Get_NB32_DCT(dev, dct, reg);
+ 
+       val &= ~0xe007c01f;
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+index 0c52791..11f1b2c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -91,19 +92,21 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+ 
+       /* Construct these booleans, based on setup options, for easy handling
+       later in this procedure */
+-      OB_NBECC = mctGet_NVbits(NV_NBECC);     /* MCA ECC (MCE) enable bit */
++      OB_NBECC = mctGet_NVbits(NV_NBECC);                     /* MCA ECC 
(MCE) enable bit */
+ 
+-      OB_ECCRedir =  mctGet_NVbits(NV_ECCRedir);      /* ECC Redirection */
++      OB_ECCRedir =  mctGet_NVbits(NV_ECCRedir);              /* ECC 
Redirection */
+ 
+-      OB_ChipKill = mctGet_NVbits(NV_ChipKill);       /* ECC Chip-kill mode */
++      OB_ChipKill = mctGet_NVbits(NV_ChipKill);               /* ECC 
Chip-kill mode */
++      OF_ScrubCTL = 0;                                        /* Scrub CTL 
for Dcache, L2, and dram */
+ 
+-      OF_ScrubCTL = 0;                /* Scrub CTL for Dcache, L2, and dram */
+-      nvbits = mctGet_NVbits(NV_DCBKScrub);
+-      /* mct_AdjustScrub_D(pDCTstatA, &nvbits); */ /* Need not adjust */
+-      OF_ScrubCTL |= (u32) nvbits << 16;
++      if (!is_fam15h()) {
++              nvbits = mctGet_NVbits(NV_DCBKScrub);
++              /* mct_AdjustScrub_D(pDCTstatA, &nvbits); */    /* Need not 
adjust */
++              OF_ScrubCTL |= (u32) nvbits << 16;
+ 
+-      nvbits = mctGet_NVbits(NV_L2BKScrub);
+-      OF_ScrubCTL |= (u32) nvbits << 8;
++              nvbits = mctGet_NVbits(NV_L2BKScrub);
++              OF_ScrubCTL |= (u32) nvbits << 8;
++      }
+ 
+       nvbits = mctGet_NVbits(NV_DramBKScrub);
+       OF_ScrubCTL |= nvbits;
+@@ -131,7 +134,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                                                       pDCTstat->ErrStatus |= 
(1 << SB_DramECCDis);
+                                               }
+                                               AllECC = 0;
+-                                              LDramECC =0;
++                                              LDramECC = 0;
+                                       }
+                               } else {
+                                       AllECC = 0;
+@@ -140,7 +143,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                                       if (OB_NBECC) {
+                                               mct_EnableDatIntlv_D(pMCTstat, 
pDCTstat);
+                                               dev = pDCTstat->dev_nbmisc;
+-                                              reg =0x44;      /* MCA NB 
Configuration */
++                                              reg = 0x44;     /* MCA NB 
Configuration */
+                                               val = Get_NB32(dev, reg);
+                                               val |= 1 << 22; /* EccEn */
+                                               Set_NB32(dev, reg, val);
+@@ -177,6 +180,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                       /*WE/RE is checked because memory config may have been 
*/
+                       if((val & 3)==3) {      /* Node has dram populated */
+                               if (isDramECCEn_D(pDCTstat)) {  /* if ECC is 
enabled on this dram */
++                                      if (is_fam15h()) {
++                                              /* Erratum 505 */
++                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);
++                                      }
+                                       dev = pDCTstat->dev_nbmisc;
+                                       val = curBase << 8;
+                                       if(OB_ECCRedir) {
+@@ -187,16 +194,18 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                                       Set_NB32(dev, 0x60, val); /* Dram Scrub 
Addr High */
+                                       Set_NB32(dev, 0x58, OF_ScrubCTL);       
/*Scrub Control */
+ 
+-                                      /* Divisor should not be set deeper than
+-                                       * divide by 16 when Dcache scrubber or
+-                                       * L2 scrubber is enabled.
+-                                       */
+-                                      if ((OF_ScrubCTL & (0x1F << 16)) || 
(OF_ScrubCTL & (0x1F << 8))) {
+-                                              val = Get_NB32(dev, 0x84);
+-                                              if ((val & 0xE0000000) > 
0x80000000) {  /* Get F3x84h[31:29]ClkDivisor for C1 */
+-                                                      val &= 0x1FFFFFFF;      
/* If ClkDivisor is deeper than divide-by-16 */
+-                                                      val |= 0x80000000;      
/* set it to divide-by-16 */
+-                                                      Set_NB32(dev, 0x84, 
val);
++                                      if (!is_fam15h()) {
++                                              /* Divisor should not be set 
deeper than
++                                               * divide by 16 when Dcache 
scrubber or
++                                               * L2 scrubber is enabled.
++                                               */
++                                              if ((OF_ScrubCTL & (0x1F << 
16)) || (OF_ScrubCTL & (0x1F << 8))) {
++                                                      val = Get_NB32(dev, 
0x84);
++                                                      if ((val & 0xE0000000) 
> 0x80000000) {  /* Get F3x84h[31:29]ClkDivisor for C1 */
++                                                              val &= 
0x1FFFFFFF;      /* If ClkDivisor is deeper than divide-by-16 */
++                                                              val |= 
0x80000000;      /* set it to divide-by-16 */
++                                                              Set_NB32(dev, 
0x84, val);
++                                                      }
+                                               }
+                                       }
+                               }       /* this node has ECC enabled dram */
+@@ -267,8 +276,8 @@ static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat)
+       }
+       for(i=0; i<ch_end; i++) {
+               if(pDCTstat->DIMMValidDCT[i] > 0){
+-                      reg = 0x90 + i * 0x100;         /* Dram Config Low */
+-                      val = Get_NB32(dev, reg);
++                      reg = 0x90;             /* Dram Config Low */
++                      val = Get_NB32_DCT(dev, i, reg);
+                       if(val & (1<<DimmEcEn)) {
+                               /* set local flag 'dram ecc capable' */
+                               isDimmECCEn = 1;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
+index 0112732..a6b9dcb 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -25,8 +26,8 @@ void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat,
+       u32 dev = pDCTstat->dev_dct;
+ 
+       /*flag for selecting HW/SW DRAM Init HW DRAM Init */
+-      reg = 0x90 + 0x100 * dct; /*DRAM Configuration Low */
+-      val = Get_NB32(dev, reg);
++      reg = 0x90; /*DRAM Configuration Low */
++      val = Get_NB32_DCT(dev, dct, reg);
+       val |= (1<<InitDram);
+-      Set_NB32(dev, reg, val);
++      Set_NB32_DCT(dev, dct, reg, val);
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+index 60bc01d..5e81808 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+@@ -18,10 +18,12 @@
+  * Foundation, Inc.
+  */
+ 
+-static void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat);
+-static void AgesaHwWlPhase1(sMCTStruct *pMCTData,
+-                                      sDCTStruct *pDCTData, u8 dimm, u8 pass);
++static void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
++static void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
++static void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
++                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
+ static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
+@@ -56,7 +58,7 @@ static void SetEccWrDQS_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pD
+                                       Addl_Index = 0x32;
+                               Addl_Index += DimmNum * 3;
+ 
+-                              val = Get_NB32_index_wait(pDCTstat->dev_dct, 
Channel * 0x100 + 0x98, Addl_Index);
++                              val = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, Channel, 0x98, Addl_Index);
+                               if (OddByte)
+                                       val >>= 16;
+                               /* Save WrDqs to stack for later usage */
+@@ -74,13 +76,13 @@ static void EnableAutoRefresh_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStr
+ {
+       u32 val;
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x8C);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
+       val &= ~(1 << DisAutoRefresh);
+-      Set_NB32(pDCTstat->dev_dct, 0x8C, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
+       val &= ~(1 << DisAutoRefresh);
+-      Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
+ }
+ 
+ static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
+@@ -88,13 +90,13 @@ static void DisableAutoRefresh_D(struct MCTStatStruc 
*pMCTstat,
+ {
+       u32 val;
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x8C);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C);
+       val |= 1 << DisAutoRefresh;
+-      Set_NB32(pDCTstat->dev_dct, 0x8C, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x8C, val);
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C);
+       val |= 1 << DisAutoRefresh;
+-      Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x8C, val);
+ }
+ 
+ 
+@@ -118,8 +120,11 @@ static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
+               DIMMValid = pDCTstat->DIMMValid;
+               PrepareC_DCT(pMCTstat, pDCTstat, dct);
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
+-                      if (DIMMValid & (1 << (dimm << 1)))
+-                              AgesaHwWlPhase1(pDCTstat->C_MCTPtr, DCTPtr, 
dimm, FirstPass);
++                      if (DIMMValid & (1 << (dimm << 1))) {
++                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
++                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
++                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
++                      }
+               }
+       }
+ }
+@@ -146,27 +151,40 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
+               pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = 
pDCTstat->TargetFreq;
+               pDCTstat->CASL = pDCTstat->DIMMCASL = pDCTstat->TargetCASL;
+               SPD2ndTiming(pMCTstat, pDCTstat, dct);
+-              ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
+-              PlatformSpec_D(pMCTstat, pDCTstat, dct);
+-              fenceDynTraining_D(pMCTstat, pDCTstat, dct);
++              if (!is_fam15h()) {
++                      ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
++                      PlatformSpec_D(pMCTstat, pDCTstat, dct);
++                      fenceDynTraining_D(pMCTstat, pDCTstat, dct);
++              }
+               Restore_OnDimmMirror(pMCTstat, pDCTstat);
+               StartupDCT_D(pMCTstat, pDCTstat, dct);
+               Clear_OnDimmMirror(pMCTstat, pDCTstat);
+               SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
+               DisableAutoRefresh_D(pMCTstat, pDCTstat);
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
+-                      if (DIMMValid & (1 << (dimm << 1)))
+-                              AgesaHwWlPhase1(pDCTstat->C_MCTPtr, 
pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
++                      if (DIMMValid & (1 << (dimm << 1))) {
++                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
++                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
++                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
++                      }
+               }
+       }
+ }
+ 
++static uint16_t fam15h_next_highest_memclk_freq(uint16_t memclk_freq)
++{
++      uint16_t fam15h_next_highest_freq_tab[] = {0, 0, 0, 0, 0x6, 0, 0xa, 0, 
0, 0, 0xe, 0, 0, 0, 0x12, 0, 0, 0, 0x16, 0, 0, 0, 0x16};
++      return fam15h_next_highest_freq_tab[memclk_freq];
++}
++
+ /* Write Levelization Training
+  * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
+  */
+ static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat)
++                                      struct DCTStatStruc *pDCTstat, uint8_t 
Pass)
+ {
++      uint16_t final_target_freq;
++
+       pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
+       pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
+       pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
+@@ -182,16 +200,39 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+               pDCTstat->DIMMValidDCT[1] = pDCTstat->DIMMValidDCT[0];
+       }
+ 
+-      PhyWLPass1(pMCTstat, pDCTstat, 0);
+-      PhyWLPass1(pMCTstat, pDCTstat, 1);
++      if (Pass == FirstPass) {
++              PhyWLPass1(pMCTstat, pDCTstat, 0);
++              PhyWLPass1(pMCTstat, pDCTstat, 1);
++      }
++
++      if (Pass == SecondPass) {
++              if (pDCTstat->TargetFreq > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
++                      /* 8.Prepare the memory subsystem for the target MEMCLK 
frequency.
++                       * NOTE: BIOS must program both DCTs to the same 
frequency.
++                       * NOTE: Fam15h steps the frequency, Fam10h slams the 
frequency.
++                       */
++                      final_target_freq = pDCTstat->TargetFreq;
++
++                      while (pDCTstat->Speed != final_target_freq) {
++                              if (is_fam15h())
++                                      pDCTstat->TargetFreq = 
fam15h_next_highest_memclk_freq(pDCTstat->Speed);
++                              else
++                                      pDCTstat->TargetFreq = 
final_target_freq;
++                              SetTargetFreq(pMCTstat, pDCTstat);
++                              PhyWLPass2(pMCTstat, pDCTstat, 0);
++                              PhyWLPass2(pMCTstat, pDCTstat, 1);
++                      }
++
++                      pDCTstat->TargetFreq = final_target_freq;
+ 
+-      if (pDCTstat->TargetFreq > 4) {
+-              /* 8.Prepare the memory subsystem for the target MEMCLK 
frequency.
+-               * Note: BIOS must program both DCTs to the same frequency.
+-               */
+-              SetTargetFreq(pMCTstat, pDCTstat);
+-              PhyWLPass2(pMCTstat, pDCTstat, 0);
+-              PhyWLPass2(pMCTstat, pDCTstat, 1);
++                      uint8_t dct;
++                      for (dct = 0; dct < 2; dct++) {
++                              sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++                              memcpy(pDCTData->WLGrossDelayFinalPass, 
pDCTData->WLGrossDelayPrevPass, sizeof(pDCTData->WLGrossDelayPrevPass));
++                              memcpy(pDCTData->WLFineDelayFinalPass, 
pDCTData->WLFineDelayPrevPass, sizeof(pDCTData->WLFineDelayPrevPass));
++                              pDCTData->WLCriticalGrossDelayFinalPass = 
pDCTData->WLCriticalGrossDelayPrevPass;
++                      }
++              }
+       }
+ 
+       SetEccWrDQS_D(pMCTstat, pDCTstat);
+@@ -200,7 +241,7 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstatA)
++                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Pass)
+ {
+       u8 Node;
+ 
+@@ -211,7 +252,7 @@ void mct_WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+               if (pDCTstat->NodePresent) {
+                       mctSMBhub_Init(Node);
+                       Clear_OnDimmMirror(pMCTstat, pDCTstat);
+-                      WriteLevelization_HW(pMCTstat, pDCTstat);
++                      WriteLevelization_HW(pMCTstat, pDCTstat, Pass);
+                       Restore_OnDimmMirror(pMCTstat, pDCTstat);
+               }
+       }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+index cda9c6b..5ef4a2c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+@@ -34,7 +34,7 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 
dct, u32 misc2)
+ 
+               if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
+                       misc2 |= 1 << OdtSwizzle;
+-              val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78);
++              val = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x78);
+ 
+               val &= 7;
+               val = ((~val) & 0xff) + 1;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+index bd8b7fb..5ea7fa6 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -23,7 +24,6 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+       u8 Dimms, DimmNum, MaxDimm, Speed;
+       u32 val;
+       u32 dct = 0;
+-      u32 reg_off = 0;
+ 
+       DimmNum = (MrsChipSel >> 20) & 0xFE;
+ 
+@@ -41,7 +41,6 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+               dct = 1;
+               DimmNum ++;
+       }
+-      reg_off = 0x100 * dct;
+       Dimms = pDCTstat->MAdimms[dct];
+ 
+       val = 0;
+@@ -95,21 +94,21 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+ static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u32 val)
+ {
+-      u32 reg_off = 0;
++      uint8_t dct = 0;
+       u32 dev = pDCTstat->dev_dct;
+ 
+       if (pDCTstat->CSPresent_DCT[0] > 0) {
+-              reg_off = 0;
++              dct = 0;
+       } else if (pDCTstat->CSPresent_DCT[1] > 0 ){
+-              reg_off = 0x100;
++              dct = 1;
+       }
+ 
+-      val |= Get_NB32(dev, reg_off + 0x7C) & ~0xFFFFFF;
++      val |= Get_NB32_DCT(dev, dct, 0x7C) & ~0xFFFFFF;
+       val |= 1 << SendControlWord;
+-      Set_NB32(dev, reg_off + 0x7C, val);
++      Set_NB32_DCT(dev, dct, 0x7C, val);
+ 
+       do {
+-              val = Get_NB32(dev, reg_off + 0x7C);
++              val = Get_NB32_DCT(dev, dct, 0x7C);
+       } while (val & (1 << SendControlWord));
+ }
+ 
+@@ -119,7 +118,6 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+       u8 MrsChipSel;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val, cw;
+-      u32 reg_off = 0x100 * dct;
+ 
+       mct_Wait(1600);
+ 
+@@ -127,7 +125,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+ 
+       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+-                      val = Get_NB32(dev, reg_off + 0xA8);
++                      val = Get_NB32_DCT(dev, dct, 0xa8);
+                       val &= ~(0xF << 8);
+ 
+                       switch (MrsChipSel) {
+@@ -144,7 +142,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+                       case 7:
+                               val |= (3 << 6) << 8;
+                       }
+-                      Set_NB32(dev, reg_off + 0xA8 , val);
++                      Set_NB32_DCT(dev, dct, 0xa8, val);
+ 
+                       for (cw=0; cw <=15; cw ++) {
+                               mct_Wait(1600);
+@@ -171,10 +169,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
+-                      val = Get_NB32(dev, 0xA8); /* TODO: dct * 0x100 + 0xA8 
*/
++                      val = Get_NB32_DCT(dev, 0, 0xA8); /* TODO: dct 0 / 1 
select */
+                       val &= ~(0xFF << 8);
+                       val |= (0x3 << (MrsChipSel & 0xFE)) << 8;
+-                      Set_NB32(dev, 0xA8, val); /* TODO: dct * 0x100 + 0xA8 */
++                      Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 
select */
+ 
+                       /* Resend control word 10 */
+                       mct_Wait(1600);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index b21b96a..51cbf16 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -18,17 +18,182 @@
+  * Foundation, Inc.
+  */
+ 
++static uint8_t fam15_dimm_dic(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
++{
++      uint8_t dic;
++
++      /* Calculate DIC based on recommendations in MR1_dct[1:0] */
++      if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++              /* TODO
++              * LRDIMM unimplemented
++              */
++              dic = 0x0;
++      } else {
++              dic = 0x1;
++      }
++
++      return dic;
++}
++
++static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
++{
++      uint8_t term = 0;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
++      uint8_t frequency_index;
++      uint8_t rank_count = pDCTData->DimmRanks[dimm];
++
++      if (is_fam15h())
++              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
++      else
++              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
++
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      if (is_fam15h()) {
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* TODO
++                       * RDIMM unimplemented
++                       */
++              } else {
++                      if (package_type == PT_GR) {
++                              /* Socket G34: Fam15h BKDG v3.14 Table 56 */
++                              if (MaxDimmsInstallable == 1) {
++                                      term = 0x0;
++                              } else if (MaxDimmsInstallable == 2) {
++                                      if ((number_of_dimms == 2) && 
(frequency_index == 0x12)) {
++                                              term = 0x1;
++                                      } else if (number_of_dimms == 1) {
++                                              term = 0x0;
++                                      } else {
++                                              term = 0x2;
++                                      }
++                              } else if (MaxDimmsInstallable == 3) {
++                                      if (number_of_dimms == 1) {
++                                              if (frequency_index <= 0xa) {
++                                                      term = 0x2;
++                                              } else {
++                                                      if (rank_count < 3) {
++                                                              term = 0x1;
++                                                      } else {
++                                                              term = 0x2;
++                                                      }
++                                              }
++                                      } else if (number_of_dimms == 2) {
++                                              term = 0x2;
++                                      }
++                              }
++                      } else {
++                              /* TODO
++                              * Other sockets unimplemented
++                              */
++                      }
++              }
++      }
++
++      return term;
++}
++
++static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
++{
++      uint8_t term = 0;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
++      uint8_t frequency_index;
++
++      if (is_fam15h())
++              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
++      else
++              frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
++
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      if (is_fam15h()) {
++              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* TODO
++                       * LRDIMM unimplemented
++                       */
++              } else if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* TODO
++                       * RDIMM unimplemented
++                       */
++              } else {
++                      if (package_type == PT_GR) {
++                              /* Socket G34: Fam15h BKDG v3.14 Table 56 */
++                              if (MaxDimmsInstallable == 1) {
++                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6))
++                                              term = 0x2;
++                                      else if ((frequency_index == 0xa) || 
(frequency_index == 0xe))
++                                              term = 0x1;
++                                      else
++                                              term = 0x3;
++                              }
++                              if (MaxDimmsInstallable == 2) {
++                                      if (number_of_dimms == 1) {
++                                              if (frequency_index <= 0x6) {
++                                                      term = 0x2;
++                                              } else if (frequency_index <= 
0xe) {
++                                                      term = 0x1;
++                                              } else {
++                                                      term = 0x3;
++                                              }
++                                      } else {
++                                              if (frequency_index <= 0xa) {
++                                                      term = 0x3;
++                                              } else if (frequency_index <= 
0xe) {
++                                                      term = 0x5;
++                                              } else {
++                                                      term = 0x4;
++                                              }
++                                      }
++                              } else if (MaxDimmsInstallable == 3) {
++                                      if (number_of_dimms == 1) {
++                                              term = 0x0;
++                                      } else if (number_of_dimms == 2) {
++                                              if (frequency_index <= 0xa) {
++                                                      if (rank == 1) {
++                                                              term = 0x0;
++                                                      } else {
++                                                              term = 0x3;
++                                                      }
++                                              } else if (frequency_index <= 
0xe) {
++                                                      if (rank == 1) {
++                                                              term = 0x0;
++                                                      } else {
++                                                              term = 0x5;
++                                                      }
++                                              }
++                                      }
++                              }
++                      } else {
++                              /* TODO
++                               * Other sockets unimplemented
++                               */
++                      }
++              }
++      }
++
++      return term;
++}
++
+ static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct);
+ 
+ static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+ 
+       do {
+-              val = Get_NB32(dev, reg_off + 0x98);
++              val = Get_NB32_DCT(dev, dct, 0x98);
+       } while (!(val & (1 << DctAccessDone)));
+ }
+ 
+@@ -54,9 +219,15 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 
MR_register_setting,
+                       if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
+                       if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
+                       if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
+-                      if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
+-                      if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
+-                      MR_register_setting &= ~0x301f8;
++                      if (is_fam15h()) {
++                              if (MR_register_setting & (1 << 18)) ret |= 1 
<< 19;
++                              if (MR_register_setting & (1 << 19)) ret |= 1 
<< 18;
++                              MR_register_setting &= ~0x000c01f8;
++                      } else {
++                              if (MR_register_setting & (1 << 16)) ret |= 1 
<< 17;
++                              if (MR_register_setting & (1 << 17)) ret |= 1 
<< 16;
++                              MR_register_setting &= ~0x000301f8;
++                      }
+                       MR_register_setting |= ret;
+               }
+       }
+@@ -65,47 +236,76 @@ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, 
u32 MR_register_setting,
+ 
+ static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+ 
+-      val = Get_NB32(dev, reg_off + 0x7C);
+-      val &= ~0xFFFFFF;
++      val = Get_NB32_DCT(dev, dct, 0x7c);
++      val &= ~0x00ffffff;
+       val |= EMRS;
+       val |= 1 << SendMrsCmd;
+-      Set_NB32(dev, reg_off + 0x7C, val);
++      Set_NB32_DCT(dev, dct, 0x7c, val);
+ 
+       do {
+-              val = Get_NB32(dev, reg_off + 0x7C);
++              val = Get_NB32_DCT(dev, dct, 0x7c);
+       } while (val & (1 << SendMrsCmd));
+ }
+ 
+ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+ 
+-      ret = 0x20000;
+-      ret |= MrsChipSel;
++      if (is_fam15h()) {
++              uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++              /* The formula for chip select number is: CS = dimm*2+rank */
++              uint8_t dimm = MrsChipSel / 2;
++              uint8_t rank = MrsChipSel % 2;
+ 
+-      /* program MrsAddress[5:3]=CAS write latency (CWL):
+-       * based on F2x[1,0]84[Tcwl] */
+-      dword = Get_NB32(dev, reg_off + 0x84);
+-      dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
++              /* FIXME: These parameters should be configurable
++               * For now, err on the side of caution and enable automatic 2x 
refresh
++               * when the DDR temperature rises above the internal limits
++               */
++              uint8_t force_2x_self_refresh = 0;      /* ASR */
++              uint8_t auto_2x_self_refresh = 1;       /* SRT */
+ 
+-      ret |= ((dword >> 20) & 7) << 3;
++              ret = 0x80000;
++              ret |= (MrsChipSel << 21);
+ 
+-      /* program MrsAddress[6]=auto self refresh method (ASR):
+-         based on F2x[1,0]84[ASR]
+-         program MrsAddress[7]=self refresh temperature range (SRT):
+-         based on F2x[1,0]84[ASR and SRT] */
+-      ret |= ((dword >> 18) & 3) << 6;
++              /* Set self refresh parameters */
++              ret |= (force_2x_self_refresh << 6);
++              ret |= (auto_2x_self_refresh << 7);
+ 
+-      /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
+-         based on F2x[1,0]84[DramTermDyn] */
+-      ret |= ((dword >> 10) & 3) << 9;
++              /* Obtain Tcwl, adjust, and set CWL with the adjusted value */
++              dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
++              ret |= ((dword - 5) << 3);
++
++              /* Obtain and set RttWr */
++              ret |= (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 
9);
++      } else {
++              ret = 0x20000;
++              ret |= (MrsChipSel << 20);
++
++              /* program MrsAddress[5:3]=CAS write latency (CWL):
++               * based on F2x[1,0]84[Tcwl] */
++              dword = Get_NB32_DCT(dev, dct, 0x84);
++              dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
++
++              ret |= ((dword >> 20) & 7) << 3;
++
++              /* program MrsAddress[6]=auto self refresh method (ASR):
++               * based on F2x[1,0]84[ASR]
++               * program MrsAddress[7]=self refresh temperature range (SRT):
++               * based on F2x[1,0]84[ASR and SRT]
++               */
++              ret |= ((dword >> 18) & 3) << 6;
++
++              /* program MrsAddress[10:9]=dynamic termination during writes 
(RTT_WR)
++               * based on F2x[1,0]84[DramTermDyn]
++               */
++              ret |= ((dword >> 10) & 3) << 9;
++      }
+ 
+       return ret;
+ }
+@@ -113,20 +313,28 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+ 
+-      ret = 0x30000;
+-      ret |= MrsChipSel;
++      if (is_fam15h()) {
++              ret = 0xc0000;
++              ret |= (MrsChipSel << 21);
+ 
+-      /* program MrsAddress[1:0]=multi purpose register address location
+-         (MPR Location):based on F2x[1,0]84[MprLoc]
+-         program MrsAddress[2]=multi purpose register
+-         (MPR):based on F2x[1,0]84[MprEn]
+-      */
+-      dword = Get_NB32(dev, reg_off + 0x84);
+-      ret |= (dword >> 24) & 7;
++              /* Program MPR and MPRLoc to 0 */
++              // ret |= 0x0;          /* MPR */
++              // ret |= (0x0 << 2);   /* MPRLoc */
++      } else {
++              ret = 0x30000;
++              ret |= (MrsChipSel << 20);
++
++              /* program MrsAddress[1:0]=multi purpose register address 
location
++               * (MPR Location):based on F2x[1,0]84[MprLoc]
++               * program MrsAddress[2]=multi purpose register
++               * (MPR):based on F2x[1,0]84[MprEn]
++               */
++              dword = Get_NB32_DCT(dev, dct, 0x84);
++              ret |= (dword >> 24) & 7;
++      }
+ 
+       return ret;
+ }
+@@ -134,48 +342,93 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
+ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+ 
+-      ret = 0x10000;
+-      ret |= MrsChipSel;
+-
+-      /* program MrsAddress[5,1]=output driver impedance control (DIC):
+-       * based on F2x[1,0]84[DrvImpCtrl] */
+-      dword = Get_NB32(dev, reg_off + 0x84);
+-      if (dword & (1 << 3))
+-              ret |= 1 << 5;
+-      if (dword & (1 << 2))
+-              ret |= 1 << 1;
+-
+-      /* program MrsAddress[9,6,2]=nominal termination resistance of ODT 
(RTT):
+-         based on F2x[1,0]84[DramTerm] */
+-      if (!(pDCTstat->Status & (1 << SB_Registered))) {
+-              if (dword & (1 << 9))
+-                      ret |= 1 << 9;
+-              if (dword & (1 << 8))
+-                      ret |= 1 << 6;
+-              if (dword & (1 << 7))
+-                      ret |= 1 << 2;
++      if (is_fam15h()) {
++              uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++              /* Set defaults */
++              uint8_t qoff = 0;       /* Enable output buffers */
++              uint8_t wrlvl = 0;      /* Disable write levelling */
++              uint8_t tqds = 0;
++              uint8_t rttnom = 0;
++              uint8_t dic = 0;
++              uint8_t additive_latency = 0;
++              uint8_t dll_enable = 0;
++
++              ret = 0x40000;
++              ret |= (MrsChipSel << 21);
++
++              /* The formula for chip select number is: CS = dimm*2+rank */
++              uint8_t dimm = MrsChipSel / 2;
++              uint8_t rank = MrsChipSel % 2;
++
++              /* Determine if TQDS should be set */
++              if ((pDCTstat->Dimmx8Present & (1 << dimm))
++                      && (((dimm & 
0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0)
++                      && (pDCTstat->Status & (1 << SB_LoadReduced)))
++                      tqds = 1;
++
++              /* Obtain RttNom */
++              rttnom = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
++
++              /* Obtain DIC */
++              dic = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
++
++              /* Load data into MRS word */
++              ret |= (qoff & 0x1) << 12;
++              ret |= (tqds & 0x1) << 11;
++              ret |= ((rttnom & 0x4) >> 2) << 9;
++              ret |= ((rttnom & 0x2) >> 1) << 6;
++              ret |= ((rttnom & 0x1) >> 0) << 2;
++              ret |= (wrlvl & 0x1) << 7;
++              ret |= ((dic & 0x2) >> 1) << 5;
++              ret |= ((dic & 0x1) >> 0) << 1;
++              ret |= (additive_latency & 0x3) << 3;
++              ret |= (dll_enable & 0x1);
+       } else {
+-              ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel);
+-      }
++              ret = 0x10000;
++              ret |= (MrsChipSel << 20);
++
++              /* program MrsAddress[5,1]=output driver impedance control 
(DIC):
++               * based on F2x[1,0]84[DrvImpCtrl]
++               */
++              dword = Get_NB32_DCT(dev, dct, 0x84);
++              if (dword & (1 << 3))
++                      ret |= 1 << 5;
++              if (dword & (1 << 2))
++                      ret |= 1 << 1;
++
++              /* program MrsAddress[9,6,2]=nominal termination resistance of 
ODT (RTT):
++               * based on F2x[1,0]84[DramTerm]
++               */
++              if (!(pDCTstat->Status & (1 << SB_Registered))) {
++                      if (dword & (1 << 9))
++                              ret |= 1 << 9;
++                      if (dword & (1 << 8))
++                              ret |= 1 << 6;
++                      if (dword & (1 << 7))
++                              ret |= 1 << 2;
++              } else {
++                      ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, 
MrsChipSel);
++              }
+ 
+-      /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
+-      if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
+-              u8 bit;
+-              /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 
& x4 */
+-              bit = (ret >> 21) << 1;
+-              if ((dct & 1) != 0)
+-                      bit ++;
+-              if (pDCTstat->Dimmx8Present & (1 << bit))
+-                      ret |= 1 << 11;
+-      }
++              /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
++              if (Get_NB32_DCT(dev, dct, 0x94) & (1 << RDqsEn)) {
++                      u8 bit;
++                      /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when 
mixed x8 & x4 */
++                      bit = (ret >> 21) << 1;
++                      if ((dct & 1) != 0)
++                              bit ++;
++                      if (pDCTstat->Dimmx8Present & (1 << bit))
++                              ret |= 1 << 11;
++              }
+ 
+-      /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
+-      if (dword & (1 << 13))
+-              ret |= 1 << 12;
++              /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */
++              if (dword & (1 << 13))
++                      ret |= 1 << 12;
++      }
+ 
+       return ret;
+ }
+@@ -183,60 +436,139 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct, u32 
MrsChipSel)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret, dword2;
+ 
+-      ret = 0x00000;
+-      ret |= MrsChipSel;
+-
+-      /* program MrsAddress[1:0]=burst length and control method
+-         (BL):based on F2x[1,0]84[BurstCtrl] */
+-      dword = Get_NB32(dev, reg_off + 0x84);
+-      ret |= dword & 3;
+-
+-      /* program MrsAddress[3]=1 (BT):interleaved */
+-      ret |= 1 << 3;
+-
+-      /* program MrsAddress[6:4,2]=read CAS latency
+-         (CL):based on F2x[1,0]88[Tcl] */
+-      dword2 = Get_NB32(dev, reg_off + 0x88);
+-      ret |= (dword2 & 0x7) << 4;             /* F2x88[2:0] to 
MrsAddress[6:4] */
+-      ret |= ((dword2 & 0x8) >> 3) << 2;      /* F2x88[3] to MrsAddress[2] */
+-
+-      /* program MrsAddress[12]=0 (PPD):slow exit */
+-      if (dword & (1 << 23))
+-              ret |= 1 << 12;
+-
+-      /* program MrsAddress[11:9]=write recovery for auto-precharge
+-         (WR):based on F2x[1,0]84[Twr] */
+-      ret |= ((dword >> 4) & 7) << 9;
+-
+-      /* program MrsAddress[8]=1 (DLL):DLL reset
+-         just issue DLL reset at first time */
+-      ret |= 1 << 8;
++      if (is_fam15h()) {
++              ret = 0x00000;
++              ret |= (MrsChipSel << 21);
++
++              /* Set defaults */
++              uint8_t ppd = 0;
++              uint8_t wr_ap = 0;
++              uint8_t dll_reset = 1;
++              uint8_t test_mode = 0;
++              uint8_t cas_latency = 0;
++              uint8_t read_burst_type = 1;
++              uint8_t burst_length = 0;
++
++              /* Obtain PchgPDModeSel */
++              dword = Get_NB32_DCT(dev, dct, 0x84);
++              ppd = (dword >> 23) & 0x1;
++
++              /* Obtain Twr */
++              dword = Get_NB32_DCT(dev, dct, 0x22c) & 0x1f;
++
++              /* Calculate wr_ap (Fam15h BKDG v3.14 Table 82) */
++              if (dword == 0x10)
++                      wr_ap = 0x0;
++              else if (dword == 0x5)
++                      wr_ap = 0x1;
++              else if (dword == 0x6)
++                      wr_ap = 0x2;
++              else if (dword == 0x7)
++                      wr_ap = 0x3;
++              else if (dword == 0x8)
++                      wr_ap = 0x4;
++              else if (dword == 0xa)
++                      wr_ap = 0x5;
++              else if (dword == 0xc)
++                      wr_ap = 0x6;
++              else if (dword == 0xe)
++                      wr_ap = 0x7;
++
++              /* Obtain Tcl */
++              dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
++
++              /* Calculate cas_latency (Fam15h BKDG v3.14 Table 83) */
++              if (dword == 0x5)
++                      cas_latency = 0x2;
++              else if (dword == 0x6)
++                      cas_latency = 0x4;
++              else if (dword == 0x7)
++                      cas_latency = 0x6;
++              else if (dword == 0x8)
++                      cas_latency = 0x8;
++              else if (dword == 0x9)
++                      cas_latency = 0xa;
++              else if (dword == 0xa)
++                      cas_latency = 0xc;
++              else if (dword == 0xb)
++                      cas_latency = 0xe;
++              else if (dword == 0xc)
++                      cas_latency = 0x1;
++              else if (dword == 0xd)
++                      cas_latency = 0x3;
++              else if (dword == 0xe)
++                      cas_latency = 0x5;
++              else if (dword == 0xf)
++                      cas_latency = 0x7;
++              else if (dword == 0x10)
++                      cas_latency = 0x9;
++
++              /* Obtain BurstCtrl */
++              burst_length = Get_NB32_DCT(dev, dct, 0x84) & 0x3;
++
++              /* Load data into MRS word */
++              ret |= (ppd & 0x1) << 12;
++              ret |= (wr_ap & 0x3) << 9;
++              ret |= (dll_reset & 0x1) << 8;
++              ret |= (test_mode & 0x1) << 7;
++              ret |= ((cas_latency & 0xe) >> 1) << 4;
++              ret |= ((cas_latency & 0x1) >> 0) << 2;
++              ret |= (read_burst_type & 0x1) << 3;
++              ret |= (burst_length & 0x3);
++      } else {
++              ret = 0x00000;
++              ret |= (MrsChipSel << 20);
++
++              /* program MrsAddress[1:0]=burst length and control method
++              (BL):based on F2x[1,0]84[BurstCtrl] */
++              dword = Get_NB32_DCT(dev, dct, 0x84);
++              ret |= dword & 3;
++
++              /* program MrsAddress[3]=1 (BT):interleaved */
++              ret |= 1 << 3;
++
++              /* program MrsAddress[6:4,2]=read CAS latency
++              (CL):based on F2x[1,0]88[Tcl] */
++              dword2 = Get_NB32_DCT(dev, dct, 0x88);
++              ret |= (dword2 & 0x7) << 4;             /* F2x88[2:0] to 
MrsAddress[6:4] */
++              ret |= ((dword2 & 0x8) >> 3) << 2;      /* F2x88[3] to 
MrsAddress[2] */
++
++              /* program MrsAddress[12]=0 (PPD):slow exit */
++              if (dword & (1 << 23))
++                      ret |= 1 << 12;
++
++              /* program MrsAddress[11:9]=write recovery for auto-precharge
++              (WR):based on F2x[1,0]84[Twr] */
++              ret |= ((dword >> 4) & 7) << 9;
++
++              /* program MrsAddress[8]=1 (DLL):DLL reset
++              just issue DLL reset at first time */
++              ret |= 1 << 8;
++      }
+ 
+       return ret;
+ }
+ 
+ static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword;
+ 
+       /*1.Program MrsAddress[10]=1
+         2.Set SendZQCmd=1
+        */
+-      dword = Get_NB32(dev, reg_off + 0x7C);
++      dword = Get_NB32_DCT(dev, dct, 0x7C);
+       dword &= ~0xFFFFFF;
+       dword |= 1 << 10;
+       dword |= 1 << SendZQCmd;
+-      Set_NB32(dev, reg_off + 0x7C, dword);
++      Set_NB32_DCT(dev, dct, 0x7C, dword);
+ 
+       /* Wait for SendZQCmd=0 */
+       do {
+-              dword = Get_NB32(dev, reg_off + 0x7C);
++              dword = Get_NB32_DCT(dev, dct, 0x7C);
+       } while (dword & (1 << SendZQCmd));
+ 
+       /* 4.Wait 512 MEMCLKs */
+@@ -248,31 +580,30 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+ {
+       u8 MrsChipSel;
+       u32 dword;
+-      u32 reg_off = 0x100 * dct;
+       u32 dev = pDCTstat->dev_dct;
+ 
+-      if (pDCTstat->DIMMAutoSpeed == 4) {
++      if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+               /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
+-              dword = Get_NB32(dev, reg_off + 0x7C);
++              dword = Get_NB32_DCT(dev, dct, 0x7c);
+               dword |= 1 << EnDramInit;
+-              Set_NB32(dev, reg_off + 0x7C, dword);
++              Set_NB32_DCT(dev, dct, 0x7c, dword);
+               mct_DCTAccessDone(pDCTstat, dct);
+ 
+               /* 4.wait 200us */
+               mct_Wait(40000);
+ 
+-              /* 5.On revision C processors, program F2x[1, 
0]7C[DeassertMemRstX] = 1. */
+-              dword = Get_NB32(dev, reg_off + 0x7C);
++              /* 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1. */
++              dword = Get_NB32_DCT(dev, dct, 0x7c);
+               dword |= 1 << DeassertMemRstX;
+-              Set_NB32(dev, reg_off + 0x7C, dword);
++              Set_NB32_DCT(dev, dct, 0x7c, dword);
+ 
+               /* 6.wait 500us */
+               mct_Wait(200000);
+ 
+               /* 7.Program F2x[1,0]7C[AssertCke]=1 */
+-              dword = Get_NB32(dev, reg_off + 0x7C);
++              dword = Get_NB32_DCT(dev, dct, 0x7c);
+               dword |= 1 << AssertCke;
+-              Set_NB32(dev, reg_off + 0x7C, dword);
++              Set_NB32_DCT(dev, dct, 0x7c, dword);
+ 
+               /* 8.wait 360ns */
+               mct_Wait(80);
+@@ -281,6 +612,13 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+                * must be done for each chip select pair */
+               if (pDCTstat->Status & (1 << SB_Registered))
+                       mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
++
++              /* The following steps are performed with load reduced DIMMs 
only and
++               * must be done for each DIMM */
++              // if (pDCTstat->Status & (1 << SB_LoadReduced))
++                      /* TODO
++                       * Implement LRDIMM configuration
++                       */
+       }
+ 
+       /* The following steps are performed once for unbuffered DIMMs and once 
for each
+@@ -289,23 +627,23 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       u32 EMRS;
+                       /* 13.Send EMRS(2) */
+-                      EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
++                      EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+                       /* 14.Send EMRS(3). Ordinarily at this time, 
MrsAddress[2:0]=000b */
+-                      EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
++                      EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+                       /* 15.Send EMRS(1) */
+-                      EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
++                      EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+                       /* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
+-                      EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel << 
20);
++                      EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel);
+                       EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+                       mct_SendMrsCmd(pDCTstat, dct, EMRS);
+ 
+-                      if (pDCTstat->DIMMAutoSpeed == 4)
++                      if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)))
+                               if (!(pDCTstat->Status & (1 << SB_Registered)))
+                                       break; /* For UDIMM, only send MR 
commands once per channel */
+               }
+@@ -314,16 +652,15 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+                               MrsChipSel ++;
+       }
+ 
+-      mct_Wait(100000);
+-
+-      if (pDCTstat->DIMMAutoSpeed == 4) {
++      if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+               /* 17.Send two ZQCL commands */
+               mct_SendZQCmd(pDCTstat, dct);
+               mct_SendZQCmd(pDCTstat, dct);
++
+               /* 18.Program F2x[1,0]7C[EnDramInit]=0 */
+-              dword = Get_NB32(dev, reg_off + 0x7C);
++              dword = Get_NB32_DCT(dev, dct, 0x7C);
+               dword &= ~(1 << EnDramInit);
+-              Set_NB32(dev, reg_off + 0x7C, dword);
++              Set_NB32_DCT(dev, dct, 0x7C, dword);
+               mct_DCTAccessDone(pDCTstat, dct);
+       }
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 91e8f77..011a94f 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -23,7 +23,10 @@
+  Description: Receiver En and DQS Timing Training feature for DDR 3 MCT
+ 
******************************************************************************/
+ 
+-static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
++static int32_t abs(int32_t val);
++static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, u8 Pass);
++static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Pass);
+ static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+                                        struct DCTStatStruc *pDCTstat);
+@@ -32,7 +35,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Channel);
+ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, 
u16 DQSRcvEnDly);
+-static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
++static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct);
+ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat);
+ 
+@@ -89,11 +92,154 @@ static void SetupRcvrPattern(struct MCTStatStruc 
*pMCTstat,
+ void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 Pass)
+ {
+-      if(mct_checkNumberOfDqsRcvEn_1Pass(Pass))
+-              dqsTrainRcvrEn_SW(pMCTstat, pDCTstat, Pass);
++      if(mct_checkNumberOfDqsRcvEn_1Pass(Pass)) {
++              if (is_fam15h())
++                      dqsTrainRcvrEn_SW_Fam15(pMCTstat, pDCTstat, Pass);
++              else
++                      dqsTrainRcvrEn_SW_Fam10(pMCTstat, pDCTstat, Pass);
++      }
+ }
+ 
+-static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
++static uint16_t fam15_receiver_enable_training_seed(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
++{
++      uint32_t dword;
++      uint16_t seed = 0;
++
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      uint8_t channel = dct;
++      if (package_type == PT_GR) {
++              /* Get the internal node number */
++              dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
++              dword = (dword >> 30) & 0x3;
++              if (dword == 1) {
++                      channel += 2;
++              }
++      }
++
++      if (pDCTstat->Status & (1 << SB_Registered)) {
++              if (package_type == PT_GR) {
++                      /* Socket G34: Fam15h BKDG v3.14 Table 99 */
++                      if (MaxDimmsInstallable == 1) {
++                              if (channel == 0)
++                                      seed = 0x43;
++                              else if (channel == 1)
++                                      seed = 0x3f;
++                              else if (channel == 2)
++                                      seed = 0x3a;
++                              else if (channel == 3)
++                                      seed = 0x35;
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (channel == 0)
++                                      seed = 0x54;
++                              else if (channel == 1)
++                                      seed = 0x4d;
++                              else if (channel == 2)
++                                      seed = 0x45;
++                              else if (channel == 3)
++                                      seed = 0x40;
++                      } else if (MaxDimmsInstallable == 3) {
++                              if (channel == 0)
++                                      seed = 0x6b;
++                              else if (channel == 1)
++                                      seed = 0x5e;
++                              else if (channel == 2)
++                                      seed = 0x4b;
++                              else if (channel == 3)
++                                      seed = 0x3d;
++                      }
++              } else if (package_type == PT_C3) {
++                      /* Socket C32: Fam15h BKDG v3.14 Table 100 */
++                      if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable 
== 2)) {
++                              if (channel == 0)
++                                      seed = 0x3f;
++                              else if (channel == 1)
++                                      seed = 0x3e;
++                      } else if (MaxDimmsInstallable == 3) {
++                              if (channel == 0)
++                                      seed = 0x47;
++                              else if (channel == 1)
++                                      seed = 0x38;
++                      }
++              }
++      } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++              if (package_type == PT_GR) {
++                      /* Socket G34: Fam15h BKDG v3.14 Table 99 */
++                      if (MaxDimmsInstallable == 1) {
++                              if (channel == 0)
++                                      seed = 0x123;
++                              else if (channel == 1)
++                                      seed = 0x122;
++                              else if (channel == 2)
++                                      seed = 0x112;
++                              else if (channel == 3)
++                                      seed = 0x102;
++                      }
++              } else if (package_type == PT_C3) {
++                      /* Socket C32: Fam15h BKDG v3.14 Table 100 */
++                      if (channel == 0)
++                              seed = 0x132;
++                      else if (channel == 1)
++                              seed = 0x122;
++              }
++      } else {
++              if (package_type == PT_GR) {
++                      /* Socket G34: Fam15h BKDG v3.14 Table 99 */
++                      if (MaxDimmsInstallable == 1) {
++                              if (channel == 0)
++                                      seed = 0x3e;
++                              else if (channel == 1)
++                                      seed = 0x38;
++                              else if (channel == 2)
++                                      seed = 0x37;
++                              else if (channel == 3)
++                                      seed = 0x31;
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (channel == 0)
++                                      seed = 0x51;
++                              else if (channel == 1)
++                                      seed = 0x4a;
++                              else if (channel == 2)
++                                      seed = 0x46;
++                              else if (channel == 3)
++                                      seed = 0x3f;
++                      } else if (MaxDimmsInstallable == 3) {
++                              if (channel == 0)
++                                      seed = 0x5e;
++                              else if (channel == 1)
++                                      seed = 0x52;
++                              else if (channel == 2)
++                                      seed = 0x48;
++                              else if (channel == 3)
++                                      seed = 0x3c;
++                      }
++              } else if (package_type == PT_C3) {
++                      /* Socket C32: Fam15h BKDG v3.14 Table 100 */
++                      if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable 
== 2)) {
++                              if (channel == 0)
++                                      seed = 0x39;
++                              else if (channel == 1)
++                                      seed = 0x32;
++                      } else if (MaxDimmsInstallable == 3) {
++                              if (channel == 0)
++                                      seed = 0x45;
++                              else if (channel == 1)
++                                      seed = 0x37;
++                      }
++              } else if (package_type == PT_M2) {
++                      /* Socket AM3: Fam15h BKDG v3.14 Table 101 */
++                      seed = 0x3a;
++              }
++      }
++
++      return seed;
++}
++
++static void read_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
+ {
+       uint8_t lane;
+       uint32_t dword;
+@@ -111,7 +257,7 @@ static void 
read_dqs_write_timing_control_registers(uint16_t* current_total_dela
+               if (lane == 8)
+                       wdt_reg = 0x32;
+               wdt_reg += dimm * 3;
+-              dword = Get_NB32_index_wait(dev, index_reg, wdt_reg);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg);
+               if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1))
+                       current_total_delay[lane] = (dword & 0x00ff0000) >> 16;
+               if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0))
+@@ -119,12 +265,124 @@ static void 
read_dqs_write_timing_control_registers(uint16_t* current_total_dela
+       }
+ }
+ 
+-static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg)
++#ifdef UNUSED_CODE
++static void write_dqs_write_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
++{
++      uint8_t lane;
++      uint32_t dword;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++              uint32_t ret_reg;
++              if ((lane == 0) || (lane == 1))
++                      ret_reg = 0x30;
++              if ((lane == 2) || (lane == 3))
++                      ret_reg = 0x31;
++              if ((lane == 4) || (lane == 5))
++                      ret_reg = 0x40;
++              if ((lane == 6) || (lane == 7))
++                      ret_reg = 0x41;
++              if (lane == 8)
++                      ret_reg = 0x32;
++              ret_reg += dimm * 3;
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
++              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
++                      dword &= ~(0xff << 16);
++                      dword |= (current_total_delay[lane] & 0xff) << 16;
++              }
++              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0)) {
++                      dword &= ~0xff;
++                      dword |= current_total_delay[lane] & 0xff;
++              }
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
++      }
++}
++#endif
++
++static void write_write_data_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
++{
++      uint8_t lane;
++      uint32_t dword;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++              uint32_t wdt_reg;
++
++              /* Calculate Write Data Timing register location */
++              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
++                      wdt_reg = 0x1;
++              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
++                      wdt_reg = 0x2;
++              if (lane == 8)
++                      wdt_reg = 0x3;
++              wdt_reg |= (dimm << 8);
++
++              /* Set Write Data Timing register values */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg);
++              if ((lane == 7) || (lane == 3)) {
++                      dword &= ~(0x7f << 24);
++                      dword |= (current_total_delay[lane] & 0x7f) << 24;
++              }
++              if ((lane == 6) || (lane == 2)) {
++                      dword &= ~(0x7f << 16);
++                      dword |= (current_total_delay[lane] & 0x7f) << 16;
++              }
++              if ((lane == 5) || (lane == 1)) {
++                      dword &= ~(0x7f << 8);
++                      dword |= (current_total_delay[lane] & 0x7f) << 8;
++              }
++              if ((lane == 8) || (lane == 4) || (lane == 0)) {
++                      dword &= ~0x7f;
++                      dword |= current_total_delay[lane] & 0x7f;
++              }
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, wdt_reg, dword);
++      }
++}
++
++static void read_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
++{
++      uint8_t lane;
++      uint32_t mask;
++      uint32_t dword;
++
++      if (is_fam15h())
++              mask = 0x3ff;
++      else
++              mask = 0x1ff;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++              uint32_t ret_reg;
++              if ((lane == 0) || (lane == 1))
++                      ret_reg = 0x10;
++              if ((lane == 2) || (lane == 3))
++                      ret_reg = 0x11;
++              if ((lane == 4) || (lane == 5))
++                      ret_reg = 0x20;
++              if ((lane == 6) || (lane == 7))
++                      ret_reg = 0x21;
++              if (lane == 8)
++                      ret_reg = 0x12;
++              ret_reg += dimm * 3;
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
++              if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
++                      current_total_delay[lane] = (dword & (mask << 16)) >> 
16;
++              }
++              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0)) {
++                      current_total_delay[lane] = dword & mask;
++              }
++      }
++}
++
++static void write_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
+ {
+       uint8_t lane;
++      uint32_t mask;
+       uint32_t dword;
+ 
+-      for (lane = 0; lane < 8; lane++) {
++      if (is_fam15h())
++              mask = 0x3ff;
++      else
++              mask = 0x1ff;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+               uint32_t ret_reg;
+               if ((lane == 0) || (lane == 1))
+                       ret_reg = 0x10;
+@@ -134,17 +392,125 @@ static void 
write_dqs_receiver_enable_control_registers(uint16_t* current_total_
+                       ret_reg = 0x20;
+               if ((lane == 6) || (lane == 7))
+                       ret_reg = 0x21;
++              if (lane == 8)
++                      ret_reg = 0x12;
+               ret_reg += dimm * 3;
+-              dword = Get_NB32_index_wait(dev, index_reg, ret_reg);
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
+               if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
+-                      dword &= ~(0x1ff << 16);
+-                      dword |= (current_total_delay[lane] & 0x1ff) << 16;
++                      dword &= ~(mask << 16);
++                      dword |= (current_total_delay[lane] & mask) << 16;
+               }
+-              if ((lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
+-                      dword &= ~0x1ff;
+-                      dword |= current_total_delay[lane] & 0x1ff;
++              if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || 
(lane == 0)) {
++                      dword &= ~mask;
++                      dword |= current_total_delay[lane] & mask;
+               }
+-              Set_NB32_index_wait(dev, index_reg, ret_reg, dword);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
++      }
++}
++
++static void read_dram_phase_recovery_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
++{
++      uint8_t lane;
++      uint32_t dword;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++              uint32_t prc_reg;
++
++              /* Calculate DRAM Phase Recovery Control register location */
++              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
++                      prc_reg = 0x50;
++              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
++                      prc_reg = 0x51;
++              if (lane == 8)
++                      prc_reg = 0x52;
++
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg);
++              if ((lane == 7) || (lane == 3)) {
++                      current_total_delay[lane] = (dword >> 24) & 0x7f;
++              }
++              if ((lane == 6) || (lane == 2)) {
++                      current_total_delay[lane] = (dword >> 16) & 0x7f;
++              }
++              if ((lane == 5) || (lane == 1)) {
++                      current_total_delay[lane] = (dword >> 8) & 0x7f;
++              }
++              if ((lane == 8) || (lane == 4) || (lane == 0)) {
++                      current_total_delay[lane] = dword & 0x7f;
++              }
++      }
++}
++
++static void write_dram_phase_recovery_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
++{
++      uint8_t lane;
++      uint32_t dword;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++              uint32_t prc_reg;
++
++              /* Calculate DRAM Phase Recovery Control register location */
++              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
++                      prc_reg = 0x50;
++              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
++                      prc_reg = 0x51;
++              if (lane == 8)
++                      prc_reg = 0x52;
++
++              /* Set DRAM Phase Recovery Control register values */
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg);
++              if ((lane == 7) || (lane == 3)) {
++                      dword &= ~(0x7f << 24);
++                      dword |= (current_total_delay[lane] & 0x7f) << 24;
++              }
++              if ((lane == 6) || (lane == 2)) {
++                      dword &= ~(0x7f << 16);
++                      dword |= (current_total_delay[lane] & 0x7f) << 16;
++              }
++              if ((lane == 5) || (lane == 1)) {
++                      dword &= ~(0x7f << 8);
++                      dword |= (current_total_delay[lane] & 0x7f) << 8;
++              }
++              if ((lane == 8) || (lane == 4) || (lane == 0)) {
++                      dword &= ~0x7f;
++                      dword |= current_total_delay[lane] & 0x7f;
++              }
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg, dword);
++      }
++}
++
++static void read_read_dqs_timing_control_registers(uint16_t* 
current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg)
++{
++      uint8_t lane;
++      uint32_t dword;
++
++      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++              uint32_t rdt_reg;
++
++              /* Calculate DRAM Read DQS Timing register location */
++              if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
++                      rdt_reg = 0x5;
++              if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
++                      rdt_reg = 0x6;
++              if (lane == 8)
++                      rdt_reg = 0x7;
++              rdt_reg |= (dimm << 8);
++
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, rdt_reg);
++              if ((lane == 7) || (lane == 3)) {
++                      current_total_delay[lane] = (dword >> 24) & 0x3f;
++              }
++              if ((lane == 6) || (lane == 2)) {
++                      current_total_delay[lane] = (dword >> 16) & 0x3f;
++              }
++              if ((lane == 5) || (lane == 1)) {
++                      current_total_delay[lane] = (dword >> 8) & 0x3f;
++              }
++              if ((lane == 8) || (lane == 4) || (lane == 0)) {
++                      current_total_delay[lane] = dword & 0x3f;
++              }
++
++              if (is_fam15h())
++                      current_total_delay[lane] >>= 1;
+       }
+ }
+ 
+@@ -160,10 +526,11 @@ static uint32_t 
convert_testaddr_and_channel_to_address(struct DCTStatStruc *pDC
+       return testaddr;
+ }
+ 
+-/* DQS Receiver Enable Training
+- * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
++/* DQS Receiver Enable Training (Family 10h)
++ * Algorithm detailed in:
++ * The Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
+  */
+-static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat,
++static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 Pass)
+ {
+       u8 Channel;
+@@ -171,7 +538,6 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+       u8 Addl_Index = 0;
+       u8 Receiver;
+       u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
+-      u8 Final_Value;
+       u16 CTLRMaxDelay;
+       u16 MaxDelay_CH[2];
+       u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B;
+@@ -188,6 +554,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+       u32 lo, hi;
+ 
+       uint32_t dword;
++      uint8_t dimm;
+       uint8_t rank;
+       uint8_t lane;
+       uint16_t current_total_delay[MAX_BYTE_LANES];
+@@ -214,14 +581,13 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+       }
+ 
+       for (ch = ch_start; ch < ch_end; ch++) {
+-              reg = 0x78 + (0x100 * ch);
+-              val = Get_NB32(dev, reg);
++              reg = 0x78;
++              val = Get_NB32_DCT(dev, ch, reg);
+               val &= ~(0x3ff << 22);
+-              val |= (0x0c8 << 22);           /* Max Rd Lat */
+-              Set_NB32(dev, reg, val);
++              val |= (0x0c8 << 22);           /* MaxRdLatency = 0xc8 */
++              Set_NB32_DCT(dev, ch, reg, val);
+       }
+ 
+-      Final_Value = 1;
+       if (Pass == FirstPass) {
+               mct_InitDQSPos4RcvrEn_D(pMCTstat, pDCTstat);
+       } else {
+@@ -260,7 +626,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+ 
+               CTLRMaxDelay = 0;
+               MaxDelay_CH[Channel] = 0;
+-              index_reg = 0x98 + 0x100 * Channel;
++              index_reg = 0x98;
+ 
+               Receiver = mct_InitReceiver_D(pDCTstat, Channel);
+               /* There are four receiver pairs, loosely associated with 
chipselects.
+@@ -268,6 +634,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                */
+               for (; Receiver < 8; Receiver += 2) {
+                       Addl_Index = (Receiver >> 1) * 3 + 0x10;
++                      dimm = (Receiver >> 1);
+ 
+                       print_debug_dqs("\t\tTrainRcvEnd52: index ", 
Addl_Index, 2);
+ 
+@@ -284,45 +651,14 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                       /* 2.8.9.9.2 (1, 6)
+                        * Retrieve gross and fine timing fields from write DQS 
registers
+                        */
+-                      
read_dqs_write_timing_control_registers(current_total_delay, dev, (Receiver >> 
1), index_reg);
++                      
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+ 
+                       /* 2.8.9.9.2 (1)
+                        * Program the Write Data Timing and Write ECC Timing 
register to
+                        * the values stored in the DQS Write Timing Control 
register
+                        * for each lane
+                        */
+-                      for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+-                              uint32_t wdt_reg;
+-
+-                              /* Calculate Write Data Timing register 
location */
+-                              if ((lane == 0) || (lane == 1) || (lane == 2) 
|| (lane == 3))
+-                                      wdt_reg = 0x1;
+-                              if ((lane == 4) || (lane == 5) || (lane == 6) 
|| (lane == 7))
+-                                      wdt_reg = 0x2;
+-                              if (lane == 8)
+-                                      wdt_reg = 0x3;
+-                              wdt_reg |= ((Receiver / 2) << 8);
+-
+-                              /* Set Write Data Timing register values */
+-                              dword = Get_NB32_index_wait(dev, index_reg, 
wdt_reg);
+-                              if ((lane == 7) || (lane == 3)) {
+-                                      dword &= ~(0x7f << 24);
+-                                      dword |= (current_total_delay[lane] & 
0x7f) << 24;
+-                              }
+-                              if ((lane == 6) || (lane == 2)) {
+-                                      dword &= ~(0x7f << 16);
+-                                      dword |= (current_total_delay[lane] & 
0x7f) << 16;
+-                              }
+-                              if ((lane == 5) || (lane == 1)) {
+-                                      dword &= ~(0x7f << 8);
+-                                      dword |= (current_total_delay[lane] & 
0x7f) << 8;
+-                              }
+-                              if ((lane == 8) || (lane == 4) || (lane == 0)) {
+-                                      dword &= ~0x7f;
+-                                      dword |= current_total_delay[lane] & 
0x7f;
+-                              }
+-                              Set_NB32_index_wait(dev, index_reg, wdt_reg, 
dword);
+-                      }
++                      
write_write_data_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+ 
+                       /* 2.8.9.9.2 (2)
+                        * Program the Read DQS Timing Control and the Read DQS 
ECC Timing Control registers
+@@ -336,12 +672,12 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                                       rdt_reg = 0x6;
+                               if (lane == 8)
+                                       rdt_reg = 0x7;
+-                              rdt_reg |= ((Receiver / 2) << 8);
++                              rdt_reg |= (dimm << 8);
+                               if (lane == 8)
+                                       dword = 0x0000003f;
+                               else
+                                       dword = 0x3f3f3f3f;
+-                              Set_NB32_index_wait(dev, index_reg, rdt_reg, 
dword);
++                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, rdt_reg, dword);
+                       }
+ 
+                       /* 2.8.9.9.2 (3)
+@@ -371,7 +707,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                       print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", 
TestAddr1B, 2);
+ 
+                       /* 2.8.9.9.2 (4, 5)
+-                       * Write 1 cache line of the appropriate test pattern 
to each test addresse
++                       * Write 1 cache line of the appropriate test pattern 
to each test address
+                        */
+                       mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, 
0); /* rank 0 of DIMM, testpattern 0 */
+                       mct_Write1LTestPattern_D(pMCTstat, pDCTstat, 
TestAddr0B, 1); /* rank 0 of DIMM, testpattern 1 */
+@@ -390,7 +726,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                       /* 2.8.9.9.2 (6)
+                        * Write gross and fine timing fields to read DQS 
registers
+                        */
+-                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+ 
+                       /* 2.8.9.9.2 (7)
+                        * Loop over all delay values up to 1 MEMCLK (0x40 
delay steps) from the initial delay values
+@@ -417,8 +753,8 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                                       break;
+ 
+                               /* 2.8.9.9.2 (7 A)
+-                              * Loop over all ranks
+-                              */
++                               * Loop over all ranks
++                               */
+                               for (rank = 0; rank < (_2Ranks + 1); rank++) {
+                                       /* 2.8.9.9.2 (7 A a-d)
+                                        * Read the first test address of the 
current rank
+@@ -434,17 +770,17 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                                                */
+                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
+                                               result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
+-                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
+                                               result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
+-                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+                                       } else {
+                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0:TestAddr1);
+                                               result_qword1 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0:TestAddr1, Channel));
+-                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+                                               proc_IOCLFLUSH_D((rank == 
0)?TestAddr0B:TestAddr1B);
+                                               result_qword2 = 
read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 
0)?TestAddr0B:TestAddr1B, Channel));
+-                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+                                       }
+                                       /* 2.8.9.9.2 (7 A e)
+                                        * Compare both read patterns and flag 
passing ranks/lanes
+@@ -533,7 +869,7 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+                               }
+ 
+                               /* Update delays in hardware */
+-                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver 
>> 1), index_reg);
++                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+ 
+                               /* Save previous results for comparison in the 
next iteration */
+                               for (lane = 0; lane < 8; lane++)
+@@ -587,7 +923,483 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc 
*pMCTstat,
+               mct_SetMaxLatency_D(pDCTstat, Channel, CTLRMaxDelay); /* 
program Ch A/B MaxAsyncLat to correspond with max delay */
+       }
+ 
+-      ResetDCTWrPtr_D(dev, index_reg, Addl_Index);
++      for (Channel = 0; Channel < 2; Channel++) {
++              ResetDCTWrPtr_D(dev, Channel, index_reg, Addl_Index);
++      }
++
++      if(_DisableDramECC) {
++              mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
++      }
++
++      if (Pass == FirstPass) {
++              /*Disable DQSRcvrEn training mode */
++              mct_DisableDQSRcvEn_D(pDCTstat);
++      }
++
++      if(!_Wrap32Dis) {
++              msr = HWCR;
++              _RDMSR(msr, &lo, &hi);
++              lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
++              _WRMSR(msr, lo, hi);
++      }
++      if(!_SSE2){
++              cr4 = read_cr4();
++              cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
++              write_cr4(cr4);
++      }
++
++#if DQS_TRAIN_DEBUG > 0
++      {
++              u8 ChannelDTD;
++              printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
++              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
++                      printk(BIOS_DEBUG, "Channel:%x: %x\n",
++                             ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]);
++              }
++      }
++#endif
++
++#if DQS_TRAIN_DEBUG > 0
++      {
++              u16 valDTD;
++              u8 ChannelDTD, ReceiverDTD;
++              u8 i;
++              u16 *p;
++
++              printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
++              for(ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
++                      printk(BIOS_DEBUG, "Channel:%x\n", ChannelDTD);
++                      for(ReceiverDTD = 0; ReceiverDTD<8; ReceiverDTD+=2) {
++                              printk(BIOS_DEBUG, "\t\tReceiver:%x:", 
ReceiverDTD);
++                              p = 
pDCTstat->CH_D_B_RCVRDLY[ChannelDTD][ReceiverDTD>>1];
++                              for (i=0;i<8; i++) {
++                                      valDTD = p[i];
++                                      printk(BIOS_DEBUG, " %03x", valDTD);
++                              }
++                              printk(BIOS_DEBUG, "\n");
++                      }
++              }
++      }
++#endif
++
++      printk(BIOS_DEBUG, "TrainRcvrEn: Status %x\n", pDCTstat->Status);
++      printk(BIOS_DEBUG, "TrainRcvrEn: ErrStatus %x\n", pDCTstat->ErrStatus);
++      printk(BIOS_DEBUG, "TrainRcvrEn: ErrCode %x\n", pDCTstat->ErrCode);
++      printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
++}
++
++/* DQS Receiver Enable Training Pattern Generation (Family 15h)
++ * Algorithm detailed in:
++ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2 (4)
++ */
++static void generate_dram_receiver_enable_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver)
++{
++      uint32_t dword;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      /* 2.10.5.7.1.1
++       * It appears that the DCT only supports 8-beat burst length mode,
++       * so do nothing here...
++       */
++
++      /* Wait for CmdSendInProg == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x250);
++      } while (dword & (0x1 << 12));
++
++      /* Set CmdTestEnable = 1 */
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword |= (0x1 << 2);
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      /* 2.10.5.8.6.1.1 Send Activate Command */
++      dword = Get_NB32_DCT(dev, dct, 0x28c);
++      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
++      dword |= ((0x1 << Receiver) << 22);
++      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
++      dword &= ~(0x3ffff);                            /* CmdAddress = 0 */
++      dword |= (0x1 << 31);                           /* SendActCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x28c, dword);
++
++      /* Wait for SendActCmd == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x28c);
++      } while (dword & (0x1 << 31));
++
++      /* Wait 75 MEMCLKs. */
++      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
++
++      /* 2.10.5.8.6.1.2 */
++      Set_NB32_DCT(dev, dct, 0x274, 0x0);             /* DQMask = 0 */
++      Set_NB32_DCT(dev, dct, 0x278, 0x0);
++
++      dword = Get_NB32_DCT(dev, dct, 0x27c);
++      dword &= ~(0xff);                               /* EccMask = 0 */
++      if (pDCTstat->DimmECCPresent == 0)
++              dword |= 0xff;                          /* EccMask = 0xff */
++      Set_NB32_DCT(dev, dct, 0x27c, dword);
++
++      /* 2.10.5.8.6.1.2 */
++      dword = Get_NB32_DCT(dev, dct, 0x270);
++      dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
++//    dword |= (0x55555);
++      dword |= (0x44443);                             /* Use AGESA seed */
++      Set_NB32_DCT(dev, dct, 0x270, dword);
++
++      /* 2.10.5.8.2 (4) */
++      dword = Get_NB32_DCT(dev, dct, 0x260);
++      dword &= ~(0x1fffff);                           /* CmdCount = 192 */
++      dword |= 192;
++      Set_NB32_DCT(dev, dct, 0x260, dword);
++
++#if 0
++      /* TODO: This applies to Fam15h model 10h and above only */
++      /* Program Bubble Count and CmdStreamLen */
++      dword = Get_NB32_DCT(dev, dct, 0x25c);
++      dword &= ~(0x3ff << 12);                        /* BubbleCnt = 0 */
++      dword &= ~(0x3ff << 22);                        /* BubbleCnt2 = 0 */
++      dword &= ~(0xff);                               /* CmdStreamLen = 1 */
++      dword |= 0x1;
++      Set_NB32_DCT(dev, dct, 0x25c, dword);
++#endif
++
++      /* Configure Target A */
++      dword = Get_NB32_DCT(dev, dct, 0x254);
++      dword &= ~(0x7 << 24);                          /* TgtChipSelect = 
Receiver */
++      dword |= (Receiver & 0x7) << 24;
++      dword &= ~(0x7 << 21);                          /* TgtBank = 0 */
++      dword &= ~(0x3ff);                              /* TgtAddress = 0 */
++      Set_NB32_DCT(dev, dct, 0x254, dword);
++
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
++      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
++      dword &= ~(0x3 << 8);                           /* CmdTgt = 0 (Target 
A) */
++      dword &= ~(0x7 << 5);                           /* CmdType = 0 (Read) */
++      dword |= (0x1 << 11);                           /* SendCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x250);
++      } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
++
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword &= ~(0x1 << 11);                          /* SendCmd = 0 */
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++
++      /* 2.10.5.8.6.1.1 Send Precharge Command */
++      /* Wait 25 MEMCLKs. */
++      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
++
++      dword = Get_NB32_DCT(dev, dct, 0x28c);
++      dword &= ~(0xff << 22);                         /* CmdChipSelect = 
Receiver */
++      dword |= ((0x1 << Receiver) << 22);
++      dword &= ~(0x7 << 19);                          /* CmdBank = 0 */
++      dword &= ~(0x3ffff);                            /* CmdAddress = 0x400 */
++      dword |= 0x400;
++      dword |= (0x1 << 30);                           /* SendPchgCmd = 1 */
++      Set_NB32_DCT(dev, dct, 0x28c, dword);
++
++      /* Wait for SendPchgCmd == 0 */
++      do {
++              dword = Get_NB32_DCT(dev, dct, 0x28c);
++      } while (dword & (0x1 << 30));
++
++      /* Wait 25 MEMCLKs. */
++      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
++
++      /* Set CmdTestEnable = 0 */
++      dword = Get_NB32_DCT(dev, dct, 0x250);
++      dword &= ~(0x1 << 2);
++      Set_NB32_DCT(dev, dct, 0x250, dword);
++}
++
++/* DQS Receiver Enable Training (Family 15h)
++ * Algorithm detailed in:
++ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2
++ * This algorithm runs once at the lowest supported MEMCLK,
++ * then once again at the highest supported MEMCLK.
++ */
++static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, u8 Pass)
++{
++      u8 Channel;
++      u8 _2Ranks;
++      u8 Addl_Index = 0;
++      u8 Receiver;
++      u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
++      u32 Errors;
++
++      u32 val;
++      u32 dev;
++      u32 index_reg;
++      u32 ch_start, ch_end, ch;
++      u32 msr;
++      u32 cr4;
++      u32 lo, hi;
++
++      uint32_t dword;
++      uint8_t dimm;
++      uint8_t rank;
++      uint8_t lane;
++      uint8_t mem_clk;
++      uint16_t initial_seed;
++      uint16_t current_total_delay[MAX_BYTE_LANES];
++      uint16_t dqs_ret_pass1_total_delay[MAX_BYTE_LANES];
++      uint16_t rank0_current_total_delay[MAX_BYTE_LANES];
++      uint16_t phase_recovery_delays[MAX_BYTE_LANES];
++      uint16_t seed[MAX_BYTE_LANES];
++      uint16_t seed_gross[MAX_BYTE_LANES];
++      uint16_t seed_fine[MAX_BYTE_LANES];
++      uint16_t seed_pre_gross[MAX_BYTE_LANES];
++
++      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
++
++      print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
++      print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
++
++      dev = pDCTstat->dev_dct;
++      index_reg = 0x98;
++      ch_start = 0;
++      ch_end = 2;
++
++      for (ch = ch_start; ch < ch_end; ch++) {
++              uint8_t max_rd_latency = 0x55;
++              uint8_t p_state;
++
++              /* 2.10.5.6 */
++              fam15EnableTrainingMode(pMCTstat, pDCTstat, ch, 1);
++
++              /* 2.10.5.2 */
++              for (p_state = 0; p_state < 3; p_state++) {
++                      val = Get_NB32_DCT_NBPstate(dev, ch, p_state, 0x210);
++                      val &= ~(0x3ff << 22);                  /* MaxRdLatency 
= max_rd_latency */
++                      val |= (max_rd_latency & 0x3ff) << 22;
++                      Set_NB32_DCT_NBPstate(dev, ch, p_state, 0x210, val);
++              }
++      }
++
++      if (Pass != FirstPass) {
++              pDCTstat->DimmTrainFail = 0;
++              pDCTstat->CSTrainFail = ~pDCTstat->CSPresent;
++      }
++
++      cr4 = read_cr4();
++      if(cr4 & ( 1 << 9)) {   /* save the old value */
++              _SSE2 = 1;
++      }
++      cr4 |= (1 << 9);        /* OSFXSR enable SSE2 */
++      write_cr4(cr4);
++
++      msr = HWCR;
++      _RDMSR(msr, &lo, &hi);
++      /* FIXME: Why use SSEDIS */
++      if(lo & (1 << 17)) {    /* save the old value */
++              _Wrap32Dis = 1;
++      }
++      lo |= (1 << 17);        /* HWCR.wrap32dis */
++      lo &= ~(1 << 15);       /* SSEDIS */
++      _WRMSR(msr, lo, hi);    /* Setting wrap32dis allows 64-bit memory 
references in real mode */
++
++      _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
++
++      Errors = 0;
++      dev = pDCTstat->dev_dct;
++
++      for (Channel = 0; Channel < 2; Channel++) {
++              print_debug_dqs("\tTrainRcvEn51: Node ", pDCTstat->Node_ID, 1);
++              print_debug_dqs("\tTrainRcvEn51: Channel ", Channel, 1);
++              pDCTstat->Channel = Channel;
++
++              mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
++
++              Receiver = mct_InitReceiver_D(pDCTstat, Channel);
++              /* There are four receiver pairs, loosely associated with 
chipselects.
++               * This is essentially looping over each DIMM.
++               */
++              for (; Receiver < 8; Receiver += 2) {
++                      Addl_Index = (Receiver >> 1) * 3 + 0x10;
++                      dimm = (Receiver >> 1);
++
++                      print_debug_dqs("\t\tTrainRcvEnd52: index ", 
Addl_Index, 2);
++
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
++                              continue;
++                      }
++
++                      /* Retrieve the total delay values from pass 1 of DQS 
receiver enable training */
++                      if (Pass != FirstPass) {
++                              
read_dqs_receiver_enable_control_registers(dqs_ret_pass1_total_delay, dev, 
Channel, dimm, index_reg);
++                      }
++
++                      /* 2.10.5.8.2
++                       * Loop over all ranks
++                       */
++                      if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver+1))
++                              _2Ranks = 1;
++                      else
++                              _2Ranks = 0;
++                      for (rank = 0; rank < (_2Ranks + 1); rank++) {
++                              /* 2.10.5.8.2 (1)
++                               * Specify the target DIMM to be trained
++                               * Set TrNibbleSel = 0
++                               *
++                               * TODO: Add support for x4 DIMMs
++                               */
++                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
++                              dword &= ~(0x3 << 4);           /* TrDimmSel */
++                              dword |= ((dimm & 0x3) << 4);
++                              dword &= ~(0x1 << 2);           /* TrNibbleSel 
*/
++                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
++
++                              /* 2.10.5.8.2 (2)
++                               * Retrieve gross and fine timing fields from 
write DQS registers
++                               */
++                              
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
++
++                              /* 2.10.5.8.2.1
++                               * Generate the DQS Receiver Enable Training 
Seed Values
++                               */
++                              if (Pass == FirstPass) {
++                                      initial_seed = 
fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, 
package_type);
++
++                                      /* Adjust seed for the minimum platform 
supported frequency */
++                                      initial_seed = (uint16_t) 
(((((uint64_t) initial_seed) *
++                                              fam15h_freq_tab[mem_clk] * 100) 
/ (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
++
++                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
++                                              uint16_t wl_pass1_delay;
++                                              wl_pass1_delay = 
current_total_delay[lane];
++
++                                              seed[lane] = initial_seed + 
wl_pass1_delay;
++                                      }
++                              } else {
++                                      uint8_t addr_prelaunch = 0;             
/* TODO: Fetch the correct value from RC2[0] */
++                                      uint16_t register_delay;
++                                      int16_t seed_prescaling;
++
++                                      memcpy(current_total_delay, 
dqs_ret_pass1_total_delay, sizeof(current_total_delay));
++                                      if ((pDCTstat->Status & (1 << 
SB_Registered))) {
++                                              if (addr_prelaunch)
++                                                      register_delay = 0x30;
++                                              else
++                                                      register_delay = 0x20;
++                                      } else if ((pDCTstat->Status & (1 << 
SB_LoadReduced))) {
++                                              /* TODO
++                                              * Load reduced DIMM support 
unimplemented
++                                              */
++                                              register_delay = 0x0;
++                                      } else {
++                                              register_delay = 0x0;
++                                      }
++
++                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
++                                              seed_prescaling = 
current_total_delay[lane] - register_delay - 0x20;
++                                              seed[lane] = (uint16_t) 
(register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 
100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
++                                      }
++                              }
++
++                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                                      seed_gross[lane] = (seed[lane] >> 5) & 
0x1f;
++                                      seed_fine[lane] = seed[lane] & 0x1f;
++
++                                      /*if (seed_gross[lane] == 0)
++                                              seed_pre_gross[lane] = 0;
++                                      else */if (seed_gross[lane] & 0x1)
++                                              seed_pre_gross[lane] = 1;
++                                      else
++                                              seed_pre_gross[lane] = 2;
++
++                                      /* Calculate phase recovery delays */
++                                      phase_recovery_delays[lane] = 
((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
++
++                                      /* Set the gross delay.
++                                       * NOTE: While the BKDG states to only 
program DqsRcvEnGrossDelay, this appears
++                                       * to have been a misprint as 
DqsRcvEnFineDelay should be set to zero as well.
++                                       */
++                                      current_total_delay[lane] = 
((seed_gross[lane] & 0x1f) << 5);
++                              }
++
++                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
++                               * Program PhRecFineDly and PhRecGrossDly
++                               */
++                              
write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, 
Channel, dimm, index_reg);
++
++                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
++                               * Program the DQS Receiver Enable delay values 
for each lane
++                               */
++                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
++
++                              /* 2.10.5.8.2 (3)
++                               * Program DqsRcvTrEn = 1
++                               */
++                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
++                              dword |= (0x1 << 13);
++                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
++
++                              /* 2.10.5.8.2 (4)
++                               * Issue 192 read requests to the target rank
++                               */
++                              
generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, Receiver + (rank & 0x1));
++
++                              /* 2.10.5.8.2 (5)
++                               * Program DqsRcvTrEn = 0
++                               */
++                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
++                              dword &= ~(0x1 << 13);
++                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
++
++                              /* 2.10.5.8.2 (6)
++                               * Read PhRecGrossDly, PhRecFineDly
++                               */
++                              
read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, 
dimm, index_reg);
++
++                              /* 2.10.5.8.2 (7)
++                               * Calculate and program the DQS Receiver 
Enable delay values
++                               */
++                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
++                                      current_total_delay[lane] = 
(phase_recovery_delays[lane] & 0x1f);
++                                      current_total_delay[lane] |= 
((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - 
seed_pre_gross[lane] + 1) << 5);
++                                      if (lane == 8)
++                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
++                                      else
++                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
++                              }
++                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
++
++                              if (rank == 0) {
++                                      /* Back up the Rank 0 delays for later 
use */
++                                      memcpy(rank0_current_total_delay, 
current_total_delay, sizeof(current_total_delay));
++                              }
++
++                              if (rank == 1) {
++                                      /* 2.10.5.8.2 (8)
++                                       * Compute the average delay across 
both ranks and program the result into
++                                       * the DQS Receiver Enable delay 
registers
++                                       */
++                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
++                                              current_total_delay[lane] = 
(rank0_current_total_delay[lane] + current_total_delay[lane]) / 2;
++                                              if (lane == 8)
++                                                      
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
++                                              else
++                                                      
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
++                                      }
++                                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
++                              }
++                      }
++
++#if DQS_TRAIN_DEBUG > 0
++                      for (lane = 0; lane < 8; lane++)
++                              print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
++#endif
++              }
++      }
++
++      /* Calculate and program MaxRdLatency */
++      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel);
+ 
+       if(_DisableDramECC) {
+               mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
+@@ -674,10 +1486,10 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc 
*pDCTstat)
+       }
+ 
+       for (ch=0; ch<ch_end; ch++) {
+-              reg = 0x78 + 0x100 * ch;
+-              val = Get_NB32(dev, reg);
++              reg = 0x78;
++              val = Get_NB32_DCT(dev, ch, reg);
+               val &= ~(1 << DqsRcvEnTrain);
+-              Set_NB32(dev, reg, val);
++              Set_NB32_DCT(dev, ch, reg, val);
+       }
+ }
+ 
+@@ -718,7 +1530,7 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u16 RcvrEnDly,
+               /* get the register index from table */
+               index = Table_DQSRcvEn_Offset[i >> 1];
+               index += Addl_Index;    /* DIMMx DqsRcvEn byte0 */
+-              val = Get_NB32_index_wait(dev, index_reg, index);
++              val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, index);
+               if(i & 1) {
+                       /* odd byte lane */
+                       val &= ~(0x1ff << 16);
+@@ -728,7 +1540,7 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, 
u16 RcvrEnDly,
+                       val &= ~0x1ff;
+                       val |= (RcvrEnDly & 0x1ff);
+               }
+-              Set_NB32_index_wait(dev, index_reg, index, val);
++              Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
+       }
+ 
+ }
+@@ -742,7 +1554,6 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
+       u32 reg;
+       u32 SubTotal;
+       u32 index_reg;
+-      u32 reg_off;
+       u32 val;
+ 
+       uint8_t cpu_val_n;
+@@ -777,17 +1588,16 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
+               Channel = 0;
+ 
+       dev = pDCTstat->dev_dct;
+-      reg_off = 0x100 * Channel;
+-      index_reg = 0x98 + reg_off;
++      index_reg = 0x98;
+ 
+       /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs 
units.*/
+-      val = Get_NB32(dev, 0x88 + reg_off);
++      val = Get_NB32_DCT(dev, Channel, 0x88);
+       SubTotal = ((val & 0x0f) + 4) << 1;     /* SubTotal is 1/2 Memclk unit 
*/
+ 
+       /* If registered DIMMs are being used then
+        *  add 1 MEMCLK to the sub-total.
+        */
+-      val = Get_NB32(dev, 0x90 + reg_off);
++      val = Get_NB32_DCT(dev, Channel, 0x90);
+       if(!(val & (1 << UnBuffDimm)))
+               SubTotal += 2;
+ 
+@@ -795,7 +1605,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
+        *  add 1, else add 2 to the sub-total.
+        *  if (AddrCmdSetup || CsOdtSetup || CkeSetup) then K := K + 2;
+        */
+-      val = Get_NB32_index_wait(dev, index_reg, 0x04);
++      val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04);
+       if(!(val & 0x00202020))
+               SubTotal += 1;
+       else
+@@ -803,7 +1613,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
+ 
+       /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
+        * then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
+-      val = Get_NB32(dev, 0x78 + reg_off);
++      val = Get_NB32_DCT(dev, Channel, 0x78);
+       SubTotal += 8 - (val & 0x0f);
+ 
+       /* Convert bits 7-5 (also referred to as the coarse delay) of
+@@ -824,7 +1634,7 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
+        * clocks (NCLKs)
+        */
+       SubTotal *= 200 * ((Get_NB32(pDCTstat->dev_nbmisc, 0xd4) & 0x1f) + 4);
+-      SubTotal /= freq_tab[((Get_NB32(pDCTstat->dev_dct, 0x94 + reg_off) & 
0x7) - 3)];
++      SubTotal /= freq_tab[((Get_NB32_DCT(pDCTstat->dev_dct, Channel, 0x94) & 
0x7) - 3)];
+       SubTotal = (SubTotal + (2 - 1)) / 2;    /* Round up */
+ 
+       /* Add "N" NCLKs to the sub-total. "N" represents part of the
+@@ -841,13 +1651,13 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc 
*pDCTstat, u8 Channel, u16 D
+       /* Program the F2x[1, 0]78[MaxRdLatency] register with
+        * the total delay value (in NCLKs).
+        */
+-      reg = 0x78 + reg_off;
+-      val = Get_NB32(dev, reg);
++      reg = 0x78;
++      val = Get_NB32_DCT(dev, Channel, reg);
+       val &= ~(0x3ff << 22);
+       val |= (SubTotal & 0x3ff) << 22;
+ 
+       /* program MaxRdLatency to correspond with current delay */
+-      Set_NB32(dev, reg, val);
++      Set_NB32_DCT(dev, Channel, reg, val);
+ }
+ 
+ static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
+@@ -877,7 +1687,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+       u32 dword;
+       u8 dn = 4; /* TODO: Rev C could be 4 */
+       u32 dev = pDCTstat->dev_dct;
+-      u32 index_reg = 0x98 + 0x100 * Channel;
++      u32 index_reg = 0x98;
+ 
+       /* FIXME: add Cx support */
+       dword = 0x00000000;
+@@ -885,7 +1695,7 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+               for(j=0; j<dn; j++)
+                       /* DIMM0 Write Data Timing Low */
+                       /* DIMM0 Write ECC Timing */
+-                      Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, 
dword);
++                      Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 
0x100 * j, dword);
+       }
+ 
+       /* errata #180 */
+@@ -893,13 +1703,13 @@ static void InitDQSPos4RcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+       for(i=5; i<=6; i++) {
+               for(j=0; j<dn; j++)
+                       /* DIMM0 Read DQS Timing Control Low */
+-                      Set_NB32_index_wait(dev, index_reg, i + 0x100 * j, 
dword);
++                      Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 
0x100 * j, dword);
+       }
+ 
+       dword = 0x0000002f;
+       for(j=0; j<dn; j++)
+               /* DIMM0 Read DQS ECC Timing Control */
+-              Set_NB32_index_wait(dev, index_reg, 7 + 0x100 * j, dword);
++              Set_NB32_index_wait_DCT(dev, Channel, index_reg, 7 + 0x100 * j, 
dword);
+ }
+ 
+ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel)
+@@ -912,13 +1722,13 @@ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, 
u8 Channel)
+       u32 val;
+ 
+       dev = pDCTstat->dev_dct;
+-      index_reg = 0x98 + Channel * 0x100;
++      index_reg = 0x98;
+       index = 0x12;
+       p = pDCTstat->CH_D_BC_RCVRDLY[Channel];
+       print_debug_dqs("\t\tSetEccDQSRcvrPos: Channel ", Channel,  2);
+       for(ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
+               val = p[ChipSel>>1];
+-              Set_NB32_index_wait(dev, index_reg, index, val);
++              Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
+               print_debug_dqs_pair("\t\tSetEccDQSRcvrPos: ChipSel ",
+                                       ChipSel, " rcvr_delay ",  val, 2);
+               index += 3;
+@@ -1002,95 +1812,305 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
+       u8 Node = 0;
+       struct DCTStatStruc *pDCTstat;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       /* FIXME: skip for Ax */
+-      while (Node < MAX_NODES_SUPPORTED) {
++      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
++              if (!pDCTstat->NodePresent)
++                      continue;
++
++              if (pDCTstat->DCTSysLimit) {
++                      if (is_fam15h()) {
++                              /* Fam15h BKDG v3.14 section 2.10.5.3.3
++                               * This picks up where InitDDRPhy left off
++                               */
++                              uint8_t dct;
++                              uint8_t index;
++                              uint32_t dword;
++                              uint32_t datc_backup;
++                              uint32_t training_dword;
++                              uint32_t fence2_config_dword;
++                              uint32_t fence_tx_pad_config_dword;
++                              uint32_t index_reg = 0x98;
++                              uint32_t dev = pDCTstat->dev_dct;
++
++                              for (dct = 0; dct < 2; dct++) {
++                                      if (!pDCTstat->DIMMValidDCT[dct])
++                                              continue;
++
++                                      /* Back up D18F2x9C_x0000_0004_dct[1:0] 
*/
++                                      datc_backup = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004);
++
++                                      /* FenceTrSel = 0x2 */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x00000008);
++                                      dword &= ~(0x3 << 6);
++                                      dword |= (0x2 << 6);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000008, dword);
++
++                                      /* Set phase recovery seed values */
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000050, 0x13131313);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000051, 0x13131313);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000052, 0x00000013);
++
++                                      training_dword = 
fenceDynTraining_D(pMCTstat, pDCTstat, dct);
++
++                                      /* Save calculated fence value to the 
TX DLL */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
++                                      dword &= ~(0x1f << 26);
++                                      dword |= ((training_dword & 0x1f) << 
26);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0000000c, dword);
++
++                                      /* 
D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x1 */
++                                      for (index = 0; index < 0x9; index++) {
++                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
++                                              dword &= ~(0x7 << 12);
++                                              dword |= (0x1 << 12);
++                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f000f | (index << 8), dword);
++                                      }
++
++                                      /* FenceTrSel = 0x1 */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x00000008);
++                                      dword &= ~(0x3 << 6);
++                                      dword |= (0x1 << 6);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000008, dword);
++
++                                      /* Set phase recovery seed values */
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000050, 0x13131313);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000051, 0x13131313);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000052, 0x00000013);
++
++                                      training_dword = 
fenceDynTraining_D(pMCTstat, pDCTstat, dct);
++
++                                      /* Save calculated fence value to the 
RX DLL */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
++                                      dword &= ~(0x1f << 21);
++                                      dword |= ((training_dword & 0x1f) << 
21);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0000000c, dword);
++
++                                      /* 
D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x0 */
++                                      for (index = 0; index < 0x9; index++) {
++                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
++                                              dword &= ~(0x7 << 12);
++                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f000f | (index << 8), dword);
++                                      }
++
++                                      /* FenceTrSel = 0x3 */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x00000008);
++                                      dword &= ~(0x3 << 6);
++                                      dword |= (0x3 << 6);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000008, dword);
++
++                                      /* Set phase recovery seed values */
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000050, 0x13131313);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000051, 0x13131313);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000052, 0x00000013);
++
++                                      fence_tx_pad_config_dword = 
fenceDynTraining_D(pMCTstat, pDCTstat, dct);
++
++                                      /* Save calculated fence value to the 
TX Pad */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
++                                      dword &= ~(0x1f << 16);
++                                      dword |= ((fence_tx_pad_config_dword & 
0x1f) << 16);
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0000000c, dword);
++
++                                      /* Program 
D18F2x9C_x0D0F_[C,8,2][2:0]31_dct[1:0] */
++                                      training_dword = 
fence_tx_pad_config_dword;
++                                      if (fence_tx_pad_config_dword < 16)
++                                              training_dword |= (0x1 << 4);
++                                      else
++                                              training_dword = 0;
++                                      for (index = 0; index < 0x3; index++) {
++                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2031 | (index << 8));
++                                              dword &= ~(0x1f);
++                                              dword |= (training_dword & 
0x1f);
++                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f2031 | (index << 8), dword);
++                                      }
++                                      for (index = 0; index < 0x3; index++) {
++                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8031 | (index << 8));
++                                              dword &= ~(0x1f);
++                                              dword |= (training_dword & 
0x1f);
++                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f8031 | (index << 8), dword);
++                                      }
++                                      for (index = 0; index < 0x3; index++) {
++                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc031 | (index << 8));
++                                              dword &= ~(0x1f);
++                                              dword |= (training_dword & 
0x1f);
++                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0fc031 | (index << 8), dword);
++                                      }
++
++                                      /* Assemble Fence2 configuration word 
(Fam15h BKDG v3.14 page 331) */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0000000c);
++                                      fence2_config_dword = 0;
++
++                                      /* TxPad */
++                                      training_dword = (dword >> 16) & 0x1f;
++                                      if (training_dword < 16)
++                                              training_dword |= 0x10;
++                                      else
++                                              training_dword = 0;
++                                      fence2_config_dword |= training_dword;
++
++                                      /* RxDll */
++                                      training_dword = (dword >> 21) & 0x1f;
++                                      if (training_dword < 16)
++                                              training_dword |= 0x10;
++                                      else
++                                              training_dword = 0;
++                                      fence2_config_dword |= (training_dword 
<< 10);
++
++                                      /* TxDll */
++                                      training_dword = (dword >> 26) & 0x1f;
++                                      if (training_dword < 16)
++                                              training_dword |= 0x10;
++                                      else
++                                              training_dword = 0;
++                                      fence2_config_dword |= (training_dword 
<< 5);
++
++                                      /* Program 
D18F2x9C_x0D0F_0[F,8:0]31_dct[1:0] */
++                                      for (index = 0; index < 0x9; index++) {
++                                              dword = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0031 | (index << 8));
++                                              dword &= ~(0x7fff);
++                                              dword |= fence2_config_dword;
++                                              Set_NB32_index_wait_DCT(dev, 
dct, index_reg, 0x0d0f0031 | (index << 8), dword);
++                                      }
+ 
+-              if(pDCTstat->DCTSysLimit) {
+-                      fenceDynTraining_D(pMCTstat, pDCTstat, 0);
+-                      fenceDynTraining_D(pMCTstat, pDCTstat, 1);
++                                      /* Restore D18F2x9C_x0000_0004_dct[1:0] 
*/
++                                      Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000004, datc_backup);
++                              }
++                      } else {
++                              fenceDynTraining_D(pMCTstat, pDCTstat, 0);
++                              fenceDynTraining_D(pMCTstat, pDCTstat, 1);
++                      }
+               }
+-              Node++;
+       }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+-static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
++static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+       u16 avRecValue;
+       u32 val;
+       u32 dev;
+-      u32 index_reg = 0x98 + 0x100 * dct;
++      u32 index_reg = 0x98;
+       u32 index;
+ 
+-      /* BIOS first programs a seed value to the phase recovery engine
+-       *  (recommended 19) registers.
+-       * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
+-       * F2x[1,0]9C_x52.) .
+-       */
+       dev = pDCTstat->dev_dct;
+-      for (index = 0x50; index <= 0x52; index ++) {
+-              val = (FenceTrnFinDlySeed & 0x1F);
+-              if (index != 0x52) {
+-                      val |= val << 8 | val << 16 | val << 24;
++
++      if (is_fam15h()) {
++              /* Set F2x[1,0]9C_x08[PhyFenceTrEn] */
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
++              val |= 1 << PhyFenceTrEn;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
++
++              /* Wait 2000 MEMCLKs */
++              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 2000);
++
++              /* Clear F2x[1,0]9C_x08[PhyFenceTrEn] */
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
++              val &= ~(1 << PhyFenceTrEn);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
++
++              /* BIOS reads the phase recovery engine registers
++               * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52.
++               * Average the fine delay components only.
++               */
++              avRecValue = 0;
++              for (index = 0x50; index <= 0x52; index++) {
++                      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
index);
++                      avRecValue += val & 0x1f;
++                      if (index != 0x52) {
++                              avRecValue += (val >> 8) & 0x1f;
++                              avRecValue += (val >> 16) & 0x1f;
++                              avRecValue += (val >> 24) & 0x1f;
++                      }
+               }
+-              Set_NB32_index_wait(dev, index_reg, index, val);
+-      }
+ 
+-      /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
+-      val = Get_NB32_index_wait(dev, index_reg, 0x08);
+-      val |= 1 << PhyFenceTrEn;
+-      Set_NB32_index_wait(dev, index_reg, 0x08, val);
+-
+-      /* Wait 200 MEMCLKs. */
+-      mct_Wait(50000);                /* wait 200us */
+-
+-      /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
+-      val = Get_NB32_index_wait(dev, index_reg, 0x08);
+-      val &= ~(1 << PhyFenceTrEn);
+-      Set_NB32_index_wait(dev, index_reg, 0x08, val);
+-
+-      /* BIOS reads the phase recovery engine registers
+-       * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
+-      avRecValue = 0;
+-      for (index = 0x50; index <= 0x52; index ++) {
+-              val = Get_NB32_index_wait(dev, index_reg, index);
+-              avRecValue += val & 0x7F;
+-              if (index != 0x52) {
+-                      avRecValue += (val >> 8) & 0x7F;
+-                      avRecValue += (val >> 16) & 0x7F;
+-                      avRecValue += (val >> 24) & 0x7F;
++              val = avRecValue / 9;
++              if (avRecValue % 9)
++                      val++;
++              avRecValue = val;
++
++              if (avRecValue < 6)
++                      avRecValue = 0;
++              else
++                      avRecValue -= 6;
++
++              return avRecValue;
++      } else {
++              /* BIOS first programs a seed value to the phase recovery engine
++               *  (recommended 19) registers.
++               * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
++               * F2x[1,0]9C_x52.) .
++               */
++              for (index = 0x50; index <= 0x52; index ++) {
++                      val = (FenceTrnFinDlySeed & 0x1F);
++                      if (index != 0x52) {
++                              val |= val << 8 | val << 16 | val << 24;
++                      }
++                      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, 
val);
+               }
+-      }
+ 
+-      val = avRecValue / 9;
+-      if (avRecValue % 9)
+-              val++;
+-      avRecValue = val;
++              /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
++              val |= 1 << PhyFenceTrEn;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
++
++              /* Wait 200 MEMCLKs. */
++              mct_Wait(50000);                /* wait 200us */
++
++              /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
++              val &= ~(1 << PhyFenceTrEn);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
++
++              /* BIOS reads the phase recovery engine registers
++               * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
++              avRecValue = 0;
++              for (index = 0x50; index <= 0x52; index ++) {
++                      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
index);
++                      avRecValue += val & 0x7F;
++                      if (index != 0x52) {
++                              avRecValue += (val >> 8) & 0x7F;
++                              avRecValue += (val >> 16) & 0x7F;
++                              avRecValue += (val >> 24) & 0x7F;
++                      }
++              }
+ 
+-      /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
+-      /* inlined mct_AdjustFenceValue() */
+-      /* TODO: The RBC0 is not supported. */
+-      /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
+-              avRecValue -= 3;
+-      else
+-      */
+-      if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
+-              avRecValue -= 8;
+-      else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
+-              avRecValue -= 8;
+-      else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
+-              avRecValue -= 8;
+-
+-      val = Get_NB32_index_wait(dev, index_reg, 0x0C);
+-      val &= ~(0x1F << 16);
+-      val |= (avRecValue & 0x1F) << 16;
+-      Set_NB32_index_wait(dev, index_reg, 0x0C, val);
+-
+-      /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control Register
+-       * delays (both channels). */
+-      val = Get_NB32_index_wait(dev, index_reg, 0x04);
+-      Set_NB32_index_wait(dev, index_reg, 0x04, val);
++              val = avRecValue / 9;
++              if (avRecValue % 9)
++                      val++;
++              avRecValue = val;
++
++              /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
++              /* inlined mct_AdjustFenceValue() */
++              /* TODO: The RBC0 is not supported. */
++              /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
++                      avRecValue -= 3;
++              else
++              */
++              if (pDCTstat->LogicalCPUID & AMD_DR_Dx)
++                      avRecValue -= 8;
++              else if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
++                      avRecValue -= 8;
++              else if (pDCTstat->LogicalCPUID & AMD_DR_Bx)
++                      avRecValue -= 8;
++
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C);
++              val &= ~(0x1F << 16);
++              val |= (avRecValue & 0x1F) << 16;
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C, val);
++
++              /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control 
Register
++               * delays (both channels).
++               */
++              val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x04);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x04, val);
++
++              return avRecValue;
++      }
+ }
+ 
+ void mct_Wait(u32 cycles)
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
+index f01e011..55068ce 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
+@@ -21,8 +21,14 @@
+ u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass)
+ {
+       u8 ret = 1;
+-      if (pass == SecondPass)
+-              ret = 0;
++
++      if (is_fam15h()) {
++              /* Fam15h needs two passes */
++              ret = 1;
++      } else {
++              if (pass == SecondPass)
++                      ret = 0;
++      }
+ 
+       return ret;
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
+index 920f514..68acc75 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
+@@ -218,12 +218,12 @@ static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc 
*pDCTstat,
+       }
+ 
+       dev = pDCTstat->dev_dct;
+-      reg = 0x78 + Channel * 0x100;
+-      val = Get_NB32(dev, reg);
++      reg = 0x78;
++      val = Get_NB32_DCT(dev, Channel, reg);
+       val &= ~(0x3ff<<22);
+       val |= MaxRdLatVal<<22;
+       /* program MaxRdLatency to correspond with current delay */
+-      Set_NB32(dev, reg, val);
++      Set_NB32_DCT(dev, Channel, reg, val);
+ }
+ 
+ static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr)
+@@ -320,30 +320,28 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
+       u32 valx;
+       u32 valxx;
+       u32 index_reg;
+-      u32 reg_off;
+       u32 dev;
+ 
+       if(pDCTstat->GangedMode)
+               Channel =  0;
+ 
+-      index_reg = 0x98 + 0x100 * Channel;
++      index_reg = 0x98;
+ 
+-      reg_off = 0x100 * Channel;
+       dev = pDCTstat->dev_dct;
+ 
+       /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs 
units.*/
+-      val = Get_NB32(dev, 0x88 + reg_off);
++      val = Get_NB32_DCT(dev, Channel, 0x88);
+       SubTotal = ((val & 0x0f) + 1) << 1;     /* SubTotal is 1/2 Memclk unit 
*/
+ 
+       /* If registered DIMMs are being used then add 1 MEMCLK to the 
sub-total*/
+-      val = Get_NB32(dev, 0x90 + reg_off);
++      val = Get_NB32_DCT(dev, Channel, 0x90);
+       if(!(val & (1 << UnBuffDimm)))
+               SubTotal += 2;
+ 
+       /*If the address prelaunch is setup for 1/2 MEMCLKs then add 1,
+        *  else add 2 to the sub-total. if (AddrCmdSetup || CsOdtSetup
+        *  || CkeSetup) then K := K + 2; */
+-      val = Get_NB32_index_wait(dev, index_reg, 0x04);
++      val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04);
+       if(!(val & 0x00202020))
+               SubTotal += 1;
+       else
+@@ -351,7 +349,7 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
+ 
+       /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
+        *  then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
+-      val = Get_NB32(dev, 0x78 + reg_off);
++      val = Get_NB32_DCT(dev, Channel, 0x78);
+       SubTotal += 8 - (val & 0x0f);
+ 
+       /* Convert bits 7-5 (also referred to as the course delay) of the 
current
+@@ -367,7 +365,7 @@ u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
+ 
+       /*New formula:
+       SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
+-      val = Get_NB32(dev, 0x94 + reg_off);
++      val = Get_NB32_DCT(dev, Channel, 0x94);
+       /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
+       val &= 7;
+       if (val >= 3) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+index 1c3e322..0ff4484 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+@@ -83,6 +83,12 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
+               pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 0;
+       }
+ 
++      if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++              pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED] = 1;
++      } else {
++              pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED] = 0;
++      }
++
+       pDCTstat->C_DCTPtr[dct]->RegMan1Present = pDCTstat->RegMan1Present;
+ 
+       for (dimm = 0; dimm < MAX_TOTAL_DIMMS; dimm++) {
+@@ -103,13 +109,13 @@ void EnableZQcalibration(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDC
+ {
+       u32 val;
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x94);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+       val |= 1 << 11;
+-      Set_NB32(pDCTstat->dev_dct, 0x94, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+       val |= 1 << 11;
+-      Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
+ }
+ 
+ void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
+@@ -117,15 +123,15 @@ void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
+ {
+       u32 val;
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x94);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+       val &= ~(1 << 11);
+       val &= ~(1 << 10);
+-      Set_NB32(pDCTstat->dev_dct, 0x94, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
+ 
+-      val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
++      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+       val &= ~(1 << 11);
+       val &= ~(1 << 10);
+-      Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
++      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
+ }
+ 
+ static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
+@@ -142,23 +148,23 @@ static void EnterSelfRefresh(struct MCTStatStruc 
*pMCTstat,
+ 
+       /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
+       if (DCT0Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x90);
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
+               val |= 1 << EnterSelfRef;
+-              Set_NB32(pDCTstat->dev_dct, 0x90, val);
++              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
+       }
+       if (DCT1Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
+               val |= 1 << EnterSelfRef;
+-              Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
++              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
+       }
+       /* Wait until the hardware resets F2x[1, 0]90[EnterSelfRefresh]=0. */
+       if (DCT0Present)
+               do {
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x90);
++                      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
+               } while (val & (1 <<EnterSelfRef));
+       if (DCT1Present)
+               do {
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
++                      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
+               } while (val & (1 <<EnterSelfRef));
+ }
+ 
+@@ -168,8 +174,11 @@ static void EnterSelfRefresh(struct MCTStatStruc 
*pMCTstat,
+ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+ {
+-      u8 DCT0Present, DCT1Present;
+-      u32 val;
++      uint8_t DCT0Present;
++      uint8_t DCT1Present;
++      uint32_t dword;
++      uint32_t mask;
++      uint32_t offset;
+ 
+       DCT0Present = pDCTstat->DIMMValidDCT[0];
+       if (pDCTstat->GangedMode)
+@@ -177,76 +186,134 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+       else
+               DCT1Present = pDCTstat->DIMMValidDCT[1];
+ 
+-      /* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
+-      if (DCT0Present) {
+-              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
+-              val |= 1 << DisAutoComp;
+-              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
+-      }
+-      if (DCT1Present) {
+-              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
+-              val |= 1 << DisAutoComp;
+-              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
++      if (is_fam15h()) {
++              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0x190 */
++              if (DCT0Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 0x0d0fe006);
++                      dword &= ~(0x0000ffff);
++                      dword |= 0x00000190;
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 
0x0d0fe006, dword);
++              }
++              if (DCT1Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 0x0d0fe006);
++                      dword &= ~(0x0000ffff);
++                      dword |= 0x00000190;
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 
0x0d0fe006, dword);
++              }
++      } else {
++              /* Program F2x[1, 0]9C[DisAutoComp]=1. */
++              if (DCT0Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 8);
++                      dword |= 1 << DisAutoComp;
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8, 
dword);
++                      mct_Wait(100);  /* Wait for 5us */
++              }
++              if (DCT1Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 8);
++                      dword |= 1 << DisAutoComp;
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8, 
dword);
++                      mct_Wait(100);  /* Wait for 5us */
++              }
+       }
+ 
+       /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
+       if (DCT0Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94);
+-              val &= ~(1 << MemClkFreqVal);
+-              Set_NB32(pDCTstat->dev_dct, 0x94, val);
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
++              dword &= ~(1 << MemClkFreqVal);
++              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
+       }
+       if (DCT1Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+-              val &= ~(1 << MemClkFreqVal);
+-              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
++              dword &= ~(1 << MemClkFreqVal);
++              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
+       }
+ 
+       /* Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK 
frequency. */
++      if (is_fam15h()) {
++              offset = 0x0;
++              mask = 0x1f;
++      } else {
++              offset = 0x1;
++              mask = 0x7;
++      }
+       if (DCT0Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94);
+-              val &= 0xFFFFFFF8;
+-              val |= pDCTstat->TargetFreq - 1;
+-              Set_NB32(pDCTstat->dev_dct, 0x94, val);
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
++              dword &= ~mask;
++              dword |= (pDCTstat->TargetFreq - offset) & mask;
++              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
+       }
+       if (DCT1Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+-              val &= 0xFFFFFFF8;
+-              val |= pDCTstat->TargetFreq - 1;
+-              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
++              dword &= ~mask;
++              dword |= (pDCTstat->TargetFreq - offset) & mask;
++              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
++      }
++
++      if (is_fam15h()) {
++              if (DCT0Present) {
++                      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 0);
++                      set_2t_configuration(pMCTstat, pDCTstat, 0);
++                      mct_BeforePlatformSpec(pMCTstat, pDCTstat, 0);
++                      mct_PlatformSpec(pMCTstat, pDCTstat, 0);
++              }
++              if (DCT1Present) {
++                      mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1);
++                      set_2t_configuration(pMCTstat, pDCTstat, 1);
++                      mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1);
++                      mct_PlatformSpec(pMCTstat, pDCTstat, 1);
++              }
+       }
+ 
+       /* Program F2x[1, 0]94[MemClkFreqVal] = 1. */
+       if (DCT0Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94);
+-              val |= 1 << MemClkFreqVal;
+-              Set_NB32(pDCTstat->dev_dct, 0x94, val);
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
++              dword |= 1 << MemClkFreqVal;
++              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, dword);
+       }
+       if (DCT1Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+-              val |= 1 << MemClkFreqVal;
+-              Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
++              dword |= 1 << MemClkFreqVal;
++              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, dword);
+       }
+ 
+       /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
+       if (DCT0Present)
+               do {
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x94);
+-              } while (val & (1 << FreqChgInProg));
++                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
++              } while (dword & (1 << FreqChgInProg));
+       if (DCT1Present)
+               do {
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
+-              } while (val & (1 << FreqChgInProg));
+-
+-      /* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
+-      if (DCT0Present) {
+-              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
+-              val &= ~(1 << DisAutoComp);
+-              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
+-      }
+-      if (DCT1Present) {
+-              val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
+-              val &= ~(1 << DisAutoComp);
+-              Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
++                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
++              } while (dword & (1 << FreqChgInProg));
++
++      if (is_fam15h()) {
++              /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0xf */
++              if (DCT0Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 0x0d0fe006);
++                      dword &= ~(0x0000ffff);
++                      dword |= 0x0000000f;
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 
0x0d0fe006, dword);
++              }
++              if (DCT1Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 0x0d0fe006);
++                      dword &= ~(0x0000ffff);
++                      dword |= 0x0000000f;
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 
0x0d0fe006, dword);
++              }
++      } else {
++              /* Program F2x[1, 0]9C[DisAutoComp] = 0. */
++              if (DCT0Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 
0x98, 8);
++                      dword &= ~(1 << DisAutoComp);
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 8, 
dword);
++                      mct_Wait(15000);        /* Wait for 750us */
++              }
++              if (DCT1Present) {
++                      dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 
0x98, 8);
++                      dword &= ~(1 << DisAutoComp);
++                      Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 1, 0x98, 8, 
dword);
++                      mct_Wait(15000);        /* Wait for 750us */
++              }
+       }
+ }
+ 
+@@ -267,29 +334,46 @@ static void ExitSelfRefresh(struct MCTStatStruc 
*pMCTstat,
+ 
+       /* Program F2x[1, 0]90[ExitSelfRef]=1 for both DCTs. */
+       if (DCT0Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x90);
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
+               val |= 1 << ExitSelfRef;
+-              Set_NB32(pDCTstat->dev_dct, 0x90, val);
++              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
+       }
+       if (DCT1Present) {
+-              val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
+               val |= 1 << ExitSelfRef;
+-              Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
++              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
+       }
+       /* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0. */
+       if (DCT0Present)
+               do {
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x90);
++                      val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
+               } while (val & (1 << ExitSelfRef));
+       if (DCT1Present)
+               do {
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
++                      val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
+               } while (val & (1 << ExitSelfRef));
+ }
+ 
+ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+ {
++      uint32_t dword;
++      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++      if (is_fam15h()) {
++              /* Program F2x[1, 0]90[DisDllShutDownSR]=1. */
++              if (pDCTstat->DIMMValidDCT[0]) {
++                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
++                      dword |= (0x1 << 27);
++                      Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, dword);
++              }
++              if (pDCTstat->DIMMValidDCT[1]) {
++                      dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
++                      dword |= (0x1 << 27);
++                      Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, dword);
++              }
++      }
++
+       /* Program F2x[1,0]90[EnterSelfRefresh]=1.
+        * Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
+        */
+@@ -305,11 +389,38 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+        */
+       ChangeMemClk(pMCTstat, pDCTstat);
+ 
++      if (is_fam15h()) {
++              uint8_t dct;
++              for (dct = 0; dct < 2; dct++) {
++                      if (pDCTstat->DIMMValidDCT[dct]) {
++                              phyAssistedMemFnceTraining(pMCTstat, pDCTstat);
++                              InitPhyCompensation(pMCTstat, pDCTstat, dct);
++                      }
++              }
++      }
++
+       /* Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
+        * Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
+        */
+       ExitSelfRefresh(pMCTstat, pDCTstat);
+ 
++      if (is_fam15h()) {
++              if ((package_type == PT_C3) || (package_type == PT_GR)) {
++                      /* Socket C32 or G34 */
++                      /* Program F2x[1, 0]90[DisDllShutDownSR]=0. */
++                      if (pDCTstat->DIMMValidDCT[0]) {
++                              dword = Get_NB32_DCT(pDCTstat->dev_dct, 0, 
0x90);
++                              dword &= ~(0x1 << 27);
++                              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, dword);
++                      }
++                      if (pDCTstat->DIMMValidDCT[1]) {
++                              dword = Get_NB32_DCT(pDCTstat->dev_dct, 1, 
0x90);
++                              dword &= ~(0x1 << 27);
++                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, dword);
++                      }
++              }
++      }
++
+       /* wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns */
+       mct_Wait(250);
+ 
+@@ -336,13 +447,13 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+ static void Modify_OnDimmMirror(struct DCTStatStruc *pDCTstat, u8 dct, u8 set)
+ {
+       u32 val;
+-      u32 reg_off = dct * 0x100 + 0x44;
+-      while (reg_off < (dct * 0x100 + 0x60)) {
+-              val = Get_NB32(pDCTstat->dev_dct, reg_off);
++      u32 reg = 0x44;
++      while (reg < 0x60) {
++              val = Get_NB32_DCT(pDCTstat->dev_dct, dct, reg);
+               if (val & (1 << CSEnable))
+                       set ? (val |= 1 << onDimmMirror) : (val &= 
~(1<<onDimmMirror));
+-              Set_NB32(pDCTstat->dev_dct, reg_off, val);
+-              reg_off += 8;
++              Set_NB32_DCT(pDCTstat->dev_dct, dct, reg, val);
++              reg += 8;
+       }
+ }
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 397fd77..35378c8 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -30,13 +30,22 @@
+  *
+  *----------------------------------------------------------------------------
+  */
+-u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue);
+-u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue);
+-void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL 
wl);
+-void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm);
+-void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass);
+-void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 
targetAddr);
+-void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm);
++u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
MRSValue);
++u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
MRSValue);
++void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++      u8 dct, u8 dimm, BOOL wl);
++void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm);
++void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass);
++void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, u8 targetAddr, uint8_t pass);
++void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass);
++
++static int32_t abs(int32_t val) {
++      if (val < 0)
++              val *= -1;
++
++      return val;
++}
++
+ /*
+  
*-----------------------------------------------------------------------------
+  *            EXPORTED FUNCTIONS
+@@ -62,34 +71,55 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 
dimm);
+  *       OUT
+  
*-----------------------------------------------------------------------------
+  */
+-void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
+-              u8 dimm, u8 pass)
++void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++              u8 dct, u8 dimm, u8 pass)
+ {
+       u8 ByteLane;
+       u32 Value, Addr;
+       u16 Addl_Data_Offset, Addl_Data_Port;
++      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ 
+       pDCTData->WLPass = pass;
+       /* 1. Specify the target DIMM that is to be trained by programming
+        * F2x[1, 0]9C_x08[TrDimmSel].
+        */
+-      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
++      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
+-                      TrDimmSelEnd,(u32)dimm);
++                      TrDimmSelEnd, (u32)dimm);
++
++      if (is_fam15h()) {
++              /* Set TrNibbleSel = 0
++               *
++               * TODO: Add support for x4 DIMMs
++               */
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
++                              2, (u32)0);
++      }
++
+       /* 2. Prepare the DIMMs for write levelization using DDR3-defined
+        * MR commands. */
+-      prepareDimms(pMCTData, pDCTData,dimm, TRUE);
++      prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
++
+       /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
+        *    satisfy DDR3-defined internal DRAM timing.
+        */
+-      pMCTData->AgesaDelay(40);
++      if (is_fam15h())
++              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
++      else
++              pMCTData->AgesaDelay(40);
++
+       /* 4. Configure the processor's DDR phy for write levelization 
training: */
+-      procConifg(pMCTData,pDCTData, dimm, pass);
++      procConfig(pMCTstat, pDCTstat, dct, dimm, pass);
++
+       /* 5. Begin write levelization training:
+-       *  Program F2x[1, 0]9C_x08[WrtLevelTrEn]=1. */
+-      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx))
+-              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
++       *  Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
++      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL))
++      {
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, 
WrtLvTrEn, 1);
++      }
+       else
+       {
+               /* Broadcast write to all D3Dbyte chipset register offset 0xc
+@@ -98,7 +128,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
+                * retain value of 3:2 (Trdimmsel)
+                * reset bit 5 (FrzPR)
+                */
+-              if (pDCTData->DctTrain)
++              if (dct)
+               {
+                       Addl_Data_Offset=0x198;
+                       Addl_Data_Port=0x19C;
+@@ -123,29 +153,127 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
+                               DctAccessDone, DctAccessDone)) == 0);
+       }
+ 
++      if (is_fam15h())
++              proc_MFENCE();
++
+       /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
+-      pMCTData->AgesaDelay(140);
++      if (is_fam15h())
++              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 200);
++      else
++              pMCTData->AgesaDelay(140);
++
+       /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
+-      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
++      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
++
+       /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
+        * to get the gross and fine delay settings
+        * for the target DIMM and save these values. */
+-      ByteLane = 0;
+-      while (ByteLane < MAX_BYTE_LANES)
+-      {
+-              getWLByteDelay(pDCTData,ByteLane, dimm);
+-              setWLByteDelay(pDCTData,ByteLane, dimm, 1);
+-              ByteLane++;
++      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
++              getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass);
++      }
++
++      pDCTData->WLCriticalGrossDelayPrevPass = 0x1f;
++}
++
++void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++              u8 dct, u8 dimm, u8 pass)
++{
++      u8 ByteLane;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++
++      if (is_fam15h()) {
++              int32_t gross_diff[MAX_BYTE_LANES];
++              int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
++              uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
++
++              /* Calculate the Critical Gross Delay */
++              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
++                      /* Calculate the gross delay differential for this lane 
*/
++                      gross_diff[ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane] + 
pDCTData->WLGrossDelay[index+ByteLane];
++                      gross_diff[ByteLane] -= 
pDCTData->WLSeedPreGrossDelay[index+ByteLane];
++
++                      /* WrDqDqsEarly values greater than 2 are reserved */
++                      if (gross_diff[ByteLane] < -2)
++                              gross_diff[ByteLane] = -2;
++
++                      /* Update the Critical Gross Delay */
++                      if (gross_diff[ByteLane] < cgd)
++                              cgd = gross_diff[ByteLane];
++              }
++
++              pDCTData->WLCriticalGrossDelayPrevPass = cgd;
++
++              /* Compensate for occasional noise/instability causing sporadic 
training failure */
++              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
++                      uint16_t total_delay_seed = 
((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
++                      uint16_t total_delay_phy = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
++                      if (abs(total_delay_phy - total_delay_seed) > 0x20) {
++                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value\n", __func__);
++                              pDCTData->WLGrossDelay[index+ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane];
++                              pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
++                      }
++              }
++      }
++}
++
++void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++              u8 dct, u8 dimm, u8 pass)
++{
++      u8 ByteLane;
++      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++
++      if (is_fam15h()) {
++              uint32_t dword;
++              int32_t gross_diff[MAX_BYTE_LANES];
++              int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
++              uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
++
++              /* Apply offset(s) if needed */
++              if (cgd < 0) {
++                      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
++                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= abs(cgd) */
++                      dword |= ((abs(cgd) & 0x3) << 24);
++                      Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
++
++                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                              /* Calculate the gross delay differential for 
this lane */
++                              gross_diff[ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane] + 
pDCTData->WLGrossDelay[index+ByteLane];
++                              gross_diff[ByteLane] -= 
pDCTData->WLSeedPreGrossDelay[index+ByteLane];
++
++                              /* Prevent underflow in the presence of noise / 
instability*/
++                              if (gross_diff[ByteLane] < cgd)
++                                      gross_diff[ByteLane] = cgd;
++
++                              pDCTData->WLGrossDelay[index+ByteLane] = 
(gross_diff[ByteLane] + (abs(cgd) & 0x3));
++                      }
++              } else {
++                      dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
++                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= 0 */
++                      Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
++              }
++      }
++
++      /* Write the adjusted gross and fine delay settings
++       * to the target DIMM. */
++      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
++              setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass);
+       }
+ 
+       /* 6. Configure DRAM Phy Control Register so that the phy stops driving
+        *    write levelization ODT. */
+-      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
++      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, 0);
+ 
++      if (is_fam15h())
++              proc_MFENCE();
++
+       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
+-      pMCTData->AgesaDelay(10);
++      if (is_fam15h())
++              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
++      else
++              pMCTData->AgesaDelay(10);
+ 
+       /* 7. Program the target DIMM back to normal operation by configuring
+        * the following (See section 2.8.5.4.1.1
+@@ -155,7 +283,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
+        * For a two DIMM system, program the Rtt value for the target DIMM
+        * to the normal operating termination:
+        */
+-      prepareDimms(pMCTData, pDCTData,dimm,FALSE);
++      prepareDimms(pMCTstat, pDCTstat, dct, dimm, FALSE);
+ }
+ 
+ /*----------------------------------------------------------------------------
+@@ -165,7 +293,7 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
+  */
+ 
+ 
/*-----------------------------------------------------------------------------
+- * u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
++ * u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 
MRSValue)
+  *
+  * Description:
+  *    This function swaps the bits in MSR register value
+@@ -177,12 +305,17 @@ void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData,
+  *
+  * 
----------------------------------------------------------------------------
+  */
+-u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
++u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
MRSValue)
+ {
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+       u32 tempW, tempW1;
+ 
+-      tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+-                      FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
++      if (is_fam15h())
++              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                              FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, 
MrsChipSelEndFam15);
++      else
++              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                      FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, 
MrsChipSelEndFam10);
+       if (tempW1 & 1)
+       {
+               if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
+@@ -201,7 +334,7 @@ u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
+ }
+ 
+ 
/*-----------------------------------------------------------------------------
+- *  u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
++ *  u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
+  *
+  *  Description:
+  *       This function swaps the bits in MSR register value
+@@ -213,12 +346,17 @@ u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
+  *
+  * 
----------------------------------------------------------------------------
+  */
+-u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
++u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
+ {
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+       u32 tempW, tempW1;
+ 
+-      tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+-                      FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
++      if (is_fam15h())
++              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                              FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, 
MrsChipSelEndFam15);
++      else
++              tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                              FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, 
MrsChipSelEndFam10);
+       if (tempW1 & 1)
+       {
+               if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
+@@ -269,7 +407,7 @@ static uint16_t 
unbuffered_dimm_nominal_termination_emrs(uint8_t number_of_dimms
+       return term;
+ }
+ 
+-static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank)
++static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t 
number_of_dimms, uint8_t frequency_index, uint8_t rank_count)
+ {
+       uint16_t term;
+ 
+@@ -300,27 +438,27 @@ static uint16_t 
unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms
+  *
+  *  Description:
+  *       This function prepares DIMMS for training
+- *
+- *   Parameters:
+- *       IN  OUT   *DCTData - Pointer to buffer with information about each 
DCT
+- *             *SPDData - Pointer to buffer with information about each DIMMs
+- *                        SPD information
+- *             *MCTData - Pointer to buffer with runtime parameters,
+- *       IN   Dimm - Logical DIMM number
+- *             WL - indicates if the routine is used for Write levelization
+- *                  training
+- *
+- *       OUT
+- *
++ *       Fam10h: BKDG Rev. 3.62 section 2.8.9.9.1
++ *       Fam15h: BKDG Rev. 3.14 section 2.10.5.8.1
+  * 
----------------------------------------------------------------------------
+  */
+-void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL 
wl)
++void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++      u8 dct, u8 dimm, BOOL wl)
+ {
+       u32 tempW, tempW1, tempW2, MrsBank;
+       u8 rank, currDimm, MemClkFreq;
++      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
+ 
+-      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
++      if (is_fam15h()) {
++              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                      FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
++      } else {
++              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
+                       FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
++      }
+       /* Configure the DCT to send initialization MR commands to the target 
DIMM
+        * by programming the F2x[1,0]7C register using the following steps.
+        */
+@@ -328,52 +466,95 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+       while ((rank < pDCTData->DimmRanks[dimm]) && (rank < 2))
+       {
+               /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank to 
be trained. */
+-              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+-                      DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, dimm*2+rank);
++              if (is_fam15h())
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsChipSelStartFam15, 
MrsChipSelEndFam15, dimm*2+rank);
++              else
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsChipSelStartFam10, 
MrsChipSelEndFam10, dimm*2+rank);
++
+               /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate 
internal DRAM
+                * register that defines the required DDR3-defined function for 
write
+                * levelization.
+                */
+-              MrsBank = swapBankBits(pDCTData,1);
+-              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+-                      DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
++              MrsBank = swapBankBits(pDCTstat, dct, 1);
++              if (is_fam15h())
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, 
MrsBank);
++              else
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, 
MrsBank);
++
+               /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required 
DDR3-defined function
+                * for write levelization.
+                */
+               tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0 */
+ 
+-              /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 
& x4 */
+-              tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+-                              FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
+-              if (tempW2)
+-              {
+-                      if (pDCTData->DimmX8Present[dimm])
+-                              tempW |= 0x800;
++              /* Retrieve normal settings of the MRS control word and clear 
Rtt_Nom */
++              if (is_fam15h()) {
++                      tempW = mct_MR1(pMCTstat, pDCTstat, dct, dimm*2+rank) & 
0xffff;
++                      tempW &= ~(0x0244);
++              } else {
++                      /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when 
mixed x8 & x4 */
++                      tempW2 = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                                      FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, 
RDqsEn);
++                      if (tempW2)
++                      {
++                              if (pDCTData->DimmX8Present[dimm])
++                                      tempW |= 0x800;
++                      }
+               }
+ 
+               /* determine Rtt_Nom for WL & Normal mode */
+-              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+-                      tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, 
wl, MemClkFreq, rank);
+-              } else {
++              if (is_fam15h()) {
+                       if (wl) {
+-                              if (rank == 0) {
+-                                      /* Get Rtt_WR for the current DIMM and 
rank */
+-                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
+-
+-                                      /* Convert dynamic termination code to 
corresponding nominal termination code */
+-                                      if (dynamic_term == 0x200)
+-                                              tempW1 = 0x04;
+-                                      else if (dynamic_term == 0x400)
+-                                              tempW1 = 0x40;
+-                                      else
+-                                              tempW1 = 0x0;
++                              if (number_of_dimms > 1) {
++                                      if (rank == 0) {
++                                              /* Get Rtt_WR for the current 
DIMM and rank */
++                                              tempW2 = fam15_rttwr(pDCTstat, 
dct, dimm, rank, package_type);
++                                      } else {
++                                              tempW2 = fam15_rttnom(pDCTstat, 
dct, dimm, rank, package_type);
++                                      }
+                               } else {
+-                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
++                                      tempW2 = fam15_rttnom(pDCTstat, dct, 
dimm, rank, package_type);
+                               }
+                       } else {
+-                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
++                              tempW2 = fam15_rttnom(pDCTstat, dct, dimm, 
rank, package_type);
++                      }
++                      tempW1 = 0;
++                      tempW1 |= ((tempW2 & 0x4) >> 2) << 9;
++                      tempW1 |= ((tempW2 & 0x2) >> 1) << 6;
++                      tempW1 |= ((tempW2 & 0x1) >> 0) << 2;
++              } else {
++                      if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                              tempW1 = RttNomTargetRegDimm(pMCTData, 
pDCTData, dimm, wl, MemClkFreq, rank);
++                      } else {
++                              if (wl) {
++                                      if (number_of_dimms > 1) {
++                                              if (rank == 0) {
++                                                      /* Get Rtt_WR for the 
current DIMM and rank */
++                                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm]);
++
++                                                      /* Convert dynamic 
termination code to corresponding nominal termination code */
++                                                      if (dynamic_term == 
0x200)
++                                                              tempW1 = 0x04;
++                                                      else if (dynamic_term 
== 0x400)
++                                                              tempW1 = 0x40;
++                                                      else
++                                                              tempW1 = 0x0;
++                                              } else {
++                                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
++                                              }
++                                      } else {
++                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
++                                      }
++                              } else {
++                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
++                              }
+                       }
+               }
++
++              /* Apply Rtt_Nom to the MRS control word */
+               tempW=tempW|tempW1;
+ 
+               /* All ranks of the target DIMM are set to write levelization 
mode. */
+@@ -393,68 +574,105 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+                               tempW = bitTestSet(tempW1, Qoff);
+                       }
+               }
+-              /* Program MrsAddress[5,1]=output driver impedance control 
(DIC):
+-               * based on F2x[1,0]84[DrvImpCtrl]
+-               */
+-              tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+-                              FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, 
DrvImpCtrlEnd);
++
++              /* Program MrsAddress[5,1]=output driver impedance control 
(DIC) */
++              if (is_fam15h()) {
++                      tempW1 = fam15_dimm_dic(pDCTstat, dct, dimm, rank, 
package_type);
++              } else {
++                      /* Read DIC from F2x[1,0]84[DrvImpCtrl] */
++                      tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                                      FUN_DCT, DRAM_MRS_REGISTER, 
DrvImpCtrlStart, DrvImpCtrlEnd);
++              }
++
++              /* Apply DIC to the MRS control word */
+               if (bitTest(tempW1, 1))
+                       tempW = bitTestSet(tempW, 5);
+               if (bitTest(tempW1, 0))
+                       tempW = bitTestSet(tempW, 1);
+ 
+-              tempW = swapAddrBits_wl(pDCTData, tempW);
++              tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
++
++              if (is_fam15h())
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsAddressStartFam15, 
MrsAddressEndFam15, tempW);
++              else
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsAddressStartFam10, 
MrsAddressEndFam10, tempW);
+ 
+-              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+-                      DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
+               /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
+                * the specified DIMM.
+                */
+-              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
++              set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
+               /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. 
*/
+-              while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
++              while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 
0x1)
+               {
+               }
++
+               /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate 
internal DRAM
+                * register that defines the required DDR3-defined function for 
Rtt_WR.
+                */
+-              MrsBank = swapBankBits(pDCTData,2);
+-              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+-                      DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
++              MrsBank = swapBankBits(pDCTstat, dct, 2);
++              if (is_fam15h())
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, 
MrsBank);
++              else
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, 
MrsBank);
++
+               /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required 
DDR3-defined function
+                * for Rtt_WR (DRAMTermDyn).
+                */
+               tempW = 0;/* PASR = 0,*/
+-              /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
+-               * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
+-              tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+-                              FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, 
PCI_MAX_HIGH);
+-              if (bitTest(tempW1,19))
+-              {tempW = bitTestSet(tempW, 7);}
+-              if (bitTest(tempW1,18))
+-              {tempW = bitTestSet(tempW, 6);}
+-              /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
+-              tempW=tempW|((tempW1&0x00700000)>>17);
+-              /* workaround for DR-B0 */
+-              if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && 
(pDCTData->Status[DCT_STATUS_REGISTERED]))
+-                      tempW+=0x8;
++
++              /* Retrieve normal settings of the MRS control word and clear 
Rtt_WR */
++              if (is_fam15h()) {
++                      tempW = mct_MR2(pMCTstat, pDCTstat, dct, dimm*2+rank) & 
0xffff;
++                      tempW &= ~(0x0600);
++              } else {
++                      /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
++                      * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
++                      tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                                      FUN_DCT, DRAM_MRS_REGISTER, 
PCI_MIN_LOW, PCI_MAX_HIGH);
++                      if (bitTest(tempW1,19))
++                      {tempW = bitTestSet(tempW, 7);}
++                      if (bitTest(tempW1,18))
++                      {tempW = bitTestSet(tempW, 6);}
++                      /* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
++                      tempW=tempW|((tempW1&0x00700000)>>17);
++                      /* workaround for DR-B0 */
++                      if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && 
(pDCTData->Status[DCT_STATUS_REGISTERED]))
++                              tempW+=0x8;
++              }
++
+               /* determine Rtt_WR for WL & Normal mode */
+-              if (pDCTData->Status[DCT_STATUS_REGISTERED])
+-                      tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, 
MemClkFreq, rank);
+-              else
+-                      tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
++              if (is_fam15h()) {
++                      tempW1 = (fam15_rttwr(pDCTstat, dct, dimm, rank, 
package_type) << 9);
++              } else {
++                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
++                              tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, 
wl, MemClkFreq, rank);
++                      else
++                              tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm]);
++              }
++
++              /* Apply Rtt_WR to the MRS control word */
+               tempW=tempW|tempW1;
+-              tempW = swapAddrBits_wl(pDCTData,tempW);
+-              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
+-                      DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
++              tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
++              if (is_fam15h())
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsAddressStartFam15, 
MrsAddressEndFam15, tempW);
++              else
++                      set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_INIT, MrsAddressStartFam10, 
MrsAddressEndFam10, tempW);
++
+               /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
+                  the specified DIMM.*/
+-              set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
++              set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
++
+               /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. 
*/
+-              while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
++              while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
+                               FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 
0x1)
+               {
+               }
+@@ -473,97 +691,163 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+                               rank = 0;
+                               while ((rank < pDCTData->DimmRanks[currDimm]) 
&& (rank < 2))
+                               {
+-
+                                       /* Program F2x[1, 0]7C[MrsChipSel[2:0]] 
for the current rank
+                                        * to be trained.
+                                        */
+-                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
+-                                              FUN_DCT, DRAM_INIT, 
MrsChipSelStart, MrsChipSelEnd, currDimm*2+rank);
++                                      if (is_fam15h())
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
++                                                      FUN_DCT, DRAM_INIT, 
MrsChipSelStartFam15, MrsChipSelEndFam15, currDimm*2+rank);
++                                      else
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
++                                                      FUN_DCT, DRAM_INIT, 
MrsChipSelStartFam10, MrsChipSelEndFam10, currDimm*2+rank);
++
+                                       /* Program F2x[1, 0]7C[MrsBank[2:0]] 
for the appropriate internal
+                                        * DRAM register that defines the 
required DDR3-defined function
+                                        * for write levelization.
+                                        */
+-                                      MrsBank = swapBankBits(pDCTData,1);
+-                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
+-                                              FUN_DCT, DRAM_INIT, 
MrsBankStart, MrsBankEnd, MrsBank);
++                                      MrsBank = swapBankBits(pDCTstat, dct, 
1);
++                                      if (is_fam15h())
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
++                                                      FUN_DCT, DRAM_INIT, 
MrsBankStartFam15, MrsBankEndFam15, MrsBank);
++                                      else
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
++                                                      FUN_DCT, DRAM_INIT, 
MrsBankStartFam10, MrsBankEndFam10, MrsBank);
++
+                                       /* Program F2x[1, 
0]7C[MrsAddress[15:0]] to the required
+                                        * DDR3-defined function for write 
levelization.
+                                        */
+                                       tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 
0, TDQS = 0, Level=0, Qoff=0 */
+ 
+-                                      /* Set TDQS=1b for x8 DIMM, TDQS=0b for 
x4 DIMM, when mixed x8 & x4 */
+-                                      tempW2 = get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
+-                                                      FUN_DCT, 
DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
+-                                      if (tempW2)
+-                                      {
+-                                              if 
(pDCTData->DimmX8Present[currDimm])
+-                                                      tempW |= 0x800;
++                                      /* Retrieve normal settings of the MRS 
control word and clear Rtt_Nom */
++                                      if (is_fam15h()) {
++                                              tempW = mct_MR1(pMCTstat, 
pDCTstat, dct, dimm*2+rank) & 0xffff;
++                                              tempW &= ~(0x0244);
++                                      } else {
++                                              /* Set TDQS=1b for x8 DIMM, 
TDQS=0b for x4 DIMM, when mixed x8 & x4 */
++                                              tempW2 = get_Bits(pDCTData, 
dct, pDCTData->NodeId,
++                                                              FUN_DCT, 
DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
++                                              if (tempW2)
++                                              {
++                                                      if 
(pDCTData->DimmX8Present[currDimm])
++                                                              tempW |= 0x800;
++                                              }
+                                       }
+ 
+                                       /* determine Rtt_Nom for WL & Normal 
mode */
+-                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
+-                                              tempW1 = 
RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
+-                                      else
+-                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
++                                      if (is_fam15h()) {
++                                              tempW2 = fam15_rttnom(pDCTstat, 
dct, dimm, rank, package_type);
++                                              tempW1 = 0;
++                                              tempW1 |= ((tempW2 & 0x4) >> 2) 
<< 9;
++                                              tempW1 |= ((tempW2 & 0x2) >> 1) 
<< 6;
++                                              tempW1 |= ((tempW2 & 0x1) >> 0) 
<< 2;
++                                      } else {
++                                              if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
++                                                      tempW1 = 
RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
++                                              else
++                                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
++                                      }
++
++                                      /* Apply Rtt_Nom to the MRS control 
word */
+                                       tempW=tempW|tempW1;
+-                                      /* program MrsAddress[5,1]=output 
driver impedance control (DIC):
+-                                       * based on F2x[1,0]84[DrvImpCtrl] */
+-                                      tempW1 = get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
+-                                                      FUN_DCT, 
DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
++
++                                      /* Program MrsAddress[5,1]=output 
driver impedance control (DIC) */
++                                      if (is_fam15h()) {
++                                              tempW1 = 
fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
++                                      } else {
++                                              /* Read DIC from 
F2x[1,0]84[DrvImpCtrl] */
++                                              tempW1 = get_Bits(pDCTData, 
dct, pDCTData->NodeId,
++                                                              FUN_DCT, 
DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
++                                      }
++
++                                      /* Apply DIC to the MRS control word */
+                                       if (bitTest(tempW1,1))
+                                       {tempW = bitTestSet(tempW, 5);}
+                                       if (bitTest(tempW1,0))
+                                       {tempW = bitTestSet(tempW, 1);}
+-                                      tempW = swapAddrBits_wl(pDCTData,tempW);
+-                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
+-                                              FUN_DCT, DRAM_INIT, 
MrsAddressStart, MrsAddressEnd, tempW);
++
++                                      tempW = swapAddrBits_wl(pDCTstat, dct, 
tempW);
++
++                                      if (is_fam15h())
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
++                                                      FUN_DCT, DRAM_INIT, 
MrsAddressStartFam15, MrsAddressEndFam15, tempW);
++                                      else
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId,
++                                                      FUN_DCT, DRAM_INIT, 
MrsAddressStartFam10, MrsAddressEndFam10, tempW);
++
+                                       /* Program F2x[1, 0]7C[SendMrsCmd]=1 to 
initiate the command
+                                        * to the specified DIMM.
+                                        */
+-                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId,
++                                      set_Bits(pDCTData, dct, 
pDCTData->NodeId,
+                                               FUN_DCT, DRAM_INIT, SendMrsCmd, 
SendMrsCmd, 1);
++
+                                       /* Wait for F2x[1, 0]7C[SendMrsCmd] to 
be cleared by hardware. */
+-                                      while ((get_Bits(pDCTData, 
pDCTData->CurrDct,
++                                      while ((get_Bits(pDCTData, dct,
+                                                       pDCTData->NodeId, 
FUN_DCT, DRAM_INIT,
+                                                       SendMrsCmd, 
SendMrsCmd)) == 1);
++
+                                       /* Program F2x[1, 0]7C[MrsBank[2:0]] 
for the appropriate internal DRAM
+                                        * register that defines the required 
DDR3-defined function for Rtt_WR.
+                                        */
+-                                      MrsBank = swapBankBits(pDCTData,2);
+-                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
+-                                              DRAM_INIT, MrsBankStart, 
MrsBankEnd, MrsBank);
++                                      MrsBank = swapBankBits(pDCTstat, dct, 
2);
++                                      if (is_fam15h())
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
++                                                      DRAM_INIT, 
MrsBankStartFam15, MrsBankEndFam15, MrsBank);
++                                      else
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
++                                                      DRAM_INIT, 
MrsBankStartFam10, MrsBankEndFam10, MrsBank);
++
+                                       /* Program F2x[1, 
0]7C[MrsAddress[15:0]] to the required DDR3-defined function
+                                        * for Rtt_WR (DRAMTermDyn).
+                                        */
+                                       tempW = 0;/* PASR = 0,*/
+-                                      /* program 
MrsAddress[7,6,5:3]=SRT,ASR,CWL,
+-                                       * based on 
F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
+-                                      tempW1 = get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
+-                                                      FUN_DCT, 
DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
+-                                      if (bitTest(tempW1,19))
+-                                      {tempW = bitTestSet(tempW, 7);}
+-                                      if (bitTest(tempW1,18))
+-                                      {tempW = bitTestSet(tempW, 6);}
+-                                      /* tempW=tempW|(((tempW1>>20)&0x7)<<3); 
*/
+-                                      tempW=tempW|((tempW1&0x00700000)>>17);
+-                                      /* workaround for DR-B0 */
+-                                      if ((pDCTData->LogicalCPUID & 
AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
+-                                              tempW+=0x8;
++
++                                      /* Retrieve normal settings of the MRS 
control word and clear Rtt_WR */
++                                      if (is_fam15h()) {
++                                              tempW = mct_MR2(pMCTstat, 
pDCTstat, dct, dimm*2+rank) & 0xffff;
++                                              tempW &= ~(0x0600);
++                                      } else {
++                                              /* program 
MrsAddress[7,6,5:3]=SRT,ASR,CWL,
++                                              * based on 
F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
++                                              tempW1 = get_Bits(pDCTData, 
dct, pDCTData->NodeId,
++                                                              FUN_DCT, 
DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
++                                              if (bitTest(tempW1,19))
++                                              {tempW = bitTestSet(tempW, 7);}
++                                              if (bitTest(tempW1,18))
++                                              {tempW = bitTestSet(tempW, 6);}
++                                              /* 
tempW=tempW|(((tempW1>>20)&0x7)<<3); */
++                                              
tempW=tempW|((tempW1&0x00700000)>>17);
++                                              /* workaround for DR-B0 */
++                                              if ((pDCTData->LogicalCPUID & 
AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
++                                                      tempW+=0x8;
++                                      }
++
+                                       /* determine Rtt_WR for WL & Normal 
mode */
+-                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
+-                                              tempW1 = RttWrRegDimm(pMCTData, 
pDCTData, currDimm, wl, MemClkFreq, rank);
+-                                      else
+-                                              tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
++                                      if (is_fam15h()) {
++                                              tempW1 = (fam15_rttwr(pDCTstat, 
dct, dimm, rank, package_type) << 9);
++                                      } else {
++                                              if 
(pDCTData->Status[DCT_STATUS_REGISTERED])
++                                                      tempW1 = 
RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
++                                              else
++                                                      tempW1 = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm]);
++                                      }
++
++                                      /* Apply Rtt_WR to the MRS control word 
*/
+                                       tempW=tempW|tempW1;
+-                                      tempW = swapAddrBits_wl(pDCTData,tempW);
+-                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
+-                                              DRAM_INIT, MrsAddressStart, 
MrsAddressEnd, tempW);
++                                      tempW = swapAddrBits_wl(pDCTstat, dct, 
tempW);
++                                      if (is_fam15h())
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
++                                                      DRAM_INIT, 
MrsAddressStartFam15, MrsAddressEndFam15, tempW);
++                                      else
++                                              set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
++                                                      DRAM_INIT, 
MrsAddressStartFam10, MrsAddressEndFam10, tempW);
++
+                                       /* Program F2x[1, 0]7C[SendMrsCmd]=1 to 
initiate the command to
+                                          the specified DIMM.*/
+-                                      set_Bits(pDCTData, pDCTData->CurrDct, 
pDCTData->NodeId, FUN_DCT,
++                                      set_Bits(pDCTData, dct, 
pDCTData->NodeId, FUN_DCT,
+                                               DRAM_INIT, SendMrsCmd, 
SendMrsCmd, 1);
++
+                                       /* Wait for F2x[1, 0]7C[SendMrsCmd] to 
be cleared by hardware. */
+-                                      while ((get_Bits(pDCTData, 
pDCTData->CurrDct, pDCTData->NodeId,
++                                      while ((get_Bits(pDCTData, dct, 
pDCTData->NodeId,
+                                                       FUN_DCT, DRAM_INIT, 
SendMrsCmd, SendMrsCmd)) == 0x1)
+                                       {
+                                       }
+@@ -587,29 +871,60 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl)
+  *       OUT
+  * 
----------------------------------------------------------------------------
+  */
+-void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
++void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm)
+ {
++      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++
+       u8 WrLvOdt1=0;
+ 
+-      if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
+-              if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
+-                      WrLvOdt1 = 0x03;
+-              } else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) 
{
+-                      WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
++      if (is_fam15h()) {
++              /* Convert DIMM number to CS */
++              uint32_t dword;
++              uint8_t cs;
++              uint8_t rank = 0;
++
++              cs = (dimm * 2) + rank;
++
++              /* Fetch preprogammed ODT pattern from configuration registers 
*/
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
((cs>3)?0x23c:0x238));
++              if ((cs == 7) || (cs == 3))
++                      WrLvOdt1 = ((dword >> 24) & 0xf);
++              else if ((cs == 6) || (cs == 2))
++                      WrLvOdt1 = ((dword >> 16) & 0xf);
++              else if ((cs == 5) || (cs == 1))
++                      WrLvOdt1 = ((dword >> 8) & 0xf);
++              else if ((cs == 4) || (cs == 0))
++                      WrLvOdt1 = (dword & 0xf);
++      } else {
++              if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
++                      if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
++                              WrLvOdt1 = 0x03;
++                      } else if 
(bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
++                              WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
++                      } else {
++                              WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
++                      }
+               } else {
+-                      WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
++                      WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
+               }
+-      } else {
+-              WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
+       }
+ 
+-      set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, 
FUN_DCT,
++      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
+ 
+ }
+ 
++#ifdef UNUSED_CODE
++static uint16_t fam15h_next_lowest_memclk_freq(uint16_t memclk_freq)
++{
++      uint16_t fam15h_next_lowest_freq_tab[] = {0, 0, 0, 0, 0x4, 0, 0x4, 0, 
0, 0, 0x6, 0, 0, 0, 0xa, 0, 0, 0, 0xe, 0, 0, 0, 0x12};
++      return fam15h_next_lowest_freq_tab[memclk_freq];
++}
++#endif
++
+ 
/*-----------------------------------------------------------------------------
+- * void procConifg(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
++ * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
+  *
+  *  Description:
+  *       This function programs the ODT values for the NB
+@@ -622,31 +937,43 @@ void programODT(sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm)
+  *       OUT
+  * 
----------------------------------------------------------------------------
+  */
+-void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
++void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass)
+ {
+-      u8 ByteLane, Seed_Gross, Seed_Fine, MemClkFreq;
++      u8 ByteLane, MemClkFreq;
++      int32_t Seed_Gross;
++      int32_t Seed_Fine;
++      uint8_t Seed_PreGross;
+       u32 Value, Addr;
+       u16 Addl_Data_Offset, Addl_Data_Port;
+-      u16 freq_tab[] = {400, 533, 667, 800};
++      sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
++      u16 fam10h_freq_tab[] = {400, 533, 667, 800};
++      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+ 
+-      /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
+-      MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
+-                              FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
++      if (is_fam15h()) {
++              /* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 
667MHz; 0x12: 800MHz; 0x16: 933MHz */
++              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                                      FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
++      } else {
++              /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
++              MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
++                                      FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
++      }
+ 
+       /* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for 
the
+        * current memory subsystem configuration.
+        */
+-      programODT(pMCTData, pDCTData, dimm);
++      programODT(pMCTstat, pDCTstat, dct, dimm);
+ 
+       /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
+-      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) {
+-              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
++      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL)) {
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                               DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, 
WrLvOdtEn, (u32)1);
+       }
+       else
+       {
+               /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 
0 for Rev.B */
+-              if (pDCTData->DctTrain)
++              if (dct)
+               {
+                       Addl_Data_Offset=0x198;
+                       Addl_Data_Port=0x19C;
+@@ -669,33 +996,94 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
+                               DctAccessDone, DctAccessDone)) == 0);
+       }
+ 
++      if (is_fam15h())
++              proc_MFENCE();
++
+       /* Wait 10 MEMCLKs to allow for ODT signal settling. */
+-      pMCTData->AgesaDelay(10);
++      if (is_fam15h())
++              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
++      else
++              pMCTData->AgesaDelay(10);
++
++      /* Program write levelling seed values */
+       if (pass == 1)
+       {
+-              if (pDCTData->Status[DCT_STATUS_REGISTERED])
+-              {
+-                      if(pDCTData->RegMan1Present & 
((1<<(dimm*2+pDCTData->DctTrain))))
++              /* Pass 1 */
++              if (is_fam15h()) {
++                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
++                      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++                      uint16_t Seed_Total = 0;
++                      if (package_type == PT_GR) {
++                              /* Socket G34: Fam15h BKDG v3.14 Table 96 */
++                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                      Seed_Total = 0x41;
++                              } else if 
(pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
++                                      Seed_Total = 0x0;
++                              } else {
++                                      Seed_Total = 0xf;
++                              }
++                      } else if (package_type == PT_C3) {
++                              /* Socket C32: Fam15h BKDG v3.14 Table 97 */
++                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                      Seed_Total = 0x3e;
++                              } else if 
(pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
++                                      Seed_Total = 0x0;
++                              } else {
++                                      Seed_Total = 0x12;
++                              }
++                      } else if (package_type == PT_M2) {
++                              /* Socket AM3: Fam15h BKDG v3.14 Table 98 */
++                              Seed_Total = 0xf;
++                      }
++                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
++                              Seed_Total += ((AddrCmdPrelaunch)?0x10:0x0);
++
++                      /* Adjust seed for the minimum platform supported 
frequency */
++                      Seed_Total = (int32_t) (((((int64_t) Seed_Total) *
++                              fam15h_freq_tab[MemClkFreq] * 100) / 
(mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
++
++                      Seed_Gross = (Seed_Total >> 5) & 0x1f;
++                      Seed_Fine = Seed_Total & 0x1f;
++
++                      /* Save seed values for later use */
++                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                              
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
++                              
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++
++                              if (Seed_Gross == 0)
++                                      Seed_PreGross = 0;
++                              else if (Seed_Gross & 0x1)
++                                      Seed_PreGross = 1;
++                              else
++                                      Seed_PreGross = 2;
++
++                              
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
++                      }
++              } else {
++                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
+                       {
+-                              Seed_Gross = 0x02;
+-                              Seed_Fine = 0x16;
++                              if(pDCTData->RegMan1Present & 
((1<<(dimm*2+dct))))
++                              {
++                                      Seed_Gross = 0x02;
++                                      Seed_Fine = 0x16;
++                              }
++                              else
++                              {
++                                      Seed_Gross = 0x02;
++                                      Seed_Fine = 0x00;
++                              }
+                       }
+                       else
+                       {
+-                              Seed_Gross = 0x02;
+-                              Seed_Fine = 0x00;
+-                      }
+-              }
+-              else
+-              {
+-                      if (MemClkFreq == 6) {
+-                              /* DDR-800 */
+-                              Seed_Gross = 0x00;
+-                              Seed_Fine = 0x1a;
+-                      } else {
+-                              /* Use settings for DDR-400 (interpolated from 
BKDG) */
+-                              Seed_Gross = 0x00;
+-                              Seed_Fine = 0x0d;
++                              if (MemClkFreq == 6) {
++                                      /* DDR-800 */
++                                      Seed_Gross = 0x00;
++                                      Seed_Fine = 0x1a;
++                              } else {
++                                      /* Use settings for DDR-400 
(interpolated from BKDG) */
++                                      Seed_Gross = 0x00;
++                                      Seed_Fine = 0x0d;
++                              }
+                       }
+               }
+               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
+@@ -711,39 +1099,91 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
+                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
+                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
+               }
+-      } else {                /* Pass 2 */
++      } else {
++              /* Pass 2 */
+               /* From BKDG, Write Leveling Seed Value. */
+-              u32 RegisterDelay, SeedTotal;
+-              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++)
+-              {
+-                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
+-                              RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) 
== 0) ? 0x20 : 0x30; */
+-                      else
+-                              RegisterDelay = 0;
+-                      SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
+-                              
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
+-                      /* SeedTotalPreScaling = (the total delay value in 
F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
+-                         training) - RegisterDelay. */
+-                      SeedTotal = (uint16_t) (RegisterDelay + ((((uint64_t) 
SeedTotal - RegisterDelay) *
+-                                                              
freq_tab[MemClkFreq-3] * 100) / (freq_tab[0] * 100)));
+-                      Seed_Gross = SeedTotal / 32;
+-                      Seed_Fine = SeedTotal & 0x1f;
+-                      if (Seed_Gross == 0)
+-                              Seed_Gross = 0;
+-                      else if (Seed_Gross & 0x1)
+-                              Seed_Gross = 1;
+-                      else
+-                              Seed_Gross = 2;
+-                      pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
+-                      pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
++              if (is_fam15h()) {
++                      uint32_t RegisterDelay;
++                      int32_t SeedTotal;
++                      int32_t SeedTotalPreScaling;
++                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
++
++                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                      if (AddrCmdPrelaunch)
++                                              RegisterDelay = 0x30;
++                                      else
++                                              RegisterDelay = 0x20;
++                              } else {
++                                      RegisterDelay = 0;
++                              }
++                              /* Retrieve WrDqDqsEarly */
++                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId), FUN_DCT, 0xa8), 25, 24, 
&Value);
++
++                              /* Calculate adjusted seed values */
++                              SeedTotal = 
(pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
++                                      
((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5);
++                              SeedTotalPreScaling = (SeedTotal - 
RegisterDelay - (0x20 * Value));
++                              SeedTotal = (int32_t) (RegisterDelay + 
((((int64_t) SeedTotalPreScaling) *
++                                      fam15h_freq_tab[MemClkFreq] * 100) / 
(fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
++
++                              if (SeedTotal >= 0) {
++                                      Seed_Gross = SeedTotal / 32;
++                                      Seed_Fine = SeedTotal % 32;
++                              } else {
++                                      Seed_Gross = (SeedTotal / 32) - 1;
++                                      Seed_Fine = (SeedTotal % 32) + 32;
++                              }
++
++                              if (Seed_Gross == 0)
++                                      Seed_PreGross = 0;
++                              else if (Seed_Gross & 0x1)
++                                      Seed_PreGross = 1;
++                              else
++                                      Seed_PreGross = 2;
++
++                              /* Save seed values for later use */
++                              
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
++                              
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++                              
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
++
++                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
++                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++                      }
++              } else {
++                      u32 RegisterDelay, SeedTotal;
++                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
++                      {
++                              if (pDCTData->Status[DCT_STATUS_REGISTERED])
++                                      RegisterDelay = 0x20; /* TODO: ((RCW2 & 
BIT0) == 0) ? 0x20 : 0x30; */
++                              else
++                                      RegisterDelay = 0;
++                              SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
++                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
++                              /* SeedTotalPreScaling = (the total delay value 
in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
++                              training) - RegisterDelay. */
++                              SeedTotal = (uint16_t) (RegisterDelay + 
((((uint64_t) SeedTotal - RegisterDelay) *
++                                                                      
fam10h_freq_tab[MemClkFreq-3] * 100) / (fam10h_freq_tab[0] * 100)));
++                              Seed_Gross = SeedTotal / 32;
++                              Seed_Fine = SeedTotal & 0x1f;
++                              if (Seed_Gross == 0)
++                                      Seed_Gross = 0;
++                              else if (Seed_Gross & 0x1)
++                                      Seed_Gross = 1;
++                              else
++                                      Seed_Gross = 2;
++                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
++                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++                      }
+               }
+       }
+ 
+-      setWLByteDelay(pDCTData, ByteLane, dimm, 0);
++      pDCTData->WLPrevMemclkFreq = MemClkFreq;
++      setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass);
+ }
+ 
+ 
/*-----------------------------------------------------------------------------
+- *  void setWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm){
++ *  void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm){
+  *
+  *  Description:
+  *       This function writes the write levelization byte delay for the Phase
+@@ -763,8 +1203,9 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct 
*pDCTData, u8 dimm, u8 pass)
+  *
+  
*-----------------------------------------------------------------------------
+  */
+-void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
++void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, u8 targetAddr, uint8_t pass)
+ {
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, 
offsetAddr;
+       u32 addr, fineDelayValue, grossDelayValue, ValueLow, ValueHigh, 
EccValue, tempW;
+ 
+@@ -777,22 +1218,26 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
+               EccValue = 0;
+               while (ByteLane < MAX_BYTE_LANES)
+               {
+-                      /* This subtract 0xC workaround might be temporary. */
+-                      if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present 
& (1<<(dimm*2+pDCTData->DctTrain))))
+-                      {
+-                              tempW = (pDCTData->WLGrossDelay[index+ByteLane] 
<< 5) | pDCTData->WLFineDelay[index+ByteLane];
+-                              tempW -= 0xC;
+-                              pDCTData->WLGrossDelay[index+ByteLane] = 
(u8)(tempW >> 5);
+-                              pDCTData->WLFineDelay[index+ByteLane] = 
(u8)(tempW & 0x1F);
+-                      }
+-                      grossDelayValue = 
pDCTData->WLGrossDelay[index+ByteLane];
+-                      /* Adjust seed gross delay overflow (greater than 3):
+-                       *      - Program seed gross delay as 2 (gross is 4 or 
6) or 1 (gross is 5).
+-                       *      - Keep original seed gross delay for later 
reference.
+-                       */
+-                      if(grossDelayValue >= 3)
+-                      {
+-                              grossDelayValue = (grossDelayValue&1)? 1 : 2;
++                      if (is_fam15h()) {
++                              grossDelayValue = 
pDCTData->WLGrossDelay[index+ByteLane];
++                      } else {
++                              /* This subtract 0xC workaround might be 
temporary. */
++                              if ((pDCTData->WLPass==2) && 
(pDCTData->RegMan1Present & (1<<(dimm*2+dct))))
++                              {
++                                      tempW = 
(pDCTData->WLGrossDelay[index+ByteLane] << 5) | 
pDCTData->WLFineDelay[index+ByteLane];
++                                      tempW -= 0xC;
++                                      pDCTData->WLGrossDelay[index+ByteLane] 
= (u8)(tempW >> 5);
++                                      pDCTData->WLFineDelay[index+ByteLane] = 
(u8)(tempW & 0x1F);
++                              }
++                              grossDelayValue = 
pDCTData->WLGrossDelay[index+ByteLane];
++                              /* Adjust seed gross delay overflow (greater 
than 3):
++                               *      - Program seed gross delay as 2 (gross 
is 4 or 6) or 1 (gross is 5).
++                               *      - Keep original seed gross delay for 
later reference.
++                               */
++                              if(grossDelayValue >= 3)
++                              {
++                                      grossDelayValue = (grossDelayValue&1)? 
1 : 2;
++                              }
+                       }
+                       fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
+                       if (ByteLane < 4)
+@@ -803,15 +1248,16 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
+                               EccValue = ((grossDelayValue << 5) | 
fineDelayValue);
+                       ByteLane++;
+               }
+-              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                               DRAM_CONT_ADD_PHASE_REC_CTRL_LOW, 0, 31, 
(u32)ValueLow);
+-              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                               DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH, 0, 31, 
(u32)ValueHigh);
+-              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                               DRAM_CONT_ADD_ECC_PHASE_REC_CTRL, 0, 31, 
(u32)EccValue);
+       }
+       else
+       {
++              /* Fam10h BKDG Rev. 3.62 2.8.9.9.1 (6) */
+               index = (u8)(MAX_BYTE_LANES * dimm);
+               grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
+               fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
+@@ -841,16 +1287,24 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm, u8 targetAddr)
+               grossStartLoc = (u8)(fineEndLoc + 1);
+               grossEndLoc = (u8)(grossStartLoc + 1);
+ 
+-              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                               (u16)addr, fineStartLoc, 
fineEndLoc,(u32)fineDelayValue);
+-              set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, 
pDCTData->NodeId, FUN_DCT,
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                               (u16)addr, grossStartLoc, grossEndLoc, 
(u32)grossDelayValue);
++
++              pDCTData->WLFineDelayPrevPass[index+ByteLane] = fineDelayValue;
++              pDCTData->WLGrossDelayPrevPass[index+ByteLane] = 
grossDelayValue;
++              if (pass == FirstPass) {
++                      pDCTData->WLFineDelayFirstPass[index+ByteLane] = 
fineDelayValue;
++                      pDCTData->WLGrossDelayFirstPass[index+ByteLane] = 
grossDelayValue;
++                      pDCTData->WLCriticalGrossDelayFirstPass = 
pDCTData->WLCriticalGrossDelayPrevPass;
++              }
+       }
+ 
+ }
+ 
+ 
/*-----------------------------------------------------------------------------
+- *  void getWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm)
++ *  void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm)
+  *
+  *  Description:
+  *       This function reads the write levelization byte delay from the Phase
+@@ -868,8 +1322,9 @@ void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 
dimm, u8 targetAddr)
+  *
+  
*-----------------------------------------------------------------------------
+  */
+-void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm)
++void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass)
+ {
++      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, 
index;
+       u32 addr, fine, gross;
+       tempB = 0;
+@@ -890,25 +1345,31 @@ void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, 
u8 dimm)
+       grossStartLoc = (u8)(fineEndLoc + 1);
+       grossEndLoc = (u8)(grossStartLoc + 1);
+ 
+-      fine = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
++      fine = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
+                               FUN_DCT, (u16)addr, fineStartLoc, fineEndLoc);
+-      gross = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
++      gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
+                               FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
+-      /* Adjust seed gross delay overflow (greater than 3):
+-       * - Adjust the trained gross delay to the original seed gross delay.
+-       */
+-      if (pDCTData->WLGrossDelay[index+ByteLane] >= 3) {
+-              gross += pDCTData->WLGrossDelay[index+ByteLane];
+-              if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
+-                      gross -= 1;
+-              else
+-                      gross -= 2;
+-      } else if ((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 
3)) {
+-              /* If seed gross delay is 0 but PRE result gross delay is 3, it 
is negative.
+-               * We will then round the negative number to 0.
++
++      if (!is_fam15h()) {
++              /* Adjust seed gross delay overflow (greater than 3):
++               * - Adjust the trained gross delay to the original seed gross 
delay.
+                */
+-              gross = 0;
+-              fine = 0;
++              if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
++              {
++                      gross += pDCTData->WLGrossDelay[index+ByteLane];
++                      if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
++                              gross -= 1;
++                      else
++                              gross -= 2;
++              }
++              else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross 
== 3))
++              {
++                      /* If seed gross delay is 0 but PRE result gross delay 
is 3, it is negative.
++                       * We will then round the negative number to 0.
++                       */
++                      gross = 0;
++                      fine = 0;
++              }
+       }
+       pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
+       pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
+index 0466c77..cf6afaa 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -134,24 +135,48 @@ static u32 get_Bits(sDCTStruct *pDCTData,
+               u16 offset, u8 low, u8 high)
+ {
+       u32 temp;
++      uint32_t dword;
++
+       /* ASSERT(node < MAX_NODES); */
+       if (dct == BOTH_DCTS)
+       {
+               /* Registers exist on DCT0 only */
++              if (is_fam15h())
++              {
++                      /* Select DCT 0 */
++                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++                      dword &= ~0x1;
++                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++              }
++
+               AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, 
low, &temp);
+       }
+       else
+       {
+-              if (dct == 1)
++              if (is_fam15h())
+               {
+-                      /* Write to dct 1 */
+-                      offset += 0x100;
++                      /* Select DCT */
++                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++                      dword &= ~0x1;
++                      dword |= (dct & 0x1);
++                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++
++                      /* Read from the selected DCT */
+                       AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
+               }
+               else
+               {
+-                      /* Write to dct 0 */
+-                      AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
++                      if (dct == 1)
++                      {
++                              /* Read from dct 1 */
++                              offset += 0x100;
++                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
++                      }
++                      else
++                      {
++                              /* Read from dct 0 */
++                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
++                      }
+               }
+       }
+       return temp;
+@@ -184,25 +209,49 @@ static void set_Bits(sDCTStruct *pDCTData,
+               u16 offset, u8 low, u8 high, u32 value)
+ {
+       u32 temp;
++      uint32_t dword;
++
+       temp = value;
+ 
+       if (dct == BOTH_DCTS)
+       {
+               /* Registers exist on DCT0 only */
++              if (is_fam15h())
++              {
++                      /* Select DCT 0 */
++                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++                      dword &= ~0x1;
++                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++              }
++
+               AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, 
low, &temp);
+       }
+       else
+       {
+-              if (dct == 1)
++              if (is_fam15h())
+               {
+-                      /* Write to dct 1 */
+-                      offset += 0x100;
++                      /* Select DCT */
++                      AmdMemPCIRead(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++                      dword &= ~0x1;
++                      dword |= (dct & 0x1);
++                      AmdMemPCIWrite(MAKE_SBDFO(0,0,24+node,1,0x10c), &dword);
++
++                      /* Write to the selected DCT */
+                       AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
+               }
+               else
+               {
+-                      /* Write to dct 0 */
+-                      AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), 
high, low, &temp);
++                      if (dct == 1)
++                      {
++                              /* Write to dct 1 */
++                              offset += 0x100;
++                              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
++                      }
++                      else
++                      {
++                              /* Write to dct 0 */
++                              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
++                      }
+               }
+       }
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
+index f846d87..162340e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -33,7 +34,8 @@
+ #define C_MAX_DIMMS 4         /* Maximum Number of DIMMs on each DCT */
+ 
+ /* STATUS Definition */
+-#define DCT_STATUS_REGISTERED 3       /* Registered DIMMs support */
++#define DCT_STATUS_REGISTERED 3               /* Registered DIMMs support */
++#define DCT_STATUS_LOAD_REDUCED 4     /* Load-Reduced DIMMs support */
+ #define DCT_STATUS_OnDimmMirror 24    /* OnDimmMirror support */
+ 
+ /* PCI Defintions */
+@@ -78,12 +80,18 @@
+ #define SendMrsCmd 26
+ #define Qoff 12
+ #define MRS_Level 7
+-#define MrsAddressStart 0
+-#define MrsAddressEnd 15
+-#define MrsBankStart 16
+-#define MrsBankEnd 18
+-#define MrsChipSelStart 20
+-#define MrsChipSelEnd 22
++#define MrsAddressStartFam10 0
++#define MrsAddressEndFam10 15
++#define MrsAddressStartFam15 0
++#define MrsAddressEndFam15 17
++#define MrsBankStartFam10 16
++#define MrsBankEndFam10 18
++#define MrsBankStartFam15 18
++#define MrsBankEndFam15 20
++#define MrsChipSelStartFam10 20
++#define MrsChipSelEndFam10 22
++#define MrsChipSelStartFam15 21
++#define MrsChipSelEndFam15 23
+ #define ASR 18
+ #define SRT 19
+ #define DramTermDynStart 10
+@@ -115,10 +123,32 @@ typedef struct _sDCTStruct
+       u8 DctTrain;                    /* Current DCT being trained */
+       u8 CurrDct;                     /* Current DCT number (0 or 1) */
+       u8 DctCSPresent;                /* Current DCT CS mapping */
++      int32_t WLSeedGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];    /* Write 
Levelization Seed Gross Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      int32_t WLSeedFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write 
Levelization Seed Fine Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      int32_t WLSeedPreGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write 
Levelization Seed Pre-Gross Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
+       u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write Levelization 
Gross Delay */
+                                                       /* per byte Lane Per 
Logical DIMM*/
+       u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];      /* Write Levelization 
Fine Delay */
+                                                       /* per byte Lane Per 
Logical DIMM*/
++      u8 WLGrossDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];    /* First-Pass 
Write Levelization Gross Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      u8 WLFineDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* First-Pass 
Write Levelization Fine Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      u8 WLGrossDelayPrevPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* Previous 
Pass Write Levelization Gross Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      u8 WLFineDelayPrevPass[MAX_BYTE_LANES*MAX_LDIMMS];      /* Previous 
Pass Write Levelization Fine Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      u8 WLGrossDelayFinalPass[MAX_BYTE_LANES*MAX_LDIMMS];    /* Final-Pass 
Write Levelization Gross Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      u8 WLFineDelayFinalPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* Final-Pass 
Write Levelization Fine Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      int32_t WLCriticalGrossDelayFirstPass;
++      int32_t WLCriticalGrossDelayPrevPass;
++      int32_t WLCriticalGrossDelayFinalPass;
++      uint16_t WLPrevMemclkFreq;
+       u16 RegMan1Present;
+       u8 DimmPresent[MAX_TOTAL_DIMMS];/* Indicates which DIMMs are present */
+                                       /* from Total Number of DIMMs(per 
Node)*/
+@@ -132,7 +162,7 @@ typedef struct _sDCTStruct
+                                       /* per byte lane */
+       u8 MaxDimmsInstalled;           /* Max Dimms Installed for current DCT 
*/
+       u8 DimmRanks[MAX_TOTAL_DIMMS];  /* Total Number of Ranks(per Dimm) */
+-      u32 LogicalCPUID;
++      uint64_t LogicalCPUID;
+       u8 WLPass;
+ } sDCTStruct;
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+index c9bcac1..aa23951 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -18,6 +18,7 @@
+  */
+ 
+ #include <string.h>
++#include <arch/cpu.h>
+ #include <arch/acpi.h>
+ #include <cpu/x86/msr.h>
+ #include <device/device.h>
+@@ -32,6 +33,23 @@
+ 
+ #define S3NV_FILE_NAME "s3nv"
+ 
++#ifdef __RAMSTAGE__
++static inline uint8_t is_fam15h(void)
++{
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      return fam15h;
++}
++#endif
++
+ static ssize_t get_s3nv_file_offset(void);
+ 
+ ssize_t get_s3nv_file_offset(void)
+@@ -47,6 +65,28 @@ ssize_t get_s3nv_file_offset(void)
+       return s3nv_region.region.offset;
+ }
+ 
++static uint32_t read_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg) {
++      if (is_fam15h()) {
++              uint32_t dword;
++#ifdef __PRE_RAM__
++              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
++#else
++              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
++#endif
++
++              /* Select DCT */
++              dword = pci_read_config32(dev_fn1, 0x10c);
++              dword &= ~0x1;
++              dword |= (dct & 0x1);
++              pci_write_config32(dev_fn1, 0x10c, dword);
++      } else {
++              /* Apply offset */
++              reg += dct * 0x100;
++      }
++
++      return pci_read_config32(dev, reg);
++}
++
+ static uint32_t read_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index)
+ {
+       uint32_t dword;
+@@ -61,12 +101,54 @@ static uint32_t read_amd_dct_index_register(device_t dev, 
uint32_t index_ctl_reg
+       return dword;
+ }
+ 
++static uint32_t read_amd_dct_index_register_dct(device_t dev, uint8_t node, 
uint8_t dct, uint32_t index_ctl_reg, uint32_t index)
++{
++      if (is_fam15h()) {
++              uint32_t dword;
++#ifdef __PRE_RAM__
++              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
++#else
++              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
++#endif
++
++              /* Select DCT */
++              dword = pci_read_config32(dev_fn1, 0x10c);
++              dword &= ~0x1;
++              dword |= (dct & 0x1);
++              pci_write_config32(dev_fn1, 0x10c, dword);
++      } else {
++              /* Apply offset */
++              index_ctl_reg += dct * 0x100;
++      }
++
++      return read_amd_dct_index_register(dev, index_ctl_reg, index);
++}
++
+ #ifdef __RAMSTAGE__
+ static uint64_t rdmsr_uint64_t(unsigned long index) {
+       msr_t msr = rdmsr(index);
+       return (((uint64_t)msr.hi) << 32) | ((uint64_t)msr.lo);
+ }
+ 
++static uint32_t read_config32_dct_nbpstate(device_t dev, uint8_t node, 
uint8_t dct, uint8_t nb_pstate, uint32_t reg) {
++      uint32_t dword;
++      device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
++
++      /* Select DCT */
++      dword = pci_read_config32(dev_fn1, 0x10c);
++      dword &= ~0x1;
++      dword |= (dct & 0x1);
++      pci_write_config32(dev_fn1, 0x10c, dword);
++
++      /* Select NB Pstate index */
++      dword = pci_read_config32(dev_fn1, 0x10c);
++      dword &= ~(0x3 << 4);
++      dword |= (nb_pstate & 0x3) << 4;
++      pci_write_config32(dev_fn1, 0x10c, dword);
++
++      return pci_read_config32(dev, reg);
++}
++
+ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
+ {
+       uint8_t i;
+@@ -82,7 +164,8 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
+               device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
+               device_t dev_fn2 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 2));
+               device_t dev_fn3 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 3));
+-              if ((!dev_fn1) || (!dev_fn2) || (!dev_fn3)) {
++              /* Test for node presence */
++              if ((!dev_fn1) || (pci_read_config32(dev_fn1, PCI_VENDOR_ID) == 
0xffffffff)) {
+                       persistent_data->node[node].node_present = 0;
+                       continue;
+               }
+@@ -95,22 +178,22 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
+                       data->f2x110 = pci_read_config32(dev_fn2, 0x110);
+ 
+                       /* Stage 2 */
+-                      data->f1x40 = pci_read_config32(dev_fn1, 0x40 + (0x100 
* channel));
+-                      data->f1x44 = pci_read_config32(dev_fn1, 0x44 + (0x100 
* channel));
+-                      data->f1x48 = pci_read_config32(dev_fn1, 0x48 + (0x100 
* channel));
+-                      data->f1x4c = pci_read_config32(dev_fn1, 0x4c + (0x100 
* channel));
+-                      data->f1x50 = pci_read_config32(dev_fn1, 0x50 + (0x100 
* channel));
+-                      data->f1x54 = pci_read_config32(dev_fn1, 0x54 + (0x100 
* channel));
+-                      data->f1x58 = pci_read_config32(dev_fn1, 0x58 + (0x100 
* channel));
+-                      data->f1x5c = pci_read_config32(dev_fn1, 0x5c + (0x100 
* channel));
+-                      data->f1x60 = pci_read_config32(dev_fn1, 0x60 + (0x100 
* channel));
+-                      data->f1x64 = pci_read_config32(dev_fn1, 0x64 + (0x100 
* channel));
+-                      data->f1x68 = pci_read_config32(dev_fn1, 0x68 + (0x100 
* channel));
+-                      data->f1x6c = pci_read_config32(dev_fn1, 0x6c + (0x100 
* channel));
+-                      data->f1x70 = pci_read_config32(dev_fn1, 0x70 + (0x100 
* channel));
+-                      data->f1x74 = pci_read_config32(dev_fn1, 0x74 + (0x100 
* channel));
+-                      data->f1x78 = pci_read_config32(dev_fn1, 0x78 + (0x100 
* channel));
+-                      data->f1x7c = pci_read_config32(dev_fn1, 0x7c + (0x100 
* channel));
++                      data->f1x40 = read_config32_dct(dev_fn1, node, channel, 
0x40);
++                      data->f1x44 = read_config32_dct(dev_fn1, node, channel, 
0x44);
++                      data->f1x48 = read_config32_dct(dev_fn1, node, channel, 
0x48);
++                      data->f1x4c = read_config32_dct(dev_fn1, node, channel, 
0x4c);
++                      data->f1x50 = read_config32_dct(dev_fn1, node, channel, 
0x50);
++                      data->f1x54 = read_config32_dct(dev_fn1, node, channel, 
0x54);
++                      data->f1x58 = read_config32_dct(dev_fn1, node, channel, 
0x58);
++                      data->f1x5c = read_config32_dct(dev_fn1, node, channel, 
0x5c);
++                      data->f1x60 = read_config32_dct(dev_fn1, node, channel, 
0x60);
++                      data->f1x64 = read_config32_dct(dev_fn1, node, channel, 
0x64);
++                      data->f1x68 = read_config32_dct(dev_fn1, node, channel, 
0x68);
++                      data->f1x6c = read_config32_dct(dev_fn1, node, channel, 
0x6c);
++                      data->f1x70 = read_config32_dct(dev_fn1, node, channel, 
0x70);
++                      data->f1x74 = read_config32_dct(dev_fn1, node, channel, 
0x74);
++                      data->f1x78 = read_config32_dct(dev_fn1, node, channel, 
0x78);
++                      data->f1x7c = read_config32_dct(dev_fn1, node, channel, 
0x7c);
+                       data->f1xf0 = pci_read_config32(dev_fn1, 0xf0);
+                       data->f1x120 = pci_read_config32(dev_fn1, 0x120);
+                       data->f1x124 = pci_read_config32(dev_fn1, 0x124);
+@@ -134,75 +217,144 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
+                       data->msrc001001f = rdmsr_uint64_t(0xc001001f);
+ 
+                       /* Stage 3 */
+-                      data->f2x40 = pci_read_config32(dev_fn2, 0x40 + (0x100 
* channel));
+-                      data->f2x44 = pci_read_config32(dev_fn2, 0x44 + (0x100 
* channel));
+-                      data->f2x48 = pci_read_config32(dev_fn2, 0x48 + (0x100 
* channel));
+-                      data->f2x4c = pci_read_config32(dev_fn2, 0x4c + (0x100 
* channel));
+-                      data->f2x50 = pci_read_config32(dev_fn2, 0x50 + (0x100 
* channel));
+-                      data->f2x54 = pci_read_config32(dev_fn2, 0x54 + (0x100 
* channel));
+-                      data->f2x58 = pci_read_config32(dev_fn2, 0x58 + (0x100 
* channel));
+-                      data->f2x5c = pci_read_config32(dev_fn2, 0x5c + (0x100 
* channel));
+-                      data->f2x60 = pci_read_config32(dev_fn2, 0x60 + (0x100 
* channel));
+-                      data->f2x64 = pci_read_config32(dev_fn2, 0x64 + (0x100 
* channel));
+-                      data->f2x68 = pci_read_config32(dev_fn2, 0x68 + (0x100 
* channel));
+-                      data->f2x6c = pci_read_config32(dev_fn2, 0x6c + (0x100 
* channel));
+-                      data->f2x78 = pci_read_config32(dev_fn2, 0x78 + (0x100 
* channel));
+-                      data->f2x7c = pci_read_config32(dev_fn2, 0x7c + (0x100 
* channel));
+-                      data->f2x80 = pci_read_config32(dev_fn2, 0x80 + (0x100 
* channel));
+-                      data->f2x84 = pci_read_config32(dev_fn2, 0x84 + (0x100 
* channel));
+-                      data->f2x88 = pci_read_config32(dev_fn2, 0x88 + (0x100 
* channel));
+-                      data->f2x8c = pci_read_config32(dev_fn2, 0x8c + (0x100 
* channel));
+-                      data->f2x90 = pci_read_config32(dev_fn2, 0x90 + (0x100 
* channel));
+-                      data->f2xa4 = pci_read_config32(dev_fn2, 0xa4 + (0x100 
* channel));
+-                      data->f2xa8 = pci_read_config32(dev_fn2, 0xa8 + (0x100 
* channel));
++                      data->f2x40 = read_config32_dct(dev_fn2, node, channel, 
0x40);
++                      data->f2x44 = read_config32_dct(dev_fn2, node, channel, 
0x44);
++                      data->f2x48 = read_config32_dct(dev_fn2, node, channel, 
0x48);
++                      data->f2x4c = read_config32_dct(dev_fn2, node, channel, 
0x4c);
++                      data->f2x50 = read_config32_dct(dev_fn2, node, channel, 
0x50);
++                      data->f2x54 = read_config32_dct(dev_fn2, node, channel, 
0x54);
++                      data->f2x58 = read_config32_dct(dev_fn2, node, channel, 
0x58);
++                      data->f2x5c = read_config32_dct(dev_fn2, node, channel, 
0x5c);
++                      data->f2x60 = read_config32_dct(dev_fn2, node, channel, 
0x60);
++                      data->f2x64 = read_config32_dct(dev_fn2, node, channel, 
0x64);
++                      data->f2x68 = read_config32_dct(dev_fn2, node, channel, 
0x68);
++                      data->f2x6c = read_config32_dct(dev_fn2, node, channel, 
0x6c);
++                      data->f2x78 = read_config32_dct(dev_fn2, node, channel, 
0x78);
++                      data->f2x7c = read_config32_dct(dev_fn2, node, channel, 
0x7c);
++                      data->f2x80 = read_config32_dct(dev_fn2, node, channel, 
0x80);
++                      data->f2x84 = read_config32_dct(dev_fn2, node, channel, 
0x84);
++                      data->f2x88 = read_config32_dct(dev_fn2, node, channel, 
0x88);
++                      data->f2x8c = read_config32_dct(dev_fn2, node, channel, 
0x8c);
++                      data->f2x90 = read_config32_dct(dev_fn2, node, channel, 
0x90);
++                      data->f2xa4 = read_config32_dct(dev_fn2, node, channel, 
0xa4);
++                      data->f2xa8 = read_config32_dct(dev_fn2, node, channel, 
0xa8);
++
++                      /* Family 15h-specific configuration */
++                      if (is_fam15h()) {
++                              data->f2x200 = read_config32_dct(dev_fn2, node, 
channel, 0x200);
++                              data->f2x204 = read_config32_dct(dev_fn2, node, 
channel, 0x204);
++                              data->f2x208 = read_config32_dct(dev_fn2, node, 
channel, 0x208);
++                              data->f2x20c = read_config32_dct(dev_fn2, node, 
channel, 0x20c);
++                              for (i=0; i<4; i++)
++                                      data->f2x210[i] = 
read_config32_dct_nbpstate(dev_fn2, node, channel, i, 0x210);
++                              data->f2x214 = read_config32_dct(dev_fn2, node, 
channel, 0x214);
++                              data->f2x218 = read_config32_dct(dev_fn2, node, 
channel, 0x218);
++                              data->f2x21c = read_config32_dct(dev_fn2, node, 
channel, 0x21c);
++                              data->f2x22c = read_config32_dct(dev_fn2, node, 
channel, 0x22c);
++                              data->f2x230 = read_config32_dct(dev_fn2, node, 
channel, 0x230);
++                              data->f2x234 = read_config32_dct(dev_fn2, node, 
channel, 0x234);
++                              data->f2x238 = read_config32_dct(dev_fn2, node, 
channel, 0x238);
++                              data->f2x23c = read_config32_dct(dev_fn2, node, 
channel, 0x23c);
++                              data->f2x240 = read_config32_dct(dev_fn2, node, 
channel, 0x240);
++
++                              data->f2x9cx0d0fe003 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe003);
++                              data->f2x9cx0d0fe013 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe013);
++                              for (i=0; i<9; i++)
++                                      data->f2x9cx0d0f0_8_0_1f[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f001f | (i 
<< 8));
++                              data->f2x9cx0d0f201f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f201f);
++                              data->f2x9cx0d0f211f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f211f);
++                              data->f2x9cx0d0f221f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f221f);
++                              data->f2x9cx0d0f801f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f801f);
++                              data->f2x9cx0d0f811f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f811f);
++                              data->f2x9cx0d0f821f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f821f);
++                              data->f2x9cx0d0fc01f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc01f);
++                              data->f2x9cx0d0fc11f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc11f);
++                              data->f2x9cx0d0fc21f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc21f);
++                              data->f2x9cx0d0f4009 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f4009);
++                              for (i=0; i<9; i++)
++                                      data->f2x9cx0d0f0_8_0_02[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0002 | (i 
<< 8));
++                              for (i=0; i<9; i++)
++                                      data->f2x9cx0d0f0_8_0_06[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0006 | (i 
<< 8));
++                              for (i=0; i<9; i++)
++                                      data->f2x9cx0d0f0_8_0_0a[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f000a | (i 
<< 8));
++
++                              data->f2x9cx0d0f2002 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2002);
++                              data->f2x9cx0d0f2102 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2102);
++                              data->f2x9cx0d0f2202 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2202);
++                              data->f2x9cx0d0f8002 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8002);
++                              data->f2x9cx0d0f8006 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8006);
++                              data->f2x9cx0d0f800a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f800a);
++                              data->f2x9cx0d0f8102 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8102);
++                              data->f2x9cx0d0f8106 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8106);
++                              data->f2x9cx0d0f810a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f810a);
++                              data->f2x9cx0d0fc002 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc002);
++                              data->f2x9cx0d0fc006 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc006);
++                              data->f2x9cx0d0fc00a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00a);
++                              data->f2x9cx0d0fc00e = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00e);
++                              data->f2x9cx0d0fc012 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc012);
++
++                              data->f2x9cx0d0f2031 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2031);
++                              data->f2x9cx0d0f2131 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2131);
++                              data->f2x9cx0d0f2231 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2231);
++                              data->f2x9cx0d0f8031 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8031);
++                              data->f2x9cx0d0f8131 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8131);
++                              data->f2x9cx0d0f8231 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8231);
++                              data->f2x9cx0d0fc031 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc031);
++                              data->f2x9cx0d0fc131 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc131);
++                              data->f2x9cx0d0fc231 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc231);
++                              for (i=0; i<9; i++)
++                                      data->f2x9cx0d0f0_0_f_31[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0031 | (i 
<< 8));
++
++                              data->f2x9cx0d0f8021 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8021);
++                      }
+ 
+                       /* Stage 4 */
+-                      data->f2x94 = pci_read_config32(dev_fn2, 0x94 + (0x100 
* channel));
++                      data->f2x94 = read_config32_dct(dev_fn2, node, channel, 
0x94);
+ 
+                       /* Stage 6 */
+                       for (i=0; i<9; i++)
+                               for (j=0; j<3; j++)
+-                                      data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
+-                      data->f2x9cx00 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x00);
+-                      data->f2x9cx0a = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0a);
+-                      data->f2x9cx0c = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0c);
++                                      data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i 
<< 8) | (j * 4));
++                      data->f2x9cx00 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x00);
++                      data->f2x9cx0a = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0a);
++                      data->f2x9cx0c = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0c);
+ 
+                       /* Stage 7 */
+-                      data->f2x9cx04 = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x04);
++                      data->f2x9cx04 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x04);
+ 
+                       /* Stage 9 */
+-                      data->f2x9cx0d0fe006 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe006);
+-                      data->f2x9cx0d0fe007 = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe007);
++                      data->f2x9cx0d0fe006 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe006);
++                      data->f2x9cx0d0fe007 = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe007);
+ 
+                       /* Stage 10 */
+                       for (i=0; i<12; i++)
+-                              data->f2x9cx10[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x10 + i);
++                              data->f2x9cx10[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x10 + i);
+                       for (i=0; i<12; i++)
+-                              data->f2x9cx20[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x20 + i);
++                              data->f2x9cx20[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x20 + i);
+                       for (i=0; i<4; i++)
+                               for (j=0; j<3; j++)
+-                                      data->f2x9cx3_0_0_3_1[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x01 + i) + 
(0x100 * j));
++                                      data->f2x9cx3_0_0_3_1[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x01 + i) + 
(0x100 * j));
+                       for (i=0; i<4; i++)
+                               for (j=0; j<3; j++)
+-                                      data->f2x9cx3_0_0_7_5[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x05 + i) + 
(0x100 * j));
+-                      data->f2x9cx0d = read_amd_dct_index_register(dev_fn2, 
0x98 + (0x100 * channel), 0x0d);
++                                      data->f2x9cx3_0_0_7_5[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x05 + i) + 
(0x100 * j));
++                      data->f2x9cx0d = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d);
+                       for (i=0; i<9; i++)
+-                              data->f2x9cx0d0f0_f_0_13[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0013 | (i 
<< 8));
++                              data->f2x9cx0d0f0_f_0_13[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0013 | (i 
<< 8));
+                       for (i=0; i<9; i++)
+-                              data->f2x9cx0d0f0_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0030 | (i 
<< 8));
++                              data->f2x9cx0d0f0_f_0_30[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0030 | (i 
<< 8));
+                       for (i=0; i<4; i++)
+-                              data->f2x9cx0d0f2_f_0_30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f2030 | (i 
<< 8));
++                              data->f2x9cx0d0f2_f_0_30[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2030 | (i 
<< 8));
+                       for (i=0; i<2; i++)
+                               for (j=0; j<3; j++)
+-                                      data->f2x9cx0d0f8_8_4_0[i][j] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i 
<< 8) | (j * 4));
+-                      data->f2x9cx0d0f812f = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f812f);
++                                      data->f2x9cx0d0f8_8_4_0[i][j] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i 
<< 8) | (j * 4));
++                      data->f2x9cx0d0f812f = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f812f);
+ 
+                       /* Stage 11 */
+                       if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
+                               for (i=0; i<12; i++)
+-                                      data->f2x9cx30[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x30 + i);
++                                      data->f2x9cx30[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x30 + i);
+                               for (i=0; i<12; i++)
+-                                      data->f2x9cx40[i] = 
read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x40 + i);
++                                      data->f2x9cx40[i] = 
read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x40 + i);
+                       }
+ 
+                       /* Other */
+@@ -212,6 +364,43 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
+       }
+ }
+ #else
++static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg, uint32_t value) {
++      if (is_fam15h()) {
++              uint32_t dword;
++              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
++
++              /* Select DCT */
++              dword = pci_read_config32(dev_fn1, 0x10c);
++              dword &= ~0x1;
++              dword |= (dct & 0x1);
++              pci_write_config32(dev_fn1, 0x10c, dword);
++      } else {
++              /* Apply offset */
++              reg += dct * 0x100;
++      }
++
++      pci_write_config32(dev, reg, value);
++}
++
++static void write_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t 
dct, uint8_t nb_pstate, uint32_t reg, uint32_t value) {
++      uint32_t dword;
++      device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
++
++      /* Select DCT */
++      dword = pci_read_config32(dev_fn1, 0x10c);
++      dword &= ~0x1;
++      dword |= (dct & 0x1);
++      pci_write_config32(dev_fn1, 0x10c, dword);
++
++      /* Select NB Pstate index */
++      dword = pci_read_config32(dev_fn1, 0x10c);
++      dword &= ~(0x3 << 4);
++      dword |= (nb_pstate & 0x3) << 4;
++      pci_write_config32(dev_fn1, 0x10c, dword);
++
++      pci_write_config32(dev, reg, value);
++}
++
+ static void write_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index, uint32_t value)
+ {
+       uint32_t dword;
+@@ -223,6 +412,25 @@ static void write_amd_dct_index_register(device_t dev, 
uint32_t index_ctl_reg, u
+               dword = pci_read_config32(dev, index_ctl_reg);
+       } while (!(dword & (1 << 31)));
+ }
++
++static void write_amd_dct_index_register_dct(device_t dev, uint8_t node, 
uint8_t dct, uint32_t index_ctl_reg, uint32_t index, uint32_t value)
++{
++      if (is_fam15h()) {
++              uint32_t dword;
++              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
++
++              /* Select DCT */
++              dword = pci_read_config32(dev_fn1, 0x10c);
++              dword &= ~0x1;
++              dword |= (dct & 0x1);
++              pci_write_config32(dev_fn1, 0x10c, dword);
++      } else {
++              /* Apply offset */
++              index_ctl_reg += dct * 0x100;
++      }
++
++      return write_amd_dct_index_register(dev, index_ctl_reg, index, value);
++}
+ #endif
+ 
+ #ifdef __PRE_RAM__
+@@ -262,31 +470,31 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       if (!persistent_data->node[node].node_present)
+                               continue;
+ 
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x40 + 
(0x100 * channel), data->f1x40);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x44 + 
(0x100 * channel), data->f1x44);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x48 + 
(0x100 * channel), data->f1x48);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x4c + 
(0x100 * channel), data->f1x4c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x50 + 
(0x100 * channel), data->f1x50);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x54 + 
(0x100 * channel), data->f1x54);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x58 + 
(0x100 * channel), data->f1x58);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x5c + 
(0x100 * channel), data->f1x5c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x60 + 
(0x100 * channel), data->f1x60);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x64 + 
(0x100 * channel), data->f1x64);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x68 + 
(0x100 * channel), data->f1x68);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x6c + 
(0x100 * channel), data->f1x6c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x70 + 
(0x100 * channel), data->f1x70);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x74 + 
(0x100 * channel), data->f1x74);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x78 + 
(0x100 * channel), data->f1x78);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x7c + 
(0x100 * channel), data->f1x7c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0xf0 + 
(0x100 * channel), data->f1xf0);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x120 + 
(0x100 * channel), data->f1x120);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x124 + 
(0x100 * channel), data->f1x124);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x10c + 
(0x100 * channel), data->f2x10c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x114 + 
(0x100 * channel), data->f2x114);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x118 + 
(0x100 * channel), data->f2x118);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x11c + 
(0x100 * channel), data->f2x11c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x1b0 + 
(0x100 * channel), data->f2x1b0);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x44 + 
(0x100 * channel), data->f3x44);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x40, data->f1x40);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x44, data->f1x44);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x48, data->f1x48);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x4c, data->f1x4c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x50, data->f1x50);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x54, data->f1x54);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x58, data->f1x58);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x5c, data->f1x5c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x60, data->f1x60);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x64, data->f1x64);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x68, data->f1x68);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x6c, data->f1x6c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x70, data->f1x70);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x74, data->f1x74);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x78, data->f1x78);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x7c, data->f1x7c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0xf0, data->f1xf0);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x120, data->f1x120);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x124, data->f1x124);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x10c, data->f2x10c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x114, data->f2x114);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x118, data->f2x118);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x11c, data->f2x11c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x1b0, data->f2x1b0);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 
channel, 0x44, data->f3x44);
+                       for (i=0; i<16; i++) {
+                               wrmsr_uint64_t(0x00000200 | i, 
data->msr0000020[i]);
+                       }
+@@ -313,31 +521,97 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       if (!persistent_data->node[node].node_present)
+                               continue;
+ 
+-                      ganged = !!(data->f2x110 & 0x10);
++                      if (is_fam15h())
++                              ganged = 0;
++                      else
++                              ganged = !!(data->f2x110 & 0x10);
+                       if ((ganged == 1) && (channel > 0))
+                               continue;
+ 
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x40 + 
(0x100 * channel), data->f2x40);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x44 + 
(0x100 * channel), data->f2x44);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x48 + 
(0x100 * channel), data->f2x48);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x4c + 
(0x100 * channel), data->f2x4c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x50 + 
(0x100 * channel), data->f2x50);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x54 + 
(0x100 * channel), data->f2x54);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x58 + 
(0x100 * channel), data->f2x58);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x5c + 
(0x100 * channel), data->f2x5c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x60 + 
(0x100 * channel), data->f2x60);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x64 + 
(0x100 * channel), data->f2x64);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x68 + 
(0x100 * channel), data->f2x68);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x6c + 
(0x100 * channel), data->f2x6c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x78 + 
(0x100 * channel), data->f2x78);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x7c + 
(0x100 * channel), data->f2x7c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x80 + 
(0x100 * channel), data->f2x80);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x84 + 
(0x100 * channel), data->f2x84);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x88 + 
(0x100 * channel), data->f2x88);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x8c + 
(0x100 * channel), data->f2x8c);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), data->f2x90);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa4 + 
(0x100 * channel), data->f2xa4);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa8 + 
(0x100 * channel), data->f2xa8);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x40, data->f2x40);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x44, data->f2x44);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x48, data->f2x48);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x4c, data->f2x4c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x50, data->f2x50);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x54, data->f2x54);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x58, data->f2x58);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x5c, data->f2x5c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x60, data->f2x60);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x64, data->f2x64);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x68, data->f2x68);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x6c, data->f2x6c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x78, data->f2x78);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x7c, data->f2x7c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x80, data->f2x80);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x84, data->f2x84);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x88, data->f2x88);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x8c, data->f2x8c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x90, data->f2x90);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0xa4, data->f2xa4);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0xa8, data->f2xa8);
++              }
++      }
++
++      /* Family 15h-specific configuration */
++      if (is_fam15h()) {
++              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++                      for (channel = 0; channel < 2; channel++) {
++                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
++                              if (!persistent_data->node[node].node_present)
++                                      continue;
++
++                              /* Initialize DCT */
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0000000b, 0x80000000);
++                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe013);
++                              dword &= ~0xffff;
++                              dword |= 0x118;
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, dword);
++
++                              /* Restore values */
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x200, data->f2x200);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x204, data->f2x204);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x208, data->f2x208);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x20c, data->f2x20c);
++                              for (i=0; i<4; i++)
++                                      write_config32_dct_nbpstate(PCI_DEV(0, 
0x18 + node, 2), node, channel, i, 0x210, data->f2x210[i]);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x214, data->f2x214);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x218, data->f2x218);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x21c, data->f2x21c);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x22c, data->f2x22c);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x230, data->f2x230);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x234, data->f2x234);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x238, data->f2x238);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x23c, data->f2x23c);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x240, data->f2x240);
++
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, data->f2x9cx0d0fe013);
++                              for (i=0; i<9; i++)
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f001f | (i << 8), data->f2x9cx0d0f0_8_0_1f[i]);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f201f, data->f2x9cx0d0f201f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f211f, data->f2x9cx0d0f211f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f221f, data->f2x9cx0d0f221f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f801f, data->f2x9cx0d0f801f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f811f, data->f2x9cx0d0f811f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f821f, data->f2x9cx0d0f821f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc01f, data->f2x9cx0d0fc01f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc11f, data->f2x9cx0d0fc11f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc21f, data->f2x9cx0d0fc21f);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f4009, data->f2x9cx0d0f4009);
++
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2031, data->f2x9cx0d0f2031);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2131, data->f2x9cx0d0f2131);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2231, data->f2x9cx0d0f2231);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8031, data->f2x9cx0d0f8031);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8131, data->f2x9cx0d0f8131);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8231, data->f2x9cx0d0f8231);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc031, data->f2x9cx0d0fc031);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc131, data->f2x9cx0d0fc131);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc231, data->f2x9cx0d0fc231);
++                              for (i=0; i<9; i++)
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0031 | (i << 8), data->f2x9cx0d0f0_0_f_31[i]);
++
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8021, data->f2x9cx0d0f8021);
++                      }
+               }
+       }
+ 
+@@ -348,33 +622,44 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       if (!persistent_data->node[node].node_present)
+                               continue;
+ 
+-                      ganged = !!(data->f2x110 & 0x10);
++                      if (is_fam15h())
++                              ganged = 0;
++                      else
++                              ganged = !!(data->f2x110 & 0x10);
+                       if ((ganged == 1) && (channel > 0))
+                               continue;
+ 
+-                      /* Disable PHY auto-compensation engine */
+-                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
+-                      if (!(dword & (1 << 30))) {
+-                              dword |= (1 << 30);
+-                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08, dword);
+-
+-                              /* Wait for 5us */
+-                              mct_Wait(100);
++                      if (is_fam15h()) {
++                              /* Program PllLockTime = 0x190 */
++                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe006);
++                              dword &= ~0xffff;
++                              dword |= 0x190;
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword);
++
++                              /* Program MemClkFreqVal = 0 */
++                              dword = read_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x94);
++                              dword &= (0x1 << 7);
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x94, dword);
++
++                              /* Restore DRAM Adddress/Timing Control 
Register */
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04);
++                      } else {
++                              /* Disable PHY auto-compensation engine */
++                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x08);
++                              if (!(dword & (1 << 30))) {
++                                      dword |= (1 << 30);
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x08, dword);
++
++                                      /* Wait for 5us */
++                                      mct_Wait(100);
++                              }
+                       }
+ 
+                       /* Restore DRAM Configuration High Register */
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x94 + 
(0x100 * channel), data->f2x94);
+-
+-                      /* Enable PHY auto-compensation engine */
+-                      dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x08);
+-                      dword &= ~(1 << 30);
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x08, dword);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x94, data->f2x94);
+               }
+       }
+ 
+-      /* Wait for 750us */
+-      mct_Wait(15000);
+-
+       /* Stage 5 */
+       for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
+               for (channel = 0; channel < 2; channel++) {
+@@ -382,17 +667,40 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       if (!persistent_data->node[node].node_present)
+                               continue;
+ 
+-                      ganged = !!(data->f2x110 & 0x10);
++                      if (is_fam15h())
++                              ganged = 0;
++                      else
++                              ganged = !!(data->f2x110 & 0x10);
+                       if ((ganged == 1) && (channel > 0))
+                               continue;
+ 
++                      dct_enabled = !(data->f2x94 & (1 << 14));
++                      if (!dct_enabled)
++                              continue;
++
+                       /* Wait for any pending PHY frequency changes to 
complete */
+                       do {
+-                              dword = read_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x08);
++                              dword = read_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x94);
+                       } while (dword & (1 << 21));
++
++                      if (is_fam15h()) {
++                              /* Program PllLockTime = 0xf */
++                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe006);
++                              dword &= ~0xffff;
++                              dword |= 0xf;
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword);
++                      } else {
++                              /* Enable PHY auto-compensation engine */
++                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x08);
++                              dword &= ~(1 << 30);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x08, dword);
++                      }
+               }
+       }
+ 
++      /* Wait for 750us */
++      mct_Wait(15000);
++
+       /* Stage 6 */
+       for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
+               for (channel = 0; channel < 2; channel++) {
+@@ -402,10 +710,49 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+ 
+                       for (i=0; i<9; i++)
+                               for (j=0; j<3; j++)
+-                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x00, data->f2x9cx00);
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0a, data->f2x9cx0a);
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0c, data->f2x9cx0c);
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]);
++                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x00, data->f2x9cx00);
++                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0a, data->f2x9cx0a);
++                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0c, data->f2x9cx0c);
++              }
++      }
++
++      /* Family 15h-specific configuration */
++      if (is_fam15h()) {
++              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++                      for (channel = 0; channel < 2; channel++) {
++                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
++                              if (!persistent_data->node[node].node_present)
++                                      continue;
++
++                              dword = 
read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0fe003);
++                              dword |= (0x3 << 13);                   /* 
DisAutoComp, DisablePredriverCal = 1 */
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, dword);
++
++                              for (i=0; i<9; i++)
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0006 | (i << 8), data->f2x9cx0d0f0_8_0_06[i]);
++                              for (i=0; i<9; i++)
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f000a | (i << 8), data->f2x9cx0d0f0_8_0_0a[i]);
++                              for (i=0; i<9; i++)
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0002 | (i << 8), (0x8000 | data->f2x9cx0d0f0_8_0_02[i]));
++
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8006, data->f2x9cx0d0f8006);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f800a, data->f2x9cx0d0f800a);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8106, data->f2x9cx0d0f8106);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f810a, data->f2x9cx0d0f810a);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc006, data->f2x9cx0d0fc006);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc00a, data->f2x9cx0d0fc00a);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc00e, data->f2x9cx0d0fc00e);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc012, data->f2x9cx0d0fc012);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8002, (0x8000 | 
data->f2x9cx0d0f8002));
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f8102, (0x8000 | 
data->f2x9cx0d0f8102));
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fc002, (0x8000 | 
data->f2x9cx0d0fc002));
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2002, (0x8000 | 
data->f2x9cx0d0f2002));
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2102, (0x8000 | 
data->f2x9cx0d0f2102));
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2202, (0x8000 | 
data->f2x9cx0d0f2202));
++
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, data->f2x9cx0d0fe003);
++                      }
+               }
+       }
+ 
+@@ -416,11 +763,15 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       if (!persistent_data->node[node].node_present)
+                               continue;
+ 
+-                      ganged = !!(data->f2x110 & 0x10);
++                      if (is_fam15h())
++                              ganged = 0;
++                      else
++                              ganged = !!(data->f2x110 & 0x10);
+                       if ((ganged == 1) && (channel > 0))
+                               continue;
+ 
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x04, data->f2x9cx04);
++                      if (!is_fam15h())
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04);
+               }
+       }
+ 
+@@ -435,16 +786,19 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       if (!dct_enabled)
+                               continue;
+ 
+-                      ganged = !!(data->f2x110 & 0x10);
++                      if (is_fam15h())
++                              ganged = 0;
++                      else
++                              ganged = !!(data->f2x110 & 0x10);
+                       if ((ganged == 1) && (channel > 0))
+                               continue;
+ 
+                       printk(BIOS_SPEW, "Taking DIMMs out of self refresh 
node: %d channel: %d\n", node, channel);
+ 
+                       /* Exit self refresh mode */
+-                      dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 
0x90 + (0x100 * channel));
++                      dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x90);
+                       dword |= (1 << 1);
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + 
(0x100 * channel), dword);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x90, dword);
+               }
+       }
+ 
+@@ -463,12 +817,12 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+ 
+                       /* Wait for transition from self refresh mode to 
complete */
+                       do {
+-                              dword = pci_read_config32(PCI_DEV(0, 0x18 + 
node, 2), 0x90 + (0x100 * channel));
++                              dword = read_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x90);
+                       } while (dword & (1 << 1));
+ 
+                       /* Restore registers */
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe006, data->f2x9cx0d0fe006);
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0fe007, data->f2x9cx0d0fe007);
++                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d0fe006, data->f2x9cx0d0fe006);
++                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d0fe007, data->f2x9cx0d0fe007);
+               }
+       }
+ 
+@@ -480,26 +834,26 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                               continue;
+ 
+                       for (i=0; i<12; i++)
+-                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x10 + i, data->f2x9cx10[i]);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x10 + i, data->f2x9cx10[i]);
+                       for (i=0; i<12; i++)
+-                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x20 + i, data->f2x9cx20[i]);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x20 + i, data->f2x9cx20[i]);
+                       for (i=0; i<4; i++)
+                               for (j=0; j<3; j++)
+-                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j), 
data->f2x9cx3_0_0_3_1[i][j]);
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
+                       for (i=0; i<4; i++)
+                               for (j=0; j<3; j++)
+-                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j), 
data->f2x9cx3_0_0_7_5[i][j]);
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d, data->f2x9cx0d);
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
++                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d, data->f2x9cx0d);
+                       for (i=0; i<9; i++)
+-                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8), 
data->f2x9cx0d0f0_f_0_13[i]);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f0013 | (i << 8), 
data->f2x9cx0d0f0_f_0_13[i]);
+                       for (i=0; i<9; i++)
+-                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8), 
data->f2x9cx0d0f0_f_0_30[i]);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f0030 | (i << 8), 
data->f2x9cx0d0f0_f_0_30[i]);
+                       for (i=0; i<4; i++)
+-                              write_amd_dct_index_register(PCI_DEV(0, 0x18 + 
node, 2), 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8), 
data->f2x9cx0d0f2_f_0_30[i]);
++                              write_amd_dct_index_register_dct(PCI_DEV(0, 
0x18 + node, 2), node, channel, 0x98, 0x0d0f2030 | (i << 8), 
data->f2x9cx0d0f2_f_0_30[i]);
+                       for (i=0; i<2; i++)
+                               for (j=0; j<3; j++)
+-                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), 
data->f2x9cx0d0f8_8_4_0[i][j]);
+-                      write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 
2), 0x98 + (0x100 * channel), 0x0d0f812f, data->f2x9cx0d0f812f);
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f8_8_4_0[i][j]);
++                      write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x98, 0x0d0f812f, data->f2x9cx0d0f812f);
+               }
+       }
+ 
+@@ -512,9 +866,9 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                                       continue;
+ 
+                               for (i=0; i<12; i++)
+-                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x30 + i, data->f2x9cx30[i]);
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x30 + i, data->f2x9cx30[i]);
+                               for (i=0; i<12; i++)
+-                                      write_amd_dct_index_register(PCI_DEV(0, 
0x18 + node, 2), 0x98 + (0x100 * channel), 0x40 + i, data->f2x9cx40[i]);
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x40 + i, data->f2x9cx40[i]);
+                       }
+               }
+       }
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti.h 
b/src/northbridge/amd/amdmct/wrappers/mcti.h
+index 38e66e1..2aba377 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti.h
++++ b/src/northbridge/amd/amdmct/wrappers/mcti.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -62,10 +63,15 @@ UPDATE AS NEEDED
+ #endif
+ 
+ #ifndef MEM_MAX_LOAD_FREQ
+-#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+- #define MEM_MAX_LOAD_FREQ            800
+-#else
+- #define MEM_MAX_LOAD_FREQ            400
++#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005    /* AMD_FAM10_DDR3 */
++ #define MEM_MAX_LOAD_FREQ                    933
++ #define MEM_MIN_PLATFORM_FREQ_FAM10          400
++ #define MEM_MIN_PLATFORM_FREQ_FAM15          333
++#else                                          /* AMD_FAM10_DDR2 */
++ #define MEM_MAX_LOAD_FREQ                    400
++ #define MEM_MIN_PLATFORM_FREQ_FAM10          200
++ /* DDR2 not available on Family 15h */
++ #define MEM_MIN_PLATFORM_FREQ_FAM15          0
+ #endif
+ #endif
+ 
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index 444adc5..9969c4f 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -44,7 +44,7 @@
+ #define MINIMUM_DRAM_BELOW_4G 0x1000000
+ 
+ static const uint16_t ddr2_limits[4] = {400, 333, 266, 200};
+-static const uint16_t ddr3_limits[4] = {800, 666, 533, 400};
++static const uint16_t ddr3_limits[16] = {933, 800, 666, 533, 400, 333, 0, 0, 
0, 0, 0, 0, 0, 0, 0, 0};
+ 
+ static u16 mctGet_NVbits(u8 index)
+ {
+@@ -81,12 +81,19 @@ static u16 mctGet_NVbits(u8 index)
+               if (get_option(&nvram, "max_mem_clock") == CB_SUCCESS) {
+                       int limit = val;
+                       if (IS_ENABLED(CONFIG_DIMM_DDR3))
+-                              limit = ddr3_limits[nvram & 3];
++                              limit = ddr3_limits[nvram & 0xf];
+                       else if (IS_ENABLED(CONFIG_DIMM_DDR2))
+-                              limit = ddr2_limits[nvram & 3];
++                              limit = ddr2_limits[nvram & 0x3];
+                       val = min(limit, val);
+               }
+               break;
++      case NV_MIN_MEMCLK:
++              /* Minimum platform supported memclk */
++              if (is_fam15h())
++                      val =  MEM_MIN_PLATFORM_FREQ_FAM15;
++              else
++                      val =  MEM_MIN_PLATFORM_FREQ_FAM10;
++              break;
+       case NV_ECC_CAP:
+ #if SYSTEM_TYPE == SERVER
+               val = 1;        /* memory bus ECC capable */
+@@ -254,6 +261,9 @@ static u16 mctGet_NVbits(u8 index)
+       case NV_L2BKScrub:
+               val = 0;        /* Disabled - See L2Scrub in BKDG */
+               break;
++      case NV_L3BKScrub:
++              val = 0;        /* Disabled - See L3Scrub in BKDG */
++              break;
+       case NV_DCBKScrub:
+               val = 0;        /* Disabled - See DcacheScrub in BKDG */
+               break;
+@@ -303,6 +313,9 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+       int ch2_count = 0;
+       uint8_t ch1_registered = 0;
+       uint8_t ch2_registered = 0;
++      uint8_t ch1_voltage = 0;
++      uint8_t ch2_voltage = 0;
++      uint8_t highest_rank_count[2];
+       int i;
+       for (i = 0; i < 15; i = i + 2) {
+               if (pDCTstat->DIMMValid & (1 << i))
+@@ -321,8 +334,28 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+               printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 2: %d DIMM(s) 
detected\n", ch2_count);
+       }
+ 
++#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
++      uint8_t dimm;
++
++      for (i = 0; i < 15; i = i + 2) {
++              if (pDCTstat->DIMMValid & (1 << i))
++                      ch1_voltage |= pDCTstat->DimmConfiguredVoltage[i];
++              if (pDCTstat->DIMMValid & (1 << (i + 1)))
++                      ch2_voltage |= pDCTstat->DimmConfiguredVoltage[i + 1];
++      }
++
++      for (i = 0; i < 2; i++) {
++              sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[i];
++              highest_rank_count[i] = 0x0;
++              for (dimm = 0; dimm < 8; dimm++) {
++                      if (pDCTData->DimmRanks[dimm] > highest_rank_count[i])
++                              highest_rank_count[i] = 
pDCTData->DimmRanks[dimm];
++              }
++      }
++#endif
++
+       /* Set limits if needed */
+-      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
(ch1_registered || ch2_registered), pDCTstat->PresetmaxFreq);
++      pDCTstat->PresetmaxFreq = mct_MaxLoadFreq(max(ch1_count, ch2_count), 
max(highest_rank_count[0], highest_rank_count[1]), (ch1_registered || 
ch2_registered), (ch1_voltage | ch2_voltage), pDCTstat->PresetmaxFreq);
+ }
+ 
+ #ifdef UNUSED_CODE
+@@ -486,7 +519,7 @@ static void mctHookAfterAnyTraining(void)
+ {
+ }
+ 
+-static u32 mctGetLogicalCPUID_D(u8 node)
++static uint64_t mctGetLogicalCPUID_D(u8 node)
+ {
+       return mctGetLogicalCPUID(node);
+ }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0034-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
 
b/resources/libreboot/patch/kgpe-d16/0034-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
deleted file mode 100644
index 9202333..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0034-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
+++ /dev/null
@@ -1,565 +0,0 @@
-From cf1d449f1ac17478863403eb4154433b4fb4a3e7 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 5 Sep 2015 19:37:57 -0500
-Subject: [PATCH 034/139] mainboard/asus/kgpe-d16: Add initial Family 15h CPU
- support
-
-Change-Id: I76f74ed4ae383f8b1f57eaaa2e025035002430f2
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/Kconfig       |   1 +
- src/mainboard/asus/kgpe-d16/cmos.default  |   3 +-
- src/mainboard/asus/kgpe-d16/cmos.layout   |  15 +-
- src/mainboard/asus/kgpe-d16/devicetree.cb |   4 +
- src/mainboard/asus/kgpe-d16/resourcemap.c | 276 +++++++++++++++++++++++++++++-
- src/mainboard/asus/kgpe-d16/romstage.c    |  58 ++++---
- 6 files changed, 326 insertions(+), 31 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-index 9471692..8906dee 100644
---- a/src/mainboard/asus/kgpe-d16/Kconfig
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -13,6 +13,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
-       select SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
-       select SUPERIO_NUVOTON_NCT5572D
-       select PARALLEL_CPU_INIT
-+      select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-       select HAVE_HARD_RESET
-       select HAVE_OPTION_TABLE
-       select HAVE_CMOS_DEFAULT
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index 39a4778..3e2ea3a 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -2,13 +2,14 @@ baud_rate = 115200
- debug_level = Spew
- multi_core = Enable
- slow_cpu = off
-+compute_unit_siblings = Enable
- iommu = Disable
- nmi = Disable
- hypertransport_speed_limit = Auto
- max_mem_clock = DDR3-1600
- minimum_memory_voltage = 1.5V
- ECC_memory = Enable
--ECC_redirection = Disable
-+ECC_redirection = Enable
- ecc_scrub_rate = 1.28us
- interleave_chip_selects = Enable
- interleave_nodes = Disable
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index 110e0bb..e55edc4 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -31,8 +31,8 @@ entries
- 401          1       e       1        interleave_chip_selects
- 402          1       e       1        interleave_nodes
- 403          1       e       1        interleave_memory_channels
--404          2       e       8        max_mem_clock
--406          1       e       2        multi_core
-+404          4       e       8        max_mem_clock
-+408          1       e       2        multi_core
- 412          4       e       6        debug_level
- 440          4       e       9        slow_cpu
- 444          1       e       1        nmi
-@@ -42,6 +42,7 @@ entries
- 457          1       e       1        ECC_redirection
- 458          4       e       11       hypertransport_speed_limit
- 462          2       e       12       minimum_memory_voltage
-+464          1       e       2        compute_unit_siblings
- 477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
-@@ -79,10 +80,12 @@ enumerations
- 6     6     Information
- 6     7     Debug
- 6     8     Spew
--8     0     DDR3-1600
--8     1     DDR3-1333
--8     2     DDR3-1066
--8     3     DDR3-800
-+8     0     DDR3-1866
-+8     1     DDR3-1600
-+8     2     DDR3-1333
-+8     3     DDR3-1066
-+8     4     DDR3-800
-+8     5     DDR3-667
- 9     0     off
- 9     1     87.5%
- 9     2     75.0%
-diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
-index a172d89..18e337e 100644
---- a/src/mainboard/asus/kgpe-d16/devicetree.cb
-+++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
-@@ -228,21 +228,25 @@ chip northbridge/amd/amdfam10/root_complex       # Root 
complex
-                       device pci 18.2 on end
-                       device pci 18.3 on end
-                       device pci 18.4 on end
-+                      device pci 18.5 on end
-                       device pci 19.0 on end          # Socket 0 node 1
-                       device pci 19.1 on end
-                       device pci 19.2 on end
-                       device pci 19.3 on end
-                       device pci 19.4 on end
-+                      device pci 19.5 on end
-                       device pci 1a.0 on end          # Socket 1 node 0
-                       device pci 1a.1 on end
-                       device pci 1a.2 on end
-                       device pci 1a.3 on end
-                       device pci 1a.4 on end
-+                      device pci 1a.5 on end
-                       device pci 1b.0 on end          # Socket 1 node 1
-                       device pci 1b.1 on end
-                       device pci 1b.2 on end
-                       device pci 1b.3 on end
-                       device pci 1b.4 on end
-+                      device pci 1b.5 on end
-               end
-       end
- end
-diff --git a/src/mainboard/asus/kgpe-d16/resourcemap.c 
b/src/mainboard/asus/kgpe-d16/resourcemap.c
-index 3e240dc..3aab8b8 100644
---- a/src/mainboard/asus/kgpe-d16/resourcemap.c
-+++ b/src/mainboard/asus/kgpe-d16/resourcemap.c
-@@ -23,7 +23,262 @@
- 
- static void setup_mb_resource_map(void)
- {
--      static const unsigned int register_values[] = {
-+      static const unsigned int fam15h_register_values[] = {
-+              /* Careful set limit registers before base registers which 
contain the enables */
-+              /* DRAM Limit i Registers
-+               * F1:0x44 i = 0
-+               * F1:0x4C i = 1
-+               * F1:0x54 i = 2
-+               * F1:0x5C i = 3
-+               * F1:0x64 i = 4
-+               * F1:0x6C i = 5
-+               * F1:0x74 i = 6
-+               * F1:0x7C i = 7
-+               * [ 2: 0] Destination Node ID
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 7: 3] Reserved
-+               * [10: 8] Interleave select
-+               *         specifies the values of A[14:12] to use with 
interleave enable.
-+               * [15:11] Reserved
-+               * [31:16] DRAM Limit Address i Bits 39-24
-+               *         This field defines the upper address bits of a 40 
bit  address
-+               *         that define the end of the DRAM region.
-+               */
-+              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x44), 0x0000f8f8, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x4C), 0x0000f8f8, 
0x00000001,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x54), 0x0000f8f8, 
0x00000002,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x5C), 0x0000f8f8, 
0x00000003,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x64), 0x0000f8f8, 
0x00000004,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x6C), 0x0000f8f8, 
0x00000005,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x74), 0x0000f8f8, 
0x00000006,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x7C), 0x0000f8f8, 
0x00000007,
-+
-+              /* DRAM Base i Registers
-+               * F1:0x40 i = 0
-+               * F1:0x48 i = 1
-+               * F1:0x50 i = 2
-+               * F1:0x58 i = 3
-+               * F1:0x60 i = 4
-+               * F1:0x68 i = 5
-+               * F1:0x70 i = 6
-+               * F1:0x78 i = 7
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads Disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes Disabled
-+               *         1 = Writes Enabled
-+               * [ 7: 2] Reserved
-+               * [10: 8] Interleave Enable
-+               *         000 = No interleave
-+               *         001 = Interleave on A[12] (2 nodes)
-+               *         010 = reserved
-+               *         011 = Interleave on A[12] and A[14] (4 nodes)
-+               *         100 = reserved
-+               *         101 = reserved
-+               *         110 = reserved
-+               *         111 = Interleve on A[12] and A[13] and A[14] (8 
nodes)
-+               * [15:11] Reserved
-+               * [31:16] DRAM Base Address i Bits 39-24
-+               *         This field defines the upper address bits of a 
40-bit address
-+               *         that define the start of the DRAM region.
-+               */
-+              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x40), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x48), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x50), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x58), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x60), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x68), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x70), 0x0000f8fc, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x78), 0x0000f8fc, 
0x00000000,
-+
-+              /* Memory-Mapped I/O Limit i Registers
-+               * F1:0x84 i = 0
-+               * F1:0x8C i = 1
-+               * F1:0x94 i = 2
-+               * F1:0x9C i = 3
-+               * F1:0xA4 i = 4
-+               * F1:0xAC i = 5
-+               * F1:0xB4 i = 6
-+               * F1:0xBC i = 7
-+               * [ 2: 0] Destination Node ID
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 3: 3] Reserved
-+               * [ 5: 4] Destination Link ID
-+               *         00 = Link 0
-+               *         01 = Link 1
-+               *         10 = Link 2
-+               *         11 = Link 3
-+               * [ 6: 6] Reserved
-+               * [ 7: 7] Non-Posted
-+               *         0 = CPU writes may be posted
-+               *         1 = CPU writes must be non-posted
-+               * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
-+               *         This field defines the upp adddress bits of a 40-bit 
address that
-+               *         defines the end of a memory-mapped I/O region n
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x84), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x8C), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x94), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x9C), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA4), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xAC), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB4), 0x00000048, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xBC), 0x00000048, 
0x00000000,
-+
-+              /* Memory-Mapped I/O Base i Registers
-+               * F1:0x80 i = 0
-+               * F1:0x88 i = 1
-+               * F1:0x90 i = 2
-+               * F1:0x98 i = 3
-+               * F1:0xA0 i = 4
-+               * F1:0xA8 i = 5
-+               * F1:0xB0 i = 6
-+               * F1:0xB8 i = 7
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes disabled
-+               *         1 = Writes Enabled
-+               * [ 2: 2] Cpu Disable
-+               *         0 = Cpu can use this I/O range
-+               *         1 = Cpu requests do not use this I/O range
-+               * [ 3: 3] Lock
-+               *         0 = base/limit registers i are read/write
-+               *         1 = base/limit registers i are read-only
-+               * [ 7: 4] Reserved
-+               * [31: 8] Memory-Mapped I/O Base Address i (39-16)
-+               *         This field defines the upper address bits of a 40bit 
address
-+               *         that defines the start of memory-mapped I/O region i
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x80), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x88), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x90), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x98), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA0), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA8), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB0), 0x000000f0, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB8), 0x000000f0, 
0x00000000,
-+
-+              /* PCI I/O Limit i Registers
-+               * F1:0xC4 i = 0
-+               * F1:0xCC i = 1
-+               * F1:0xD4 i = 2
-+               * F1:0xDC i = 3
-+               * [ 2: 0] Destination Node ID
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 3: 3] Reserved
-+               * [ 5: 4] Destination Link ID
-+               *         00 = Link 0
-+               *         01 = Link 1
-+               *         10 = Link 2
-+               *         11 = Link 3
-+               * [11: 6] Reserved
-+               * [24:12] PCI I/O Limit Address i
-+               *         This field defines the end of PCI I/O region n
-+               * [31:25] Reserved
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC4), 0xFE000FC8, 
0x00fff010, /* link 1 of cpu 0 --> AMD SR5690 */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xCC), 0xFE000FC8, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD4), 0xFE000FC8, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xDC), 0xFE000FC8, 
0x00000000,
-+
-+              /* PCI I/O Base i Registers
-+               * F1:0xC0 i = 0
-+               * F1:0xC8 i = 1
-+               * F1:0xD0 i = 2
-+               * F1:0xD8 i = 3
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads Disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes Disabled
-+               *         1 = Writes Enabled
-+               * [ 3: 2] Reserved
-+               * [ 4: 4] VGA Enable
-+               *         0 = VGA matches Disabled
-+               *         1 = matches all address < 64K and where A[9:0] is in 
the
-+               *             range 3B0-3BB or 3C0-3DF independent of the base 
& limit registers
-+               * [ 5: 5] ISA Enable
-+               *         0 = ISA matches Disabled
-+               *         1 = Blocks address < 64K and in the last 768 bytes 
of eack 1K block
-+               *             from matching agains this base/limit pair
-+               * [11: 6] Reserved
-+               * [24:12] PCI I/O Base i
-+               *         This field defines the start of PCI I/O region n
-+               * [31:25] Reserved
-+               */
-+//            PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC0), 0xFE000FCC, 
0x00001013,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC8), 0xFE000FCC, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD0), 0xFE000FCC, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD8), 0xFE000FCC, 
0x00000000,
-+
-+              /* Config Base and Limit i Registers
-+               * F1:0xE0 i = 0
-+               * F1:0xE4 i = 1
-+               * F1:0xE8 i = 2
-+               * F1:0xEC i = 3
-+               * [ 0: 0] Read Enable
-+               *         0 = Reads Disabled
-+               *         1 = Reads Enabled
-+               * [ 1: 1] Write Enable
-+               *         0 = Writes Disabled
-+               *         1 = Writes Enabled
-+               * [ 2: 2] Device Number Compare Enable
-+               *         0 = The ranges are based on bus number
-+               *         1 = The ranges are ranges of devices on bus 0
-+               * [ 3: 3] Reserved
-+               * [ 6: 4] Destination Node
-+               *         000 = Node 0
-+               *         001 = Node 1
-+               *         010 = Node 2
-+               *         011 = Node 3
-+               *         100 = Node 4
-+               *         101 = Node 5
-+               *         110 = Node 6
-+               *         111 = Node 7
-+               * [ 7: 7] Reserved
-+               * [ 9: 8] Destination Link
-+               *         00 = Link 0
-+               *         01 = Link 1
-+               *         10 = Link 2
-+               *         11 - Link 3
-+               * [15:10] Reserved
-+               * [23:16] Bus Number Base i
-+               *         This field defines the lowest bus number in 
configuration region i
-+               * [31:24] Bus Number Limit i
-+               *         This field defines the highest bus number in 
configuration region i
-+               */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE0), 0x0000FC88, 
0x05000103, /* link 1 of cpu 0 --> AMD SR5690 */
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE4), 0x0000FC88, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE8), 0x0000FC88, 
0x00000000,
-+              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xEC), 0x0000FC88, 
0x00000000,
-+
-+      };
-+
-+      static const unsigned int fam10h_register_values[] = {
-               /* Careful set limit registers before base registers which 
contain the enables */
-               /* DRAM Limit i Registers
-                * F1:0x44 i = 0
-@@ -279,6 +534,21 @@ static void setup_mb_resource_map(void)
-       };
- 
-       int max;
--      max = ARRAY_SIZE(register_values);
--      setup_resource_map(register_values, max);
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      if (fam15h) {
-+              max = ARRAY_SIZE(fam15h_register_values);
-+              setup_resource_map(fam15h_register_values, max);
-+      } else {
-+              max = ARRAY_SIZE(fam10h_register_values);
-+              setup_resource_map(fam10h_register_values, max);
-+      }
- }
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index a3f3310..9ea7cec 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -42,6 +42,7 @@
- #include <superio/nuvoton/common/nuvoton.h>
- #include <superio/nuvoton/nct5572d/nct5572d.h>
- #include <cpu/x86/bist.h>
-+#include <smp/spinlock.h>
- // #include "northbridge/amd/amdk8/incoherent_ht.c"
- #include <southbridge/amd/sb700/sb700.h>
- #include <southbridge/amd/sb700/smbus.h>
-@@ -202,20 +203,20 @@ void DIMMSetVoltages(struct MCTStatStruc *pMCTstat,
-               if (pDCTstat->NodePresent && (node & 0x1)) {
-                       /* Set voltages */
-                       if (allowed_voltages & 0x8) {
--                              set_voltage = 1150;
-+                              set_voltage = 0x8;
-                               set_ddr3_voltage(socket, 3);
-                       } else if (allowed_voltages & 0x4) {
--                              set_voltage = 1250;
-+                              set_voltage = 0x4;
-                               set_ddr3_voltage(socket, 2);
-                       } else if (allowed_voltages & 0x2) {
--                              set_voltage = 1350;
-+                              set_voltage = 0x2;
-                               set_ddr3_voltage(socket, 1);
-                       } else {
--                              set_voltage = 1500;
-+                              set_voltage = 0x1;
-                               set_ddr3_voltage(socket, 0);
-                       }
- 
--                      /* Save final DIMM voltages for SMBIOS use */
-+                      /* Save final DIMM voltages for MCT and SMBIOS use */
-                       if (pDCTstat->NodePresent) {
-                               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; 
dimm++) {
-                                       pDCTstat->DimmConfiguredVoltage[dimm] = 
set_voltage;
-@@ -229,6 +230,9 @@ void DIMMSetVoltages(struct MCTStatStruc *pMCTstat,
-                       }
-               }
-       }
-+
-+      /* Allow the DDR supply voltages to settle */
-+      udelay(100000);
- }
- 
- static void set_peripheral_control_lines(void) {
-@@ -288,6 +292,18 @@ static void execute_memory_test(void)
- }
- #endif
- 
-+static spinlock_t printk_spinlock CAR_GLOBAL;
-+
-+spinlock_t* romstage_console_lock(void)
-+{
-+      return car_get_var_ptr(&printk_spinlock);
-+}
-+
-+void initialize_romstage_console_lock(void)
-+{
-+      car_get_var(printk_spinlock) = SPIN_LOCK_UNLOCKED;
-+}
-+
- void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
- {
-       struct sys_info *sysinfo = &sysinfo_car;
-@@ -302,6 +318,9 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       int s3resume = acpi_is_wakeup_s3();
- 
-       if (!cpu_init_detectedx && boot_cpu()) {
-+              /* Initialize the printk spinlock */
-+              initialize_romstage_console_lock();
-+
-               /* Nothing special needs to be done to find bus 0 */
-               /* Allow the HT devices to be found */
-               set_bsp_node_CHtExtNodeCfgEn();
-@@ -354,7 +373,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       post_code(0x33);
- 
--      cpuSetAMDMSR();
-+      cpuSetAMDMSR(0);
-       post_code(0x34);
- 
-       amd_ht_init(sysinfo);
-@@ -368,18 +387,21 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       setup_mb_resource_map();
-       post_code(0x36);
- 
--      /* wait for all the APs core0 started by finalize_node_setup. */
--      /* FIXME: A bunch of cores are going to start output to serial at once.
--       * It would be nice to fix up prink spinlocks for ROM XIP mode.
--       * I think it could be done by putting the spinlock flag in the cache
--       * of the BSP located right after sysinfo.
--       */
-+      /* Wait for all the APs core0 started by finalize_node_setup. */
-       wait_all_core0_started();
- 
-       /* run _early_setup before soft-reset. */
-       sr5650_early_setup();
-       sb7xx_51xx_early_setup();
- 
-+      if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
-+              /* Core0 on each node is configured. Now setup any additional 
cores. */
-+              printk(BIOS_DEBUG, "start_other_cores()\n");
-+              start_other_cores();
-+              post_code(0x37);
-+              wait_all_other_cores_started(bsp_apicid);
-+      }
-+
-       if (IS_ENABLED(CONFIG_SET_FIDVID)) {
-               msr = rdmsr(0xc0010071);
-               printk(BIOS_DEBUG, "\nBegin FIDVID MSR 0xc0010071 0x%08x 
0x%08x\n", msr.hi, msr.lo);
-@@ -389,11 +411,13 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-               post_code(0x39);
- 
-+              #if IS_ENABLED(CONFIG_SET_FIDVID)
-               if (!warm_reset_detect(0)) {                    // BSP is node 0
-                       init_fidvid_bsp(bsp_apicid, sysinfo->nodes);
-               } else {
-                       init_fidvid_stage2(bsp_apicid, 0);      // BSP is node 0
-               }
-+              #endif
- 
-               post_code(0x3A);
- 
-@@ -402,21 +426,13 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               printk(BIOS_DEBUG, "End FIDVIDMSR 0xc0010071 0x%08x 0x%08x\n", 
msr.hi, msr.lo);
-       }
- 
--      if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
--              /* Core0 on each node is configured. Now setup any additional 
cores. */
--              printk(BIOS_DEBUG, "start_other_cores()\n");
--              start_other_cores();
--              post_code(0x37);
--              wait_all_other_cores_started(bsp_apicid);
--      }
--
-       post_code(0x38);
- 
-       init_timer(); // Need to use TMICT to synconize FID/VID
- 
-       sr5650_htinit();
- 
--      /* Reset for HT, FIDVID, PLL and errata changes to take affect. */
-+      /* Reset for HT, FIDVID, PLL and errata changes to take effect. */
-       if (!warm_reset_detect(0)) {
-               printk(BIOS_INFO, "...WARM RESET...\n\n\n");
-               soft_reset();
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0035-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
 
b/resources/libreboot/patch/kgpe-d16/0035-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
deleted file mode 100644
index e7068f9..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0035-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From fa4ef470b6b41bdab0063e754df2a8ec8a805238 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 16 Oct 2015 14:08:32 -0500
-Subject: [PATCH 035/139] cpu/amd/family_10h-family_15h: Add Family 15h
- microcode file
-
-Change-Id: I019f94b99d2fc33e19567acecaaad93813ab6b04
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/Makefile.inc | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/Makefile.inc 
b/src/cpu/amd/family_10h-family_15h/Makefile.inc
-index 5a81ab8..6cd2513 100644
---- a/src/cpu/amd/family_10h-family_15h/Makefile.inc
-+++ b/src/cpu/amd/family_10h-family_15h/Makefile.inc
-@@ -12,3 +12,8 @@ ramstage-$(CONFIG_HAVE_ACPI_TABLES) += powernow_acpi.c
- cbfs-files-$(CONFIG_CPU_MICROCODE_MULTIPLE_FILES) += microcode_amd.bin
- microcode_amd.bin-file := 
3rdparty/blobs/cpu/amd/family_10h-family_14h/microcode_amd.bin
- microcode_amd.bin-type := microcode
-+
-+# Microcode for Family 15h
-+cbfs-files-$(CONFIG_CPU_MICROCODE_MULTIPLE_FILES) += microcode_amd_fam15h.bin
-+microcode_amd_fam15h.bin-file := 
3rdparty/blobs/cpu/amd/family_15h/microcode_amd_fam15h.bin
-+microcode_amd_fam15h.bin-type := microcode
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0035-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
 
b/resources/libreboot/patch/kgpe-d16/0035-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
new file mode 100644
index 0000000..b9d6f92
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0035-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch
@@ -0,0 +1,556 @@
+From 2774e3488cb3fa2139cd40930a035f0fcfc13ec5 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 5 Sep 2015 19:37:57 -0500
+Subject: [PATCH 035/143] mainboard/asus/kgpe-d16: Add initial Family 15h CPU
+ support
+
+Change-Id: I76f74ed4ae383f8b1f57eaaa2e025035002430f2
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/Kconfig       |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.default  |    3 +-
+ src/mainboard/asus/kgpe-d16/cmos.layout   |   15 +-
+ src/mainboard/asus/kgpe-d16/devicetree.cb |    4 +
+ src/mainboard/asus/kgpe-d16/resourcemap.c |  276 ++++++++++++++++++++++++++++-
+ src/mainboard/asus/kgpe-d16/romstage.c    |   56 +++---
+ 6 files changed, 325 insertions(+), 30 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+index 9471692..8906dee 100644
+--- a/src/mainboard/asus/kgpe-d16/Kconfig
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -13,6 +13,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+       select SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
+       select SUPERIO_NUVOTON_NCT5572D
+       select PARALLEL_CPU_INIT
++      select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
+       select HAVE_HARD_RESET
+       select HAVE_OPTION_TABLE
+       select HAVE_CMOS_DEFAULT
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index 39a4778..3e2ea3a 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -2,13 +2,14 @@ baud_rate = 115200
+ debug_level = Spew
+ multi_core = Enable
+ slow_cpu = off
++compute_unit_siblings = Enable
+ iommu = Disable
+ nmi = Disable
+ hypertransport_speed_limit = Auto
+ max_mem_clock = DDR3-1600
+ minimum_memory_voltage = 1.5V
+ ECC_memory = Enable
+-ECC_redirection = Disable
++ECC_redirection = Enable
+ ecc_scrub_rate = 1.28us
+ interleave_chip_selects = Enable
+ interleave_nodes = Disable
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 110e0bb..e55edc4 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -31,8 +31,8 @@ entries
+ 401          1       e       1        interleave_chip_selects
+ 402          1       e       1        interleave_nodes
+ 403          1       e       1        interleave_memory_channels
+-404          2       e       8        max_mem_clock
+-406          1       e       2        multi_core
++404          4       e       8        max_mem_clock
++408          1       e       2        multi_core
+ 412          4       e       6        debug_level
+ 440          4       e       9        slow_cpu
+ 444          1       e       1        nmi
+@@ -42,6 +42,7 @@ entries
+ 457          1       e       1        ECC_redirection
+ 458          4       e       11       hypertransport_speed_limit
+ 462          2       e       12       minimum_memory_voltage
++464          1       e       2        compute_unit_siblings
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+@@ -79,10 +80,12 @@ enumerations
+ 6     6     Information
+ 6     7     Debug
+ 6     8     Spew
+-8     0     DDR3-1600
+-8     1     DDR3-1333
+-8     2     DDR3-1066
+-8     3     DDR3-800
++8     0     DDR3-1866
++8     1     DDR3-1600
++8     2     DDR3-1333
++8     3     DDR3-1066
++8     4     DDR3-800
++8     5     DDR3-667
+ 9     0     off
+ 9     1     87.5%
+ 9     2     75.0%
+diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
+index f4769fd..cd22893 100644
+--- a/src/mainboard/asus/kgpe-d16/devicetree.cb
++++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
+@@ -229,21 +229,25 @@ chip northbridge/amd/amdfam10/root_complex       # Root 
complex
+                       device pci 18.2 on end
+                       device pci 18.3 on end
+                       device pci 18.4 on end
++                      device pci 18.5 on end
+                       device pci 19.0 on end          # Socket 0 node 1
+                       device pci 19.1 on end
+                       device pci 19.2 on end
+                       device pci 19.3 on end
+                       device pci 19.4 on end
++                      device pci 19.5 on end
+                       device pci 1a.0 on end          # Socket 1 node 0
+                       device pci 1a.1 on end
+                       device pci 1a.2 on end
+                       device pci 1a.3 on end
+                       device pci 1a.4 on end
++                      device pci 1a.5 on end
+                       device pci 1b.0 on end          # Socket 1 node 1
+                       device pci 1b.1 on end
+                       device pci 1b.2 on end
+                       device pci 1b.3 on end
+                       device pci 1b.4 on end
++                      device pci 1b.5 on end
+               end
+       end
+ end
+diff --git a/src/mainboard/asus/kgpe-d16/resourcemap.c 
b/src/mainboard/asus/kgpe-d16/resourcemap.c
+index 3e240dc..3aab8b8 100644
+--- a/src/mainboard/asus/kgpe-d16/resourcemap.c
++++ b/src/mainboard/asus/kgpe-d16/resourcemap.c
+@@ -23,7 +23,262 @@
+ 
+ static void setup_mb_resource_map(void)
+ {
+-      static const unsigned int register_values[] = {
++      static const unsigned int fam15h_register_values[] = {
++              /* Careful set limit registers before base registers which 
contain the enables */
++              /* DRAM Limit i Registers
++               * F1:0x44 i = 0
++               * F1:0x4C i = 1
++               * F1:0x54 i = 2
++               * F1:0x5C i = 3
++               * F1:0x64 i = 4
++               * F1:0x6C i = 5
++               * F1:0x74 i = 6
++               * F1:0x7C i = 7
++               * [ 2: 0] Destination Node ID
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 7: 3] Reserved
++               * [10: 8] Interleave select
++               *         specifies the values of A[14:12] to use with 
interleave enable.
++               * [15:11] Reserved
++               * [31:16] DRAM Limit Address i Bits 39-24
++               *         This field defines the upper address bits of a 40 
bit  address
++               *         that define the end of the DRAM region.
++               */
++              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x44), 0x0000f8f8, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x4C), 0x0000f8f8, 
0x00000001,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x54), 0x0000f8f8, 
0x00000002,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x5C), 0x0000f8f8, 
0x00000003,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x64), 0x0000f8f8, 
0x00000004,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x6C), 0x0000f8f8, 
0x00000005,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x74), 0x0000f8f8, 
0x00000006,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x7C), 0x0000f8f8, 
0x00000007,
++
++              /* DRAM Base i Registers
++               * F1:0x40 i = 0
++               * F1:0x48 i = 1
++               * F1:0x50 i = 2
++               * F1:0x58 i = 3
++               * F1:0x60 i = 4
++               * F1:0x68 i = 5
++               * F1:0x70 i = 6
++               * F1:0x78 i = 7
++               * [ 0: 0] Read Enable
++               *         0 = Reads Disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes Disabled
++               *         1 = Writes Enabled
++               * [ 7: 2] Reserved
++               * [10: 8] Interleave Enable
++               *         000 = No interleave
++               *         001 = Interleave on A[12] (2 nodes)
++               *         010 = reserved
++               *         011 = Interleave on A[12] and A[14] (4 nodes)
++               *         100 = reserved
++               *         101 = reserved
++               *         110 = reserved
++               *         111 = Interleve on A[12] and A[13] and A[14] (8 
nodes)
++               * [15:11] Reserved
++               * [31:16] DRAM Base Address i Bits 39-24
++               *         This field defines the upper address bits of a 
40-bit address
++               *         that define the start of the DRAM region.
++               */
++              // PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x40), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x48), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x50), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x58), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x60), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x68), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x70), 0x0000f8fc, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x78), 0x0000f8fc, 
0x00000000,
++
++              /* Memory-Mapped I/O Limit i Registers
++               * F1:0x84 i = 0
++               * F1:0x8C i = 1
++               * F1:0x94 i = 2
++               * F1:0x9C i = 3
++               * F1:0xA4 i = 4
++               * F1:0xAC i = 5
++               * F1:0xB4 i = 6
++               * F1:0xBC i = 7
++               * [ 2: 0] Destination Node ID
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 3: 3] Reserved
++               * [ 5: 4] Destination Link ID
++               *         00 = Link 0
++               *         01 = Link 1
++               *         10 = Link 2
++               *         11 = Link 3
++               * [ 6: 6] Reserved
++               * [ 7: 7] Non-Posted
++               *         0 = CPU writes may be posted
++               *         1 = CPU writes must be non-posted
++               * [31: 8] Memory-Mapped I/O Limit Address i (39-16)
++               *         This field defines the upp adddress bits of a 40-bit 
address that
++               *         defines the end of a memory-mapped I/O region n
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x84), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x8C), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x94), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x9C), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA4), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xAC), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB4), 0x00000048, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xBC), 0x00000048, 
0x00000000,
++
++              /* Memory-Mapped I/O Base i Registers
++               * F1:0x80 i = 0
++               * F1:0x88 i = 1
++               * F1:0x90 i = 2
++               * F1:0x98 i = 3
++               * F1:0xA0 i = 4
++               * F1:0xA8 i = 5
++               * F1:0xB0 i = 6
++               * F1:0xB8 i = 7
++               * [ 0: 0] Read Enable
++               *         0 = Reads disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes disabled
++               *         1 = Writes Enabled
++               * [ 2: 2] Cpu Disable
++               *         0 = Cpu can use this I/O range
++               *         1 = Cpu requests do not use this I/O range
++               * [ 3: 3] Lock
++               *         0 = base/limit registers i are read/write
++               *         1 = base/limit registers i are read-only
++               * [ 7: 4] Reserved
++               * [31: 8] Memory-Mapped I/O Base Address i (39-16)
++               *         This field defines the upper address bits of a 40bit 
address
++               *         that defines the start of memory-mapped I/O region i
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x80), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x88), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x90), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0x98), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA0), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xA8), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB0), 0x000000f0, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xB8), 0x000000f0, 
0x00000000,
++
++              /* PCI I/O Limit i Registers
++               * F1:0xC4 i = 0
++               * F1:0xCC i = 1
++               * F1:0xD4 i = 2
++               * F1:0xDC i = 3
++               * [ 2: 0] Destination Node ID
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 3: 3] Reserved
++               * [ 5: 4] Destination Link ID
++               *         00 = Link 0
++               *         01 = Link 1
++               *         10 = Link 2
++               *         11 = Link 3
++               * [11: 6] Reserved
++               * [24:12] PCI I/O Limit Address i
++               *         This field defines the end of PCI I/O region n
++               * [31:25] Reserved
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC4), 0xFE000FC8, 
0x00fff010, /* link 1 of cpu 0 --> AMD SR5690 */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xCC), 0xFE000FC8, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD4), 0xFE000FC8, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xDC), 0xFE000FC8, 
0x00000000,
++
++              /* PCI I/O Base i Registers
++               * F1:0xC0 i = 0
++               * F1:0xC8 i = 1
++               * F1:0xD0 i = 2
++               * F1:0xD8 i = 3
++               * [ 0: 0] Read Enable
++               *         0 = Reads Disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes Disabled
++               *         1 = Writes Enabled
++               * [ 3: 2] Reserved
++               * [ 4: 4] VGA Enable
++               *         0 = VGA matches Disabled
++               *         1 = matches all address < 64K and where A[9:0] is in 
the
++               *             range 3B0-3BB or 3C0-3DF independent of the base 
& limit registers
++               * [ 5: 5] ISA Enable
++               *         0 = ISA matches Disabled
++               *         1 = Blocks address < 64K and in the last 768 bytes 
of eack 1K block
++               *             from matching agains this base/limit pair
++               * [11: 6] Reserved
++               * [24:12] PCI I/O Base i
++               *         This field defines the start of PCI I/O region n
++               * [31:25] Reserved
++               */
++//            PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC0), 0xFE000FCC, 
0x00001013,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xC8), 0xFE000FCC, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD0), 0xFE000FCC, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xD8), 0xFE000FCC, 
0x00000000,
++
++              /* Config Base and Limit i Registers
++               * F1:0xE0 i = 0
++               * F1:0xE4 i = 1
++               * F1:0xE8 i = 2
++               * F1:0xEC i = 3
++               * [ 0: 0] Read Enable
++               *         0 = Reads Disabled
++               *         1 = Reads Enabled
++               * [ 1: 1] Write Enable
++               *         0 = Writes Disabled
++               *         1 = Writes Enabled
++               * [ 2: 2] Device Number Compare Enable
++               *         0 = The ranges are based on bus number
++               *         1 = The ranges are ranges of devices on bus 0
++               * [ 3: 3] Reserved
++               * [ 6: 4] Destination Node
++               *         000 = Node 0
++               *         001 = Node 1
++               *         010 = Node 2
++               *         011 = Node 3
++               *         100 = Node 4
++               *         101 = Node 5
++               *         110 = Node 6
++               *         111 = Node 7
++               * [ 7: 7] Reserved
++               * [ 9: 8] Destination Link
++               *         00 = Link 0
++               *         01 = Link 1
++               *         10 = Link 2
++               *         11 - Link 3
++               * [15:10] Reserved
++               * [23:16] Bus Number Base i
++               *         This field defines the lowest bus number in 
configuration region i
++               * [31:24] Bus Number Limit i
++               *         This field defines the highest bus number in 
configuration region i
++               */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE0), 0x0000FC88, 
0x05000103, /* link 1 of cpu 0 --> AMD SR5690 */
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE4), 0x0000FC88, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xE8), 0x0000FC88, 
0x00000000,
++              PCI_ADDR(CONFIG_CBB, CONFIG_CDB, 1, 0xEC), 0x0000FC88, 
0x00000000,
++
++      };
++
++      static const unsigned int fam10h_register_values[] = {
+               /* Careful set limit registers before base registers which 
contain the enables */
+               /* DRAM Limit i Registers
+                * F1:0x44 i = 0
+@@ -279,6 +534,21 @@ static void setup_mb_resource_map(void)
+       };
+ 
+       int max;
+-      max = ARRAY_SIZE(register_values);
+-      setup_resource_map(register_values, max);
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      if (fam15h) {
++              max = ARRAY_SIZE(fam15h_register_values);
++              setup_resource_map(fam15h_register_values, max);
++      } else {
++              max = ARRAY_SIZE(fam10h_register_values);
++              setup_resource_map(fam10h_register_values, max);
++      }
+ }
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index a58fd0f..4b4e305 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -42,6 +42,7 @@
+ #include <superio/nuvoton/common/nuvoton.h>
+ #include <superio/nuvoton/nct5572d/nct5572d.h>
+ #include <cpu/x86/bist.h>
++#include <smp/spinlock.h>
+ // #include "northbridge/amd/amdk8/incoherent_ht.c"
+ #include <southbridge/amd/sb700/sb700.h>
+ #include <southbridge/amd/sb700/smbus.h>
+@@ -202,20 +203,20 @@ void DIMMSetVoltages(struct MCTStatStruc *pMCTstat,
+               if (pDCTstat->NodePresent && (node & 0x1)) {
+                       /* Set voltages */
+                       if (allowed_voltages & 0x8) {
+-                              set_voltage = 1150;
++                              set_voltage = 0x8;
+                               set_ddr3_voltage(socket, 3);
+                       } else if (allowed_voltages & 0x4) {
+-                              set_voltage = 1250;
++                              set_voltage = 0x4;
+                               set_ddr3_voltage(socket, 2);
+                       } else if (allowed_voltages & 0x2) {
+-                              set_voltage = 1350;
++                              set_voltage = 0x2;
+                               set_ddr3_voltage(socket, 1);
+                       } else {
+-                              set_voltage = 1500;
++                              set_voltage = 0x1;
+                               set_ddr3_voltage(socket, 0);
+                       }
+ 
+-                      /* Save final DIMM voltages for SMBIOS use */
++                      /* Save final DIMM voltages for MCT and SMBIOS use */
+                       if (pDCTstat->NodePresent) {
+                               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; 
dimm++) {
+                                       pDCTstat->DimmConfiguredVoltage[dimm] = 
set_voltage;
+@@ -229,6 +230,9 @@ void DIMMSetVoltages(struct MCTStatStruc *pMCTstat,
+                       }
+               }
+       }
++
++      /* Allow the DDR supply voltages to settle */
++      udelay(100000);
+ }
+ 
+ static void set_peripheral_control_lines(void) {
+@@ -288,6 +292,18 @@ static void execute_memory_test(void)
+ }
+ #endif
+ 
++static spinlock_t printk_spinlock CAR_GLOBAL;
++
++spinlock_t* romstage_console_lock(void)
++{
++      return car_get_var_ptr(&printk_spinlock);
++}
++
++void initialize_romstage_console_lock(void)
++{
++      car_get_var(printk_spinlock) = SPIN_LOCK_UNLOCKED;
++}
++
+ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
+ {
+       struct sys_info *sysinfo = &sysinfo_car;
+@@ -302,6 +318,9 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+       int s3resume = acpi_is_wakeup_s3();
+ 
+       if (!cpu_init_detectedx && boot_cpu()) {
++              /* Initialize the printk spinlock */
++              initialize_romstage_console_lock();
++
+               /* Nothing special needs to be done to find bus 0 */
+               /* Allow the HT devices to be found */
+               set_bsp_node_CHtExtNodeCfgEn();
+@@ -368,18 +387,21 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+       setup_mb_resource_map();
+       post_code(0x36);
+ 
+-      /* wait for all the APs core0 started by finalize_node_setup. */
+-      /* FIXME: A bunch of cores are going to start output to serial at once.
+-       * It would be nice to fix up prink spinlocks for ROM XIP mode.
+-       * I think it could be done by putting the spinlock flag in the cache
+-       * of the BSP located right after sysinfo.
+-       */
++      /* Wait for all the APs core0 started by finalize_node_setup. */
+       wait_all_core0_started();
+ 
+       /* run _early_setup before soft-reset. */
+       sr5650_early_setup();
+       sb7xx_51xx_early_setup();
+ 
++      if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
++              /* Core0 on each node is configured. Now setup any additional 
cores. */
++              printk(BIOS_DEBUG, "start_other_cores()\n");
++              start_other_cores();
++              post_code(0x37);
++              wait_all_other_cores_started(bsp_apicid);
++      }
++
+       if (IS_ENABLED(CONFIG_SET_FIDVID)) {
+               msr = rdmsr(0xc0010071);
+               printk(BIOS_DEBUG, "\nBegin FIDVID MSR 0xc0010071 0x%08x 
0x%08x\n", msr.hi, msr.lo);
+@@ -389,11 +411,13 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+               post_code(0x39);
+ 
++              #if IS_ENABLED(CONFIG_SET_FIDVID)
+               if (!warm_reset_detect(0)) {                    // BSP is node 0
+                       init_fidvid_bsp(bsp_apicid, sysinfo->nodes);
+               } else {
+                       init_fidvid_stage2(bsp_apicid, 0);      // BSP is node 0
+               }
++              #endif
+ 
+               post_code(0x3A);
+ 
+@@ -402,21 +426,13 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               printk(BIOS_DEBUG, "End FIDVIDMSR 0xc0010071 0x%08x 0x%08x\n", 
msr.hi, msr.lo);
+       }
+ 
+-      if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
+-              /* Core0 on each node is configured. Now setup any additional 
cores. */
+-              printk(BIOS_DEBUG, "start_other_cores()\n");
+-              start_other_cores();
+-              post_code(0x37);
+-              wait_all_other_cores_started(bsp_apicid);
+-      }
+-
+       post_code(0x38);
+ 
+       init_timer(); // Need to use TMICT to synconize FID/VID
+ 
+       sr5650_htinit();
+ 
+-      /* Reset for HT, FIDVID, PLL and errata changes to take affect. */
++      /* Reset for HT, FIDVID, PLL and errata changes to take effect. */
+       if (!warm_reset_detect(0)) {
+               printk(BIOS_INFO, "...WARM RESET...\n\n\n");
+               soft_reset();
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0036-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
 
b/resources/libreboot/patch/kgpe-d16/0036-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
deleted file mode 100644
index cd1a613..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0036-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From fd67f1513d362a0a02f999b632c62b7b5c074a50 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 1 Jun 2015 20:35:42 -0500
-Subject: [PATCH 036/139] amdmct/mct_ddr3: Disable Fam10h-specific MTRR setup
- on Fam15h
-
-Change-Id: I5c12b5ef8564402601634e9f3528bbf9303e0b33
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 12 +++++++-----
- 1 file changed, 7 insertions(+), 5 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 74066b1..4677c73 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1842,11 +1842,13 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
- 
-       if (nv_DQSTrainCTL) {
-               mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
--              /* TODO: should be in mctHookBeforeAnyTraining */
--              _WRMSR(0x26C, 0x04040404, 0x04040404);
--              _WRMSR(0x26D, 0x04040404, 0x04040404);
--              _WRMSR(0x26E, 0x04040404, 0x04040404);
--              _WRMSR(0x26F, 0x04040404, 0x04040404);
-+              if (!is_fam15h()) {
-+                      /* TODO: should be in mctHookBeforeAnyTraining */
-+                      _WRMSR(0x26C, 0x04040404, 0x04040404);
-+                      _WRMSR(0x26D, 0x04040404, 0x04040404);
-+                      _WRMSR(0x26E, 0x04040404, 0x04040404);
-+                      _WRMSR(0x26F, 0x04040404, 0x04040404);
-+              }
-               mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
- 
-               if (is_fam15h()) {
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0036-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
 
b/resources/libreboot/patch/kgpe-d16/0036-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
new file mode 100644
index 0000000..ea9887b
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0036-cpu-amd-family_10h-family_15h-Add-Family-15h-microco.patch
@@ -0,0 +1,28 @@
+From 6cef66c3f775f0c1910d848b4fede77925126c5a Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 16 Oct 2015 14:08:32 -0500
+Subject: [PATCH 036/143] cpu/amd/family_10h-family_15h: Add Family 15h
+ microcode file
+
+Change-Id: I019f94b99d2fc33e19567acecaaad93813ab6b04
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/Makefile.inc |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/Makefile.inc 
b/src/cpu/amd/family_10h-family_15h/Makefile.inc
+index 5a81ab8..6cd2513 100644
+--- a/src/cpu/amd/family_10h-family_15h/Makefile.inc
++++ b/src/cpu/amd/family_10h-family_15h/Makefile.inc
+@@ -12,3 +12,8 @@ ramstage-$(CONFIG_HAVE_ACPI_TABLES) += powernow_acpi.c
+ cbfs-files-$(CONFIG_CPU_MICROCODE_MULTIPLE_FILES) += microcode_amd.bin
+ microcode_amd.bin-file := 
3rdparty/blobs/cpu/amd/family_10h-family_14h/microcode_amd.bin
+ microcode_amd.bin-type := microcode
++
++# Microcode for Family 15h
++cbfs-files-$(CONFIG_CPU_MICROCODE_MULTIPLE_FILES) += microcode_amd_fam15h.bin
++microcode_amd_fam15h.bin-file := 
3rdparty/blobs/cpu/amd/family_15h/microcode_amd_fam15h.bin
++microcode_amd_fam15h.bin-type := microcode
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0037-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
 
b/resources/libreboot/patch/kgpe-d16/0037-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
new file mode 100644
index 0000000..96e544c
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0037-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch
@@ -0,0 +1,38 @@
+From c24f0d24c3957484dafd1d2b91fd1b1a43060c7d Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 1 Jun 2015 20:35:42 -0500
+Subject: [PATCH 037/143] amdmct/mct_ddr3: Disable Fam10h-specific MTRR setup
+ on Fam15h
+
+Change-Id: I5c12b5ef8564402601634e9f3528bbf9303e0b33
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |   12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 74066b1..4677c73 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1842,11 +1842,13 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+ 
+       if (nv_DQSTrainCTL) {
+               mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
+-              /* TODO: should be in mctHookBeforeAnyTraining */
+-              _WRMSR(0x26C, 0x04040404, 0x04040404);
+-              _WRMSR(0x26D, 0x04040404, 0x04040404);
+-              _WRMSR(0x26E, 0x04040404, 0x04040404);
+-              _WRMSR(0x26F, 0x04040404, 0x04040404);
++              if (!is_fam15h()) {
++                      /* TODO: should be in mctHookBeforeAnyTraining */
++                      _WRMSR(0x26C, 0x04040404, 0x04040404);
++                      _WRMSR(0x26D, 0x04040404, 0x04040404);
++                      _WRMSR(0x26E, 0x04040404, 0x04040404);
++                      _WRMSR(0x26F, 0x04040404, 0x04040404);
++              }
+               mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
+ 
+               if (is_fam15h()) {
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0037-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0037-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
deleted file mode 100644
index d8c5a24..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0037-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 5ae2feaab88902ab9d5bb95eab1ec396f9c01b9f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 1 Jun 2015 23:58:59 -0500
-Subject: [PATCH 037/139] cpu/amd/car: Add romstage BSP stack overrun detection
-
-Change-Id: Ia2e8f99be9df388e492a633c49df21ca1c57ba13
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/car/cache_as_ram.inc    | 6 +++++-
- src/cpu/amd/car/post_cache_as_ram.c | 8 ++++++++
- 2 files changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
-index 6542906..4ccde3f 100644
---- a/src/cpu/amd/car/cache_as_ram.inc
-+++ b/src/cpu/amd/car/cache_as_ram.inc
-@@ -24,7 +24,7 @@
- #include <cpu/amd/mtrr.h>
- 
- #define CacheSize             CONFIG_DCACHE_RAM_SIZE
--#define CacheBase             (0xd0000 - CacheSize)
-+#define CacheBase             CONFIG_DCACHE_RAM_BASE
- #define CacheSizeBSPStack     CONFIG_DCACHE_BSP_STACK_SIZE
- #define CacheSizeBSPSlush     CONFIG_DCACHE_BSP_STACK_SLUSH
- 
-@@ -473,6 +473,10 @@ fam10_end_part1:
-       movl    $(CacheBase + CacheSize), %eax
-       movl    %eax, %esp
- 
-+      /* Poison the lower stack boundary */
-+      movl    $((CacheBase + CacheSize) - CacheSizeBSPStack), %eax
-+      movl    $0xdeadbeef, (%eax)
-+
-       post_code(0xa3)
- 
-       jmp     CAR_FAM10_ap_out
-diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
-index 257b41a..787bedd 100644
---- a/src/cpu/amd/car/post_cache_as_ram.c
-+++ b/src/cpu/amd/car/post_cache_as_ram.c
-@@ -110,6 +110,14 @@ void post_cache_as_ram(void)
-       void *resume_backup_memory = NULL;
-       uint32_t family = amd_fam1x_cpu_family();
- 
-+      /* Verify that the BSP didn't overrun the lower stack
-+       * boundary during romstage execution
-+       */
-+      volatile uint32_t *lower_stack_boundary;
-+      lower_stack_boundary = (void *)((CONFIG_DCACHE_RAM_BASE + 
CONFIG_DCACHE_RAM_SIZE) - CONFIG_STACK_SIZE);
-+      if ((*lower_stack_boundary) != 0xdeadbeef)
-+              printk(BIOS_WARNING, "BSP overran lower stack boundary.  
Undefined behaviour may result!\n");
-+
-       struct romstage_handoff *handoff;
-       handoff = romstage_handoff_find_or_add();
-       if (handoff != NULL)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
new file mode 100644
index 0000000..5300db1
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch
@@ -0,0 +1,59 @@
+From ed27521eaee0dd334c658fb68d0c8ebaa6a126cc Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 1 Jun 2015 23:58:59 -0500
+Subject: [PATCH 038/143] cpu/amd/car: Add romstage BSP stack overrun
+ detection
+
+Change-Id: Ia2e8f99be9df388e492a633c49df21ca1c57ba13
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/car/cache_as_ram.inc    |    6 +++++-
+ src/cpu/amd/car/post_cache_as_ram.c |    8 ++++++++
+ 2 files changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
+index 6542906..4ccde3f 100644
+--- a/src/cpu/amd/car/cache_as_ram.inc
++++ b/src/cpu/amd/car/cache_as_ram.inc
+@@ -24,7 +24,7 @@
+ #include <cpu/amd/mtrr.h>
+ 
+ #define CacheSize             CONFIG_DCACHE_RAM_SIZE
+-#define CacheBase             (0xd0000 - CacheSize)
++#define CacheBase             CONFIG_DCACHE_RAM_BASE
+ #define CacheSizeBSPStack     CONFIG_DCACHE_BSP_STACK_SIZE
+ #define CacheSizeBSPSlush     CONFIG_DCACHE_BSP_STACK_SLUSH
+ 
+@@ -473,6 +473,10 @@ fam10_end_part1:
+       movl    $(CacheBase + CacheSize), %eax
+       movl    %eax, %esp
+ 
++      /* Poison the lower stack boundary */
++      movl    $((CacheBase + CacheSize) - CacheSizeBSPStack), %eax
++      movl    $0xdeadbeef, (%eax)
++
+       post_code(0xa3)
+ 
+       jmp     CAR_FAM10_ap_out
+diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
+index 257b41a..787bedd 100644
+--- a/src/cpu/amd/car/post_cache_as_ram.c
++++ b/src/cpu/amd/car/post_cache_as_ram.c
+@@ -110,6 +110,14 @@ void post_cache_as_ram(void)
+       void *resume_backup_memory = NULL;
+       uint32_t family = amd_fam1x_cpu_family();
+ 
++      /* Verify that the BSP didn't overrun the lower stack
++       * boundary during romstage execution
++       */
++      volatile uint32_t *lower_stack_boundary;
++      lower_stack_boundary = (void *)((CONFIG_DCACHE_RAM_BASE + 
CONFIG_DCACHE_RAM_SIZE) - CONFIG_STACK_SIZE);
++      if ((*lower_stack_boundary) != 0xdeadbeef)
++              printk(BIOS_WARNING, "BSP overran lower stack boundary.  
Undefined behaviour may result!\n");
++
+       struct romstage_handoff *handoff;
+       handoff = romstage_handoff_find_or_add();
+       if (handoff != NULL)
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
 
b/resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
deleted file mode 100644
index b0ad3b3..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0038-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From e3a15e1b280319fc3c95617b46630b31cf9b571e Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 2 Jun 2015 13:25:23 -0500
-Subject: [PATCH 038/139] cpu/amd/car: Increase Family 10h CAR size limit to
- 128k
-
-This resolves issues with 4-node (32-core) systems not having
-sufficient CAR memory to boot.
-
-Change-Id: I5378df7fe8c034ba30f7fdf454f81dd10a0c2ae4
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/car/post_cache_as_ram.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
-index 787bedd..2282cee 100644
---- a/src/cpu/amd/car/post_cache_as_ram.c
-+++ b/src/cpu/amd/car/post_cache_as_ram.c
-@@ -114,7 +114,7 @@ void post_cache_as_ram(void)
-        * boundary during romstage execution
-        */
-       volatile uint32_t *lower_stack_boundary;
--      lower_stack_boundary = (void *)((CONFIG_DCACHE_RAM_BASE + 
CONFIG_DCACHE_RAM_SIZE) - CONFIG_STACK_SIZE);
-+      lower_stack_boundary = (void *)((CONFIG_DCACHE_RAM_BASE + 
CONFIG_DCACHE_RAM_SIZE) - CONFIG_DCACHE_BSP_STACK_SIZE);
-       if ((*lower_stack_boundary) != 0xdeadbeef)
-               printk(BIOS_WARNING, "BSP overran lower stack boundary.  
Undefined behaviour may result!\n");
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
 
b/resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
new file mode 100644
index 0000000..17285a1
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch
@@ -0,0 +1,31 @@
+From 3cc65b99ac7b00ba5960c5c40a984bebafcf379a Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 2 Jun 2015 13:25:23 -0500
+Subject: [PATCH 039/143] cpu/amd/car: Increase Family 10h CAR size limit to
+ 128k
+
+This resolves issues with 4-node (32-core) systems not having
+sufficient CAR memory to boot.
+
+Change-Id: I5378df7fe8c034ba30f7fdf454f81dd10a0c2ae4
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/car/post_cache_as_ram.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
+index 787bedd..2282cee 100644
+--- a/src/cpu/amd/car/post_cache_as_ram.c
++++ b/src/cpu/amd/car/post_cache_as_ram.c
+@@ -114,7 +114,7 @@ void post_cache_as_ram(void)
+        * boundary during romstage execution
+        */
+       volatile uint32_t *lower_stack_boundary;
+-      lower_stack_boundary = (void *)((CONFIG_DCACHE_RAM_BASE + 
CONFIG_DCACHE_RAM_SIZE) - CONFIG_STACK_SIZE);
++      lower_stack_boundary = (void *)((CONFIG_DCACHE_RAM_BASE + 
CONFIG_DCACHE_RAM_SIZE) - CONFIG_DCACHE_BSP_STACK_SIZE);
+       if ((*lower_stack_boundary) != 0xdeadbeef)
+               printk(BIOS_WARNING, "BSP overran lower stack boundary.  
Undefined behaviour may result!\n");
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
 
b/resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
deleted file mode 100644
index 9364346..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From f14fb79d7a979b95ad94b35e5127dfa033b5734c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 2 Jun 2015 20:18:44 -0500
-Subject: [PATCH 039/139] cpu/amd/car: Move AP stacks below the BSP stack to
- free up space
-
-Caching SPD data during startup requires additional CAR space.
-There was a large chunk of free space between the AP stack top and
-the BSP stack bottom; moving the AP stacks below the BSP stack
-allows this space to be utilized.
-
-Change-Id: I51af31442f2b77cb64a4b788751ccc7186acb283
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/Kconfig 
b/src/cpu/amd/family_10h-family_15h/Kconfig
-index 7c47e27..81b1d1e 100644
---- a/src/cpu/amd/family_10h-family_15h/Kconfig
-+++ b/src/cpu/amd/family_10h-family_15h/Kconfig
-@@ -33,7 +33,7 @@ config DCACHE_RAM_SIZE
- 
- config DCACHE_BSP_STACK_SIZE
-       hex
--      default 0x2000
-+      default 0x4000
- 
- config DCACHE_BSP_STACK_SLUSH
-       hex
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0040-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
 
b/resources/libreboot/patch/kgpe-d16/0040-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
new file mode 100644
index 0000000..d7a949a
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0040-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch
@@ -0,0 +1,33 @@
+From 4dfbaf7e6fd49d46c58f8f5e58d0ce4e7e97fa04 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 2 Jun 2015 20:18:44 -0500
+Subject: [PATCH 040/143] cpu/amd/car: Move AP stacks below the BSP stack to
+ free up space
+
+Caching SPD data during startup requires additional CAR space.
+There was a large chunk of free space between the AP stack top and
+the BSP stack bottom; moving the AP stacks below the BSP stack
+allows this space to be utilized.
+
+Change-Id: I51af31442f2b77cb64a4b788751ccc7186acb283
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/Kconfig |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/Kconfig 
b/src/cpu/amd/family_10h-family_15h/Kconfig
+index 7c47e27..81b1d1e 100644
+--- a/src/cpu/amd/family_10h-family_15h/Kconfig
++++ b/src/cpu/amd/family_10h-family_15h/Kconfig
+@@ -33,7 +33,7 @@ config DCACHE_RAM_SIZE
+ 
+ config DCACHE_BSP_STACK_SIZE
+       hex
+-      default 0x2000
++      default 0x4000
+ 
+ config DCACHE_BSP_STACK_SLUSH
+       hex
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0040-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
 
b/resources/libreboot/patch/kgpe-d16/0040-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
deleted file mode 100644
index d70b895..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0040-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
+++ /dev/null
@@ -1,461 +0,0 @@
-From f26e90bcbbd7b5966ac353a7e7ba63fa188ffac0 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 2 Jun 2015 20:51:59 -0500
-Subject: [PATCH 040/139] northbridge/amd/amdmct: Read SPD data into cache to
- decrease bootup time
-
-Change-Id: Ic16a927a3f1fc6f7cb1aea36a8abe8cc1999cb52
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 161 +++++++++++++++-------------
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |   7 ++
- 2 files changed, 92 insertions(+), 76 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 4677c73..5344ff9 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -180,7 +180,7 @@ static void mct_WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
- static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct);
- static void SyncSetting(struct DCTStatStruc *pDCTstat);
--static u8 crcCheck(u8 smbaddr);
-+static uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm);
- static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
- static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
- 
-@@ -1170,6 +1170,20 @@ static void precise_memclk_delay_fam15(struct 
MCTStatStruc *pMCTstat, struct DCT
-       precise_ndelay_fam15(pMCTstat, delay_ns);
- }
- 
-+static void read_spd_bytes(struct MCTStatStruc *pMCTstat,
-+                      struct DCTStatStruc *pDCTstat, uint8_t dimm)
-+{
-+      uint16_t addr;
-+      uint16_t byte;
-+
-+      addr = Get_DIMMAddress_D(pDCTstat, dimm);
-+      pDCTstat->spd_data.spd_address[dimm] = addr;
-+
-+      for (byte = 0; byte < 256; byte++) {
-+              pDCTstat->spd_data.spd_bytes[dimm][byte] = mctRead_SPD(addr, 
byte);
-+      }
-+}
-+
- static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstatA)
- {
-@@ -1275,7 +1289,7 @@ restartinit:
-                               mct_InitialMCT_D(pMCTstat, pDCTstat);
- 
-                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
--                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
-+                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node */
- 
-                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_preInitDCT\n");
-                               mct_preInitDCT(pMCTstat, pDCTstat);
-@@ -2435,7 +2449,6 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-       u32 dword;
-       u32 dev;
-       u32 val;
--      u16 smbaddr;
- 
-       printk(BIOS_DEBUG, "%s: Start\n", __func__);
- 
-@@ -2455,64 +2468,62 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-       for ( i = 0; i< MAX_DIMMS_SUPPORTED; i++) {
-               LDIMM = i >> 1;
-               if (pDCTstat->DIMMValid & (1 << i)) {
--                      smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
--
--                      val = mctRead_SPD(smbaddr, SPD_MTBDivisor); /* 
MTB=Dividend/Divisor */
--                      MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 
0xFF)<<4);
-+                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDivisor];    /* MTB=Dividend/Divisor */
-+                      MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDividend] & 0xff) << 4);
-                       MTB16x /= val; /* transfer to MTB*16 */
- 
--                      byte = mctRead_SPD(smbaddr, SPD_tRPmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRPmin];
-                       val = byte * MTB16x;
-                       if (Trp < val)
-                               Trp = val;
- 
--                      byte = mctRead_SPD(smbaddr, SPD_tRRDmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRRDmin];
-                       val = byte * MTB16x;
-                       if (Trrd < val)
-                               Trrd = val;
- 
--                      byte = mctRead_SPD(smbaddr, SPD_tRCDmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCDmin];
-                       val = byte * MTB16x;
-                       if (Trcd < val)
-                               Trcd = val;
- 
--                      byte = mctRead_SPD(smbaddr, SPD_tRTPmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRTPmin];
-                       val = byte * MTB16x;
-                       if (Trtp < val)
-                               Trtp = val;
- 
--                      byte = mctRead_SPD(smbaddr, SPD_tWRmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tWRmin];
-                       val = byte * MTB16x;
-                       if (Twr < val)
-                               Twr = val;
- 
--                      byte = mctRead_SPD(smbaddr, SPD_tWTRmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tWTRmin];
-                       val = byte * MTB16x;
-                       if (Twtr < val)
-                               Twtr = val;
- 
--                      val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xFF;
-+                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xFF;
-                       val >>= 4;
-                       val <<= 8;
--                      val |= mctRead_SPD(smbaddr, SPD_tRCmin) & 0xFF;
-+                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCmin] & 0xFF;
-                       val *= MTB16x;
-                       if (Trc < val)
-                               Trc = val;
- 
--                      byte = mctRead_SPD(smbaddr, SPD_Density) & 0xF;
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Density] & 0xF;
-                       if (Trfc[LDIMM] < byte)
-                               Trfc[LDIMM] = byte;
- 
--                      val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xF;
-+                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xF;
-                       val <<= 8;
--                      val |= (mctRead_SPD(smbaddr, SPD_tRASmin) & 0xFF);
-+                      val |= (pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRASmin] & 0xFF);
-                       val *= MTB16x;
-                       if (Tras < val)
-                               Tras = val;
- 
--                      val = mctRead_SPD(smbaddr, SPD_Upper_tFAW) & 0xF;
-+                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tFAW] & 0xF;
-                       val <<= 8;
--                      val |= mctRead_SPD(smbaddr, SPD_tFAWmin) & 0xFF;
-+                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tFAWmin] & 0xFF;
-                       val *= MTB16x;
-                       if (Tfaw < val)
-                               Tfaw = val;
-@@ -2928,7 +2939,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-       u8 CLactual, CLdesired, CLT_Fail;
-       uint16_t min_frequency_tck16x;
- 
--      u8 smbaddr, byte = 0, bytex = 0;
-+      u8 byte = 0, bytex = 0;
- 
-       CASLatLow = 0xFF;
-       CASLatHigh = 0xFF;
-@@ -2949,28 +2960,27 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
- 
-       for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
-               if (pDCTstat->DIMMValid & (1 << i)) {
--                      smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
-                       /* Step 1: Determine the common set of supported CAS 
Latency
-                        * values for all modules on the memory channel using 
the CAS
-                        * Latencies Supported in SPD bytes 14 and 15.
-                        */
--                      byte = mctRead_SPD(smbaddr, SPD_CASLow);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_CASLow];
-                       CASLatLow &= byte;
--                      byte = mctRead_SPD(smbaddr, SPD_CASHigh);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_CASHigh];
-                       CASLatHigh &= byte;
-                       /* Step 2: Determine tAAmin(all) which is the largest 
tAAmin
-                          value for all modules on the memory channel (SPD 
byte 16). */
--                      byte = mctRead_SPD(smbaddr, SPD_MTBDivisor);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDivisor];
- 
--                      MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 
0xFF)<<4);
-+                      MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDividend] & 0xFF)<<4);
-                       MTB16x /= byte; /* transfer to MTB*16 */
- 
--                      byte = mctRead_SPD(smbaddr, SPD_tAAmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tAAmin];
-                       if (tAAmin16x < byte * MTB16x)
-                               tAAmin16x = byte * MTB16x;
-                       /* Step 3: Determine tCKmin(all) which is the largest 
tCKmin
-                          value for all modules on the memory channel (SPD 
byte 12). */
--                      byte = mctRead_SPD(smbaddr, SPD_tCKmin);
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tCKmin];
- 
-                       if (tCKmin16x < byte * MTB16x)
-                               tCKmin16x = byte * MTB16x;
-@@ -3341,7 +3351,6 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
-       u8 byte;
-       u16 word;
-       u32 dword;
--      u16 smbaddr;
- 
-       dev = pDCTstat->dev_dct;
- 
-@@ -3352,16 +3361,14 @@ static void SPDSetBanks_D(struct MCTStatStruc 
*pMCTstat,
-                       byte -= 3;
- 
-               if (pDCTstat->DIMMValid & (1<<byte)) {
--                      smbaddr = Get_DIMMAddress_D(pDCTstat, (ChipSel + dct));
--
--                      byte = mctRead_SPD(smbaddr, SPD_Addressing);
-+                      byte = pDCTstat->spd_data.spd_bytes[ChipSel + 
dct][SPD_Addressing];
-                       Rows = (byte >> 3) & 0x7; /* Rows:0b=12-bit,... */
-                       Cols = byte & 0x7; /* Cols:0b=9-bit,... */
- 
--                      byte = mctRead_SPD(smbaddr, SPD_Density);
-+                      byte = pDCTstat->spd_data.spd_bytes[ChipSel + 
dct][SPD_Density];
-                       Banks = (byte >> 4) & 7; /* Banks:0b=3-bit,... */
- 
--                      byte = mctRead_SPD(smbaddr, SPD_Organization);
-+                      byte = pDCTstat->spd_data.spd_bytes[ChipSel + 
dct][SPD_Organization];
-                       Ranks = ((byte >> 3) & 7) + 1;
- 
-                       /* Configure Bank encoding
-@@ -3456,46 +3463,42 @@ static void SPDCalcWidth_D(struct MCTStatStruc 
*pMCTstat,
-        * and determine the width mode: 64-bit, 64-bit muxed, 128-bit.
-        */
-       u8 i;
--      u8 smbaddr, smbaddr1;
-       u8 byte, byte1;
- 
-       /* Check Symmetry of Channel A and Channel B DIMMs
-         (must be matched for 128-bit mode).*/
-       for (i=0; i < MAX_DIMMS_SUPPORTED; i += 2) {
-               if ((pDCTstat->DIMMValid & (1 << i)) && (pDCTstat->DIMMValid & 
(1<<(i+1)))) {
--                      smbaddr = Get_DIMMAddress_D(pDCTstat, i);
--                      smbaddr1 = Get_DIMMAddress_D(pDCTstat, i+1);
--
--                      byte = mctRead_SPD(smbaddr, SPD_Addressing) & 0x7;
--                      byte1 = mctRead_SPD(smbaddr1, SPD_Addressing) & 0x7;
-+                      byte = pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] 
& 0x7;
-+                      byte1 = pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Addressing] & 0x7;
-                       if (byte != byte1) {
-                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
-                               break;
-                       }
- 
--                      byte =   mctRead_SPD(smbaddr, SPD_Density) & 0x0f;
--                      byte1 =  mctRead_SPD(smbaddr1, SPD_Density) & 0x0f;
-+                      byte =   pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 
0x0f;
-+                      byte1 =  pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Density] & 0x0f;
-                       if (byte != byte1) {
-                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
-                               break;
-                       }
- 
--                      byte = mctRead_SPD(smbaddr, SPD_Organization) & 0x7;
--                      byte1 = mctRead_SPD(smbaddr1, SPD_Organization) & 0x7;
-+                      byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7;
-+                      byte1 = pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Organization] & 0x7;
-                       if (byte != byte1) {
-                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
-                               break;
-                       }
- 
--                      byte = (mctRead_SPD(smbaddr, SPD_Organization) >> 3) & 
0x7;
--                      byte1 = (mctRead_SPD(smbaddr1, SPD_Organization) >> 3) 
& 0x7;
-+                      byte = 
(pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3) & 0x7;
-+                      byte1 = (pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Organization] >> 3) & 0x7;
-                       if (byte != byte1) {
-                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
-                               break;
-                       }
- 
--                      byte = mctRead_SPD(smbaddr, SPD_DMBANKS) & 7;    /* 
#ranks-1 */
--                      byte1 = mctRead_SPD(smbaddr1, SPD_DMBANKS) & 7;   /* 
#ranks-1 */
-+                      byte = pDCTstat->spd_data.spd_bytes[i][SPD_DMBANKS] & 
7;         /* #ranks-1 */
-+                      byte1 = pDCTstat->spd_data.spd_bytes[i + 
1][SPD_DMBANKS] & 7;     /* #ranks-1 */
-                       if (byte != byte1) {
-                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
-                               break;
-@@ -3676,8 +3679,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                       status = mctRead_SPD(smbaddr, SPD_ByteUse);
-                       if (status >= 0) { /* SPD access is ok */
-                               pDCTstat->DIMMPresent |= 1 << i;
--                              if (crcCheck(smbaddr)) { /* CRC is OK */
--                                      byte = mctRead_SPD(smbaddr, SPD_TYPE);
-+                              read_spd_bytes(pMCTstat, pDCTstat, i);
-+                              if (crcCheck(pDCTstat, i)) { /* CRC is OK */
-+                                      byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
-                                       if (byte == JED_DDR3SDRAM) {
-                                               /*Dimm is 'Present'*/
-                                               pDCTstat->DIMMValid |= 1 << i;
-@@ -3690,36 +3694,41 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                       } else {
-                                               /*if NV_SPDCHK_RESTRT is set to 
1, ignore faulty SPD checksum*/
-                                               pDCTstat->ErrStatus |= 
1<<SB_DIMMChkSum;
--                                              byte = mctRead_SPD(smbaddr, 
SPD_TYPE);
-+                                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
-                                               if (byte == JED_DDR3SDRAM)
-                                                       pDCTstat->DIMMValid |= 
1 << i;
-                                       }
-                               }
-+
-+                              /* Zero DIMM SPD data cache if DIMM not present 
/ valid */
-+                              if (!(pDCTstat->DIMMValid & (1 << i)))
-+                                      memset(pDCTstat->spd_data.spd_bytes[i], 
0, 256);
-+
-                               /* Get module information for SMBIOS */
-                               if (pDCTstat->DIMMValid & (1 << i)) {
-                                       pDCTstat->DimmManufacturerID[i] = 0;
-                                       for (k = 0; k < 8; k++)
--                                              pDCTstat->DimmManufacturerID[i] 
|= ((uint64_t)mctRead_SPD(smbaddr, SPD_MANID_START + k)) << (k * 8);
-+                                              pDCTstat->DimmManufacturerID[i] 
|= ((uint64_t)pDCTstat->spd_data.spd_bytes[i][SPD_MANID_START + k]) << (k * 8);
-                                       for (k = 0; k < SPD_PARTN_LENGTH; k++)
--                                              pDCTstat->DimmPartNumber[i][k] 
= mctRead_SPD(smbaddr, SPD_PARTN_START + k);
-+                                              pDCTstat->DimmPartNumber[i][k] 
= pDCTstat->spd_data.spd_bytes[i][SPD_PARTN_START + k];
-                                       
pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
-                                       pDCTstat->DimmRevisionNumber[i] = 0;
-                                       for (k = 0; k < 2; k++)
--                                              pDCTstat->DimmRevisionNumber[i] 
|= ((uint16_t)mctRead_SPD(smbaddr, SPD_REVNO_START + k)) << (k * 8);
-+                                              pDCTstat->DimmRevisionNumber[i] 
|= ((uint16_t)pDCTstat->spd_data.spd_bytes[i][SPD_REVNO_START + k]) << (k * 8);
-                                       pDCTstat->DimmSerialNumber[i] = 0;
-                                       for (k = 0; k < 4; k++)
--                                              pDCTstat->DimmSerialNumber[i] 
|= ((uint32_t)mctRead_SPD(smbaddr, SPD_SERIAL_START + k)) << (k * 8);
--                                      pDCTstat->DimmRows[i] = 
(mctRead_SPD(smbaddr, SPD_Addressing) & 0x38) >> 3;
--                                      pDCTstat->DimmCols[i] = 
mctRead_SPD(smbaddr, SPD_Addressing) & 0x7;
--                                      pDCTstat->DimmRanks[i] = 
((mctRead_SPD(smbaddr, SPD_Organization) & 0x38) >> 3) + 1;
--                                      pDCTstat->DimmBanks[i] = 1ULL << 
(((mctRead_SPD(smbaddr, SPD_Density) & 0x70) >> 4) + 3);
--                                      pDCTstat->DimmWidth[i] = 1ULL << 
((mctRead_SPD(smbaddr, SPD_BusWidth) & 0x7) + 3);
-+                                              pDCTstat->DimmSerialNumber[i] 
|= ((uint32_t)pDCTstat->spd_data.spd_bytes[i][SPD_SERIAL_START + k]) << (k * 8);
-+                                      pDCTstat->DimmRows[i] = 
(pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x38) >> 3;
-+                                      pDCTstat->DimmCols[i] = 
pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x7;
-+                                      pDCTstat->DimmRanks[i] = 
((pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x38) >> 3) + 1;
-+                                      pDCTstat->DimmBanks[i] = 1ULL << 
(((pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 0x70) >> 4) + 3);
-+                                      pDCTstat->DimmWidth[i] = 1ULL << 
((pDCTstat->spd_data.spd_bytes[i][SPD_BusWidth] & 0x7) + 3);
-                               }
-                               /* Check supported voltage(s) */
--                              pDCTstat->DimmSupportedVoltages[i] = 
mctRead_SPD(smbaddr, SPD_Voltage) & 0x7;
-+                              pDCTstat->DimmSupportedVoltages[i] = 
pDCTstat->spd_data.spd_bytes[i][SPD_Voltage] & 0x7;
-                               pDCTstat->DimmSupportedVoltages[i] ^= 0x1;      
/* Invert LSB to convert from SPD format to internal bitmap format */
-                               /* Check module type */
--                              byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE) & 0x7;
-+                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_DIMMTYPE] & 0x7;
-                               if (byte == JED_RDIMM || byte == JED_MiniRDIMM) 
{
-                                       RegDIMMPresent |= 1 << i;
-                                       pDCTstat->DimmRegistered[i] = 1;
-@@ -3733,13 +3742,13 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                       pDCTstat->DimmLoadReduced[i] = 0;
-                               }
-                               /* Check ECC capable */
--                              byte = mctRead_SPD(smbaddr, SPD_BusWidth);
-+                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_BusWidth];
-                               if (byte & JED_ECC) {
-                                       /* DIMM is ECC capable */
-                                       pDCTstat->DimmECCPresent |= 1 << i;
-                               }
-                               /* Check if x4 device */
--                              devwidth = mctRead_SPD(smbaddr, 
SPD_Organization) & 0x7; /* 0:x4,1:x8,2:x16 */
-+                              devwidth = 
pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7; /* 0:x4,1:x8,2:x16 */
-                               if (devwidth == 0) {
-                                       /* DIMM is made with x4 or x16 drams */
-                                       pDCTstat->Dimmx4Present |= 1 << i;
-@@ -3749,7 +3758,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                       pDCTstat->Dimmx16Present |= 1 << i;
-                               }
- 
--                              byte = (mctRead_SPD(smbaddr, SPD_Organization) 
>> 3);
-+                              byte = 
(pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3);
-                               byte &= 7;
-                               if (byte == 3) { /* 4ranks */
-                                       /* if any DIMMs are QR, we have to make 
two passes through DIMMs*/
-@@ -3784,7 +3793,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
- 
-                               /* check address mirror support for unbuffered 
dimm */
-                               /* check number of registers on a dimm for 
registered dimm */
--                              byte = mctRead_SPD(smbaddr, SPD_AddressMirror);
-+                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_AddressMirror];
-                               if (RegDIMMPresent & (1 << i)) {
-                                       if ((byte & 3) > 1)
-                                               pDCTstat->MirrPresU_NumRegR |= 
1 << i;
-@@ -3793,20 +3802,20 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                               pDCTstat->MirrPresU_NumRegR |= 
1 << i;
-                               }
-                               /* Get byte62: Reference Raw Card information. 
We dont need it now. */
--                              /* byte = mctRead_SPD(smbaddr, SPD_RefRawCard); 
*/
-+                              /* byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_RefRawCard]; */
-                               /* Get Byte65/66 for register manufacture ID 
code */
--                              if ((0x97 == mctRead_SPD(smbaddr, 
SPD_RegManufactureID_H)) &&
--                                  (0x80 == mctRead_SPD(smbaddr, 
SPD_RegManufactureID_L))) {
--                                      if (0x16 == mctRead_SPD(smbaddr, 
SPD_RegManRevID))
-+                              if ((0x97 == 
pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_H]) &&
-+                                  (0x80 == 
pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_L])) {
-+                                      if (0x16 == 
pDCTstat->spd_data.spd_bytes[i][SPD_RegManRevID])
-                                               pDCTstat->RegMan2Present |= 1 
<< i;
-                                       else
-                                               pDCTstat->RegMan1Present |= 1 
<< i;
-                               }
-                               /* Get Control word values for RC3. We dont 
need it. */
--                              byte = mctRead_SPD(smbaddr, 70);
-+                              byte = pDCTstat->spd_data.spd_bytes[i][70];
-                               pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); 
/* C3 = SPD byte 70 [7:4] */
-                               /* Get Control word values for RC4, and RC5 */
--                              byte = mctRead_SPD(smbaddr, 71);
-+                              byte = pDCTstat->spd_data.spd_bytes[i][71];
-                               pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 
2); /* RC4 = SPD byte 71 [3:0] */
-                               pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); 
/* RC5 = SPD byte 71 [7:4] */
-                       }
-@@ -6184,14 +6193,14 @@ static void AfterDramInit_D(struct DCTStatStruc 
*pDCTstat, u8 dct) {
-  *  1010      001111  16      3       10      4GB
-  *  1011      010111  16      3       11      8GB
-  */
--u8 crcCheck(u8 smbaddr)
-+uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm)
- {
-       u8 byte_use;
-       u8 Index;
-       u16 CRC;
-       u8 byte, i;
- 
--      byte_use = mctRead_SPD(smbaddr, SPD_ByteUse);
-+      byte_use = pDCTstat->spd_data.spd_bytes[dimm][SPD_ByteUse];
-       if (byte_use & 0x80)
-               byte_use = 117;
-       else
-@@ -6199,7 +6208,7 @@ u8 crcCheck(u8 smbaddr)
- 
-       CRC = 0;
-       for (Index = 0; Index < byte_use; Index ++) {
--              byte = mctRead_SPD(smbaddr, Index);
-+              byte = pDCTstat->spd_data.spd_bytes[dimm][Index];
-               CRC ^= byte << 8;
-               for (i=0; i<8; i++) {
-                       if (CRC & 0x8000) {
-@@ -6209,5 +6218,5 @@ u8 crcCheck(u8 smbaddr)
-                               CRC <<= 1;
-               }
-       }
--      return CRC == (mctRead_SPD(smbaddr, SPD_byte_127) << 8 | 
mctRead_SPD(smbaddr, SPD_byte_126));
-+      return CRC == (pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_127] << 8 | 
pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_126]);
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 50fbff7..5bb09b4 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -322,6 +322,11 @@ struct MCTStatStruc {
- 
===============================================================================*/
- #include "mwlc_d.h"           /* I have to */
- 
-+struct amd_spd_node_data {
-+      uint8_t spd_bytes[MAX_DIMMS_SUPPORTED][256];    /* [DIMM][byte] */
-+      uint8_t spd_address[MAX_DIMMS_SUPPORTED];       /* [DIMM] */
-+} __attribute__((packed));
-+
- struct DCTStatStruc {         /* A per Node structure*/
- /* DCTStatStruct_F -  start */
-       u8 Node_ID;             /* Node ID of current controller */
-@@ -615,6 +620,8 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-       char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
-       uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
-       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
-+
-+      struct amd_spd_node_data spd_data;
- } __attribute__((packed));
- 
- struct amd_s3_persistent_mct_channel_data {
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0041-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
 
b/resources/libreboot/patch/kgpe-d16/0041-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
deleted file mode 100644
index ced4d6e..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0041-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 25cdb73c425c4f6a074308a69e0225ea2ee657ab Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 4 Jun 2015 00:07:05 -0500
-Subject: [PATCH 041/139] cpu/amd/car: Initialize entire CAR space instead of
- only half
-
-Change-Id: If2b6c875e523f595e662d5d62322c3c3f96ccb4a
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/car/cache_as_ram.inc | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
-index 4ccde3f..9edc41f 100644
---- a/src/cpu/amd/car/cache_as_ram.inc
-+++ b/src/cpu/amd/car/cache_as_ram.inc
-@@ -460,12 +460,12 @@ fam10_end_part1:
-       /* Read the range with lodsl. */
-       cld
-       movl    $CacheBase, %esi
--      movl    $(CacheSize >> 2), %ecx
-+      movl    $CacheSize, %ecx
-       rep     lodsl
- 
-       /* Clear the range. */
-       movl    $CacheBase, %edi
--      movl    $(CacheSize >> 2), %ecx
-+      movl    $CacheSize, %ecx
-       xorl    %eax, %eax
-       rep     stosl
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
 
b/resources/libreboot/patch/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
new file mode 100644
index 0000000..23c1b3d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0041-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch
@@ -0,0 +1,461 @@
+From 6f89a93a630dac9cd6588c69040f81c9ddebb0df Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 2 Jun 2015 20:51:59 -0500
+Subject: [PATCH 041/143] northbridge/amd/amdmct: Read SPD data into cache to
+ decrease bootup time
+
+Change-Id: Ic16a927a3f1fc6f7cb1aea36a8abe8cc1999cb52
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |  161 ++++++++++++++-------------
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |    7 ++
+ 2 files changed, 92 insertions(+), 76 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 4677c73..5344ff9 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -180,7 +180,7 @@ static void mct_WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+ static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct);
+ static void SyncSetting(struct DCTStatStruc *pDCTstat);
+-static u8 crcCheck(u8 smbaddr);
++static uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm);
+ static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
+ static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
+ 
+@@ -1170,6 +1170,20 @@ static void precise_memclk_delay_fam15(struct 
MCTStatStruc *pMCTstat, struct DCT
+       precise_ndelay_fam15(pMCTstat, delay_ns);
+ }
+ 
++static void read_spd_bytes(struct MCTStatStruc *pMCTstat,
++                      struct DCTStatStruc *pDCTstat, uint8_t dimm)
++{
++      uint16_t addr;
++      uint16_t byte;
++
++      addr = Get_DIMMAddress_D(pDCTstat, dimm);
++      pDCTstat->spd_data.spd_address[dimm] = addr;
++
++      for (byte = 0; byte < 256; byte++) {
++              pDCTstat->spd_data.spd_bytes[dimm][byte] = mctRead_SPD(addr, 
byte);
++      }
++}
++
+ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+ {
+@@ -1275,7 +1289,7 @@ restartinit:
+                               mct_InitialMCT_D(pMCTstat, pDCTstat);
+ 
+                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mctSMBhub_Init\n");
+-                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node*/
++                              mctSMBhub_Init(Node);           /* Switch SMBUS 
crossbar to proper node */
+ 
+                               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_preInitDCT\n");
+                               mct_preInitDCT(pMCTstat, pDCTstat);
+@@ -2435,7 +2449,6 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+       u32 dword;
+       u32 dev;
+       u32 val;
+-      u16 smbaddr;
+ 
+       printk(BIOS_DEBUG, "%s: Start\n", __func__);
+ 
+@@ -2455,64 +2468,62 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+       for ( i = 0; i< MAX_DIMMS_SUPPORTED; i++) {
+               LDIMM = i >> 1;
+               if (pDCTstat->DIMMValid & (1 << i)) {
+-                      smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
+-
+-                      val = mctRead_SPD(smbaddr, SPD_MTBDivisor); /* 
MTB=Dividend/Divisor */
+-                      MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 
0xFF)<<4);
++                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDivisor];    /* MTB=Dividend/Divisor */
++                      MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDividend] & 0xff) << 4);
+                       MTB16x /= val; /* transfer to MTB*16 */
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_tRPmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRPmin];
+                       val = byte * MTB16x;
+                       if (Trp < val)
+                               Trp = val;
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_tRRDmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRRDmin];
+                       val = byte * MTB16x;
+                       if (Trrd < val)
+                               Trrd = val;
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_tRCDmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCDmin];
+                       val = byte * MTB16x;
+                       if (Trcd < val)
+                               Trcd = val;
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_tRTPmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRTPmin];
+                       val = byte * MTB16x;
+                       if (Trtp < val)
+                               Trtp = val;
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_tWRmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tWRmin];
+                       val = byte * MTB16x;
+                       if (Twr < val)
+                               Twr = val;
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_tWTRmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tWTRmin];
+                       val = byte * MTB16x;
+                       if (Twtr < val)
+                               Twtr = val;
+ 
+-                      val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xFF;
++                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xFF;
+                       val >>= 4;
+                       val <<= 8;
+-                      val |= mctRead_SPD(smbaddr, SPD_tRCmin) & 0xFF;
++                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCmin] & 0xFF;
+                       val *= MTB16x;
+                       if (Trc < val)
+                               Trc = val;
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_Density) & 0xF;
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Density] & 0xF;
+                       if (Trfc[LDIMM] < byte)
+                               Trfc[LDIMM] = byte;
+ 
+-                      val = mctRead_SPD(smbaddr, SPD_Upper_tRAS_tRC) & 0xF;
++                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xF;
+                       val <<= 8;
+-                      val |= (mctRead_SPD(smbaddr, SPD_tRASmin) & 0xFF);
++                      val |= (pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRASmin] & 0xFF);
+                       val *= MTB16x;
+                       if (Tras < val)
+                               Tras = val;
+ 
+-                      val = mctRead_SPD(smbaddr, SPD_Upper_tFAW) & 0xF;
++                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tFAW] & 0xF;
+                       val <<= 8;
+-                      val |= mctRead_SPD(smbaddr, SPD_tFAWmin) & 0xFF;
++                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tFAWmin] & 0xFF;
+                       val *= MTB16x;
+                       if (Tfaw < val)
+                               Tfaw = val;
+@@ -2928,7 +2939,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+       u8 CLactual, CLdesired, CLT_Fail;
+       uint16_t min_frequency_tck16x;
+ 
+-      u8 smbaddr, byte = 0, bytex = 0;
++      u8 byte = 0, bytex = 0;
+ 
+       CASLatLow = 0xFF;
+       CASLatHigh = 0xFF;
+@@ -2949,28 +2960,27 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+ 
+       for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) {
+               if (pDCTstat->DIMMValid & (1 << i)) {
+-                      smbaddr = Get_DIMMAddress_D(pDCTstat, (dct + i));
+                       /* Step 1: Determine the common set of supported CAS 
Latency
+                        * values for all modules on the memory channel using 
the CAS
+                        * Latencies Supported in SPD bytes 14 and 15.
+                        */
+-                      byte = mctRead_SPD(smbaddr, SPD_CASLow);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_CASLow];
+                       CASLatLow &= byte;
+-                      byte = mctRead_SPD(smbaddr, SPD_CASHigh);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_CASHigh];
+                       CASLatHigh &= byte;
+                       /* Step 2: Determine tAAmin(all) which is the largest 
tAAmin
+                          value for all modules on the memory channel (SPD 
byte 16). */
+-                      byte = mctRead_SPD(smbaddr, SPD_MTBDivisor);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDivisor];
+ 
+-                      MTB16x = ((mctRead_SPD(smbaddr, SPD_MTBDividend) & 
0xFF)<<4);
++                      MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_MTBDividend] & 0xFF)<<4);
+                       MTB16x /= byte; /* transfer to MTB*16 */
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_tAAmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tAAmin];
+                       if (tAAmin16x < byte * MTB16x)
+                               tAAmin16x = byte * MTB16x;
+                       /* Step 3: Determine tCKmin(all) which is the largest 
tCKmin
+                          value for all modules on the memory channel (SPD 
byte 12). */
+-                      byte = mctRead_SPD(smbaddr, SPD_tCKmin);
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tCKmin];
+ 
+                       if (tCKmin16x < byte * MTB16x)
+                               tCKmin16x = byte * MTB16x;
+@@ -3341,7 +3351,6 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat,
+       u8 byte;
+       u16 word;
+       u32 dword;
+-      u16 smbaddr;
+ 
+       dev = pDCTstat->dev_dct;
+ 
+@@ -3352,16 +3361,14 @@ static void SPDSetBanks_D(struct MCTStatStruc 
*pMCTstat,
+                       byte -= 3;
+ 
+               if (pDCTstat->DIMMValid & (1<<byte)) {
+-                      smbaddr = Get_DIMMAddress_D(pDCTstat, (ChipSel + dct));
+-
+-                      byte = mctRead_SPD(smbaddr, SPD_Addressing);
++                      byte = pDCTstat->spd_data.spd_bytes[ChipSel + 
dct][SPD_Addressing];
+                       Rows = (byte >> 3) & 0x7; /* Rows:0b=12-bit,... */
+                       Cols = byte & 0x7; /* Cols:0b=9-bit,... */
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_Density);
++                      byte = pDCTstat->spd_data.spd_bytes[ChipSel + 
dct][SPD_Density];
+                       Banks = (byte >> 4) & 7; /* Banks:0b=3-bit,... */
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_Organization);
++                      byte = pDCTstat->spd_data.spd_bytes[ChipSel + 
dct][SPD_Organization];
+                       Ranks = ((byte >> 3) & 7) + 1;
+ 
+                       /* Configure Bank encoding
+@@ -3456,46 +3463,42 @@ static void SPDCalcWidth_D(struct MCTStatStruc 
*pMCTstat,
+        * and determine the width mode: 64-bit, 64-bit muxed, 128-bit.
+        */
+       u8 i;
+-      u8 smbaddr, smbaddr1;
+       u8 byte, byte1;
+ 
+       /* Check Symmetry of Channel A and Channel B DIMMs
+         (must be matched for 128-bit mode).*/
+       for (i=0; i < MAX_DIMMS_SUPPORTED; i += 2) {
+               if ((pDCTstat->DIMMValid & (1 << i)) && (pDCTstat->DIMMValid & 
(1<<(i+1)))) {
+-                      smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+-                      smbaddr1 = Get_DIMMAddress_D(pDCTstat, i+1);
+-
+-                      byte = mctRead_SPD(smbaddr, SPD_Addressing) & 0x7;
+-                      byte1 = mctRead_SPD(smbaddr1, SPD_Addressing) & 0x7;
++                      byte = pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] 
& 0x7;
++                      byte1 = pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Addressing] & 0x7;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+ 
+-                      byte =   mctRead_SPD(smbaddr, SPD_Density) & 0x0f;
+-                      byte1 =  mctRead_SPD(smbaddr1, SPD_Density) & 0x0f;
++                      byte =   pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 
0x0f;
++                      byte1 =  pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Density] & 0x0f;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_Organization) & 0x7;
+-                      byte1 = mctRead_SPD(smbaddr1, SPD_Organization) & 0x7;
++                      byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7;
++                      byte1 = pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Organization] & 0x7;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+ 
+-                      byte = (mctRead_SPD(smbaddr, SPD_Organization) >> 3) & 
0x7;
+-                      byte1 = (mctRead_SPD(smbaddr1, SPD_Organization) >> 3) 
& 0x7;
++                      byte = 
(pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3) & 0x7;
++                      byte1 = (pDCTstat->spd_data.spd_bytes[i + 
1][SPD_Organization] >> 3) & 0x7;
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+                       }
+ 
+-                      byte = mctRead_SPD(smbaddr, SPD_DMBANKS) & 7;    /* 
#ranks-1 */
+-                      byte1 = mctRead_SPD(smbaddr1, SPD_DMBANKS) & 7;   /* 
#ranks-1 */
++                      byte = pDCTstat->spd_data.spd_bytes[i][SPD_DMBANKS] & 
7;         /* #ranks-1 */
++                      byte1 = pDCTstat->spd_data.spd_bytes[i + 
1][SPD_DMBANKS] & 7;     /* #ranks-1 */
+                       if (byte != byte1) {
+                               pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO);
+                               break;
+@@ -3676,8 +3679,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                       status = mctRead_SPD(smbaddr, SPD_ByteUse);
+                       if (status >= 0) { /* SPD access is ok */
+                               pDCTstat->DIMMPresent |= 1 << i;
+-                              if (crcCheck(smbaddr)) { /* CRC is OK */
+-                                      byte = mctRead_SPD(smbaddr, SPD_TYPE);
++                              read_spd_bytes(pMCTstat, pDCTstat, i);
++                              if (crcCheck(pDCTstat, i)) { /* CRC is OK */
++                                      byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
+                                       if (byte == JED_DDR3SDRAM) {
+                                               /*Dimm is 'Present'*/
+                                               pDCTstat->DIMMValid |= 1 << i;
+@@ -3690,36 +3694,41 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                       } else {
+                                               /*if NV_SPDCHK_RESTRT is set to 
1, ignore faulty SPD checksum*/
+                                               pDCTstat->ErrStatus |= 
1<<SB_DIMMChkSum;
+-                                              byte = mctRead_SPD(smbaddr, 
SPD_TYPE);
++                                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
+                                               if (byte == JED_DDR3SDRAM)
+                                                       pDCTstat->DIMMValid |= 
1 << i;
+                                       }
+                               }
++
++                              /* Zero DIMM SPD data cache if DIMM not present 
/ valid */
++                              if (!(pDCTstat->DIMMValid & (1 << i)))
++                                      memset(pDCTstat->spd_data.spd_bytes[i], 
0, 256);
++
+                               /* Get module information for SMBIOS */
+                               if (pDCTstat->DIMMValid & (1 << i)) {
+                                       pDCTstat->DimmManufacturerID[i] = 0;
+                                       for (k = 0; k < 8; k++)
+-                                              pDCTstat->DimmManufacturerID[i] 
|= ((uint64_t)mctRead_SPD(smbaddr, SPD_MANID_START + k)) << (k * 8);
++                                              pDCTstat->DimmManufacturerID[i] 
|= ((uint64_t)pDCTstat->spd_data.spd_bytes[i][SPD_MANID_START + k]) << (k * 8);
+                                       for (k = 0; k < SPD_PARTN_LENGTH; k++)
+-                                              pDCTstat->DimmPartNumber[i][k] 
= mctRead_SPD(smbaddr, SPD_PARTN_START + k);
++                                              pDCTstat->DimmPartNumber[i][k] 
= pDCTstat->spd_data.spd_bytes[i][SPD_PARTN_START + k];
+                                       
pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0;
+                                       pDCTstat->DimmRevisionNumber[i] = 0;
+                                       for (k = 0; k < 2; k++)
+-                                              pDCTstat->DimmRevisionNumber[i] 
|= ((uint16_t)mctRead_SPD(smbaddr, SPD_REVNO_START + k)) << (k * 8);
++                                              pDCTstat->DimmRevisionNumber[i] 
|= ((uint16_t)pDCTstat->spd_data.spd_bytes[i][SPD_REVNO_START + k]) << (k * 8);
+                                       pDCTstat->DimmSerialNumber[i] = 0;
+                                       for (k = 0; k < 4; k++)
+-                                              pDCTstat->DimmSerialNumber[i] 
|= ((uint32_t)mctRead_SPD(smbaddr, SPD_SERIAL_START + k)) << (k * 8);
+-                                      pDCTstat->DimmRows[i] = 
(mctRead_SPD(smbaddr, SPD_Addressing) & 0x38) >> 3;
+-                                      pDCTstat->DimmCols[i] = 
mctRead_SPD(smbaddr, SPD_Addressing) & 0x7;
+-                                      pDCTstat->DimmRanks[i] = 
((mctRead_SPD(smbaddr, SPD_Organization) & 0x38) >> 3) + 1;
+-                                      pDCTstat->DimmBanks[i] = 1ULL << 
(((mctRead_SPD(smbaddr, SPD_Density) & 0x70) >> 4) + 3);
+-                                      pDCTstat->DimmWidth[i] = 1ULL << 
((mctRead_SPD(smbaddr, SPD_BusWidth) & 0x7) + 3);
++                                              pDCTstat->DimmSerialNumber[i] 
|= ((uint32_t)pDCTstat->spd_data.spd_bytes[i][SPD_SERIAL_START + k]) << (k * 8);
++                                      pDCTstat->DimmRows[i] = 
(pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x38) >> 3;
++                                      pDCTstat->DimmCols[i] = 
pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x7;
++                                      pDCTstat->DimmRanks[i] = 
((pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x38) >> 3) + 1;
++                                      pDCTstat->DimmBanks[i] = 1ULL << 
(((pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 0x70) >> 4) + 3);
++                                      pDCTstat->DimmWidth[i] = 1ULL << 
((pDCTstat->spd_data.spd_bytes[i][SPD_BusWidth] & 0x7) + 3);
+                               }
+                               /* Check supported voltage(s) */
+-                              pDCTstat->DimmSupportedVoltages[i] = 
mctRead_SPD(smbaddr, SPD_Voltage) & 0x7;
++                              pDCTstat->DimmSupportedVoltages[i] = 
pDCTstat->spd_data.spd_bytes[i][SPD_Voltage] & 0x7;
+                               pDCTstat->DimmSupportedVoltages[i] ^= 0x1;      
/* Invert LSB to convert from SPD format to internal bitmap format */
+                               /* Check module type */
+-                              byte = mctRead_SPD(smbaddr, SPD_DIMMTYPE) & 0x7;
++                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_DIMMTYPE] & 0x7;
+                               if (byte == JED_RDIMM || byte == JED_MiniRDIMM) 
{
+                                       RegDIMMPresent |= 1 << i;
+                                       pDCTstat->DimmRegistered[i] = 1;
+@@ -3733,13 +3742,13 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                       pDCTstat->DimmLoadReduced[i] = 0;
+                               }
+                               /* Check ECC capable */
+-                              byte = mctRead_SPD(smbaddr, SPD_BusWidth);
++                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_BusWidth];
+                               if (byte & JED_ECC) {
+                                       /* DIMM is ECC capable */
+                                       pDCTstat->DimmECCPresent |= 1 << i;
+                               }
+                               /* Check if x4 device */
+-                              devwidth = mctRead_SPD(smbaddr, 
SPD_Organization) & 0x7; /* 0:x4,1:x8,2:x16 */
++                              devwidth = 
pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7; /* 0:x4,1:x8,2:x16 */
+                               if (devwidth == 0) {
+                                       /* DIMM is made with x4 or x16 drams */
+                                       pDCTstat->Dimmx4Present |= 1 << i;
+@@ -3749,7 +3758,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                       pDCTstat->Dimmx16Present |= 1 << i;
+                               }
+ 
+-                              byte = (mctRead_SPD(smbaddr, SPD_Organization) 
>> 3);
++                              byte = 
(pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3);
+                               byte &= 7;
+                               if (byte == 3) { /* 4ranks */
+                                       /* if any DIMMs are QR, we have to make 
two passes through DIMMs*/
+@@ -3784,7 +3793,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+ 
+                               /* check address mirror support for unbuffered 
dimm */
+                               /* check number of registers on a dimm for 
registered dimm */
+-                              byte = mctRead_SPD(smbaddr, SPD_AddressMirror);
++                              byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_AddressMirror];
+                               if (RegDIMMPresent & (1 << i)) {
+                                       if ((byte & 3) > 1)
+                                               pDCTstat->MirrPresU_NumRegR |= 
1 << i;
+@@ -3793,20 +3802,20 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                               pDCTstat->MirrPresU_NumRegR |= 
1 << i;
+                               }
+                               /* Get byte62: Reference Raw Card information. 
We dont need it now. */
+-                              /* byte = mctRead_SPD(smbaddr, SPD_RefRawCard); 
*/
++                              /* byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_RefRawCard]; */
+                               /* Get Byte65/66 for register manufacture ID 
code */
+-                              if ((0x97 == mctRead_SPD(smbaddr, 
SPD_RegManufactureID_H)) &&
+-                                  (0x80 == mctRead_SPD(smbaddr, 
SPD_RegManufactureID_L))) {
+-                                      if (0x16 == mctRead_SPD(smbaddr, 
SPD_RegManRevID))
++                              if ((0x97 == 
pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_H]) &&
++                                  (0x80 == 
pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_L])) {
++                                      if (0x16 == 
pDCTstat->spd_data.spd_bytes[i][SPD_RegManRevID])
+                                               pDCTstat->RegMan2Present |= 1 
<< i;
+                                       else
+                                               pDCTstat->RegMan1Present |= 1 
<< i;
+                               }
+                               /* Get Control word values for RC3. We dont 
need it. */
+-                              byte = mctRead_SPD(smbaddr, 70);
++                              byte = pDCTstat->spd_data.spd_bytes[i][70];
+                               pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); 
/* C3 = SPD byte 70 [7:4] */
+                               /* Get Control word values for RC4, and RC5 */
+-                              byte = mctRead_SPD(smbaddr, 71);
++                              byte = pDCTstat->spd_data.spd_bytes[i][71];
+                               pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 
2); /* RC4 = SPD byte 71 [3:0] */
+                               pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); 
/* RC5 = SPD byte 71 [7:4] */
+                       }
+@@ -6184,14 +6193,14 @@ static void AfterDramInit_D(struct DCTStatStruc 
*pDCTstat, u8 dct) {
+  *  1010      001111  16      3       10      4GB
+  *  1011      010111  16      3       11      8GB
+  */
+-u8 crcCheck(u8 smbaddr)
++uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm)
+ {
+       u8 byte_use;
+       u8 Index;
+       u16 CRC;
+       u8 byte, i;
+ 
+-      byte_use = mctRead_SPD(smbaddr, SPD_ByteUse);
++      byte_use = pDCTstat->spd_data.spd_bytes[dimm][SPD_ByteUse];
+       if (byte_use & 0x80)
+               byte_use = 117;
+       else
+@@ -6199,7 +6208,7 @@ u8 crcCheck(u8 smbaddr)
+ 
+       CRC = 0;
+       for (Index = 0; Index < byte_use; Index ++) {
+-              byte = mctRead_SPD(smbaddr, Index);
++              byte = pDCTstat->spd_data.spd_bytes[dimm][Index];
+               CRC ^= byte << 8;
+               for (i=0; i<8; i++) {
+                       if (CRC & 0x8000) {
+@@ -6209,5 +6218,5 @@ u8 crcCheck(u8 smbaddr)
+                               CRC <<= 1;
+               }
+       }
+-      return CRC == (mctRead_SPD(smbaddr, SPD_byte_127) << 8 | 
mctRead_SPD(smbaddr, SPD_byte_126));
++      return CRC == (pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_127] << 8 | 
pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_126]);
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 50fbff7..5bb09b4 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -322,6 +322,11 @@ struct MCTStatStruc {
+ 
===============================================================================*/
+ #include "mwlc_d.h"           /* I have to */
+ 
++struct amd_spd_node_data {
++      uint8_t spd_bytes[MAX_DIMMS_SUPPORTED][256];    /* [DIMM][byte] */
++      uint8_t spd_address[MAX_DIMMS_SUPPORTED];       /* [DIMM] */
++} __attribute__((packed));
++
+ struct DCTStatStruc {         /* A per Node structure*/
+ /* DCTStatStruct_F -  start */
+       u8 Node_ID;             /* Node ID of current controller */
+@@ -615,6 +620,8 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+       char DimmPartNumber[MAX_DIMMS_SUPPORTED][SPD_PARTN_LENGTH+1];
+       uint16_t DimmRevisionNumber[MAX_DIMMS_SUPPORTED];
+       uint32_t DimmSerialNumber[MAX_DIMMS_SUPPORTED];
++
++      struct amd_spd_node_data spd_data;
+ } __attribute__((packed));
+ 
+ struct amd_s3_persistent_mct_channel_data {
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0042-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
 
b/resources/libreboot/patch/kgpe-d16/0042-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
deleted file mode 100644
index d0f9f58..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0042-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 32a016ee1dea33731b9994fe23a4c43421006f99 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 4 Jun 2015 00:10:03 -0500
-Subject: [PATCH 042/139] amd/amdmct/mct_ddr3: Improve SPD DIMM detect
- reliability
-
-Change-Id: Ifab63eca2233c63a6a42ab8b7e742f8e47fb2a09
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 13 ++++++++++++-
- 1 file changed, 12 insertions(+), 1 deletion(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 5344ff9..e60adb7 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -3657,6 +3657,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-       u8 devwidth;
-       u16 DimmSlots;
-       u8 byte = 0, bytex;
-+      uint8_t crc_status;
- 
-       /* preload data structure with addrs */
-       mctGet_DIMMAddr(pDCTstat, pDCTstat->Node_ID);
-@@ -3677,10 +3678,20 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                       int status;
-                       smbaddr = Get_DIMMAddress_D(pDCTstat, i);
-                       status = mctRead_SPD(smbaddr, SPD_ByteUse);
-+                      if (status >= 0) {
-+                              /* Verify result */
-+                              status = mctRead_SPD(smbaddr, SPD_ByteUse);
-+                      }
-                       if (status >= 0) { /* SPD access is ok */
-                               pDCTstat->DIMMPresent |= 1 << i;
-                               read_spd_bytes(pMCTstat, pDCTstat, i);
--                              if (crcCheck(pDCTstat, i)) { /* CRC is OK */
-+                              crc_status = crcCheck(pDCTstat, i);
-+                              if (!crc_status) {
-+                                      /* Try again in case there was a 
transient glitch */
-+                                      read_spd_bytes(pMCTstat, pDCTstat, i);
-+                                      crc_status = crcCheck(pDCTstat, i);
-+                              }
-+                              if (crc_status) { /* CRC is OK */
-                                       byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
-                                       if (byte == JED_DDR3SDRAM) {
-                                               /*Dimm is 'Present'*/
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0042-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
 
b/resources/libreboot/patch/kgpe-d16/0042-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
new file mode 100644
index 0000000..aed4b9d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0042-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch
@@ -0,0 +1,34 @@
+From 60a55771f802ef5c3fa3b080e7d130ca24acab45 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 4 Jun 2015 00:07:05 -0500
+Subject: [PATCH 042/143] cpu/amd/car: Initialize entire CAR space instead of
+ only half
+
+Change-Id: If2b6c875e523f595e662d5d62322c3c3f96ccb4a
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/car/cache_as_ram.inc |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
+index 4ccde3f..9edc41f 100644
+--- a/src/cpu/amd/car/cache_as_ram.inc
++++ b/src/cpu/amd/car/cache_as_ram.inc
+@@ -460,12 +460,12 @@ fam10_end_part1:
+       /* Read the range with lodsl. */
+       cld
+       movl    $CacheBase, %esi
+-      movl    $(CacheSize >> 2), %ecx
++      movl    $CacheSize, %ecx
+       rep     lodsl
+ 
+       /* Clear the range. */
+       movl    $CacheBase, %edi
+-      movl    $(CacheSize >> 2), %ecx
++      movl    $CacheSize, %ecx
+       xorl    %eax, %eax
+       rep     stosl
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
 
b/resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
new file mode 100644
index 0000000..8445869
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch
@@ -0,0 +1,49 @@
+From 3333f1b6ab84234f51aa901ec29cdc6d7f0998c5 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 4 Jun 2015 00:10:03 -0500
+Subject: [PATCH 043/143] amd/amdmct/mct_ddr3: Improve SPD DIMM detect
+ reliability
+
+Change-Id: Ifab63eca2233c63a6a42ab8b7e742f8e47fb2a09
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |   13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 5344ff9..e60adb7 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -3657,6 +3657,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+       u8 devwidth;
+       u16 DimmSlots;
+       u8 byte = 0, bytex;
++      uint8_t crc_status;
+ 
+       /* preload data structure with addrs */
+       mctGet_DIMMAddr(pDCTstat, pDCTstat->Node_ID);
+@@ -3677,10 +3678,20 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                       int status;
+                       smbaddr = Get_DIMMAddress_D(pDCTstat, i);
+                       status = mctRead_SPD(smbaddr, SPD_ByteUse);
++                      if (status >= 0) {
++                              /* Verify result */
++                              status = mctRead_SPD(smbaddr, SPD_ByteUse);
++                      }
+                       if (status >= 0) { /* SPD access is ok */
+                               pDCTstat->DIMMPresent |= 1 << i;
+                               read_spd_bytes(pMCTstat, pDCTstat, i);
+-                              if (crcCheck(pDCTstat, i)) { /* CRC is OK */
++                              crc_status = crcCheck(pDCTstat, i);
++                              if (!crc_status) {
++                                      /* Try again in case there was a 
transient glitch */
++                                      read_spd_bytes(pMCTstat, pDCTstat, i);
++                                      crc_status = crcCheck(pDCTstat, i);
++                              }
++                              if (crc_status) { /* CRC is OK */
+                                       byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
+                                       if (byte == JED_DDR3SDRAM) {
+                                               /*Dimm is 'Present'*/
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
 
b/resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
deleted file mode 100644
index 8884130..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0043-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
+++ /dev/null
@@ -1,781 +0,0 @@
-From dbe04aaef5ba56c90824eb62aea47e281b75149f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 4 Jun 2015 00:11:03 -0500
-Subject: [PATCH 043/139] amd/amdmct/mct_ddr3: Use training values from
- previous boot if possible
-
-DRAM training accounts for most of the romstage startup time, yet
-if the hardware configuration has not changed from the previous boot
-the previously discovered training values are still valid.  Use them
-if the DIMM configuration has not changed since the last boot.
-
-Change-Id: I37ed277b16476d38e4af76c6ae827a575c6b017d
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/cmos.layout       |   1 +
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   | 206 +++++++++++++++++---------
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |   6 +
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 175 +++++++++++++++++++---
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.h |  10 +-
- src/northbridge/amd/amdmct/wrappers/mcti_d.c  |   4 +
- 6 files changed, 308 insertions(+), 94 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index e55edc4..7944631 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -43,6 +43,7 @@ entries
- 458          4       e       11       hypertransport_speed_limit
- 462          2       e       12       minimum_memory_voltage
- 464          1       e       2        compute_unit_siblings
-+465          1       r       0        allow_spd_nvram_cache_restore
- 477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index e60adb7..20e66f2 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -39,7 +39,8 @@
- static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstatA);
- static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstatA);
-+                              struct DCTStatStruc *pDCTstatA,
-+                              uint8_t allow_config_restore);
- static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstatA);
- static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
-@@ -355,8 +356,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
-                                       else if (drive_strength == 0x3)
-                                               calibration_code = 0xfff;
-                               }
--                      }
--                      else if (ddr_voltage_index & 0x2) {
-+                      } else if (ddr_voltage_index & 0x2) {
-                               /* 1.35V */
-                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 42 */
-                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-@@ -390,8 +390,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
-                                       else if (drive_strength == 0x3)
-                                               calibration_code = 0xdb6;
-                               }
--                      }
--                      else if (ddr_voltage_index & 0x1) {
-+                      } else if (ddr_voltage_index & 0x1) {
-                               /* 1.5V */
-                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 41 */
-                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-@@ -426,8 +425,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
-                                               calibration_code = 0xb6d;
-                               }
-                       }
--              }
--              else if (package_type == PT_C3) {
-+              } else if (package_type == PT_C3) {
-                       /* Socket C32 */
-                       if (ddr_voltage_index & 0x4) {
-                               /* 1.25V */
-@@ -473,8 +471,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
-                                       else if (drive_strength == 0x3)
-                                               calibration_code = 0xfff;
-                               }
--                      }
--                      else if (ddr_voltage_index & 0x2) {
-+                      } else if (ddr_voltage_index & 0x2) {
-                               /* 1.35V */
-                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 45 */
-                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-@@ -518,8 +515,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
-                                       else if (drive_strength == 0x3)
-                                               calibration_code = 0xdb6;
-                               }
--                      }
--                      else if (ddr_voltage_index & 0x1) {
-+                      } else if (ddr_voltage_index & 0x1) {
-                               /* 1.5V */
-                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 44 */
-                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-@@ -619,8 +615,7 @@ static uint32_t 
fam15h_phy_predriver_cmd_addr_calibration_code(struct DCTStatStr
-                       else if (drive_strength == 0x3)
-                               calibration_code = 0xb64;
-               }
--      }
--      else if (ddr_voltage_index & 0x2) {
-+      } else if (ddr_voltage_index & 0x2) {
-               /* 1.35V */
-               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 51 */
-               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-@@ -654,8 +649,7 @@ static uint32_t 
fam15h_phy_predriver_cmd_addr_calibration_code(struct DCTStatStr
-                       else if (drive_strength == 0x3)
-                               calibration_code = 0x924;
-               }
--      }
--      else if (ddr_voltage_index & 0x1) {
-+      } else if (ddr_voltage_index & 0x1) {
-               /* 1.5V */
-               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 50 */
-               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-@@ -736,8 +730,7 @@ static uint32_t 
fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *p
-                       else if (drive_strength == 0x3)
-                               calibration_code = 0xff6;
-               }
--      }
--      else if (ddr_voltage_index & 0x2) {
-+      } else if (ddr_voltage_index & 0x2) {
-               /* 1.35V */
-               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 54 */
-               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-@@ -771,8 +764,7 @@ static uint32_t 
fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *p
-                       else if (drive_strength == 0x3)
-                               calibration_code = 0xdad;
-               }
--      }
--      else if (ddr_voltage_index & 0x1) {
-+      } else if (ddr_voltage_index & 0x1) {
-               /* 1.5V */
-               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 53 */
-               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-@@ -841,16 +833,13 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                       else if (MemClkFreq == 0x6) {
-                               /* DDR3-800 */
-                               calibration_code = 0x10112222;
--                      }
--                      else if (MemClkFreq == 0xa) {
-+                      } else if (MemClkFreq == 0xa) {
-                               /* DDR3-1066 */
-                               calibration_code = 0x20112222;
--                      }
--                      else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) {
-+                      } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) 
{
-                               /* DDR3-1333 - DDR3-1600 */
-                               calibration_code = 0x30112222;
--                      }
--                      else if (MemClkFreq == 0x16) {
-+                      } else if (MemClkFreq == 0x16) {
-                               /* DDR3-1866 */
-                               calibration_code = 0x30332222;
-                       }
-@@ -860,16 +849,13 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                               if (MemClkFreq == 0x4) {
-                                       /* DDR3-667 */
-                                       calibration_code = 0x00112222;
--                              }
--                              else if (MemClkFreq == 0x6) {
-+                              } else if (MemClkFreq == 0x6) {
-                                       /* DDR3-800 */
-                                       calibration_code = 0x10112222;
--                              }
--                              else if (MemClkFreq == 0xa) {
-+                              } else if (MemClkFreq == 0xa) {
-                                       /* DDR3-1066 */
-                                       calibration_code = 0x20112222;
--                              }
--                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
-+                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
-                                       /* DDR3-1333 - DDR3-1600 */
-                                       calibration_code = 0x30112222;
-                               }
-@@ -881,20 +867,16 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                               if (MemClkFreq == 0x4) {
-                                       /* DDR3-667 */
-                                       calibration_code = 0x10222222;
--                              }
--                              else if (MemClkFreq == 0x6) {
-+                              } else if (MemClkFreq == 0x6) {
-                                       /* DDR3-800 */
-                                       calibration_code = 0x20222222;
--                              }
--                              else if (MemClkFreq == 0xa) {
-+                              } else if (MemClkFreq == 0xa) {
-                                       /* DDR3-1066 */
-                                       calibration_code = 0x30222222;
--                              }
--                              else if (MemClkFreq == 0xe) {
-+                              } else if (MemClkFreq == 0xe) {
-                                       /* DDR3-1333 */
-                                       calibration_code = 0x30222222;
--                              }
--                              else if (MemClkFreq == 0x12) {
-+                              } else if (MemClkFreq == 0x12) {
-                                       /* DDR3-1600 */
-                                       if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-                                               calibration_code = 0x30222222;
-@@ -1081,8 +1063,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
-                                       || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
-                                       /* DDR3-667 - DDR3-1333 */
-                                       slow_access = 0;
--                              }
--                              else if (MemClkFreq == 0x12) {
-+                              } else if (MemClkFreq == 0x12) {
-                                       /* DDR3-1600 */
-                                       if (rank_count_dimm0 == 1)
-                                               slow_access = 0;
-@@ -1098,8 +1079,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
-                                       || (MemClkFreq == 0xa)) {
-                                       /* DDR3-667 - DDR3-1066 */
-                                       slow_access = 0;
--                              }
--                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
-+                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
-                                       /* DDR3-1333 - DDR3-1600 */
-                                       slow_access = 1;
-                               }
-@@ -1184,6 +1164,30 @@ static void read_spd_bytes(struct MCTStatStruc 
*pMCTstat,
-       }
- }
- 
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-+static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      uint8_t dimm;
-+
-+      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
-+              calculate_spd_hash(pDCTstat->spd_data.spd_bytes[dimm], 
&pDCTstat->spd_data.spd_hash[dimm]);
-+      }
-+}
-+
-+static void compare_nvram_spd_hashes(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      uint8_t dimm;
-+
-+      pDCTstat->spd_data.nvram_spd_match = 1;
-+      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
-+              if (pDCTstat->spd_data.spd_hash[dimm] != 
pDCTstat->spd_data.nvram_spd_hash[dimm])
-+                      pDCTstat->spd_data.nvram_spd_match = 0;
-+      }
-+}
-+#endif
-+
- static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstatA)
- {
-@@ -1232,6 +1236,8 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
-        */
-       u8 Node, NodesWmem;
-       u32 node_sys_base;
-+      uint8_t nvram;
-+      uint8_t allow_config_restore;
- 
-       uint8_t s3resume = acpi_is_wakeup_s3();
- 
-@@ -1248,7 +1254,7 @@ restartinit:
- 
- #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
--              restore_mct_information_from_nvram();
-+              restore_mct_information_from_nvram(0);
- #endif
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-@@ -1298,11 +1304,26 @@ restartinit:
-                       node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
-               }
- 
-+              /* If the boot fails make sure training is attempted after 
reset */
-+              nvram = 0;
-+              set_option("allow_spd_nvram_cache_restore", &nvram);
-+
- #if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
-               DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
- #endif
- 
-+              /* If DIMM configuration has not changed since last boot 
restore training values */
-+              allow_config_restore = 1;
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
-+
-+                      if (pDCTstat->NodePresent)
-+                              if (!pDCTstat->spd_data.nvram_spd_match)
-+                                      allow_config_restore = 0;
-+              }
-+
-               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-                       struct DCTStatStruc *pDCTstat;
-                       pDCTstat = pDCTstatA + Node;
-@@ -1336,14 +1357,33 @@ restartinit:
-               CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
-               mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
- 
-+              /* FIXME
-+               * Previous training values should only be used if the current 
desired
-+               * speed is the same as the speed used in the previous boot.
-+               * How to get the desired speed at this point in the code?
-+               */
-+#if 0
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      struct DCTStatStruc *pDCTstat;
-+                      pDCTstat = pDCTstatA + Node;
-+
-+                      if (pDCTstat->NodePresent) {
-+                              if (pDCTstat->spd_data.nvram_memclk[0] != 
pDCTstat->DIMMAutoSpeed)
-+                                      allow_config_restore = 0;
-+                      }
-+              }
-+#endif
-+
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
--              DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable 
and DQS signal timing*/
-+              DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get 
Receiver Enable and DQS signal timing*/
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
-               UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
- 
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
--              mct_OtherTiming(pMCTstat, pDCTstatA);
-+              if (!allow_config_restore) {
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
-+                      mct_OtherTiming(pMCTstat, pDCTstatA);
-+              }
- 
-               if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 
1st pass of DIMM spare enabled*/
-                       goto restartinit;
-@@ -1825,7 +1865,7 @@ static void exit_training_mode_fam15(struct MCTStatStruc 
*pMCTstat,
- }
- 
- static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstatA)
-+                              struct DCTStatStruc *pDCTstatA, uint8_t 
allow_config_restore)
- {
-       u8 nv_DQSTrainCTL;
- 
-@@ -1833,9 +1873,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-               return;
-       }
- 
--      nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
--      /* FIXME: BOZO- DQS training every time*/
--      nv_DQSTrainCTL = 1;
-+      // nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
-+      nv_DQSTrainCTL = !allow_config_restore;
- 
-       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
-       phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
-@@ -1854,15 +1893,16 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-               }
-       }
- 
-+      mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
-+      if (!is_fam15h()) {
-+              /* TODO: should be in mctHookBeforeAnyTraining */
-+              _WRMSR(0x26C, 0x04040404, 0x04040404);
-+              _WRMSR(0x26D, 0x04040404, 0x04040404);
-+              _WRMSR(0x26E, 0x04040404, 0x04040404);
-+              _WRMSR(0x26F, 0x04040404, 0x04040404);
-+      }
-+
-       if (nv_DQSTrainCTL) {
--              mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
--              if (!is_fam15h()) {
--                      /* TODO: should be in mctHookBeforeAnyTraining */
--                      _WRMSR(0x26C, 0x04040404, 0x04040404);
--                      _WRMSR(0x26D, 0x04040404, 0x04040404);
--                      _WRMSR(0x26E, 0x04040404, 0x04040404);
--                      _WRMSR(0x26F, 0x04040404, 0x04040404);
--              }
-               mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
- 
-               if (is_fam15h()) {
-@@ -1892,18 +1932,25 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-                       exit_training_mode_fam15(pMCTstat, pDCTstatA);
-               else
-                       mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
-+      } else {
-+              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
- 
--              /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
--              mctHookAfterAnyTraining();
--              mctSaveDQSSigTmg_D();
-+              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass);
- 
--              MCTMemClr_D(pMCTstat, pDCTstatA);
--      } else {
--              mctGetDQSSigTmg_D();    /* get values into data structure */
--              LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA);       /* load values 
into registers.*/
--              /* mctDoWarmResetMemClr_D(); */
--              MCTMemClr_D(pMCTstat, pDCTstatA);
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DIMM training 
configuration from NVRAM\n");
-+              restore_mct_information_from_nvram(1);
-+#endif
-+
-+              if (is_fam15h())
-+                      exit_training_mode_fam15(pMCTstat, pDCTstatA);
-       }
-+
-+      /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
-+      mctHookAfterAnyTraining();
-+
-+      /* mctDoWarmResetMemClr_D(); */
-+      MCTMemClr_D(pMCTstat, pDCTstatA);
- }
- 
- static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
-@@ -3913,6 +3960,8 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat)
- {
-       u8 err_code;
-+      uint8_t nvram;
-+      uint8_t allow_config_restore;
- 
-       /* Preconfigure DCT0 */
-       DCTPreInit_D(pMCTstat, pDCTstat, 0);
-@@ -3927,6 +3976,27 @@ static void mct_preInitDCT(struct MCTStatStruc 
*pMCTstat,
-                               pDCTstat->ErrCode = err_code;   /* Using DCT0 
Error code to update pDCTstat.ErrCode */
-               }
-       }
-+
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-+      calculate_and_store_spd_hashes(pMCTstat, pDCTstat);
-+
-+      if (load_spd_hashes_from_nvram(pDCTstat) < 0) {
-+              pDCTstat->spd_data.nvram_spd_match = 0;
-+      }
-+      else {
-+              compare_nvram_spd_hashes(pMCTstat, pDCTstat);
-+      }
-+#else
-+      pDCTstat->spd_data.nvram_spd_match = 0;
-+#endif
-+
-+      /* Check to see if restoration of SPD data from NVRAM is allowed */
-+      allow_config_restore = 0;
-+      if (get_option(&nvram, "allow_spd_nvram_cache_restore") == CB_SUCCESS)
-+              allow_config_restore = !!nvram;
-+
-+      if (!allow_config_restore)
-+              pDCTstat->spd_data.nvram_spd_match = 0;
- }
- 
- static void mct_initDCT(struct MCTStatStruc *pMCTstat,
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 5bb09b4..539ecc3 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -325,6 +325,10 @@ struct MCTStatStruc {
- struct amd_spd_node_data {
-       uint8_t spd_bytes[MAX_DIMMS_SUPPORTED][256];    /* [DIMM][byte] */
-       uint8_t spd_address[MAX_DIMMS_SUPPORTED];       /* [DIMM] */
-+      uint64_t spd_hash[MAX_DIMMS_SUPPORTED];         /* [DIMM] */
-+      uint64_t nvram_spd_hash[MAX_DIMMS_SUPPORTED];   /* [DIMM] */
-+      uint8_t nvram_spd_match;
-+      uint8_t nvram_memclk[2];                        /* [channel] */
- } __attribute__((packed));
- 
- struct DCTStatStruc {         /* A per Node structure*/
-@@ -784,6 +788,8 @@ struct amd_s3_persistent_mct_channel_data {
- 
- struct amd_s3_persistent_node_data {
-       uint32_t node_present;
-+      uint64_t spd_hash[MAX_DIMMS_SUPPORTED];
-+      uint8_t memclk[2];
-       struct amd_s3_persistent_mct_channel_data channel[2];
- } __attribute__((packed));
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index aa23951..fa1873a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -26,8 +26,10 @@
- #include <device/pci_ops.h>
- #include <console/console.h>
- #include <cbfs.h>
-+#include <cbmem.h>
- #include <spi-generic.h>
- #include <spi_flash.h>
-+#include <pc80/mc146818rtc.h>
- 
- #include "s3utils.h"
- 
-@@ -124,6 +126,68 @@ static uint32_t read_amd_dct_index_register_dct(device_t 
dev, uint8_t node, uint
-       return read_amd_dct_index_register(dev, index_ctl_reg, index);
- }
- 
-+/* Non-cryptographic 64-bit hash function taken from Stack Overflow:
-+ * http://stackoverflow.com/a/13326345
-+ * Any 64-bit hash with sufficiently low collision potential
-+ * could be used instead.
-+ */
-+void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash)
-+{
-+      const unsigned long long prime = 2654435789ULL;
-+      uint16_t byte;
-+      *spd_hash = 104395301;
-+
-+      for (byte = 0; byte < 256; byte++)
-+              *spd_hash += (spd_data[byte] * prime) ^ (*spd_hash >> 23);
-+
-+      *spd_hash = *spd_hash ^ (*spd_hash << 37);
-+}
-+
-+static struct amd_s3_persistent_data * map_s3nv_in_nvram(void)
-+{
-+      ssize_t s3nv_offset;
-+      ssize_t s3nv_file_offset;
-+      void * s3nv_cbfs_file_ptr;
-+      struct amd_s3_persistent_data *persistent_data;
-+
-+      /* Obtain CBFS file offset */
-+      s3nv_offset = get_s3nv_file_offset();
-+      if (s3nv_offset == -1)
-+              return NULL;
-+
-+      /* Align flash pointer to nearest boundary */
-+      s3nv_file_offset = s3nv_offset;
-+      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
-+      s3nv_offset += CONFIG_S3_DATA_SIZE;
-+      s3nv_file_offset = s3nv_offset - s3nv_file_offset;
-+
-+      /* Map data structure in CBFS and restore settings */
-+      s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, 
CBFS_TYPE_RAW, NULL);
-+      if (!s3nv_cbfs_file_ptr) {
-+              printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", 
S3NV_FILE_NAME);
-+              return NULL;
-+      }
-+      persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
-+
-+      return persistent_data;
-+}
-+
-+#ifdef __PRE_RAM__
-+int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat)
-+{
-+      struct amd_s3_persistent_data *persistent_data;
-+
-+      persistent_data = map_s3nv_in_nvram();
-+      if (!persistent_data)
-+              return -1;
-+
-+      memcpy(pDCTstat->spd_data.nvram_spd_hash, 
persistent_data->node[pDCTstat->Node_ID].spd_hash, 
sizeof(pDCTstat->spd_data.nvram_spd_hash));
-+      memcpy(pDCTstat->spd_data.nvram_memclk, 
persistent_data->node[pDCTstat->Node_ID].memclk, 
sizeof(pDCTstat->spd_data.nvram_memclk));
-+
-+      return 0;
-+}
-+#endif
-+
- #ifdef __RAMSTAGE__
- static uint64_t rdmsr_uint64_t(unsigned long index) {
-       msr_t msr = rdmsr(index);
-@@ -149,6 +213,31 @@ static uint32_t read_config32_dct_nbpstate(device_t dev, 
uint8_t node, uint8_t d
-       return pci_read_config32(dev, reg);
- }
- 
-+static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_data)
-+{
-+      uint8_t node;
-+      uint8_t dimm;
-+      uint8_t channel;
-+      struct amdmct_memory_info *mem_info;
-+      mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
-+      if (mem_info == NULL) {
-+              /* can't find amdmct information in cbmem */
-+              for (node = 0; node < MAX_NODES_SUPPORTED; node++)
-+                      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
-+                              persistent_data->node[node].spd_hash[dimm] = 
0xffffffffffffffffULL;
-+
-+              return;
-+      }
-+
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++)
-+              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
-+                      
calculate_spd_hash(mem_info->dct_stat[node].spd_data.spd_bytes[dimm], 
&persistent_data->node[node].spd_hash[dimm]);
-+
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++)
-+              for (channel = 0; channel < 2; channel++)
-+                      persistent_data->node[node].memclk[channel] = 
mem_info->dct_stat[node].Speed;
-+}
-+
- void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
- {
-       uint8_t i;
-@@ -441,7 +530,7 @@ static void wrmsr_uint64_t(unsigned long index, uint64_t 
value) {
-       wrmsr(index, msr);
- }
- 
--void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data)
-+void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data, uint8_t training_only)
- {
-       uint8_t i;
-       uint8_t j;
-@@ -451,6 +540,51 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-       uint8_t dct_enabled;
-       uint32_t dword;
- 
-+      if (training_only) {
-+              /* Only restore the Receiver Enable and DQS training registers 
*/
-+              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+                      for (channel = 0; channel < 2; channel++) {
-+                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
-+                              if (!persistent_data->node[node].node_present)
-+                                      continue;
-+
-+                              /* Restore training parameters */
-+                              for (i=0; i<4; i++)
-+                                      for (j=0; j<3; j++)
-+                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
-+                              for (i=0; i<4; i++)
-+                                      for (j=0; j<3; j++)
-+                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
-+
-+                              for (i=0; i<12; i++)
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x10 + i, data->f2x9cx10[i]);
-+                              for (i=0; i<12; i++)
-+                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x20 + i, data->f2x9cx20[i]);
-+
-+                              if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
-+                                      for (i=0; i<12; i++)
-+                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x30 + i, data->f2x9cx30[i]);
-+                                      for (i=0; i<12; i++)
-+                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x40 + i, data->f2x9cx40[i]);
-+                              }
-+
-+                              /* Restore MaxRdLatency */
-+                              if (is_fam15h()) {
-+                                      for (i=0; i<4; i++)
-+                                              
write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 
0x210, data->f2x210[i]);
-+                              }
-+                              else {
-+                                      write_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x78, data->f2x78);
-+                              }
-+
-+                              /* Other timing control registers */
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x8c, data->f2x8c);
-+                      }
-+              }
-+
-+              return;
-+      }
-+
-       /* Load data from data structure into DCTs */
-       /* Stage 1 */
-       for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-@@ -501,7 +635,8 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       wrmsr_uint64_t(0x00000250, data->msr00000250);
-                       wrmsr_uint64_t(0x00000258, data->msr00000258);
-                       /* FIXME
--                       * Restoring these MSRs causes a hang on resume
-+                       * Restoring these MSRs causes a hang on resume due to
-+                       * destroying CAR while still executing from CAR!
-                        * For now, skip restoration...
-                        */
-                       // for (i=0; i<8; i++)
-@@ -890,6 +1025,8 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
- #ifdef __RAMSTAGE__
- int8_t save_mct_information_to_nvram(void)
- {
-+      uint8_t nvram;
-+
-       if (acpi_is_wakeup_s3())
-               return 0;
- 
-@@ -909,6 +1046,9 @@ int8_t save_mct_information_to_nvram(void)
-       /* Obtain MCT configuration data */
-       copy_mct_data_to_save_variable(persistent_data);
- 
-+      /* Save RAM SPD data at the same time */
-+      copy_cbmem_spd_data_to_save_variable(persistent_data);
-+
-       /* Obtain CBFS file offset */
-       s3nv_offset = get_s3nv_file_offset();
-       if (s3nv_offset == -1)
-@@ -949,36 +1089,23 @@ int8_t save_mct_information_to_nvram(void)
-       /* Restore SPI MMIO address */
-       pci_write_config32(lpc_dev, 0xa0, spi_mmio_prev);
- 
-+      /* Allow training bypass if DIMM configuration is unchanged on next 
boot */
-+      nvram = 1;
-+      set_option("allow_spd_nvram_cache_restore", &nvram);
-+
-       return 0;
- }
- #endif
- 
--int8_t restore_mct_information_from_nvram(void)
-+int8_t restore_mct_information_from_nvram(uint8_t training_only)
- {
--      ssize_t s3nv_offset;
--      ssize_t s3nv_file_offset;
--      void * s3nv_cbfs_file_ptr;
-       struct amd_s3_persistent_data *persistent_data;
- 
--      /* Obtain CBFS file offset */
--      s3nv_offset = get_s3nv_file_offset();
--      if (s3nv_offset == -1)
-+      persistent_data = map_s3nv_in_nvram();
-+      if (!persistent_data)
-               return -1;
- 
--      /* Align flash pointer to nearest boundary */
--      s3nv_file_offset = s3nv_offset;
--      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
--      s3nv_offset += CONFIG_S3_DATA_SIZE;
--      s3nv_file_offset = s3nv_offset - s3nv_file_offset;
--
--      /* Map data structure in CBFS and restore settings */
--      s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, 
CBFS_TYPE_RAW, NULL);
--      if (!s3nv_cbfs_file_ptr) {
--              printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", 
S3NV_FILE_NAME);
--              return -1;
--      }
--      persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
--      restore_mct_data_from_save_variable(persistent_data);
-+      restore_mct_data_from_save_variable(persistent_data, training_only);
- 
-       return 0;
--}
-\ No newline at end of file
-+}
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-index dcddcad..82f73a7 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-@@ -20,9 +20,15 @@
- #include "../wrappers/mcti.h"
- #include "mct_d.h"
- 
-+void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash);
-+
-+#ifdef __PRE_RAM__
-+int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat);
-+#endif
-+
- #ifdef __RAMSTAGE__
- int8_t save_mct_information_to_nvram(void);
- #endif
--int8_t restore_mct_information_from_nvram(void);
-+int8_t restore_mct_information_from_nvram(uint8_t training_only);
- void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data);
--void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data);
-\ No newline at end of file
-+void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data, uint8_t training_only);
-\ No newline at end of file
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index 1d4eade..af34d3b 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -399,14 +399,18 @@ static void mctHookAfterCPU(void)
- }
- 
- 
-+#if IS_ENABLED(CONFIG_DIMM_DDR2)
- static void mctSaveDQSSigTmg_D(void)
- {
- }
-+#endif
- 
- 
-+#if IS_ENABLED(CONFIG_DIMM_DDR2)
- static void mctGetDQSSigTmg_D(void)
- {
- }
-+#endif
- 
- 
- static void mctHookBeforeECC(void)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0044-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
 
b/resources/libreboot/patch/kgpe-d16/0044-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
new file mode 100644
index 0000000..e1c7c3f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0044-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch
@@ -0,0 +1,781 @@
+From d95a5bb7caa2d95f531ff529269509b9c38bbf72 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 4 Jun 2015 00:11:03 -0500
+Subject: [PATCH 044/143] amd/amdmct/mct_ddr3: Use training values from
+ previous boot if possible
+
+DRAM training accounts for most of the romstage startup time, yet
+if the hardware configuration has not changed from the previous boot
+the previously discovered training values are still valid.  Use them
+if the DIMM configuration has not changed since the last boot.
+
+Change-Id: I37ed277b16476d38e4af76c6ae827a575c6b017d
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.layout       |    1 +
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |  206 +++++++++++++++++--------
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |    6 +
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c |  175 ++++++++++++++++++---
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.h |   10 +-
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c  |    4 +
+ 6 files changed, 308 insertions(+), 94 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index e55edc4..7944631 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -43,6 +43,7 @@ entries
+ 458          4       e       11       hypertransport_speed_limit
+ 462          2       e       12       minimum_memory_voltage
+ 464          1       e       2        compute_unit_siblings
++465          1       r       0        allow_spd_nvram_cache_restore
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index e60adb7..20e66f2 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -39,7 +39,8 @@
+ static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA);
+ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstatA);
++                              struct DCTStatStruc *pDCTstatA,
++                              uint8_t allow_config_restore);
+ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA);
+ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
+@@ -355,8 +356,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
+                                       else if (drive_strength == 0x3)
+                                               calibration_code = 0xfff;
+                               }
+-                      }
+-                      else if (ddr_voltage_index & 0x2) {
++                      } else if (ddr_voltage_index & 0x2) {
+                               /* 1.35V */
+                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 42 */
+                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
+@@ -390,8 +390,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
+                                       else if (drive_strength == 0x3)
+                                               calibration_code = 0xdb6;
+                               }
+-                      }
+-                      else if (ddr_voltage_index & 0x1) {
++                      } else if (ddr_voltage_index & 0x1) {
+                               /* 1.5V */
+                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 41 */
+                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
+@@ -426,8 +425,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
+                                               calibration_code = 0xb6d;
+                               }
+                       }
+-              }
+-              else if (package_type == PT_C3) {
++              } else if (package_type == PT_C3) {
+                       /* Socket C32 */
+                       if (ddr_voltage_index & 0x4) {
+                               /* 1.25V */
+@@ -473,8 +471,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
+                                       else if (drive_strength == 0x3)
+                                               calibration_code = 0xfff;
+                               }
+-                      }
+-                      else if (ddr_voltage_index & 0x2) {
++                      } else if (ddr_voltage_index & 0x2) {
+                               /* 1.35V */
+                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 45 */
+                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
+@@ -518,8 +515,7 @@ static uint32_t 
fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTs
+                                       else if (drive_strength == 0x3)
+                                               calibration_code = 0xdb6;
+                               }
+-                      }
+-                      else if (ddr_voltage_index & 0x1) {
++                      } else if (ddr_voltage_index & 0x1) {
+                               /* 1.5V */
+                               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 
Table 44 */
+                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
+@@ -619,8 +615,7 @@ static uint32_t 
fam15h_phy_predriver_cmd_addr_calibration_code(struct DCTStatStr
+                       else if (drive_strength == 0x3)
+                               calibration_code = 0xb64;
+               }
+-      }
+-      else if (ddr_voltage_index & 0x2) {
++      } else if (ddr_voltage_index & 0x2) {
+               /* 1.35V */
+               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 51 */
+               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+@@ -654,8 +649,7 @@ static uint32_t 
fam15h_phy_predriver_cmd_addr_calibration_code(struct DCTStatStr
+                       else if (drive_strength == 0x3)
+                               calibration_code = 0x924;
+               }
+-      }
+-      else if (ddr_voltage_index & 0x1) {
++      } else if (ddr_voltage_index & 0x1) {
+               /* 1.5V */
+               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 50 */
+               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+@@ -736,8 +730,7 @@ static uint32_t 
fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *p
+                       else if (drive_strength == 0x3)
+                               calibration_code = 0xff6;
+               }
+-      }
+-      else if (ddr_voltage_index & 0x2) {
++      } else if (ddr_voltage_index & 0x2) {
+               /* 1.35V */
+               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 54 */
+               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+@@ -771,8 +764,7 @@ static uint32_t 
fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *p
+                       else if (drive_strength == 0x3)
+                               calibration_code = 0xdad;
+               }
+-      }
+-      else if (ddr_voltage_index & 0x1) {
++      } else if (ddr_voltage_index & 0x1) {
+               /* 1.5V */
+               /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 53 */
+               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
+@@ -841,16 +833,13 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                       else if (MemClkFreq == 0x6) {
+                               /* DDR3-800 */
+                               calibration_code = 0x10112222;
+-                      }
+-                      else if (MemClkFreq == 0xa) {
++                      } else if (MemClkFreq == 0xa) {
+                               /* DDR3-1066 */
+                               calibration_code = 0x20112222;
+-                      }
+-                      else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) {
++                      } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) 
{
+                               /* DDR3-1333 - DDR3-1600 */
+                               calibration_code = 0x30112222;
+-                      }
+-                      else if (MemClkFreq == 0x16) {
++                      } else if (MemClkFreq == 0x16) {
+                               /* DDR3-1866 */
+                               calibration_code = 0x30332222;
+                       }
+@@ -860,16 +849,13 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                               if (MemClkFreq == 0x4) {
+                                       /* DDR3-667 */
+                                       calibration_code = 0x00112222;
+-                              }
+-                              else if (MemClkFreq == 0x6) {
++                              } else if (MemClkFreq == 0x6) {
+                                       /* DDR3-800 */
+                                       calibration_code = 0x10112222;
+-                              }
+-                              else if (MemClkFreq == 0xa) {
++                              } else if (MemClkFreq == 0xa) {
+                                       /* DDR3-1066 */
+                                       calibration_code = 0x20112222;
+-                              }
+-                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
++                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
+                                       /* DDR3-1333 - DDR3-1600 */
+                                       calibration_code = 0x30112222;
+                               }
+@@ -881,20 +867,16 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                               if (MemClkFreq == 0x4) {
+                                       /* DDR3-667 */
+                                       calibration_code = 0x10222222;
+-                              }
+-                              else if (MemClkFreq == 0x6) {
++                              } else if (MemClkFreq == 0x6) {
+                                       /* DDR3-800 */
+                                       calibration_code = 0x20222222;
+-                              }
+-                              else if (MemClkFreq == 0xa) {
++                              } else if (MemClkFreq == 0xa) {
+                                       /* DDR3-1066 */
+                                       calibration_code = 0x30222222;
+-                              }
+-                              else if (MemClkFreq == 0xe) {
++                              } else if (MemClkFreq == 0xe) {
+                                       /* DDR3-1333 */
+                                       calibration_code = 0x30222222;
+-                              }
+-                              else if (MemClkFreq == 0x12) {
++                              } else if (MemClkFreq == 0x12) {
+                                       /* DDR3-1600 */
+                                       if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
+                                               calibration_code = 0x30222222;
+@@ -1081,8 +1063,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+                                       || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
+                                       /* DDR3-667 - DDR3-1333 */
+                                       slow_access = 0;
+-                              }
+-                              else if (MemClkFreq == 0x12) {
++                              } else if (MemClkFreq == 0x12) {
+                                       /* DDR3-1600 */
+                                       if (rank_count_dimm0 == 1)
+                                               slow_access = 0;
+@@ -1098,8 +1079,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+                                       || (MemClkFreq == 0xa)) {
+                                       /* DDR3-667 - DDR3-1066 */
+                                       slow_access = 0;
+-                              }
+-                              else if ((MemClkFreq == 0xe) || (MemClkFreq == 
0x12)) {
++                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
+                                       /* DDR3-1333 - DDR3-1600 */
+                                       slow_access = 1;
+                               }
+@@ -1184,6 +1164,30 @@ static void read_spd_bytes(struct MCTStatStruc 
*pMCTstat,
+       }
+ }
+ 
++#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
++static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      uint8_t dimm;
++
++      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
++              calculate_spd_hash(pDCTstat->spd_data.spd_bytes[dimm], 
&pDCTstat->spd_data.spd_hash[dimm]);
++      }
++}
++
++static void compare_nvram_spd_hashes(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      uint8_t dimm;
++
++      pDCTstat->spd_data.nvram_spd_match = 1;
++      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
++              if (pDCTstat->spd_data.spd_hash[dimm] != 
pDCTstat->spd_data.nvram_spd_hash[dimm])
++                      pDCTstat->spd_data.nvram_spd_match = 0;
++      }
++}
++#endif
++
+ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+ {
+@@ -1232,6 +1236,8 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
+        */
+       u8 Node, NodesWmem;
+       u32 node_sys_base;
++      uint8_t nvram;
++      uint8_t allow_config_restore;
+ 
+       uint8_t s3resume = acpi_is_wakeup_s3();
+ 
+@@ -1248,7 +1254,7 @@ restartinit:
+ 
+ #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
+-              restore_mct_information_from_nvram();
++              restore_mct_information_from_nvram(0);
+ #endif
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+@@ -1298,11 +1304,26 @@ restartinit:
+                       node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
+               }
+ 
++              /* If the boot fails make sure training is attempted after 
reset */
++              nvram = 0;
++              set_option("allow_spd_nvram_cache_restore", &nvram);
++
+ #if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DIMMSetVoltage\n");
+               DIMMSetVoltages(pMCTstat, pDCTstatA);   /* Set the DIMM 
voltages (mainboard specific) */
+ #endif
+ 
++              /* If DIMM configuration has not changed since last boot 
restore training values */
++              allow_config_restore = 1;
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
++
++                      if (pDCTstat->NodePresent)
++                              if (!pDCTstat->spd_data.nvram_spd_match)
++                                      allow_config_restore = 0;
++              }
++
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+                       struct DCTStatStruc *pDCTstat;
+                       pDCTstat = pDCTstatA + Node;
+@@ -1336,14 +1357,33 @@ restartinit:
+               CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
+               mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
+ 
++              /* FIXME
++               * Previous training values should only be used if the current 
desired
++               * speed is the same as the speed used in the previous boot.
++               * How to get the desired speed at this point in the code?
++               */
++#if 0
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      struct DCTStatStruc *pDCTstat;
++                      pDCTstat = pDCTstatA + Node;
++
++                      if (pDCTstat->NodePresent) {
++                              if (pDCTstat->spd_data.nvram_memclk[0] != 
pDCTstat->DIMMAutoSpeed)
++                                      allow_config_restore = 0;
++                      }
++              }
++#endif
++
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
+-              DQSTiming_D(pMCTstat, pDCTstatA);       /* Get Receiver Enable 
and DQS signal timing*/
++              DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get 
Receiver Enable and DQS signal timing*/
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
+               UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
+ 
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+-              mct_OtherTiming(pMCTstat, pDCTstatA);
++              if (!allow_config_restore) {
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
++                      mct_OtherTiming(pMCTstat, pDCTstatA);
++              }
+ 
+               if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 
1st pass of DIMM spare enabled*/
+                       goto restartinit;
+@@ -1825,7 +1865,7 @@ static void exit_training_mode_fam15(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstatA)
++                              struct DCTStatStruc *pDCTstatA, uint8_t 
allow_config_restore)
+ {
+       u8 nv_DQSTrainCTL;
+ 
+@@ -1833,9 +1873,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+               return;
+       }
+ 
+-      nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
+-      /* FIXME: BOZO- DQS training every time*/
+-      nv_DQSTrainCTL = 1;
++      // nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
++      nv_DQSTrainCTL = !allow_config_restore;
+ 
+       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
+       phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
+@@ -1854,15 +1893,16 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+               }
+       }
+ 
++      mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
++      if (!is_fam15h()) {
++              /* TODO: should be in mctHookBeforeAnyTraining */
++              _WRMSR(0x26C, 0x04040404, 0x04040404);
++              _WRMSR(0x26D, 0x04040404, 0x04040404);
++              _WRMSR(0x26E, 0x04040404, 0x04040404);
++              _WRMSR(0x26F, 0x04040404, 0x04040404);
++      }
++
+       if (nv_DQSTrainCTL) {
+-              mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
+-              if (!is_fam15h()) {
+-                      /* TODO: should be in mctHookBeforeAnyTraining */
+-                      _WRMSR(0x26C, 0x04040404, 0x04040404);
+-                      _WRMSR(0x26D, 0x04040404, 0x04040404);
+-                      _WRMSR(0x26E, 0x04040404, 0x04040404);
+-                      _WRMSR(0x26F, 0x04040404, 0x04040404);
+-              }
+               mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
+ 
+               if (is_fam15h()) {
+@@ -1892,18 +1932,25 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+                       exit_training_mode_fam15(pMCTstat, pDCTstatA);
+               else
+                       mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
++      } else {
++              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
+ 
+-              /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+-              mctHookAfterAnyTraining();
+-              mctSaveDQSSigTmg_D();
++              mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass);
+ 
+-              MCTMemClr_D(pMCTstat, pDCTstatA);
+-      } else {
+-              mctGetDQSSigTmg_D();    /* get values into data structure */
+-              LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA);       /* load values 
into registers.*/
+-              /* mctDoWarmResetMemClr_D(); */
+-              MCTMemClr_D(pMCTstat, pDCTstatA);
++#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DIMM training 
configuration from NVRAM\n");
++              restore_mct_information_from_nvram(1);
++#endif
++
++              if (is_fam15h())
++                      exit_training_mode_fam15(pMCTstat, pDCTstatA);
+       }
++
++      /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
++      mctHookAfterAnyTraining();
++
++      /* mctDoWarmResetMemClr_D(); */
++      MCTMemClr_D(pMCTstat, pDCTstatA);
+ }
+ 
+ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
+@@ -3913,6 +3960,8 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+ {
+       u8 err_code;
++      uint8_t nvram;
++      uint8_t allow_config_restore;
+ 
+       /* Preconfigure DCT0 */
+       DCTPreInit_D(pMCTstat, pDCTstat, 0);
+@@ -3927,6 +3976,27 @@ static void mct_preInitDCT(struct MCTStatStruc 
*pMCTstat,
+                               pDCTstat->ErrCode = err_code;   /* Using DCT0 
Error code to update pDCTstat.ErrCode */
+               }
+       }
++
++#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
++      calculate_and_store_spd_hashes(pMCTstat, pDCTstat);
++
++      if (load_spd_hashes_from_nvram(pDCTstat) < 0) {
++              pDCTstat->spd_data.nvram_spd_match = 0;
++      }
++      else {
++              compare_nvram_spd_hashes(pMCTstat, pDCTstat);
++      }
++#else
++      pDCTstat->spd_data.nvram_spd_match = 0;
++#endif
++
++      /* Check to see if restoration of SPD data from NVRAM is allowed */
++      allow_config_restore = 0;
++      if (get_option(&nvram, "allow_spd_nvram_cache_restore") == CB_SUCCESS)
++              allow_config_restore = !!nvram;
++
++      if (!allow_config_restore)
++              pDCTstat->spd_data.nvram_spd_match = 0;
+ }
+ 
+ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 5bb09b4..539ecc3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -325,6 +325,10 @@ struct MCTStatStruc {
+ struct amd_spd_node_data {
+       uint8_t spd_bytes[MAX_DIMMS_SUPPORTED][256];    /* [DIMM][byte] */
+       uint8_t spd_address[MAX_DIMMS_SUPPORTED];       /* [DIMM] */
++      uint64_t spd_hash[MAX_DIMMS_SUPPORTED];         /* [DIMM] */
++      uint64_t nvram_spd_hash[MAX_DIMMS_SUPPORTED];   /* [DIMM] */
++      uint8_t nvram_spd_match;
++      uint8_t nvram_memclk[2];                        /* [channel] */
+ } __attribute__((packed));
+ 
+ struct DCTStatStruc {         /* A per Node structure*/
+@@ -784,6 +788,8 @@ struct amd_s3_persistent_mct_channel_data {
+ 
+ struct amd_s3_persistent_node_data {
+       uint32_t node_present;
++      uint64_t spd_hash[MAX_DIMMS_SUPPORTED];
++      uint8_t memclk[2];
+       struct amd_s3_persistent_mct_channel_data channel[2];
+ } __attribute__((packed));
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+index aa23951..fa1873a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -26,8 +26,10 @@
+ #include <device/pci_ops.h>
+ #include <console/console.h>
+ #include <cbfs.h>
++#include <cbmem.h>
+ #include <spi-generic.h>
+ #include <spi_flash.h>
++#include <pc80/mc146818rtc.h>
+ 
+ #include "s3utils.h"
+ 
+@@ -124,6 +126,68 @@ static uint32_t read_amd_dct_index_register_dct(device_t 
dev, uint8_t node, uint
+       return read_amd_dct_index_register(dev, index_ctl_reg, index);
+ }
+ 
++/* Non-cryptographic 64-bit hash function taken from Stack Overflow:
++ * http://stackoverflow.com/a/13326345
++ * Any 64-bit hash with sufficiently low collision potential
++ * could be used instead.
++ */
++void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash)
++{
++      const unsigned long long prime = 2654435789ULL;
++      uint16_t byte;
++      *spd_hash = 104395301;
++
++      for (byte = 0; byte < 256; byte++)
++              *spd_hash += (spd_data[byte] * prime) ^ (*spd_hash >> 23);
++
++      *spd_hash = *spd_hash ^ (*spd_hash << 37);
++}
++
++static struct amd_s3_persistent_data * map_s3nv_in_nvram(void)
++{
++      ssize_t s3nv_offset;
++      ssize_t s3nv_file_offset;
++      void * s3nv_cbfs_file_ptr;
++      struct amd_s3_persistent_data *persistent_data;
++
++      /* Obtain CBFS file offset */
++      s3nv_offset = get_s3nv_file_offset();
++      if (s3nv_offset == -1)
++              return NULL;
++
++      /* Align flash pointer to nearest boundary */
++      s3nv_file_offset = s3nv_offset;
++      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
++      s3nv_offset += CONFIG_S3_DATA_SIZE;
++      s3nv_file_offset = s3nv_offset - s3nv_file_offset;
++
++      /* Map data structure in CBFS and restore settings */
++      s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, 
CBFS_TYPE_RAW, NULL);
++      if (!s3nv_cbfs_file_ptr) {
++              printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", 
S3NV_FILE_NAME);
++              return NULL;
++      }
++      persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
++
++      return persistent_data;
++}
++
++#ifdef __PRE_RAM__
++int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat)
++{
++      struct amd_s3_persistent_data *persistent_data;
++
++      persistent_data = map_s3nv_in_nvram();
++      if (!persistent_data)
++              return -1;
++
++      memcpy(pDCTstat->spd_data.nvram_spd_hash, 
persistent_data->node[pDCTstat->Node_ID].spd_hash, 
sizeof(pDCTstat->spd_data.nvram_spd_hash));
++      memcpy(pDCTstat->spd_data.nvram_memclk, 
persistent_data->node[pDCTstat->Node_ID].memclk, 
sizeof(pDCTstat->spd_data.nvram_memclk));
++
++      return 0;
++}
++#endif
++
+ #ifdef __RAMSTAGE__
+ static uint64_t rdmsr_uint64_t(unsigned long index) {
+       msr_t msr = rdmsr(index);
+@@ -149,6 +213,31 @@ static uint32_t read_config32_dct_nbpstate(device_t dev, 
uint8_t node, uint8_t d
+       return pci_read_config32(dev, reg);
+ }
+ 
++static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_data)
++{
++      uint8_t node;
++      uint8_t dimm;
++      uint8_t channel;
++      struct amdmct_memory_info *mem_info;
++      mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
++      if (mem_info == NULL) {
++              /* can't find amdmct information in cbmem */
++              for (node = 0; node < MAX_NODES_SUPPORTED; node++)
++                      for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
++                              persistent_data->node[node].spd_hash[dimm] = 
0xffffffffffffffffULL;
++
++              return;
++      }
++
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++)
++              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
++                      
calculate_spd_hash(mem_info->dct_stat[node].spd_data.spd_bytes[dimm], 
&persistent_data->node[node].spd_hash[dimm]);
++
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++)
++              for (channel = 0; channel < 2; channel++)
++                      persistent_data->node[node].memclk[channel] = 
mem_info->dct_stat[node].Speed;
++}
++
+ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
+ {
+       uint8_t i;
+@@ -441,7 +530,7 @@ static void wrmsr_uint64_t(unsigned long index, uint64_t 
value) {
+       wrmsr(index, msr);
+ }
+ 
+-void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data)
++void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data, uint8_t training_only)
+ {
+       uint8_t i;
+       uint8_t j;
+@@ -451,6 +540,51 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+       uint8_t dct_enabled;
+       uint32_t dword;
+ 
++      if (training_only) {
++              /* Only restore the Receiver Enable and DQS training registers 
*/
++              for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++                      for (channel = 0; channel < 2; channel++) {
++                              struct amd_s3_persistent_mct_channel_data* data 
= &persistent_data->node[node].channel[channel];
++                              if (!persistent_data->node[node].node_present)
++                                      continue;
++
++                              /* Restore training parameters */
++                              for (i=0; i<4; i++)
++                                      for (j=0; j<3; j++)
++                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
++                              for (i=0; i<4; i++)
++                                      for (j=0; j<3; j++)
++                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
++
++                              for (i=0; i<12; i++)
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x10 + i, data->f2x9cx10[i]);
++                              for (i=0; i<12; i++)
++                                      
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x20 + i, data->f2x9cx20[i]);
++
++                              if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
++                                      for (i=0; i<12; i++)
++                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x30 + i, data->f2x9cx30[i]);
++                                      for (i=0; i<12; i++)
++                                              
write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 
0x98, 0x40 + i, data->f2x9cx40[i]);
++                              }
++
++                              /* Restore MaxRdLatency */
++                              if (is_fam15h()) {
++                                      for (i=0; i<4; i++)
++                                              
write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 
0x210, data->f2x210[i]);
++                              }
++                              else {
++                                      write_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x78, data->f2x78);
++                              }
++
++                              /* Other timing control registers */
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x8c, data->f2x8c);
++                      }
++              }
++
++              return;
++      }
++
+       /* Load data from data structure into DCTs */
+       /* Stage 1 */
+       for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
+@@ -501,7 +635,8 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       wrmsr_uint64_t(0x00000250, data->msr00000250);
+                       wrmsr_uint64_t(0x00000258, data->msr00000258);
+                       /* FIXME
+-                       * Restoring these MSRs causes a hang on resume
++                       * Restoring these MSRs causes a hang on resume due to
++                       * destroying CAR while still executing from CAR!
+                        * For now, skip restoration...
+                        */
+                       // for (i=0; i<8; i++)
+@@ -890,6 +1025,8 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+ #ifdef __RAMSTAGE__
+ int8_t save_mct_information_to_nvram(void)
+ {
++      uint8_t nvram;
++
+       if (acpi_is_wakeup_s3())
+               return 0;
+ 
+@@ -909,6 +1046,9 @@ int8_t save_mct_information_to_nvram(void)
+       /* Obtain MCT configuration data */
+       copy_mct_data_to_save_variable(persistent_data);
+ 
++      /* Save RAM SPD data at the same time */
++      copy_cbmem_spd_data_to_save_variable(persistent_data);
++
+       /* Obtain CBFS file offset */
+       s3nv_offset = get_s3nv_file_offset();
+       if (s3nv_offset == -1)
+@@ -949,36 +1089,23 @@ int8_t save_mct_information_to_nvram(void)
+       /* Restore SPI MMIO address */
+       pci_write_config32(lpc_dev, 0xa0, spi_mmio_prev);
+ 
++      /* Allow training bypass if DIMM configuration is unchanged on next 
boot */
++      nvram = 1;
++      set_option("allow_spd_nvram_cache_restore", &nvram);
++
+       return 0;
+ }
+ #endif
+ 
+-int8_t restore_mct_information_from_nvram(void)
++int8_t restore_mct_information_from_nvram(uint8_t training_only)
+ {
+-      ssize_t s3nv_offset;
+-      ssize_t s3nv_file_offset;
+-      void * s3nv_cbfs_file_ptr;
+       struct amd_s3_persistent_data *persistent_data;
+ 
+-      /* Obtain CBFS file offset */
+-      s3nv_offset = get_s3nv_file_offset();
+-      if (s3nv_offset == -1)
++      persistent_data = map_s3nv_in_nvram();
++      if (!persistent_data)
+               return -1;
+ 
+-      /* Align flash pointer to nearest boundary */
+-      s3nv_file_offset = s3nv_offset;
+-      s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
+-      s3nv_offset += CONFIG_S3_DATA_SIZE;
+-      s3nv_file_offset = s3nv_offset - s3nv_file_offset;
+-
+-      /* Map data structure in CBFS and restore settings */
+-      s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, 
CBFS_TYPE_RAW, NULL);
+-      if (!s3nv_cbfs_file_ptr) {
+-              printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", 
S3NV_FILE_NAME);
+-              return -1;
+-      }
+-      persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
+-      restore_mct_data_from_save_variable(persistent_data);
++      restore_mct_data_from_save_variable(persistent_data, training_only);
+ 
+       return 0;
+-}
+\ No newline at end of file
++}
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+index dcddcad..82f73a7 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+@@ -20,9 +20,15 @@
+ #include "../wrappers/mcti.h"
+ #include "mct_d.h"
+ 
++void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash);
++
++#ifdef __PRE_RAM__
++int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat);
++#endif
++
+ #ifdef __RAMSTAGE__
+ int8_t save_mct_information_to_nvram(void);
+ #endif
+-int8_t restore_mct_information_from_nvram(void);
++int8_t restore_mct_information_from_nvram(uint8_t training_only);
+ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data);
+-void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data);
+\ No newline at end of file
++void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* 
persistent_data, uint8_t training_only);
+\ No newline at end of file
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index 9969c4f..5ca8eac 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -400,14 +400,18 @@ static void mctHookAfterCPU(void)
+ }
+ 
+ 
++#if IS_ENABLED(CONFIG_DIMM_DDR2)
+ static void mctSaveDQSSigTmg_D(void)
+ {
+ }
++#endif
+ 
+ 
++#if IS_ENABLED(CONFIG_DIMM_DDR2)
+ static void mctGetDQSSigTmg_D(void)
+ {
+ }
++#endif
+ 
+ 
+ static void mctHookBeforeECC(void)
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0044-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
 
b/resources/libreboot/patch/kgpe-d16/0044-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
deleted file mode 100644
index 9ed1c3d..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0044-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
+++ /dev/null
@@ -1,261 +0,0 @@
-From a8478c829628eb43b1222ad981600ff742d271e8 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 5 Jun 2015 21:13:30 -0500
-Subject: [PATCH 044/139] northbridge/amd/amdfam10: Enable CC6 DRAM save area
- setup
-
-Change-Id: Ibeb35da3395dc77a21a2f92f0e1d0845be53d175
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/northbridge.c  |  70 +++++++++++++++
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 132 ++++++++++++++++++++++++++++
- 2 files changed, 202 insertions(+)
-
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index baf77d6..51eac77 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -706,6 +706,8 @@ struct chip_operations northbridge_amd_amdfam10_ops = {
- static void amdfam10_domain_read_resources(device_t dev)
- {
-       unsigned reg;
-+      uint8_t nvram;
-+      uint8_t enable_cc6;
- 
-       /* Find the already assigned resource pairs */
-       get_fx_devs();
-@@ -749,6 +751,74 @@ static void amdfam10_domain_read_resources(device_t dev)
-       /* Reserve lower DRAM region to force PCI MMIO region to correct 
location above 0xefffffff */
-       ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
- #endif
-+
-+      if (is_fam15h()) {
-+              enable_cc6 = 0;
-+              if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
-+                      enable_cc6 = !!nvram;
-+
-+              if (enable_cc6) {
-+                      uint8_t node;
-+                      uint8_t interleaved;
-+                      int8_t range;
-+                      int8_t max_range;
-+                      uint8_t max_node;
-+                      uint64_t max_range_limit;
-+                      uint32_t dword;
-+                      uint32_t dword2;
-+                      uint64_t qword;
-+                      uint8_t num_nodes;
-+
-+                      /* Find highest DRAM range (DramLimitAddr) */
-+                      max_node = 0;
-+                      max_range = -1;
-+                      interleaved = 0;
-+                      max_range_limit = 0;
-+                      for (range = 0; range < 8; range++) {
-+                              dword = f1_read_config32(0x40 + (range * 0x8));
-+                              if (!(dword & 0x3))
-+                                      continue;
-+
-+                              if ((dword >> 8) & 0x7)
-+                                      interleaved = 1;
-+
-+                              dword = f1_read_config32(0x44 + (range * 0x8));
-+                              dword2 = f1_read_config32(0x144 + (range * 
0x8));
-+                              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 
24;
-+                              qword |= (((uint64_t)dword2) & 0xff) << 40;
-+
-+                              if (qword > max_range_limit) {
-+                                      max_range = range;
-+                                      max_range_limit = qword;
-+                                      max_node = dword & 0x7;
-+                              }
-+                      }
-+
-+                      num_nodes = 0;
-+                      device_t node_dev;
-+                      for (node = 0; node < FX_DEVS; node++) {
-+                              node_dev = get_node_pci(node, 0);
-+                              /* Test for node presence */
-+                              if ((node_dev) && (pci_read_config32(node_dev, 
PCI_VENDOR_ID) != 0xffffffff))
-+                                      num_nodes++;
-+                      }
-+
-+                      /* Calculate CC6 sotrage area size */
-+                      if (interleaved)
-+                              qword = (0x1000000 * num_nodes);
-+                      else
-+                              qword = 0x1000000;
-+
-+                      /* Reserve the CC6 save segment */
-+                      reserved_ram_resource(dev, 8, max_range_limit >> 10, 
qword >> 10);
-+
-+                      /* Set up the C-state base address */
-+                      msr_t c_state_addr_msr;
-+                      c_state_addr_msr = rdmsr(0xc0010073);
-+                      c_state_addr_msr.lo = 0xe0e0;           /* CstateAddr = 
0xe0e0 */
-+                      wrmsr(0xc0010073, c_state_addr_msr);
-+              }
-+      }
- }
- 
- static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 20e66f2..2798506 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1188,6 +1188,100 @@ static void compare_nvram_spd_hashes(struct 
MCTStatStruc *pMCTstat,
- }
- #endif
- 
-+static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t 
num_nodes)
-+{
-+      uint8_t interleaved;
-+      uint8_t destination_node;
-+      int8_t range;
-+      int8_t max_range;
-+      uint8_t max_node;
-+      uint64_t max_range_limit;
-+      uint32_t dword;
-+      uint32_t dword2;
-+      uint64_t qword;
-+
-+      interleaved = 0;
-+      if (pMCTstat->GStatus & (1 << GSB_NodeIntlv))
-+              interleaved = 1;
-+
-+      /* Find highest DRAM range (DramLimitAddr) */
-+      max_node = 0;
-+      max_range = -1;
-+      max_range_limit = 0;
-+      for (range = 0; range < 8; range++) {
-+              dword = Get_NB32(pDCTstat->dev_map, 0x40 + (range * 0x8));
-+              if (!(dword & 0x3))
-+                      continue;
-+
-+              dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
-+              dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
-+              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
-+              qword |= (((uint64_t)dword2) & 0xff) << 40;
-+
-+              if (qword > max_range_limit) {
-+                      max_range = range;
-+                      max_range_limit = qword;
-+                      max_node = dword & 0x7;
-+              }
-+      }
-+
-+      if (pDCTstat->Node_ID == max_node) {
-+              if (max_range >= 0) {
-+                      if (interleaved)
-+                              /* Move upper limit down by 16M * the number of 
nodes */
-+                              max_range_limit -= (0x1000000 * num_nodes);
-+                      else
-+                              /* Move upper limit down by 16M */
-+                              max_range_limit -= 0x1000000;
-+
-+                      /* Store modified range */
-+                      dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 
0x8));
-+                      dword &= ~(0xffff << 16);               /* 
DramLimit[39:24] = max_range_limit[39:24] */
-+                      dword |= (max_range_limit >> 24) & 0xffff;
-+                      Set_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8), 
dword);
-+
-+                      dword = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 
0x8));
-+                      dword &= ~(0xffff << 16);               /* 
DramLimit[47:40] = max_range_limit[47:40] */
-+                      dword |= (max_range_limit >> 40) & 0xff;
-+                      Set_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8), 
dword);
-+              }
-+      }
-+
-+      /* Determine save state destination node */
-+      if (interleaved)
-+              destination_node = Get_NB32(pDCTstat->dev_host, 0x60) & 0x7;
-+      else
-+              destination_node = max_node;
-+
-+      /* Set save state destination node */
-+      dword = Get_NB32(pDCTstat->dev_link, 0x128);
-+      dword &= ~(0x3f << 12);                         /* 
CoreSaveStateDestNode = destination_node */
-+      dword |= (destination_node & 0x3f) << 12;
-+      Set_NB32(pDCTstat->dev_link, 0x128, dword);
-+}
-+
-+static void lock_dram_config(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      uint32_t dword;
-+
-+      dword = Get_NB32(pDCTstat->dev_dct, 0x118);
-+      dword |= 0x1 << 19;             /* LockDramCfg = 1 */
-+      Set_NB32(pDCTstat->dev_dct, 0x118, dword);
-+}
-+
-+static void set_cc6_save_enable(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t enable)
-+{
-+      uint32_t dword;
-+
-+      dword = Get_NB32(pDCTstat->dev_dct, 0x118);
-+      dword &= ~(0x1 << 18);          /* CC6SaveEn = enable */
-+      dword |= (enable & 0x1) << 18;
-+      Set_NB32(pDCTstat->dev_dct, 0x118, dword);
-+}
-+
- static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstatA)
- {
-@@ -1237,6 +1331,7 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
-       u8 Node, NodesWmem;
-       u32 node_sys_base;
-       uint8_t nvram;
-+      uint8_t enable_cc6;
-       uint8_t allow_config_restore;
- 
-       uint8_t s3resume = acpi_is_wakeup_s3();
-@@ -1406,6 +1501,43 @@ restartinit:
-                       mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
-               }
- 
-+              if (is_fam15h()) {
-+                      enable_cc6 = 0;
-+                      if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
-+                              enable_cc6 = !!nvram;
-+
-+                      if (enable_cc6) {
-+                              uint8_t num_nodes;
-+
-+                              num_nodes = 0;
-+                              for (Node = 0; Node < MAX_NODES_SUPPORTED; 
Node++) {
-+                                      struct DCTStatStruc *pDCTstat;
-+                                      pDCTstat = pDCTstatA + Node;
-+
-+                                      if (pDCTstat->NodePresent)
-+                                              num_nodes++;
-+                              }
-+
-+                              for (Node = 0; Node < MAX_NODES_SUPPORTED; 
Node++) {
-+                                      struct DCTStatStruc *pDCTstat;
-+                                      pDCTstat = pDCTstatA + Node;
-+
-+                                      if (pDCTstat->NodePresent)
-+                                              
set_up_cc6_storage_fam15(pMCTstat, pDCTstat, num_nodes);
-+                              }
-+
-+                              for (Node = 0; Node < MAX_NODES_SUPPORTED; 
Node++) {
-+                                      struct DCTStatStruc *pDCTstat;
-+                                      pDCTstat = pDCTstatA + Node;
-+
-+                                      if (pDCTstat->NodePresent) {
-+                                              lock_dram_config(pMCTstat, 
pDCTstat);
-+                                              set_cc6_save_enable(pMCTstat, 
pDCTstat, 1);
-+                                      }
-+                              }
-+                      }
-+              }
-+
-               mct_FinalMCT_D(pMCTstat, pDCTstatA);
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: 
%x\n", pMCTstat->GStatus);
-       }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0045-mainboard-asus-kgpe-d16-Enable-CC6.patch
 
b/resources/libreboot/patch/kgpe-d16/0045-mainboard-asus-kgpe-d16-Enable-CC6.patch
deleted file mode 100644
index 26ddad6..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0045-mainboard-asus-kgpe-d16-Enable-CC6.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 32b3afadc08bd155e25b12a0af8b11b629c064c3 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 5 Jun 2015 21:14:23 -0500
-Subject: [PATCH 045/139] mainboard/asus/kgpe-d16: Enable CC6
-
-Change-Id: Iae1cbe7d3a6471561abfdb8e182bc764c38bb222
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/cmos.default      |  1 +
- src/mainboard/asus/kgpe-d16/cmos.layout       |  3 ++-
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 10 +++++++++-
- 3 files changed, 12 insertions(+), 2 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index 3e2ea3a..bfd2020 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -14,6 +14,7 @@ ecc_scrub_rate = 1.28us
- interleave_chip_selects = Enable
- interleave_nodes = Disable
- interleave_memory_channels = Enable
-+cpu_cc6_state = Enable
- ieee1394 = Enable
- power_on_after_fail = On
- boot_option = Fallback
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index 7944631..630219e 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -43,7 +43,8 @@ entries
- 458          4       e       11       hypertransport_speed_limit
- 462          2       e       12       minimum_memory_voltage
- 464          1       e       2        compute_unit_siblings
--465          1       r       0        allow_spd_nvram_cache_restore
-+465          1       e       1        cpu_cc6_state
-+466          1       r       0        allow_spd_nvram_cache_restore
- 477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index fa1873a..83c7b02 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -625,7 +625,11 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x124, data->f1x124);
-                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x10c, data->f2x10c);
-                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x114, data->f2x114);
--                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x118, data->f2x118);
-+                      if (is_fam15h())
-+                              /* Do not set LockDramCfg or CC6SaveEn at this 
time */
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x118, data->f2x118 & ~(0x3 << 18));
-+                      else
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x118, data->f2x118);
-                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x11c, data->f2x11c);
-                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x1b0, data->f2x1b0);
-                       write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 
channel, 0x44, data->f3x44);
-@@ -1017,6 +1021,10 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
- 
-                       /* ECC scrub rate control */
-                       pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x58, 
data->f3x58);
-+
-+                      if (is_fam15h())
-+                              /* Set LockDramCfg and CC6SaveEn */
-+                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x118, data->f2x118);
-               }
-       }
- }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0045-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
 
b/resources/libreboot/patch/kgpe-d16/0045-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
new file mode 100644
index 0000000..1437a1f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0045-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch
@@ -0,0 +1,261 @@
+From a43c033cd8bcfd0742d1f52847c09bef8280b5f3 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 5 Jun 2015 21:13:30 -0500
+Subject: [PATCH 045/143] northbridge/amd/amdfam10: Enable CC6 DRAM save area
+ setup
+
+Change-Id: Ibeb35da3395dc77a21a2f92f0e1d0845be53d175
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/northbridge.c  |   70 ++++++++++++++
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |  132 +++++++++++++++++++++++++++
+ 2 files changed, 202 insertions(+)
+
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index fcf85a7..e5612fa 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -706,6 +706,8 @@ struct chip_operations northbridge_amd_amdfam10_ops = {
+ static void amdfam10_domain_read_resources(device_t dev)
+ {
+       unsigned reg;
++      uint8_t nvram;
++      uint8_t enable_cc6;
+ 
+       /* Find the already assigned resource pairs */
+       get_fx_devs();
+@@ -749,6 +751,74 @@ static void amdfam10_domain_read_resources(device_t dev)
+       /* Reserve lower DRAM region to force PCI MMIO region to correct 
location above 0xefffffff */
+       ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
+ #endif
++
++      if (is_fam15h()) {
++              enable_cc6 = 0;
++              if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
++                      enable_cc6 = !!nvram;
++
++              if (enable_cc6) {
++                      uint8_t node;
++                      uint8_t interleaved;
++                      int8_t range;
++                      int8_t max_range;
++                      uint8_t max_node;
++                      uint64_t max_range_limit;
++                      uint32_t dword;
++                      uint32_t dword2;
++                      uint64_t qword;
++                      uint8_t num_nodes;
++
++                      /* Find highest DRAM range (DramLimitAddr) */
++                      max_node = 0;
++                      max_range = -1;
++                      interleaved = 0;
++                      max_range_limit = 0;
++                      for (range = 0; range < 8; range++) {
++                              dword = f1_read_config32(0x40 + (range * 0x8));
++                              if (!(dword & 0x3))
++                                      continue;
++
++                              if ((dword >> 8) & 0x7)
++                                      interleaved = 1;
++
++                              dword = f1_read_config32(0x44 + (range * 0x8));
++                              dword2 = f1_read_config32(0x144 + (range * 
0x8));
++                              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 
24;
++                              qword |= (((uint64_t)dword2) & 0xff) << 40;
++
++                              if (qword > max_range_limit) {
++                                      max_range = range;
++                                      max_range_limit = qword;
++                                      max_node = dword & 0x7;
++                              }
++                      }
++
++                      num_nodes = 0;
++                      device_t node_dev;
++                      for (node = 0; node < FX_DEVS; node++) {
++                              node_dev = get_node_pci(node, 0);
++                              /* Test for node presence */
++                              if ((node_dev) && (pci_read_config32(node_dev, 
PCI_VENDOR_ID) != 0xffffffff))
++                                      num_nodes++;
++                      }
++
++                      /* Calculate CC6 sotrage area size */
++                      if (interleaved)
++                              qword = (0x1000000 * num_nodes);
++                      else
++                              qword = 0x1000000;
++
++                      /* Reserve the CC6 save segment */
++                      reserved_ram_resource(dev, 8, max_range_limit >> 10, 
qword >> 10);
++
++                      /* Set up the C-state base address */
++                      msr_t c_state_addr_msr;
++                      c_state_addr_msr = rdmsr(0xc0010073);
++                      c_state_addr_msr.lo = 0xe0e0;           /* CstateAddr = 
0xe0e0 */
++                      wrmsr(0xc0010073, c_state_addr_msr);
++              }
++      }
+ }
+ 
+ static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 20e66f2..2798506 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1188,6 +1188,100 @@ static void compare_nvram_spd_hashes(struct 
MCTStatStruc *pMCTstat,
+ }
+ #endif
+ 
++static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t 
num_nodes)
++{
++      uint8_t interleaved;
++      uint8_t destination_node;
++      int8_t range;
++      int8_t max_range;
++      uint8_t max_node;
++      uint64_t max_range_limit;
++      uint32_t dword;
++      uint32_t dword2;
++      uint64_t qword;
++
++      interleaved = 0;
++      if (pMCTstat->GStatus & (1 << GSB_NodeIntlv))
++              interleaved = 1;
++
++      /* Find highest DRAM range (DramLimitAddr) */
++      max_node = 0;
++      max_range = -1;
++      max_range_limit = 0;
++      for (range = 0; range < 8; range++) {
++              dword = Get_NB32(pDCTstat->dev_map, 0x40 + (range * 0x8));
++              if (!(dword & 0x3))
++                      continue;
++
++              dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
++              dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
++              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
++              qword |= (((uint64_t)dword2) & 0xff) << 40;
++
++              if (qword > max_range_limit) {
++                      max_range = range;
++                      max_range_limit = qword;
++                      max_node = dword & 0x7;
++              }
++      }
++
++      if (pDCTstat->Node_ID == max_node) {
++              if (max_range >= 0) {
++                      if (interleaved)
++                              /* Move upper limit down by 16M * the number of 
nodes */
++                              max_range_limit -= (0x1000000 * num_nodes);
++                      else
++                              /* Move upper limit down by 16M */
++                              max_range_limit -= 0x1000000;
++
++                      /* Store modified range */
++                      dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 
0x8));
++                      dword &= ~(0xffff << 16);               /* 
DramLimit[39:24] = max_range_limit[39:24] */
++                      dword |= (max_range_limit >> 24) & 0xffff;
++                      Set_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8), 
dword);
++
++                      dword = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 
0x8));
++                      dword &= ~(0xffff << 16);               /* 
DramLimit[47:40] = max_range_limit[47:40] */
++                      dword |= (max_range_limit >> 40) & 0xff;
++                      Set_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8), 
dword);
++              }
++      }
++
++      /* Determine save state destination node */
++      if (interleaved)
++              destination_node = Get_NB32(pDCTstat->dev_host, 0x60) & 0x7;
++      else
++              destination_node = max_node;
++
++      /* Set save state destination node */
++      dword = Get_NB32(pDCTstat->dev_link, 0x128);
++      dword &= ~(0x3f << 12);                         /* 
CoreSaveStateDestNode = destination_node */
++      dword |= (destination_node & 0x3f) << 12;
++      Set_NB32(pDCTstat->dev_link, 0x128, dword);
++}
++
++static void lock_dram_config(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      uint32_t dword;
++
++      dword = Get_NB32(pDCTstat->dev_dct, 0x118);
++      dword |= 0x1 << 19;             /* LockDramCfg = 1 */
++      Set_NB32(pDCTstat->dev_dct, 0x118, dword);
++}
++
++static void set_cc6_save_enable(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t enable)
++{
++      uint32_t dword;
++
++      dword = Get_NB32(pDCTstat->dev_dct, 0x118);
++      dword &= ~(0x1 << 18);          /* CC6SaveEn = enable */
++      dword |= (enable & 0x1) << 18;
++      Set_NB32(pDCTstat->dev_dct, 0x118, dword);
++}
++
+ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstatA)
+ {
+@@ -1237,6 +1331,7 @@ static void mctAutoInitMCT_D(struct MCTStatStruc 
*pMCTstat,
+       u8 Node, NodesWmem;
+       u32 node_sys_base;
+       uint8_t nvram;
++      uint8_t enable_cc6;
+       uint8_t allow_config_restore;
+ 
+       uint8_t s3resume = acpi_is_wakeup_s3();
+@@ -1406,6 +1501,43 @@ restartinit:
+                       mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
+               }
+ 
++              if (is_fam15h()) {
++                      enable_cc6 = 0;
++                      if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
++                              enable_cc6 = !!nvram;
++
++                      if (enable_cc6) {
++                              uint8_t num_nodes;
++
++                              num_nodes = 0;
++                              for (Node = 0; Node < MAX_NODES_SUPPORTED; 
Node++) {
++                                      struct DCTStatStruc *pDCTstat;
++                                      pDCTstat = pDCTstatA + Node;
++
++                                      if (pDCTstat->NodePresent)
++                                              num_nodes++;
++                              }
++
++                              for (Node = 0; Node < MAX_NODES_SUPPORTED; 
Node++) {
++                                      struct DCTStatStruc *pDCTstat;
++                                      pDCTstat = pDCTstatA + Node;
++
++                                      if (pDCTstat->NodePresent)
++                                              
set_up_cc6_storage_fam15(pMCTstat, pDCTstat, num_nodes);
++                              }
++
++                              for (Node = 0; Node < MAX_NODES_SUPPORTED; 
Node++) {
++                                      struct DCTStatStruc *pDCTstat;
++                                      pDCTstat = pDCTstatA + Node;
++
++                                      if (pDCTstat->NodePresent) {
++                                              lock_dram_config(pMCTstat, 
pDCTstat);
++                                              set_cc6_save_enable(pMCTstat, 
pDCTstat, 1);
++                                      }
++                              }
++                      }
++              }
++
+               mct_FinalMCT_D(pMCTstat, pDCTstatA);
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: 
%x\n", pMCTstat->GStatus);
+       }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch 
b/resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch
deleted file mode 100644
index 026d843..0000000
--- a/resources/libreboot/patch/kgpe-d16/0046-cpu-amd-Add-CC6-support.patch
+++ /dev/null
@@ -1,1307 +0,0 @@
-From 674911f61b4b32b0707962fa6a5a7e50811f721a Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 8 Jun 2015 19:35:06 -0500
-Subject: [PATCH 046/139] cpu/amd: Add CC6 support
-
-Change-Id: I44ce157cda97fb85f3e8f3d7262d4712b5410670
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/arch/x86/acpigen.c                            |  26 +++-
- src/arch/x86/include/arch/acpigen.h               |   3 +
- src/cpu/amd/family_10h-family_15h/fidvid.c        | 170 +++++++++++-----------
- src/cpu/amd/family_10h-family_15h/init_cpus.c     |  80 ++++++++++
- src/cpu/amd/family_10h-family_15h/powernow_acpi.c | 135 +++++++++++++++--
- src/include/cpu/amd/powernow.h                    |   2 +
- src/mainboard/asus/kgpe-d16/cmos.default          |   1 +
- src/mainboard/asus/kgpe-d16/cmos.layout           |   5 +-
- src/northbridge/amd/amdfam10/link_control.c       |  78 ++++++++++
- src/northbridge/amd/amdfam10/northbridge.c        |  58 ++++----
- src/northbridge/amd/amdht/AsPsDefs.h              |   3 +-
- src/northbridge/amd/amdmct/amddefs.h              |  66 +++++----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c       |  57 +++++---
- src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c    |   8 +
- src/southbridge/amd/sb700/early_setup.c           |  20 ++-
- src/southbridge/amd/sb700/fadt.c                  |   4 +
- src/southbridge/amd/sb700/sb700.h                 |   7 +-
- src/southbridge/amd/sb700/sm.c                    |   5 +-
- src/southbridge/amd/sb800/fadt.c                  |   3 +
- src/southbridge/amd/sb800/sb800.h                 |   8 +-
- 20 files changed, 539 insertions(+), 200 deletions(-)
-
-diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c
-index 3aa823c..4136e65 100644
---- a/src/arch/x86/acpigen.c
-+++ b/src/arch/x86/acpigen.c
-@@ -1,6 +1,7 @@
- /*
-  * This file is part of the coreboot project.
-  *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  * Copyright (C) 2009 Rudolf Marek <address@hidden>
-  *
-  * This program is free software; you can redistribute it and/or modify
-@@ -21,11 +22,11 @@
- #define ACPIGEN_LENSTACK_SIZE 10
- 
- /*
-- * If you need to change this, change acpigen_write_f and
-+ * If you need to change this, change acpigen_write_len_f and
-  * acpigen_pop_len
-  */
- 
--#define ACPIGEN_MAXLEN 0xfff
-+#define ACPIGEN_MAXLEN 0xfffff
- 
- #include <string.h>
- #include <arch/acpigen.h>
-@@ -43,6 +44,7 @@ void acpigen_write_len_f(void)
-       len_stack[ltop++] = gencurrent;
-       acpigen_emit_byte(0);
-       acpigen_emit_byte(0);
-+      acpigen_emit_byte(0);
- }
- 
- void acpigen_pop_len(void)
-@@ -52,9 +54,10 @@ void acpigen_pop_len(void)
-       char *p = len_stack[--ltop];
-       len = gencurrent - p;
-       ASSERT(len <= ACPIGEN_MAXLEN)
--      /* generate store length for 0xfff max */
--      p[0] = (0x40 | (len & 0xf));
-+      /* generate store length for 0xfffff max */
-+      p[0] = (0x80 | (len & 0xf));
-       p[1] = (len >> 4 & 0xff);
-+      p[2] = (len >> 12 & 0xff);
- 
- }
- 
-@@ -483,6 +486,21 @@ void acpigen_write_CST_package(acpi_cstate_t *cstate, int 
nentries)
-       acpigen_pop_len();
- }
- 
-+void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype, 
u32 index)
-+{
-+      acpigen_write_name("_CSD");
-+      acpigen_write_package(1);
-+      acpigen_write_package(6);
-+      acpigen_write_byte(6);  // 6 values
-+      acpigen_write_byte(0);  // revision 0
-+      acpigen_write_dword(domain);
-+      acpigen_write_dword(coordtype);
-+      acpigen_write_dword(numprocs);
-+      acpigen_write_dword(index);
-+      acpigen_pop_len();
-+      acpigen_pop_len();
-+}
-+
- void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list)
- {
- /*
-diff --git a/src/arch/x86/include/arch/acpigen.h 
b/src/arch/x86/include/arch/acpigen.h
-index a3e65eb..8e50960 100644
---- a/src/arch/x86/include/arch/acpigen.h
-+++ b/src/arch/x86/include/arch/acpigen.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2009 Rudolf Marek <address@hidden>
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -55,6 +56,8 @@ typedef enum { SW_ALL=0xfc, SW_ANY=0xfd, HW_ALL=0xfe } 
PSD_coord;
- void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
- void acpigen_write_CST_package_entry(acpi_cstate_t *cstate);
- void acpigen_write_CST_package(acpi_cstate_t *entry, int nentries);
-+typedef enum { CSD_HW_ALL=0xfe } CSD_coord;
-+void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype, 
u32 index);
- void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len);
- void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list);
- void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
-diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
-index 2e26645..0e870e3 100644
---- a/src/cpu/amd/family_10h-family_15h/fidvid.c
-+++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
-@@ -169,87 +169,87 @@ static void applyBoostFIDOffset(device_t dev, uint32_t 
nodeid) {
- }
- 
- static void enableNbPState1( device_t dev ) {
--  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
--  if (cpuRev & AMD_FAM10_C3) {
--    u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
--    if ( nbPState){
--      u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & NB_VID1_MASK) >> 
NB_VID1_SHIFT;
--      u32 i;
--      for (i = nbPState; i < NM_PS_REG; i++) {
--         msr_t msr =  rdmsr(PS_REG_BASE + i);
--         if (msr.hi &  PS_EN_MASK ) {
--            msr.hi |= NB_DID_M_ON;
--            msr.lo &= NB_VID_MASK_OFF;
--          msr.lo |= ( nbVid1 << NB_VID_POS);
--          wrmsr(PS_REG_BASE + i, msr);
--       }
--      }
--    }
--  }
-+      uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
-+      if (cpuRev & AMD_FAM10_C3) {
-+              u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
-+              if ( nbPState){
-+                      u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & 
NB_VID1_MASK) >> NB_VID1_SHIFT;
-+                      u32 i;
-+                      for (i = nbPState; i < NM_PS_REG; i++) {
-+                              msr_t msr =  rdmsr(PS_REG_BASE + i);
-+                              if (msr.hi &  PS_EN_MASK ) {
-+                              msr.hi |= NB_DID_M_ON;
-+                              msr.lo &= NB_VID_MASK_OFF;
-+                              msr.lo |= ( nbVid1 << NB_VID_POS);
-+                              wrmsr(PS_REG_BASE + i, msr);
-+                              }
-+                      }
-+              }
-+      }
- }
- 
--static u8 setPStateMaxVal( device_t dev ) {
--      u8 i,maxpstate=0;
--      for (i = 0; i < NM_PS_REG; i++) {
--         msr_t msr =  rdmsr(PS_REG_BASE + i);
--         if (msr.hi & PS_IDD_VALUE_MASK) {
--         msr.hi |= PS_EN_MASK ;
--           wrmsr(PS_REG_BASE + i, msr);
--       }
--         if (msr.hi & PS_EN_MASK) {
--         maxpstate = i;
--       }
--      }
--      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
--      u32 reg = pci_read_config32(dev, CPTC2);
--      reg &= PS_MAX_VAL_MASK;
--      reg |= (maxpstate << PS_MAX_VAL_POS);
--      pci_write_config32(dev, CPTC2,reg);
--      return maxpstate;
-+static u8 setPStateMaxVal(device_t dev) {
-+      u8 i, maxpstate=0;
-+      for (i = 0; i < NM_PS_REG; i++) {
-+              msr_t msr = rdmsr(PS_REG_BASE + i);
-+              if (msr.hi & PS_IDD_VALUE_MASK) {
-+                      msr.hi |= PS_EN_MASK ;
-+                      wrmsr(PS_REG_BASE + i, msr);
-+              }
-+              if (msr.hi & PS_EN_MASK) {
-+                      maxpstate = i;
-+              }
-+      }
-+      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
-+      u32 reg = pci_read_config32(dev, CPTC2);
-+      reg &= PS_MAX_VAL_MASK;
-+      reg |= (maxpstate << PS_MAX_VAL_POS);
-+      pci_write_config32(dev, CPTC2,reg);
-+      return maxpstate;
- }
- 
- static void dualPlaneOnly(  device_t dev ) {
--  // BKDG 2.4.2.7
--
--  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
--  if ((mctGetProcessorPackageType() ==  AMD_PKGTYPE_AM3_2r2)
--      && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no 
constant for E
--    if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
--       && (pci_read_config32(dev, 0xA0) & PVI_MODE) ){
--      if (cpuid_edx(0x80000007) & CPB_MASK) {
--          // revision E only, but E is apparently not supported yet, 
therefore untested
--         msr_t minPstate = rdmsr(0xC0010065);
--         wrmsr(0xC0010065, rdmsr(0xC0010068) );
--         wrmsr(0xC0010068,minPstate);
--      } else {
--       msr_t msr;
--         msr.lo=0; msr.hi=0;
--         wrmsr(0xC0010064, rdmsr(0xC0010068) );
--         wrmsr(0xC0010068, msr );
--      }
--
--      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
--      u8 maxpstate = setPStateMaxVal(dev);
--
--      u32 reg = pci_read_config32(dev, HTC_REG);
--      reg &= HTC_PS_LMT_MASK;
--      reg |= (maxpstate << PS_LIMIT_POS);
--      pci_write_config32(dev, HTC_REG,reg);
--
--    }
--  }
-+      // BKDG 2.4.2.7
-+
-+      uint64_t cpuRev = mctGetLogicalCPUID(0xFF);
-+      if ((mctGetProcessorPackageType() == AMD_PKGTYPE_AM3_2r2)
-+              && (cpuRev & (AMD_DR_Cx | AMD_DR_Ex))) {
-+              if ((pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
-+                      && (pci_read_config32(dev, 0xA0) & PVI_MODE)) {
-+                      if (cpuid_edx(0x80000007) & CPB_MASK) {
-+                              // revision E only, but E is apparently not 
supported yet, therefore untested
-+                              msr_t minPstate = rdmsr(0xC0010065);
-+                              wrmsr(0xC0010065, rdmsr(0xC0010068));
-+                              wrmsr(0xC0010068, minPstate);
-+                      } else {
-+                              msr_t msr;
-+                              msr.lo=0; msr.hi=0;
-+                              wrmsr(0xC0010064, rdmsr(0xC0010068) );
-+                              wrmsr(0xC0010068, msr);
-+                      }
-+
-+                      //FIXME: CPTC2 and HTC_REG should get max per node, not 
per core ?
-+                      u8 maxpstate = setPStateMaxVal(dev);
-+
-+                      u32 reg = pci_read_config32(dev, HTC_REG);
-+                      reg &= HTC_PS_LMT_MASK;
-+                      reg |= (maxpstate << PS_LIMIT_POS);
-+                      pci_write_config32(dev, HTC_REG,reg);
-+              }
-+      }
- }
- 
- static int vidTo100uV(u8 vid)
--{// returns voltage corresponding to vid in tenths of mV, i.e. hundreds of uV
-- // BKDG #31116 rev 3.48 2.4.1.6
--  int voltage;
--  if (vid >= 0x7c) {
--    voltage = 0;
--  } else {
--    voltage = (15500 - (125*vid));
--  }
--  return voltage;
-+{
-+      // returns voltage corresponding to vid in tenths of mV, i.e. hundreds 
of uV
-+      // BKDG #31116 rev 3.48 2.4.1.6
-+      int voltage;
-+      if (vid >= 0x7c) {
-+              voltage = 0;
-+      } else {
-+              voltage = (15500 - (125*vid));
-+      }
-+      return voltage;
- }
- 
- static void setVSRamp(device_t dev) {
-@@ -348,7 +348,7 @@ static void recalculateVsSlamTimeSettingOnCorePre(device_t 
dev)
-       }
- 
-       /* Get AltVID */
--      dtemp = pci_read_config32(dev, 0xDC);
-+      dtemp = pci_read_config32(dev, 0xdc);
-       bValue = (u8) (dtemp & BIT_MASK_7);
- 
-       /* Use the VID with the lowest voltage (higher VID) */
-@@ -512,15 +512,15 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 
cpuRev) {
-            values (min latency) */
-       u32 nbPstate = pci_read_config32(dev,0x1f0) & NB_PSTATE_MASK;
-         u8 nbSynPtrAdj;
--      if ((cpuRev & (AMD_DR_Bx|AMD_DA_Cx) )
--          || ( (cpuRev & AMD_RB_C3) && (nbPstate!=0)))  {
--        nbSynPtrAdj = 5;
-+      if ((cpuRev & (AMD_DR_Bx | AMD_DA_Cx | AMD_FAM15_ALL) )
-+              || ((cpuRev & AMD_RB_C3) && (nbPstate != 0))) {
-+              nbSynPtrAdj = 5;
-       } else {
--          nbSynPtrAdj = 6;
-+              nbSynPtrAdj = 6;
-       }
- 
--      u32 dword = pci_read_config32(dev, 0xDc);
--        dword &= ~ NB_SYN_PTR_ADJ_MASK;
-+      u32 dword = pci_read_config32(dev, 0xdc);
-+        dword &= ~NB_SYN_PTR_ADJ_MASK;
-       dword |= nbSynPtrAdj << NB_SYN_PTR_ADJ_POS;
-         /* NbsynPtrAdj set to 5 or 6 per BKDG (needs reset) */
-       pci_write_config32(dev, 0xdc, dword);
-@@ -552,7 +552,7 @@ static void config_acpi_pwr_state_ctrl_regs(device_t dev, 
u32 cpuRev, u8 procPkg
-                       }
-               } else { // rev C or later
-                       // same doubt as cache scrubbing: ok to check current 
state ?
--                      dword = pci_read_config32(dev, 0xDC);
-+                      dword = pci_read_config32(dev, 0xdc);
-                       u32 cacheFlushOnHalt = dword & (7 << 16);
-                       if (!cacheFlushOnHalt) {
-                               c1 = 0x80;
-@@ -623,11 +623,11 @@ static void prep_fid_change(void)
-               printk(BIOS_DEBUG, "  F3x80: %08x\n", dword);
-               dword = pci_read_config32(dev, 0x84);
-               printk(BIOS_DEBUG, "  F3x84: %08x\n", dword);
--              dword = pci_read_config32(dev, 0xD4);
-+              dword = pci_read_config32(dev, 0xd4);
-               printk(BIOS_DEBUG, "  F3xD4: %08x\n", dword);
--              dword = pci_read_config32(dev, 0xD8);
-+              dword = pci_read_config32(dev, 0xd8);
-               printk(BIOS_DEBUG, "  F3xD8: %08x\n", dword);
--              dword = pci_read_config32(dev, 0xDC);
-+              dword = pci_read_config32(dev, 0xdc);
-               printk(BIOS_DEBUG, "  F3xDC: %08x\n", dword);
-       }
- }
-@@ -756,7 +756,7 @@ static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid, 
u32 dev, u8 pviMode)
-          * synchronization between cores and we don't think
-          * PstatMaxVal is going to be 0 on cold reset anyway ?
-        */
--        if ( ! (pci_read_config32(dev, 0xDC) & (~ PS_MAX_VAL_MASK)) ) {
-+        if (!(pci_read_config32(dev, 0xdc) & (~PS_MAX_VAL_MASK))) {
-          printk(BIOS_ERR,"F3xDC[PstateMaxVal] is zero. Northbridge voltage 
setting will fail. fixPsNbVidBeforeWR in fidvid.c needs fixing. See AMD # 31116 
rev 3.48 BKDG 2.4.2.9.1 \n");
-       };
- 
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index aced850..818431b 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -30,6 +30,14 @@
- #include <northbridge/amd/amdfam10/raminit_amdmct.c>
- #include <reset.h>
- 
-+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700)
-+#include <southbridge/amd/sb700/sb700.h>
-+#endif
-+
-+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
-+#include <southbridge/amd/sb800/sb800.h>
-+#endif
-+
- #if IS_ENABLED(CONFIG_SET_FIDVID)
- static void prep_fid_change(void);
- static void init_fidvid_stage2(u32 apicid, u32 nodeid);
-@@ -874,6 +882,8 @@ void cpuSetAMDMSR(uint8_t node_id)
-       u8 i;
-       u32 platform;
-       uint64_t revision;
-+      uint8_t nvram;
-+      uint8_t enable_c_states;
- 
-       printk(BIOS_DEBUG, "cpuSetAMDMSR ");
- 
-@@ -936,6 +946,42 @@ void cpuSetAMDMSR(uint8_t node_id)
-               wrmsr(FP_CFG, msr);
-       }
- 
-+#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || 
IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
-+      if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
-+              /* Set up message triggered C1E */
-+              msr = rdmsr(0xc0010055);
-+              msr.lo &= ~0xffff;              /* IOMsgAddr = ACPI_PM_EVT_BLK 
*/
-+              msr.lo |= ACPI_PM_EVT_BLK & 0xffff;
-+              msr.lo |= (0x1 << 29);          /* BmStsClrOnHltEn = 1 */
-+              if (revision & AMD_DR_GT_D0) {
-+                      msr.lo &= ~(0x1 << 28); /* C1eOnCmpHalt = 0 */
-+                      msr.lo &= ~(0x1 << 27); /* SmiOnCmpHalt = 0 */
-+              }
-+              wrmsr(0xc0010055, msr);
-+
-+              msr = rdmsr(0xc0010015);
-+              msr.lo |= (0x1 << 12);          /* HltXSpCycEn = 1 */
-+              wrmsr(0xc0010015, msr);
-+      }
-+
-+      if (revision & (AMD_DR_Ex | AMD_FAM15_ALL)) {
-+              enable_c_states = 0;
-+              if (IS_ENABLED(CONFIG_HAVE_ACPI_TABLES))
-+                      if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
-+                              enable_c_states = !!nvram;
-+
-+              if (enable_c_states) {
-+                      /* Set up the C-state base address */
-+                      msr_t c_state_addr_msr;
-+                      c_state_addr_msr = rdmsr(0xc0010073);
-+                      c_state_addr_msr.lo = ACPI_CPU_P_LVL2;  /* CstateAddr = 
ACPI_CPU_P_LVL2 */
-+                      wrmsr(0xc0010073, c_state_addr_msr);
-+              }
-+      }
-+#else
-+      enable_c_states = 0;
-+#endif
-+
-       printk(BIOS_DEBUG, " done\n");
- }
- 
-@@ -950,6 +996,7 @@ static void cpuSetAMDPCI(u8 node)
-       u32 platform;
-       u32 val;
-       u8 offset;
-+      uint32_t dword;
-       uint64_t revision;
- 
-       printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node);
-@@ -1008,6 +1055,39 @@ static void cpuSetAMDPCI(u8 node)
-          if (revision & (AMD_DR_B2 | AMD_DR_B3))
-          dctPhyDiag(); */
- 
-+      if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
-+              /* Set up message triggered C1E */
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0xd4);
-+              dword &= ~(0x1 << 14);                  /* 
CacheFlushImmOnAllHalt = !is_fam15h() */
-+              dword |= (is_fam15h()?0:1) << 14;
-+              pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0xdc);
-+              dword |= 0x1 << 26;                     /* IgnCpuPrbEn = 1 */
-+              dword &= ~(0x7f << 19);                 /* CacheFlushOnHaltTmr 
= 0x28 */
-+              dword |= 0x28 << 19;
-+              dword |= 0x7 << 16;                     /* CacheFlushOnHaltCtl 
= 0x7 */
-+              pci_write_config32(NODE_PCI(node, 3), 0xdc, dword);
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0xa0);
-+              dword |= 0x1 << 10;                     /* IdleExitEn = 1 */
-+              pci_write_config32(NODE_PCI(node, 3), 0xa0, dword);
-+
-+              if (revision & AMD_DR_GT_D0) {
-+                      dword = pci_read_config32(NODE_PCI(node, 3), 0x188);
-+                      dword |= 0x1 << 4;                      /* 
EnStpGntOnFlushMaskWakeup = 1 */
-+                      pci_write_config32(NODE_PCI(node, 3), 0x188, dword);
-+              } else {
-+                      dword = pci_read_config32(NODE_PCI(node, 4), 0x128);
-+                      dword &= ~(0x1 << 31);                  /* CstateMsgDis 
= 0 */
-+                      pci_write_config32(NODE_PCI(node, 4), 0x128, dword);
-+              }
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0xd4);
-+              dword |= 0x1 << 13;                     /* MTC1eEn = 1 */
-+              pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
-+      }
-+
-       printk(BIOS_DEBUG, " done\n");
- }
- 
-diff --git a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c 
b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
-index 84e5514..028ae3f 100644
---- a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
-+++ b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
-@@ -21,6 +21,7 @@
- 
- #include <console/console.h>
- #include <stdint.h>
-+#include <option.h>
- #include <cpu/x86/msr.h>
- #include <arch/acpigen.h>
- #include <cpu/amd/powernow.h>
-@@ -34,21 +35,29 @@
- #include <northbridge/amd/amdmct/mct/mct.h>
- #include <northbridge/amd/amdmct/amddefs.h>
- 
-+static inline uint8_t is_fam15h(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      return fam15h;
-+}
-+
- static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 
*pstate_power,
-                               u32 *pstate_latency, u32 *pstate_control,
-                               u32 *pstate_status, int coreID,
--                              u32 pcontrol_blk, u8 plen, u8 onlyBSP,
-                               uint8_t single_link)
- {
-       int i;
-       struct cpuid_result cpuid1;
- 
--      if ((onlyBSP) && (coreID != 0)) {
--          plen = 0;
--          pcontrol_blk = 0;
--      }
--
--      acpigen_write_processor(coreID, pcontrol_blk, plen);
-       acpigen_write_empty_PCT();
-       acpigen_write_name("_PSS");
- 
-@@ -92,9 +101,62 @@ static void write_pstates_for_core(u8 pstate_num, u16 
*pstate_feq, u32 *pstate_p
-               if (cpu)
-                       acpigen_write_PSD_package(cpu->path.apic.apic_id, 1, 
SW_ANY);
-       }
-+}
- 
--      /* patch the whole Processor token length */
--      acpigen_pop_len();
-+static void write_cstates_for_core(int coreID)
-+{
-+      /* Generate C state entries */
-+      uint8_t cstate_count = 1;
-+      acpi_cstate_t cstate;
-+
-+      if (is_fam15h()) {
-+              cstate.ctype = 2;
-+              cstate.latency = 100;
-+              cstate.power = 0;
-+              cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO;
-+              cstate.resource.bit_width = 8;
-+              cstate.resource.bit_offset = 0;
-+              cstate.resource.addrl = rdmsr(0xc0010073).lo + 1;
-+              cstate.resource.addrh = 0;
-+              cstate.resource.resv = 1;
-+      } else {
-+              cstate.ctype = 2;
-+              cstate.latency = 75;
-+              cstate.power = 0;
-+              cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO;
-+              cstate.resource.bit_width = 8;
-+              cstate.resource.bit_offset = 0;
-+              cstate.resource.addrl = rdmsr(0xc0010073).lo;
-+              cstate.resource.addrh = 0;
-+              cstate.resource.resv = 1;
-+      }
-+
-+      acpigen_write_CST_package(&cstate, cstate_count);
-+
-+      /* Find the local APIC ID for the specified core ID */
-+      if (is_fam15h()) {
-+              struct device* cpu;
-+              int cpu_index = 0;
-+              for (cpu = all_devices; cpu; cpu = cpu->next) {
-+                      if ((cpu->path.type != DEVICE_PATH_APIC) ||
-+                              (cpu->bus->dev->path.type != 
DEVICE_PATH_CPU_CLUSTER))
-+                              continue;
-+                      if (!cpu->enabled)
-+                              continue;
-+                      if (cpu_index == coreID)
-+                              break;
-+                      cpu_index++;
-+              }
-+
-+              if (cpu) {
-+                      /* TODO
-+                       * Detect dual core status and skip CSD generation if 
dual core is disabled
-+                       */
-+
-+                      /* Generate C state dependency entries */
-+                      acpigen_write_CSD_package((cpu->path.apic.apic_id >> 1) 
& 0x7f, 2, CSD_HW_ALL, 0);
-+              }
-+      }
- }
- 
- /*
-@@ -125,6 +187,15 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-       u8 index;
-       msr_t msr;
- 
-+      uint8_t nvram;
-+      uint8_t enable_c_states;
-+
-+      enable_c_states = 0;
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
-+      if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
-+              enable_c_states = !!nvram;
-+#endif
-+
-       /* Get the Processor Brand String using cpuid(0x8000000x) command 
x=2,3,4 */
-       cpuid1 = cpuid(0x80000002);
-       v = (u32 *) processor_brand;
-@@ -200,6 +271,10 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-               return;
-       }
- 
-+      if (fam15h)
-+              /* Set P_LVL2 P_BLK entry */
-+              *(((uint8_t *)pcontrol_blk) + 0x04) = (rdmsr(0xc0010073).lo + 
1) & 0xff;
-+
-       uint8_t pviModeFlag;
-       uint8_t Pstate_max;
-       uint8_t cpufid;
-@@ -318,18 +393,56 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
-                           Pstate_latency[index]);
-       }
- 
-+      /* Enter processor block scope */
-       char pscope[] = "\\_PR";
--
-       acpigen_write_scope(pscope);
-+
-       for (index = 0; index < total_core_count; index++) {
-               /* Determine if this is a single-link processor */
-               node_index = 0x18 + (index / cores_per_node);
-               dtemp = pci_read_config32(dev_find_slot(0, 
PCI_DEVFN(node_index, 0)), 0x80);
-               single_link = !!(((dtemp & 0xff00) >> 8) == 0);
- 
-+              /* Enter processor core scope */
-+              uint8_t plen_cur = plen;
-+              uint32_t pcontrol_blk_cur = pcontrol_blk;
-+              if ((onlyBSP) && (index != 0)) {
-+                      plen_cur = 0;
-+                      pcontrol_blk_cur = 0;
-+              }
-+              acpigen_write_processor(index, pcontrol_blk_cur, plen_cur);
-+
-+              /* Write P-state status and dependency objects */
-               write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_power,
-                               Pstate_latency, Pstate_control, Pstate_status,
--                              index, pcontrol_blk, plen, onlyBSP, 
single_link);
-+                              index, single_link);
-+
-+              /* Write C-state status and dependency objects */
-+              if (fam15h && enable_c_states)
-+                      write_cstates_for_core(index);
-+
-+              /* Exit processor core scope */
-+              acpigen_pop_len();
-       }
-+
-+      /* Exit processor block scope */
-       acpigen_pop_len();
- }
-+
-+void amd_powernow_update_fadt(acpi_fadt_t * fadt)
-+{
-+      if (is_fam15h()) {
-+              fadt->p_lvl2_lat = 101;         /* NOTE: While the BKDG states 
this should
-+                                               * be set to 100, there is no 
way to meet
-+                                               * the other FADT requirements. 
 I suspect
-+                                               * there is an error in the 
BKDG for ACPI
-+                                               * 1.x support; disable all 
FADT-based C
-+                                               * states > 2... */
-+              fadt->p_lvl3_lat = 1001;
-+              fadt->flags |= 0x1 << 2;        /* FLAGS.PROC_C1 = 1 */
-+              fadt->flags |= 0x1 << 3;        /* FLAGS.P_LVL2_UP = 1 */
-+      } else {
-+              fadt->cst_cnt = 0;
-+      }
-+      fadt->pstate_cnt = 0;
-+}
-diff --git a/src/include/cpu/amd/powernow.h b/src/include/cpu/amd/powernow.h
-index 85356bd..07817d9 100644
---- a/src/include/cpu/amd/powernow.h
-+++ b/src/include/cpu/amd/powernow.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2009 Rudolf Marek <address@hidden>
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -21,5 +22,6 @@
- #define POWERNOW_H
- 
- void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP);
-+void amd_powernow_update_fadt(acpi_fadt_t * fadt);
- 
- #endif
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index bfd2020..e3eb4fe 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -14,6 +14,7 @@ ecc_scrub_rate = 1.28us
- interleave_chip_selects = Enable
- interleave_nodes = Disable
- interleave_memory_channels = Enable
-+cpu_c_states = Enable
- cpu_cc6_state = Enable
- ieee1394 = Enable
- power_on_after_fail = On
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index 630219e..7f9f661 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -43,8 +43,9 @@ entries
- 458          4       e       11       hypertransport_speed_limit
- 462          2       e       12       minimum_memory_voltage
- 464          1       e       2        compute_unit_siblings
--465          1       e       1        cpu_cc6_state
--466          1       r       0        allow_spd_nvram_cache_restore
-+465          1       e       1        cpu_c_states
-+466          1       e       1        cpu_cc6_state
-+467          1       r       0        allow_spd_nvram_cache_restore
- 477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
-diff --git a/src/northbridge/amd/amdfam10/link_control.c 
b/src/northbridge/amd/amdfam10/link_control.c
-index 1091ef4..4acd66c 100644
---- a/src/northbridge/amd/amdfam10/link_control.c
-+++ b/src/northbridge/amd/amdfam10/link_control.c
-@@ -49,15 +49,93 @@ static inline uint8_t is_fam15h(void)
- 
- static void nb_control_init(struct device *dev)
- {
-+      uint8_t nvram;
-+      uint8_t enable_c_states;
-+      uint8_t enable_cc6;
-       uint32_t dword;
- 
-       printk(BIOS_DEBUG, "NB: Function 4 Link Control.. ");
- 
-+      /* Configure L3 Power Control */
-+      dword = pci_read_config32(dev, 0x1c4);
-+      dword |= (0x1 << 8);                    /* L3PwrSavEn = 1 */
-+      pci_write_config32(dev, 0x1c4, dword);
-+
-       if (is_fam15h()) {
-+              /* Configure L3 Control 2 */
-+              dword = pci_read_config32(dev, 0x1cc);
-+              dword &= ~(0x7 << 6);                   /* 
ImplRdProjDelayThresh = 0x2 */
-+              dword |= (0x2 << 6);
-+              pci_write_config32(dev, 0x1cc, dword);
-+
-+              /* Configure TDP Accumulator Divisor Control */
-+              dword = pci_read_config32(dev, 0x104);
-+              dword &= ~(0xfff << 2);                 /* TdpAccDivRate = 0xc8 
*/
-+              dword |= (0xc8 << 2);
-+              dword &= ~0x3;                          /* TdpAccDivVal = 0x1 */
-+              dword |= 0x1;
-+              pci_write_config32(dev, 0x104, dword);
-+
-+              /* Configure Sample and Residency Timers */
-+              dword = pci_read_config32(dev, 0x110);
-+              dword &= ~0xfff;                        /* CSampleTimer = 0x1 */
-+              dword |= 0x1;
-+              pci_write_config32(dev, 0x110, dword);
-+
-+              /* Configure APM TDP Control */
-+              dword = pci_read_config32(dev, 0x16c);
-+              dword |= (0x1 << 4);                    /* ApmTdpLimitIntEn = 1 
*/
-+              pci_write_config32(dev, 0x16c, dword);
-+
-               /* Enable APM */
-               dword = pci_read_config32(dev, 0x15c);
-               dword |= (0x1 << 7);                    /* ApmMasterEn = 1 */
-               pci_write_config32(dev, 0x15c, dword);
-+
-+              enable_c_states = 0;
-+              enable_cc6 = 0;
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
-+              if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
-+                      enable_c_states = !!nvram;
-+
-+              if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
-+                      enable_cc6 = !!nvram;
-+#endif
-+
-+              if (enable_c_states) {
-+                      /* Configure C-state Control 1 */
-+                      dword = pci_read_config32(dev, 0x118);
-+                      dword |= (0x1 << 24);           /* PwrGateEnCstAct1 = 1 
*/
-+                      dword &= ~(0x7 << 21);          /* ClkDivisorCstAct1 = 
0x0 */
-+                      dword &= ~(0x3 << 18);          /* 
CacheFlushTmrSelCstAct1 = 0x1 */
-+                      dword |= (0x1 << 18);
-+                      dword |= (0x1 << 17);           /* CacheFlushEnCstAct1 
= 1 */
-+                      dword |= (0x1 << 16);           /* CpuPrbEnCstAct1 = 1 
*/
-+                      dword &= ~(0x1 << 8);           /* PwrGateEnCstAct0 = 0 
*/
-+                      dword &= ~(0x7 << 5);           /* ClkDivisorCstAct0 = 
0x0 */
-+                      dword &= ~(0x3 << 2);           /* 
CacheFlushTmrSelCstAct0 = 0x2 */
-+                      dword |= (0x2 << 2);
-+                      dword |= (0x1 << 1);            /* CacheFlushEnCstAct0 
= 1 */
-+                      dword |= 0x1;                   /* CpuPrbEnCstAct0 = 1 
*/
-+                      pci_write_config32(dev, 0x118, dword);
-+
-+                      /* Configure C-state Control 2 */
-+                      dword = pci_read_config32(dev, 0x11c);
-+                      dword &= ~(0x1 << 8);           /* PwrGateEnCstAct2 = 0 
*/
-+                      dword &= ~(0x7 << 5);           /* ClkDivisorCstAct2 = 
0x0 */
-+                      dword &= ~(0x3 << 2);           /* 
CacheFlushTmrSelCstAct0 = 0x0 */
-+                      dword &= ~(0x1 << 1);           /* CacheFlushEnCstAct0 
= 0 */
-+                      dword &= ~(0x1);                /* CpuPrbEnCstAct0 = 0 
*/
-+                      pci_write_config32(dev, 0x11c, dword);
-+
-+                      /* Configure C-state Policy Control 1 */
-+                      dword = pci_read_config32(dev, 0x128);
-+                      dword &= ~(0x7f << 5);          /* CacheFlushTmr = 0x28 
*/
-+                      dword |= (0x28 << 5);
-+                      dword &= ~0x1;                  /* CoreCstateMode = 
!enable_cc6 */
-+                      dword |= ((enable_cc6)?0:1);
-+                      pci_write_config32(dev, 0x128, dword);
-+              }
-       }
- 
-       printk(BIOS_DEBUG, "done.\n");
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 51eac77..3fc31c0 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -770,53 +770,49 @@ static void amdfam10_domain_read_resources(device_t dev)
-                       uint8_t num_nodes;
- 
-                       /* Find highest DRAM range (DramLimitAddr) */
-+                      num_nodes = 0;
-                       max_node = 0;
-                       max_range = -1;
-                       interleaved = 0;
-                       max_range_limit = 0;
--                      for (range = 0; range < 8; range++) {
--                              dword = f1_read_config32(0x40 + (range * 0x8));
--                              if (!(dword & 0x3))
--                                      continue;
--
--                              if ((dword >> 8) & 0x7)
--                                      interleaved = 1;
--
--                              dword = f1_read_config32(0x44 + (range * 0x8));
--                              dword2 = f1_read_config32(0x144 + (range * 
0x8));
--                              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 
24;
--                              qword |= (((uint64_t)dword2) & 0xff) << 40;
--
--                              if (qword > max_range_limit) {
--                                      max_range = range;
--                                      max_range_limit = qword;
--                                      max_node = dword & 0x7;
--                              }
--                      }
--
--                      num_nodes = 0;
-                       device_t node_dev;
-                       for (node = 0; node < FX_DEVS; node++) {
-                               node_dev = get_node_pci(node, 0);
-                               /* Test for node presence */
--                              if ((node_dev) && (pci_read_config32(node_dev, 
PCI_VENDOR_ID) != 0xffffffff))
--                                      num_nodes++;
-+                              if ((!node_dev) || (pci_read_config32(node_dev, 
PCI_VENDOR_ID) == 0xffffffff))
-+                                      continue;
-+
-+                              num_nodes++;
-+                              for (range = 0; range < 8; range++) {
-+                                      dword = 
pci_read_config32(get_node_pci(node, 1), 0x40 + (range * 0x8));
-+                                      if (!(dword & 0x3))
-+                                              continue;
-+
-+                                      if ((dword >> 8) & 0x7)
-+                                              interleaved = 1;
-+
-+                                      dword = 
pci_read_config32(get_node_pci(node, 1), 0x44 + (range * 0x8));
-+                                      dword2 = 
pci_read_config32(get_node_pci(node, 1), 0x144 + (range * 0x8));
-+                                      qword = 0xffffff;
-+                                      qword |= ((((uint64_t)dword) >> 16) & 
0xffff) << 24;
-+                                      qword |= (((uint64_t)dword2) & 0xff) << 
40;
-+
-+                                      if (qword > max_range_limit) {
-+                                              max_range = range;
-+                                              max_range_limit = qword;
-+                                              max_node = dword & 0x7;
-+                                      }
-+                              }
-                       }
- 
--                      /* Calculate CC6 sotrage area size */
-+                      /* Calculate CC6 storage area size */
-                       if (interleaved)
-                               qword = (0x1000000 * num_nodes);
-                       else
-                               qword = 0x1000000;
- 
-                       /* Reserve the CC6 save segment */
--                      reserved_ram_resource(dev, 8, max_range_limit >> 10, 
qword >> 10);
--
--                      /* Set up the C-state base address */
--                      msr_t c_state_addr_msr;
--                      c_state_addr_msr = rdmsr(0xc0010073);
--                      c_state_addr_msr.lo = 0xe0e0;           /* CstateAddr = 
0xe0e0 */
--                      wrmsr(0xc0010073, c_state_addr_msr);
-+                      reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 
10, qword >> 10);
-               }
-       }
- }
-diff --git a/src/northbridge/amd/amdht/AsPsDefs.h 
b/src/northbridge/amd/amdht/AsPsDefs.h
-index caeb9b4..7f29dd1 100644
---- a/src/northbridge/amd/amdht/AsPsDefs.h
-+++ b/src/northbridge/amd/amdht/AsPsDefs.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -254,7 +255,7 @@
- #define DUAL_PLANE_NB_VID_SHIFT 17/* for CPU rev <= C */
- 
- 
--#define NM_PS_REG 5                   /* number of P-state MSR registers */
-+#define NM_PS_REG (is_fam15h()?8:5)   /* number of P-state MSR registers */
- 
- /* sFidVidInit.outFlags defines */
- #define PWR_CK_OK 0                   /* System board check OK */
-diff --git a/src/northbridge/amd/amdmct/amddefs.h 
b/src/northbridge/amd/amdmct/amddefs.h
-index 20a77d3..7aa4698 100644
---- a/src/northbridge/amd/amdmct/amddefs.h
-+++ b/src/northbridge/amd/amdmct/amddefs.h
-@@ -53,32 +53,34 @@
- /*
-  * Groups - Create as many as you wish, from the above public values
-  */
--#define       AMD_NPT_F2      (AMD_NPT_F2C | AMD_NPT_F2D | AMD_NPT_F2E | 
AMD_NPT_F2G | AMD_NPT_F2J | AMD_NPT_F2K)
--#define       AMD_NPT_F3      (AMD_NPT_F3L)
--#define       AMD_NPT_Fx      (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2 | 
AMD_NPT_F3)
--#define       AMD_NPT_Gx      (AMD_NPT_G0A | AMD_NPT_G1B)
--#define       AMD_NPT_ALL     (AMD_NPT_Fx | AMD_NPT_Gx)
--#define       AMD_FINEDELAY   (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2)
--#define       AMD_GT_F0       (AMD_NPT_ALL AND NOT AMD_NPT_F0)
--#define       AMD_DR_Ax       (AMD_DR_A0A + AMD_DR_A1B + AMD_DR_A2)
--#define       AMD_DR_Bx       (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_B3 
| AMD_DR_BA)
--#define       AMD_DR_LT_B2    (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)
--#define       AMD_DR_LT_B3    (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_BA)
--#define       AMD_DR_GT_B0    (AMD_DR_ALL & ~(AMD_DR_B0))
--#define       AMD_DR_GT_Bx    (AMD_DR_ALL & ~(AMD_DR_Ax | AMD_DR_Bx))
--#define       AMD_DR_ALL      (AMD_DR_Bx)
--#define       AMD_FAM10_ALL   (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | AMD_DA_C3 
| AMD_DA_C2 | AMD_RB_C3 | AMD_HY_D1 | AMD_PH_E0)
--#define AMD_FAM10_LT_D  (AMD_FAM10_ALL & ~(AMD_HY_D0))
--#define       AMD_FAM10_GT_B0 (AMD_FAM10_ALL & ~(AMD_DR_B0))
--#define AMD_FAM10_REV_D       (AMD_HY_D0 | AMD_HY_D1)
--#define       AMD_DA_Cx       (AMD_DA_C2 | AMD_DA_C3)
--#define       AMD_DR_Cx       (AMD_RB_C2 | AMD_RB_C3 | AMD_DA_Cx)
--#define       AMD_FAM10_C3       (AMD_RB_C3 | AMD_DA_C3)
--#define       AMD_DR_Dx       (AMD_HY_D0 | AMD_HY_D1)
--#define       AMD_DRBH_Cx     (AMD_DR_Cx | AMD_HY_D0 )
--#define       AMD_DRBA23_RBC2 (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 )
-+#define       AMD_NPT_F2              (AMD_NPT_F2C | AMD_NPT_F2D | 
AMD_NPT_F2E | AMD_NPT_F2G | AMD_NPT_F2J | AMD_NPT_F2K)
-+#define       AMD_NPT_F3              (AMD_NPT_F3L)
-+#define       AMD_NPT_Fx              (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2 | 
AMD_NPT_F3)
-+#define       AMD_NPT_Gx              (AMD_NPT_G0A | AMD_NPT_G1B)
-+#define       AMD_NPT_ALL             (AMD_NPT_Fx | AMD_NPT_Gx)
-+#define       AMD_FINEDELAY           (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2)
-+#define       AMD_GT_F0               (AMD_NPT_ALL AND NOT AMD_NPT_F0)
-+#define       AMD_DR_Ax               (AMD_DR_A0A + AMD_DR_A1B + AMD_DR_A2)
-+#define       AMD_DR_Bx               (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | 
AMD_DR_B3 | AMD_DR_BA)
-+#define       AMD_DR_Cx               (AMD_RB_C2 | AMD_RB_C3 | AMD_DA_Cx)
-+#define       AMD_DR_Dx               (AMD_HY_D0 | AMD_HY_D1)
-+#define       AMD_DR_Ex               (AMD_PH_E0)
-+#define       AMD_DR_LT_B2            (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)
-+#define       AMD_DR_LT_B3            (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | 
AMD_DR_BA)
-+#define       AMD_DR_GT_B0            (AMD_DR_ALL & ~(AMD_DR_B0))
-+#define       AMD_DR_GT_Bx            (AMD_DR_ALL & ~(AMD_DR_Ax | AMD_DR_Bx))
-+#define       AMD_DR_GT_D0            ((AMD_DR_Dx & ~(AMD_HY_D0)) | AMD_DR_Ex)
-+#define       AMD_DR_ALL              (AMD_DR_Bx)
-+#define       AMD_FAM10_ALL           (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | 
AMD_DA_C3 | AMD_DA_C2 | AMD_RB_C3 | AMD_HY_D1 | AMD_PH_E0)
-+#define AMD_FAM10_LT_D        (AMD_FAM10_ALL & ~(AMD_HY_D0))
-+#define       AMD_FAM10_GT_B0         (AMD_FAM10_ALL & ~(AMD_DR_B0))
-+#define AMD_FAM10_REV_D               (AMD_HY_D0 | AMD_HY_D1)
-+#define       AMD_DA_Cx               (AMD_DA_C2 | AMD_DA_C3)
-+#define       AMD_FAM10_C3            (AMD_RB_C3 | AMD_DA_C3)
-+#define       AMD_DRBH_Cx             (AMD_DR_Cx | AMD_HY_D0 )
-+#define       AMD_DRBA23_RBC2         (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | 
AMD_RB_C2 )
- #define       AMD_DR_DAC2_OR_C3       (AMD_DA_C2 | AMD_DA_C3 | AMD_RB_C3)
--#define       AMD_FAM15_ALL   (AMD_OR_B2 | AMD_OR_C0)
-+#define       AMD_FAM15_ALL           (AMD_OR_B2 | AMD_OR_C0)
- 
- /*
-  *  Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH 
CPUPLATFORMTYPE RETURN VALUE
-@@ -91,9 +93,9 @@
- #define       AMD_PTYPE_MC    0x020   /* Multi Core (>2) */
- #define       AMD_PTYPE_UMA   0x040   /* UMA required */
- 
--      /*
--       * Groups - Create as many as you wish, from the above public values
--       */
-+/*
-+ * Groups - Create as many as you wish, from the above public values
-+ */
- #define       AMD_PTYPE_ALL   0xFFFFFFFF      /* A mask for all */
- 
- 
-@@ -102,11 +104,11 @@
-  */
- #define HTPHY_LINKTYPE_HT3            0x00000001
- #define HTPHY_LINKTYPE_HT1            0x00000002
--#define HTPHY_LINKTYPE_COHERENT       0x00000004
-+#define HTPHY_LINKTYPE_COHERENT               0x00000004
- #define HTPHY_LINKTYPE_NONCOHERENT    0x00000008
- #define HTPHY_LINKTYPE_CONNECTED      (HTPHY_LINKTYPE_COHERENT | 
HTPHY_LINKTYPE_NONCOHERENT)
- #define HTPHY_LINKTYPE_GANGED         0x00000010
--#define HTPHY_LINKTYPE_UNGANGED       0x00000020
-+#define HTPHY_LINKTYPE_UNGANGED               0x00000020
- #define HTPHY_LINKTYPE_ALL            0x7FFFFFFF
- 
- 
-@@ -114,7 +116,7 @@
-  * CPU HT PHY REGISTERS, FIELDS, AND MASKS
-  */
- #define HTPHY_OFFSET_MASK             0xE00001FF
--#define HTPHY_WRITE_CMD               0x40000000
-+#define HTPHY_WRITE_CMD                       0x40000000
- #define HTPHY_IS_COMPLETE_MASK                0x80000000
- #define HTPHY_DIRECT_MAP              0x20000000
- #define HTPHY_DIRECT_OFFSET_MASK      0xE000FFFF
-@@ -162,4 +164,4 @@
- #define AMD_PKGTYPE_S1gX 2
- #define AMD_PKGTYPE_G34 3
- #define AMD_PKGTYPE_ASB2 4
--#define AMD_PKGTYPE_C32 5
-+#define AMD_PKGTYPE_C32 5
-\ No newline at end of file
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 2798506..4044c36 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1197,6 +1197,7 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
-       int8_t max_range;
-       uint8_t max_node;
-       uint64_t max_range_limit;
-+      uint8_t byte;
-       uint32_t dword;
-       uint32_t dword2;
-       uint64_t qword;
-@@ -1216,7 +1217,8 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
- 
-               dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
-               dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
--              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
-+              qword = 0xffffff;
-+              qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24;
-               qword |= (((uint64_t)dword2) & 0xff) << 40;
- 
-               if (qword > max_range_limit) {
-@@ -1226,26 +1228,35 @@ static void set_up_cc6_storage_fam15(struct 
MCTStatStruc *pMCTstat,
-               }
-       }
- 
--      if (pDCTstat->Node_ID == max_node) {
--              if (max_range >= 0) {
--                      if (interleaved)
--                              /* Move upper limit down by 16M * the number of 
nodes */
--                              max_range_limit -= (0x1000000 * num_nodes);
--                      else
--                              /* Move upper limit down by 16M */
--                              max_range_limit -= 0x1000000;
--
--                      /* Store modified range */
--                      dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 
0x8));
--                      dword &= ~(0xffff << 16);               /* 
DramLimit[39:24] = max_range_limit[39:24] */
--                      dword |= (max_range_limit >> 24) & 0xffff;
--                      Set_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8), 
dword);
--
--                      dword = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 
0x8));
--                      dword &= ~(0xffff << 16);               /* 
DramLimit[47:40] = max_range_limit[47:40] */
--                      dword |= (max_range_limit >> 40) & 0xff;
--                      Set_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8), 
dword);
--              }
-+      if (max_range >= 0) {
-+              if (interleaved)
-+                      /* Move upper limit down by 16M * the number of nodes */
-+                      max_range_limit -= (0x1000000 * num_nodes);
-+              else
-+                      /* Move upper limit down by 16M */
-+                      max_range_limit -= 0x1000000;
-+
-+              /* Disable the range */
-+              dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
-+              byte = dword & 0x3;
-+              dword &= ~(0x3);
-+              Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword);
-+
-+              /* Store modified range */
-+              dword = Get_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8));
-+              dword &= ~(0xffff << 16);               /* DramLimit[39:24] = 
max_range_limit[39:24] */
-+              dword |= ((max_range_limit >> 24) & 0xffff) << 16;
-+              Set_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8), dword);
-+
-+              dword = Get_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8));
-+              dword &= ~0xff;                 /* DramLimit[47:40] = 
max_range_limit[47:40] */
-+              dword |= (max_range_limit >> 40) & 0xff;
-+              Set_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8), dword);
-+
-+              /* Reenable the range */
-+              dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
-+              dword |= byte;
-+              Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword);
-       }
- 
-       /* Determine save state destination node */
-@@ -1531,8 +1542,8 @@ restartinit:
-                                       pDCTstat = pDCTstatA + Node;
- 
-                                       if (pDCTstat->NodePresent) {
--                                              lock_dram_config(pMCTstat, 
pDCTstat);
-                                               set_cc6_save_enable(pMCTstat, 
pDCTstat, 1);
-+                                              lock_dram_config(pMCTstat, 
pDCTstat);
-                                       }
-                               }
-                       }
-@@ -5110,7 +5121,7 @@ static void mct_HTMemMapExt(struct MCTStatStruc 
*pMCTstat,
-               /* get base/limit from Node0 */
-               reg = 0x40 + (Node << 3);               /* Node0/Dram Base 0 */
-               val = Get_NB32(dev, reg);
--              Drambase = val >> ( 16 + 3);
-+              Drambase = val >> (16 + 3);
- 
-               reg = 0x44 + (Node << 3);               /* Node0/Dram Base 0 */
-               val = Get_NB32(dev, reg);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-index 11f1b2c..3a9fecc 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-@@ -159,6 +159,14 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                       if (MemClrECC) {
-                               MCTMemClrSync_D(pMCTstat, pDCTstatA);
-                       }
-+
-+                      if (pDCTstat->LogicalCPUID & (AMD_DR_GT_D0 | 
AMD_FAM15_ALL)) {
-+                              /* Set up message triggered C1E */
-+                              val = pci_read_config32(pDCTstat->dev_nbmisc, 
0xd4);
-+                              val &= ~(0x1 << 15);                    /* 
StutterScrubEn = DRAM scrub enabled */
-+                              val |= (mctGet_NVbits(NV_DramBKScrub)?1:0) << 
15;
-+                              pci_write_config32(pDCTstat->dev_nbmisc, 0xd4, 
val);
-+                      }
-               }       /* if Node present */
-       }
- 
-diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
-index a6849b0..fd3b099 100644
---- a/src/southbridge/amd/sb700/early_setup.c
-+++ b/src/southbridge/amd/sb700/early_setup.c
-@@ -22,6 +22,7 @@
- #define _SB700_EARLY_SETUP_C_
- 
- #include <stdint.h>
-+#include <option.h>
- #include <arch/acpi.h>
- #include <arch/cpu.h>
- #include <arch/io.h>
-@@ -271,10 +272,6 @@ void enable_fid_change_on_sb(u32 sbbusn, u32 sbdn)
-       byte &= ~(1<<6);
-       pmio_write(0x8d, byte);
- 
--      byte = pmio_read(0x61);
--      byte &= ~0x04;
--      pmio_write(0x61, byte);
--
-       byte = pmio_read(0x42);
-       byte &= ~0x04;
-       pmio_write(0x42, byte);
-@@ -560,6 +557,13 @@ static void sb700_devices_por_init(void)
- static void sb700_pmio_por_init(void)
- {
-       u8 byte;
-+      uint8_t enable_c_states;
-+
-+      enable_c_states = 0;
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
-+      if (get_option(&byte, "cpu_c_states") == CB_SUCCESS)
-+              enable_c_states = !!byte;
-+#endif
- 
-       printk(BIOS_INFO, "sb700_pmio_por_init()\n");
-       /* K8KbRstEn, KB_RST# control for K8 system. */
-@@ -621,6 +625,14 @@ static void sb700_pmio_por_init(void)
-       byte |= 1 << 0;
-       pmio_write(0xB2, byte);
- 
-+      /* Set up IOAPIC and BM_STS monitoring */
-+      byte = pmio_read(0x61);
-+      if (enable_c_states)
-+              byte |= 0x4;
-+      else
-+              byte &= ~0x04;
-+      pmio_write(0x61, byte);
-+
-       // FIXME: Enabling this causes boot to hang while initializing 
processors.
- //    /* Enable automatic C1e state switch */
- //    byte = pmio_read(0xc9);
-diff --git a/src/southbridge/amd/sb700/fadt.c 
b/src/southbridge/amd/sb700/fadt.c
-index 96996a3..6b1924f 100644
---- a/src/southbridge/amd/sb700/fadt.c
-+++ b/src/southbridge/amd/sb700/fadt.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -26,6 +27,7 @@
- #include <arch/acpi.h>
- #include <arch/io.h>
- #include <device/device.h>
-+#include <cpu/amd/powernow.h>
- #include "sb700.h"
- 
- void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
-@@ -156,5 +158,7 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
-       fadt->x_gpe1_blk.addrl = 0;
-       fadt->x_gpe1_blk.addrh = 0x0;
- 
-+      amd_powernow_update_fadt(fadt);
-+
-       header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t));
- }
-diff --git a/src/southbridge/amd/sb700/sb700.h 
b/src/southbridge/amd/sb700/sb700.h
-index b477091..941a4fd 100644
---- a/src/southbridge/amd/sb700/sb700.h
-+++ b/src/southbridge/amd/sb700/sb700.h
-@@ -36,10 +36,11 @@
- 
- #define ACPI_PM_EVT_BLK               (SB700_ACPI_IO_BASE + 0x00) /* 4 bytes 
*/
- #define ACPI_PM1_CNT_BLK      (SB700_ACPI_IO_BASE + 0x04) /* 2 bytes */
--#define ACPI_PMA_CNT_BLK      (SB700_ACPI_IO_BASE + 0x0E) /* 1 byte */
--#define ACPI_PM_TMR_BLK               (SB700_ACPI_IO_BASE + 0x18) /* 4 bytes 
*/
--#define ACPI_GPE0_BLK         (SB700_ACPI_IO_BASE + 0x10) /* 8 bytes */
-+#define ACPI_PMA_CNT_BLK      (SB700_ACPI_IO_BASE + 0x16) /* 1 byte */
-+#define ACPI_PM_TMR_BLK               (SB700_ACPI_IO_BASE + 0x20) /* 4 bytes 
*/
-+#define ACPI_GPE0_BLK         (SB700_ACPI_IO_BASE + 0x18) /* 8 bytes */
- #define ACPI_CPU_CONTROL      (SB700_ACPI_IO_BASE + 0x08) /* 6 bytes */
-+#define ACPI_CPU_P_LVL2               (ACPI_CPU_CONTROL + 0x4)    /* 1 byte */
- 
- extern void pm_iowrite(u8 reg, u8 value);
- extern u8 pm_ioread(u8 reg);
-diff --git a/src/southbridge/amd/sb700/sm.c b/src/southbridge/amd/sb700/sm.c
-index a4b78d0..81e3046 100644
---- a/src/southbridge/amd/sb700/sm.c
-+++ b/src/southbridge/amd/sb700/sm.c
-@@ -114,7 +114,10 @@ static void sm_init(device_t dev)
-       pci_write_config8(dev, 0x41, byte);
- 
-       byte = pm_ioread(0x61);
--      byte |= 1 << 1;         /* Set to enable NB/SB handshake during IOAPIC 
interrupt for AMD K8/K7 */
-+      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
-+              byte &= ~(1 << 1);      /* Clear for non-K8 CPUs */
-+      else
-+              byte |= 1 << 1;         /* Set to enable NB/SB handshake during 
IOAPIC interrupt for AMD K8/K7 */
-       pm_iowrite(0x61, byte);
- 
-       /* disable SMI */
-diff --git a/src/southbridge/amd/sb800/fadt.c 
b/src/southbridge/amd/sb800/fadt.c
-index fea98f9..5250e20 100644
---- a/src/southbridge/amd/sb800/fadt.c
-+++ b/src/southbridge/amd/sb800/fadt.c
-@@ -26,6 +26,7 @@
- #include <arch/acpi.h>
- #include <arch/io.h>
- #include <device/device.h>
-+#include <cpu/amd/powernow.h>
- #include "sb800.h"
- 
- void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
-@@ -156,5 +157,7 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
-       fadt->x_gpe1_blk.addrl = 0;
-       fadt->x_gpe1_blk.addrh = 0x0;
- 
-+      amd_powernow_update_fadt(fadt);
-+
-       header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t));
- }
-diff --git a/src/southbridge/amd/sb800/sb800.h 
b/src/southbridge/amd/sb800/sb800.h
-index 9049182..3e3f077 100644
---- a/src/southbridge/amd/sb800/sb800.h
-+++ b/src/southbridge/amd/sb800/sb800.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -35,10 +36,11 @@
- 
- #define ACPI_PM_EVT_BLK               (SB800_ACPI_IO_BASE + 0x00) /* 4 bytes 
*/
- #define ACPI_PM1_CNT_BLK      (SB800_ACPI_IO_BASE + 0x04) /* 2 bytes */
--#define ACPI_PMA_CNT_BLK      (SB800_ACPI_IO_BASE + 0x0F) /* 1 byte */
--#define ACPI_PM_TMR_BLK               (SB800_ACPI_IO_BASE + 0x18) /* 4 bytes 
*/
--#define ACPI_GPE0_BLK         (SB800_ACPI_IO_BASE + 0x10) /* 8 bytes */
-+#define ACPI_PMA_CNT_BLK      (SB800_ACPI_IO_BASE + 0x17) /* 1 byte */
-+#define ACPI_PM_TMR_BLK               (SB800_ACPI_IO_BASE + 0x20) /* 4 bytes 
*/
-+#define ACPI_GPE0_BLK         (SB800_ACPI_IO_BASE + 0x18) /* 8 bytes */
- #define ACPI_CPU_CONTROL      (SB800_ACPI_IO_BASE + 0x08) /* 6 bytes */
-+#define ACPI_CPU_P_LVL2               (ACPI_CPU_CONTROL + 0x4)    /* 1 byte */
- 
- void pm_iowrite(u8 reg, u8 value);
- u8 pm_ioread(u8 reg);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0046-mainboard-asus-kgpe-d16-Enable-CC6.patch
 
b/resources/libreboot/patch/kgpe-d16/0046-mainboard-asus-kgpe-d16-Enable-CC6.patch
new file mode 100644
index 0000000..f11eca2
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0046-mainboard-asus-kgpe-d16-Enable-CC6.patch
@@ -0,0 +1,70 @@
+From 9517e40030e0b2a648df74095d705ed85a6b7f09 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 5 Jun 2015 21:14:23 -0500
+Subject: [PATCH 046/143] mainboard/asus/kgpe-d16: Enable CC6
+
+Change-Id: Iae1cbe7d3a6471561abfdb8e182bc764c38bb222
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.default      |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout       |    3 ++-
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c |   10 +++++++++-
+ 3 files changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index 3e2ea3a..bfd2020 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -14,6 +14,7 @@ ecc_scrub_rate = 1.28us
+ interleave_chip_selects = Enable
+ interleave_nodes = Disable
+ interleave_memory_channels = Enable
++cpu_cc6_state = Enable
+ ieee1394 = Enable
+ power_on_after_fail = On
+ boot_option = Fallback
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 7944631..630219e 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -43,7 +43,8 @@ entries
+ 458          4       e       11       hypertransport_speed_limit
+ 462          2       e       12       minimum_memory_voltage
+ 464          1       e       2        compute_unit_siblings
+-465          1       r       0        allow_spd_nvram_cache_restore
++465          1       e       1        cpu_cc6_state
++466          1       r       0        allow_spd_nvram_cache_restore
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+index fa1873a..83c7b02 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -625,7 +625,11 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, 
channel, 0x124, data->f1x124);
+                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x10c, data->f2x10c);
+                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x114, data->f2x114);
+-                      write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x118, data->f2x118);
++                      if (is_fam15h())
++                              /* Do not set LockDramCfg or CC6SaveEn at this 
time */
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x118, data->f2x118 & ~(0x3 << 18));
++                      else
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x118, data->f2x118);
+                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x11c, data->f2x11c);
+                       write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, 
channel, 0x1b0, data->f2x1b0);
+                       write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 
channel, 0x44, data->f3x44);
+@@ -1017,6 +1021,10 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+ 
+                       /* ECC scrub rate control */
+                       pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x58, 
data->f3x58);
++
++                      if (is_fam15h())
++                              /* Set LockDramCfg and CC6SaveEn */
++                              write_config32_dct(PCI_DEV(0, 0x18 + node, 2), 
node, channel, 0x118, data->f2x118);
+               }
+       }
+ }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0047-cpu-amd-Add-CC6-support.patch 
b/resources/libreboot/patch/kgpe-d16/0047-cpu-amd-Add-CC6-support.patch
new file mode 100644
index 0000000..e063019
--- /dev/null
+++ b/resources/libreboot/patch/kgpe-d16/0047-cpu-amd-Add-CC6-support.patch
@@ -0,0 +1,1318 @@
+From 8f0d565329ddc702412d6941a5a0fea7c81e73e8 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 8 Jun 2015 19:35:06 -0500
+Subject: [PATCH 047/143] cpu/amd: Add CC6 support
+
+Change-Id: I44ce157cda97fb85f3e8f3d7262d4712b5410670
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/arch/x86/acpigen.c                            |   26 +++-
+ src/arch/x86/include/arch/acpigen.h               |    3 +
+ src/cpu/amd/family_10h-family_15h/fidvid.c        |  170 ++++++++++-----------
+ src/cpu/amd/family_10h-family_15h/init_cpus.c     |   81 ++++++++++
+ src/cpu/amd/family_10h-family_15h/powernow_acpi.c |  135 ++++++++++++++--
+ src/include/cpu/amd/powernow.h                    |    2 +
+ src/mainboard/asus/kgpe-d16/cmos.default          |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout           |    5 +-
+ src/northbridge/amd/amdfam10/link_control.c       |   81 +++++++++-
+ src/northbridge/amd/amdfam10/northbridge.c        |   58 ++++---
+ src/northbridge/amd/amdht/AsPsDefs.h              |    3 +-
+ src/northbridge/amd/amdmct/amddefs.h              |   66 ++++----
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c       |   57 ++++---
+ src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c    |    8 +
+ src/southbridge/amd/sb700/early_setup.c           |   20 ++-
+ src/southbridge/amd/sb700/fadt.c                  |    5 +
+ src/southbridge/amd/sb700/sb700.h                 |    7 +-
+ src/southbridge/amd/sb700/sm.c                    |    5 +-
+ src/southbridge/amd/sb800/fadt.c                  |    4 +
+ src/southbridge/amd/sb800/sb800.h                 |    8 +-
+ 20 files changed, 544 insertions(+), 201 deletions(-)
+
+diff --git a/src/arch/x86/acpigen.c b/src/arch/x86/acpigen.c
+index 3aa823c..4136e65 100644
+--- a/src/arch/x86/acpigen.c
++++ b/src/arch/x86/acpigen.c
+@@ -1,6 +1,7 @@
+ /*
+  * This file is part of the coreboot project.
+  *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  * Copyright (C) 2009 Rudolf Marek <address@hidden>
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -21,11 +22,11 @@
+ #define ACPIGEN_LENSTACK_SIZE 10
+ 
+ /*
+- * If you need to change this, change acpigen_write_f and
++ * If you need to change this, change acpigen_write_len_f and
+  * acpigen_pop_len
+  */
+ 
+-#define ACPIGEN_MAXLEN 0xfff
++#define ACPIGEN_MAXLEN 0xfffff
+ 
+ #include <string.h>
+ #include <arch/acpigen.h>
+@@ -43,6 +44,7 @@ void acpigen_write_len_f(void)
+       len_stack[ltop++] = gencurrent;
+       acpigen_emit_byte(0);
+       acpigen_emit_byte(0);
++      acpigen_emit_byte(0);
+ }
+ 
+ void acpigen_pop_len(void)
+@@ -52,9 +54,10 @@ void acpigen_pop_len(void)
+       char *p = len_stack[--ltop];
+       len = gencurrent - p;
+       ASSERT(len <= ACPIGEN_MAXLEN)
+-      /* generate store length for 0xfff max */
+-      p[0] = (0x40 | (len & 0xf));
++      /* generate store length for 0xfffff max */
++      p[0] = (0x80 | (len & 0xf));
+       p[1] = (len >> 4 & 0xff);
++      p[2] = (len >> 12 & 0xff);
+ 
+ }
+ 
+@@ -483,6 +486,21 @@ void acpigen_write_CST_package(acpi_cstate_t *cstate, int 
nentries)
+       acpigen_pop_len();
+ }
+ 
++void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype, 
u32 index)
++{
++      acpigen_write_name("_CSD");
++      acpigen_write_package(1);
++      acpigen_write_package(6);
++      acpigen_write_byte(6);  // 6 values
++      acpigen_write_byte(0);  // revision 0
++      acpigen_write_dword(domain);
++      acpigen_write_dword(coordtype);
++      acpigen_write_dword(numprocs);
++      acpigen_write_dword(index);
++      acpigen_pop_len();
++      acpigen_pop_len();
++}
++
+ void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list)
+ {
+ /*
+diff --git a/src/arch/x86/include/arch/acpigen.h 
b/src/arch/x86/include/arch/acpigen.h
+index a3e65eb..8e50960 100644
+--- a/src/arch/x86/include/arch/acpigen.h
++++ b/src/arch/x86/include/arch/acpigen.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2009 Rudolf Marek <address@hidden>
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -55,6 +56,8 @@ typedef enum { SW_ALL=0xfc, SW_ANY=0xfd, HW_ALL=0xfe } 
PSD_coord;
+ void acpigen_write_PSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
+ void acpigen_write_CST_package_entry(acpi_cstate_t *cstate);
+ void acpigen_write_CST_package(acpi_cstate_t *entry, int nentries);
++typedef enum { CSD_HW_ALL=0xfe } CSD_coord;
++void acpigen_write_CSD_package(u32 domain, u32 numprocs, CSD_coord coordtype, 
u32 index);
+ void acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len);
+ void acpigen_write_TSS_package(int entries, acpi_tstate_t *tstate_list);
+ void acpigen_write_TSD_package(u32 domain, u32 numprocs, PSD_coord coordtype);
+diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
+index e8e0818..0e7d299 100644
+--- a/src/cpu/amd/family_10h-family_15h/fidvid.c
++++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
+@@ -169,87 +169,87 @@ static void applyBoostFIDOffset(device_t dev, uint32_t 
nodeid) {
+ }
+ 
+ static void enableNbPState1( device_t dev ) {
+-  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
+-  if (cpuRev & AMD_FAM10_C3) {
+-    u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
+-    if ( nbPState){
+-      u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & NB_VID1_MASK) >> 
NB_VID1_SHIFT;
+-      u32 i;
+-      for (i = nbPState; i < NM_PS_REG; i++) {
+-         msr_t msr =  rdmsr(PS_REG_BASE + i);
+-         if (msr.hi &  PS_EN_MASK ) {
+-            msr.hi |= NB_DID_M_ON;
+-            msr.lo &= NB_VID_MASK_OFF;
+-          msr.lo |= ( nbVid1 << NB_VID_POS);
+-          wrmsr(PS_REG_BASE + i, msr);
+-       }
+-      }
+-    }
+-  }
++      uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
++      if (cpuRev & AMD_FAM10_C3) {
++              u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK);
++              if ( nbPState){
++                      u32 nbVid1 = (pci_read_config32(dev, 0x1F4) & 
NB_VID1_MASK) >> NB_VID1_SHIFT;
++                      u32 i;
++                      for (i = nbPState; i < NM_PS_REG; i++) {
++                              msr_t msr =  rdmsr(PS_REG_BASE + i);
++                              if (msr.hi &  PS_EN_MASK ) {
++                              msr.hi |= NB_DID_M_ON;
++                              msr.lo &= NB_VID_MASK_OFF;
++                              msr.lo |= ( nbVid1 << NB_VID_POS);
++                              wrmsr(PS_REG_BASE + i, msr);
++                              }
++                      }
++              }
++      }
+ }
+ 
+-static u8 setPStateMaxVal( device_t dev ) {
+-      u8 i,maxpstate=0;
+-      for (i = 0; i < NM_PS_REG; i++) {
+-         msr_t msr =  rdmsr(PS_REG_BASE + i);
+-         if (msr.hi & PS_IDD_VALUE_MASK) {
+-         msr.hi |= PS_EN_MASK ;
+-           wrmsr(PS_REG_BASE + i, msr);
+-       }
+-         if (msr.hi & PS_EN_MASK) {
+-         maxpstate = i;
+-       }
+-      }
+-      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
+-      u32 reg = pci_read_config32(dev, CPTC2);
+-      reg &= PS_MAX_VAL_MASK;
+-      reg |= (maxpstate << PS_MAX_VAL_POS);
+-      pci_write_config32(dev, CPTC2,reg);
+-      return maxpstate;
++static u8 setPStateMaxVal(device_t dev) {
++      u8 i, maxpstate=0;
++      for (i = 0; i < NM_PS_REG; i++) {
++              msr_t msr = rdmsr(PS_REG_BASE + i);
++              if (msr.hi & PS_IDD_VALUE_MASK) {
++                      msr.hi |= PS_EN_MASK ;
++                      wrmsr(PS_REG_BASE + i, msr);
++              }
++              if (msr.hi & PS_EN_MASK) {
++                      maxpstate = i;
++              }
++      }
++      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
++      u32 reg = pci_read_config32(dev, CPTC2);
++      reg &= PS_MAX_VAL_MASK;
++      reg |= (maxpstate << PS_MAX_VAL_POS);
++      pci_write_config32(dev, CPTC2,reg);
++      return maxpstate;
+ }
+ 
+ static void dualPlaneOnly(  device_t dev ) {
+-  // BKDG 2.4.2.7
+-
+-  uint64_t cpuRev =  mctGetLogicalCPUID(0xFF);
+-  if ((mctGetProcessorPackageType() ==  AMD_PKGTYPE_AM3_2r2)
+-      && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no 
constant for E
+-    if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
+-       && (pci_read_config32(dev, 0xA0) & PVI_MODE) ){
+-      if (cpuid_edx(0x80000007) & CPB_MASK) {
+-          // revision E only, but E is apparently not supported yet, 
therefore untested
+-         msr_t minPstate = rdmsr(0xC0010065);
+-         wrmsr(0xC0010065, rdmsr(0xC0010068) );
+-         wrmsr(0xC0010068,minPstate);
+-      } else {
+-       msr_t msr;
+-         msr.lo=0; msr.hi=0;
+-         wrmsr(0xC0010064, rdmsr(0xC0010068) );
+-         wrmsr(0xC0010068, msr );
+-      }
+-
+-      //FIXME: CPTC2 and HTC_REG should get max per node, not per core ?
+-      u8 maxpstate = setPStateMaxVal(dev);
+-
+-      u32 reg = pci_read_config32(dev, HTC_REG);
+-      reg &= HTC_PS_LMT_MASK;
+-      reg |= (maxpstate << PS_LIMIT_POS);
+-      pci_write_config32(dev, HTC_REG,reg);
+-
+-    }
+-  }
++      // BKDG 2.4.2.7
++
++      uint64_t cpuRev = mctGetLogicalCPUID(0xFF);
++      if ((mctGetProcessorPackageType() == AMD_PKGTYPE_AM3_2r2)
++              && (cpuRev & (AMD_DR_Cx | AMD_DR_Ex))) {
++              if ((pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK)
++                      && (pci_read_config32(dev, 0xA0) & PVI_MODE)) {
++                      if (cpuid_edx(0x80000007) & CPB_MASK) {
++                              // revision E only, but E is apparently not 
supported yet, therefore untested
++                              msr_t minPstate = rdmsr(0xC0010065);
++                              wrmsr(0xC0010065, rdmsr(0xC0010068));
++                              wrmsr(0xC0010068, minPstate);
++                      } else {
++                              msr_t msr;
++                              msr.lo=0; msr.hi=0;
++                              wrmsr(0xC0010064, rdmsr(0xC0010068) );
++                              wrmsr(0xC0010068, msr);
++                      }
++
++                      //FIXME: CPTC2 and HTC_REG should get max per node, not 
per core ?
++                      u8 maxpstate = setPStateMaxVal(dev);
++
++                      u32 reg = pci_read_config32(dev, HTC_REG);
++                      reg &= HTC_PS_LMT_MASK;
++                      reg |= (maxpstate << PS_LIMIT_POS);
++                      pci_write_config32(dev, HTC_REG,reg);
++              }
++      }
+ }
+ 
+ static int vidTo100uV(u8 vid)
+-{// returns voltage corresponding to vid in tenths of mV, i.e. hundreds of uV
+- // BKDG #31116 rev 3.48 2.4.1.6
+-  int voltage;
+-  if (vid >= 0x7c) {
+-    voltage = 0;
+-  } else {
+-    voltage = (15500 - (125*vid));
+-  }
+-  return voltage;
++{
++      // returns voltage corresponding to vid in tenths of mV, i.e. hundreds 
of uV
++      // BKDG #31116 rev 3.48 2.4.1.6
++      int voltage;
++      if (vid >= 0x7c) {
++              voltage = 0;
++      } else {
++              voltage = (15500 - (125*vid));
++      }
++      return voltage;
+ }
+ 
+ static void setVSRamp(device_t dev) {
+@@ -348,7 +348,7 @@ static void recalculateVsSlamTimeSettingOnCorePre(device_t 
dev)
+       }
+ 
+       /* Get AltVID */
+-      dtemp = pci_read_config32(dev, 0xDC);
++      dtemp = pci_read_config32(dev, 0xdc);
+       bValue = (u8) (dtemp & BIT_MASK_7);
+ 
+       /* Use the VID with the lowest voltage (higher VID) */
+@@ -512,15 +512,15 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 
cpuRev) {
+            values (min latency) */
+       u32 nbPstate = pci_read_config32(dev,0x1f0) & NB_PSTATE_MASK;
+         u8 nbSynPtrAdj;
+-      if ((cpuRev & (AMD_DR_Bx|AMD_DA_Cx) )
+-          || ( (cpuRev & AMD_RB_C3) && (nbPstate!=0)))  {
+-        nbSynPtrAdj = 5;
++      if ((cpuRev & (AMD_DR_Bx | AMD_DA_Cx | AMD_FAM15_ALL) )
++              || ((cpuRev & AMD_RB_C3) && (nbPstate != 0))) {
++              nbSynPtrAdj = 5;
+       } else {
+-          nbSynPtrAdj = 6;
++              nbSynPtrAdj = 6;
+       }
+ 
+-      u32 dword = pci_read_config32(dev, 0xDc);
+-        dword &= ~ NB_SYN_PTR_ADJ_MASK;
++      u32 dword = pci_read_config32(dev, 0xdc);
++        dword &= ~NB_SYN_PTR_ADJ_MASK;
+       dword |= nbSynPtrAdj << NB_SYN_PTR_ADJ_POS;
+         /* NbsynPtrAdj set to 5 or 6 per BKDG (needs reset) */
+       pci_write_config32(dev, 0xdc, dword);
+@@ -552,7 +552,7 @@ static void config_acpi_pwr_state_ctrl_regs(device_t dev, 
u32 cpuRev, u8 procPkg
+                       }
+               } else { // rev C or later
+                       // same doubt as cache scrubbing: ok to check current 
state ?
+-                      dword = pci_read_config32(dev, 0xDC);
++                      dword = pci_read_config32(dev, 0xdc);
+                       u32 cacheFlushOnHalt = dword & (7 << 16);
+                       if (!cacheFlushOnHalt) {
+                               c1 = 0x80;
+@@ -623,11 +623,11 @@ static void prep_fid_change(void)
+               printk(BIOS_DEBUG, "  F3x80: %08x\n", dword);
+               dword = pci_read_config32(dev, 0x84);
+               printk(BIOS_DEBUG, "  F3x84: %08x\n", dword);
+-              dword = pci_read_config32(dev, 0xD4);
++              dword = pci_read_config32(dev, 0xd4);
+               printk(BIOS_DEBUG, "  F3xD4: %08x\n", dword);
+-              dword = pci_read_config32(dev, 0xD8);
++              dword = pci_read_config32(dev, 0xd8);
+               printk(BIOS_DEBUG, "  F3xD8: %08x\n", dword);
+-              dword = pci_read_config32(dev, 0xDC);
++              dword = pci_read_config32(dev, 0xdc);
+               printk(BIOS_DEBUG, "  F3xDC: %08x\n", dword);
+       }
+ }
+@@ -756,7 +756,7 @@ static void fixPsNbVidBeforeWR(u32 newNbVid, u32 coreid, 
u32 dev, u8 pviMode)
+          * synchronization between cores and we don't think
+          * PstatMaxVal is going to be 0 on cold reset anyway ?
+        */
+-        if ( ! (pci_read_config32(dev, 0xDC) & (~ PS_MAX_VAL_MASK)) ) {
++        if (!(pci_read_config32(dev, 0xdc) & (~PS_MAX_VAL_MASK))) {
+          printk(BIOS_ERR,"F3xDC[PstateMaxVal] is zero. Northbridge voltage 
setting will fail. fixPsNbVidBeforeWR in fidvid.c needs fixing. See AMD # 31116 
rev 3.48 BKDG 2.4.2.9.1 \n");
+       };
+ 
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index aced850..061bba2 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -30,6 +30,14 @@
+ #include <northbridge/amd/amdfam10/raminit_amdmct.c>
+ #include <reset.h>
+ 
++#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700)
++#include <southbridge/amd/sb700/sb700.h>
++#endif
++
++#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
++#include <southbridge/amd/sb800/sb800.h>
++#endif
++
+ #if IS_ENABLED(CONFIG_SET_FIDVID)
+ static void prep_fid_change(void);
+ static void init_fidvid_stage2(u32 apicid, u32 nodeid);
+@@ -874,6 +882,7 @@ void cpuSetAMDMSR(uint8_t node_id)
+       u8 i;
+       u32 platform;
+       uint64_t revision;
++      uint8_t enable_c_states;
+ 
+       printk(BIOS_DEBUG, "cpuSetAMDMSR ");
+ 
+@@ -936,6 +945,44 @@ void cpuSetAMDMSR(uint8_t node_id)
+               wrmsr(FP_CFG, msr);
+       }
+ 
++#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || 
IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
++      uint8_t nvram;
++
++      if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
++              /* Set up message triggered C1E */
++              msr = rdmsr(0xc0010055);
++              msr.lo &= ~0xffff;              /* IOMsgAddr = ACPI_PM_EVT_BLK 
*/
++              msr.lo |= ACPI_PM_EVT_BLK & 0xffff;
++              msr.lo |= (0x1 << 29);          /* BmStsClrOnHltEn = 1 */
++              if (revision & AMD_DR_GT_D0) {
++                      msr.lo &= ~(0x1 << 28); /* C1eOnCmpHalt = 0 */
++                      msr.lo &= ~(0x1 << 27); /* SmiOnCmpHalt = 0 */
++              }
++              wrmsr(0xc0010055, msr);
++
++              msr = rdmsr(0xc0010015);
++              msr.lo |= (0x1 << 12);          /* HltXSpCycEn = 1 */
++              wrmsr(0xc0010015, msr);
++      }
++
++      if (revision & (AMD_DR_Ex | AMD_FAM15_ALL)) {
++              enable_c_states = 0;
++              if (IS_ENABLED(CONFIG_HAVE_ACPI_TABLES))
++                      if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
++                              enable_c_states = !!nvram;
++
++              if (enable_c_states) {
++                      /* Set up the C-state base address */
++                      msr_t c_state_addr_msr;
++                      c_state_addr_msr = rdmsr(0xc0010073);
++                      c_state_addr_msr.lo = ACPI_CPU_P_LVL2;  /* CstateAddr = 
ACPI_CPU_P_LVL2 */
++                      wrmsr(0xc0010073, c_state_addr_msr);
++              }
++      }
++#else
++      enable_c_states = 0;
++#endif
++
+       printk(BIOS_DEBUG, " done\n");
+ }
+ 
+@@ -950,6 +997,7 @@ static void cpuSetAMDPCI(u8 node)
+       u32 platform;
+       u32 val;
+       u8 offset;
++      uint32_t dword;
+       uint64_t revision;
+ 
+       printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node);
+@@ -1008,6 +1056,39 @@ static void cpuSetAMDPCI(u8 node)
+          if (revision & (AMD_DR_B2 | AMD_DR_B3))
+          dctPhyDiag(); */
+ 
++      if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
++              /* Set up message triggered C1E */
++              dword = pci_read_config32(NODE_PCI(node, 3), 0xd4);
++              dword &= ~(0x1 << 14);                  /* 
CacheFlushImmOnAllHalt = !is_fam15h() */
++              dword |= (is_fam15h()?0:1) << 14;
++              pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0xdc);
++              dword |= 0x1 << 26;                     /* IgnCpuPrbEn = 1 */
++              dword &= ~(0x7f << 19);                 /* CacheFlushOnHaltTmr 
= 0x28 */
++              dword |= 0x28 << 19;
++              dword |= 0x7 << 16;                     /* CacheFlushOnHaltCtl 
= 0x7 */
++              pci_write_config32(NODE_PCI(node, 3), 0xdc, dword);
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0xa0);
++              dword |= 0x1 << 10;                     /* IdleExitEn = 1 */
++              pci_write_config32(NODE_PCI(node, 3), 0xa0, dword);
++
++              if (revision & AMD_DR_GT_D0) {
++                      dword = pci_read_config32(NODE_PCI(node, 3), 0x188);
++                      dword |= 0x1 << 4;                      /* 
EnStpGntOnFlushMaskWakeup = 1 */
++                      pci_write_config32(NODE_PCI(node, 3), 0x188, dword);
++              } else {
++                      dword = pci_read_config32(NODE_PCI(node, 4), 0x128);
++                      dword &= ~(0x1 << 31);                  /* CstateMsgDis 
= 0 */
++                      pci_write_config32(NODE_PCI(node, 4), 0x128, dword);
++              }
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0xd4);
++              dword |= 0x1 << 13;                     /* MTC1eEn = 1 */
++              pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
++      }
++
+       printk(BIOS_DEBUG, " done\n");
+ }
+ 
+diff --git a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c 
b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
+index 84e5514..028ae3f 100644
+--- a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
++++ b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c
+@@ -21,6 +21,7 @@
+ 
+ #include <console/console.h>
+ #include <stdint.h>
++#include <option.h>
+ #include <cpu/x86/msr.h>
+ #include <arch/acpigen.h>
+ #include <cpu/amd/powernow.h>
+@@ -34,21 +35,29 @@
+ #include <northbridge/amd/amdmct/mct/mct.h>
+ #include <northbridge/amd/amdmct/amddefs.h>
+ 
++static inline uint8_t is_fam15h(void)
++{
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      return fam15h;
++}
++
+ static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 
*pstate_power,
+                               u32 *pstate_latency, u32 *pstate_control,
+                               u32 *pstate_status, int coreID,
+-                              u32 pcontrol_blk, u8 plen, u8 onlyBSP,
+                               uint8_t single_link)
+ {
+       int i;
+       struct cpuid_result cpuid1;
+ 
+-      if ((onlyBSP) && (coreID != 0)) {
+-          plen = 0;
+-          pcontrol_blk = 0;
+-      }
+-
+-      acpigen_write_processor(coreID, pcontrol_blk, plen);
+       acpigen_write_empty_PCT();
+       acpigen_write_name("_PSS");
+ 
+@@ -92,9 +101,62 @@ static void write_pstates_for_core(u8 pstate_num, u16 
*pstate_feq, u32 *pstate_p
+               if (cpu)
+                       acpigen_write_PSD_package(cpu->path.apic.apic_id, 1, 
SW_ANY);
+       }
++}
+ 
+-      /* patch the whole Processor token length */
+-      acpigen_pop_len();
++static void write_cstates_for_core(int coreID)
++{
++      /* Generate C state entries */
++      uint8_t cstate_count = 1;
++      acpi_cstate_t cstate;
++
++      if (is_fam15h()) {
++              cstate.ctype = 2;
++              cstate.latency = 100;
++              cstate.power = 0;
++              cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO;
++              cstate.resource.bit_width = 8;
++              cstate.resource.bit_offset = 0;
++              cstate.resource.addrl = rdmsr(0xc0010073).lo + 1;
++              cstate.resource.addrh = 0;
++              cstate.resource.resv = 1;
++      } else {
++              cstate.ctype = 2;
++              cstate.latency = 75;
++              cstate.power = 0;
++              cstate.resource.space_id = ACPI_ADDRESS_SPACE_IO;
++              cstate.resource.bit_width = 8;
++              cstate.resource.bit_offset = 0;
++              cstate.resource.addrl = rdmsr(0xc0010073).lo;
++              cstate.resource.addrh = 0;
++              cstate.resource.resv = 1;
++      }
++
++      acpigen_write_CST_package(&cstate, cstate_count);
++
++      /* Find the local APIC ID for the specified core ID */
++      if (is_fam15h()) {
++              struct device* cpu;
++              int cpu_index = 0;
++              for (cpu = all_devices; cpu; cpu = cpu->next) {
++                      if ((cpu->path.type != DEVICE_PATH_APIC) ||
++                              (cpu->bus->dev->path.type != 
DEVICE_PATH_CPU_CLUSTER))
++                              continue;
++                      if (!cpu->enabled)
++                              continue;
++                      if (cpu_index == coreID)
++                              break;
++                      cpu_index++;
++              }
++
++              if (cpu) {
++                      /* TODO
++                       * Detect dual core status and skip CSD generation if 
dual core is disabled
++                       */
++
++                      /* Generate C state dependency entries */
++                      acpigen_write_CSD_package((cpu->path.apic.apic_id >> 1) 
& 0x7f, 2, CSD_HW_ALL, 0);
++              }
++      }
+ }
+ 
+ /*
+@@ -125,6 +187,15 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+       u8 index;
+       msr_t msr;
+ 
++      uint8_t nvram;
++      uint8_t enable_c_states;
++
++      enable_c_states = 0;
++#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
++      if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
++              enable_c_states = !!nvram;
++#endif
++
+       /* Get the Processor Brand String using cpuid(0x8000000x) command 
x=2,3,4 */
+       cpuid1 = cpuid(0x80000002);
+       v = (u32 *) processor_brand;
+@@ -200,6 +271,10 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+               return;
+       }
+ 
++      if (fam15h)
++              /* Set P_LVL2 P_BLK entry */
++              *(((uint8_t *)pcontrol_blk) + 0x04) = (rdmsr(0xc0010073).lo + 
1) & 0xff;
++
+       uint8_t pviModeFlag;
+       uint8_t Pstate_max;
+       uint8_t cpufid;
+@@ -318,18 +393,56 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 
onlyBSP)
+                           Pstate_latency[index]);
+       }
+ 
++      /* Enter processor block scope */
+       char pscope[] = "\\_PR";
+-
+       acpigen_write_scope(pscope);
++
+       for (index = 0; index < total_core_count; index++) {
+               /* Determine if this is a single-link processor */
+               node_index = 0x18 + (index / cores_per_node);
+               dtemp = pci_read_config32(dev_find_slot(0, 
PCI_DEVFN(node_index, 0)), 0x80);
+               single_link = !!(((dtemp & 0xff00) >> 8) == 0);
+ 
++              /* Enter processor core scope */
++              uint8_t plen_cur = plen;
++              uint32_t pcontrol_blk_cur = pcontrol_blk;
++              if ((onlyBSP) && (index != 0)) {
++                      plen_cur = 0;
++                      pcontrol_blk_cur = 0;
++              }
++              acpigen_write_processor(index, pcontrol_blk_cur, plen_cur);
++
++              /* Write P-state status and dependency objects */
+               write_pstates_for_core(Pstate_num, Pstate_feq, Pstate_power,
+                               Pstate_latency, Pstate_control, Pstate_status,
+-                              index, pcontrol_blk, plen, onlyBSP, 
single_link);
++                              index, single_link);
++
++              /* Write C-state status and dependency objects */
++              if (fam15h && enable_c_states)
++                      write_cstates_for_core(index);
++
++              /* Exit processor core scope */
++              acpigen_pop_len();
+       }
++
++      /* Exit processor block scope */
+       acpigen_pop_len();
+ }
++
++void amd_powernow_update_fadt(acpi_fadt_t * fadt)
++{
++      if (is_fam15h()) {
++              fadt->p_lvl2_lat = 101;         /* NOTE: While the BKDG states 
this should
++                                               * be set to 100, there is no 
way to meet
++                                               * the other FADT requirements. 
 I suspect
++                                               * there is an error in the 
BKDG for ACPI
++                                               * 1.x support; disable all 
FADT-based C
++                                               * states > 2... */
++              fadt->p_lvl3_lat = 1001;
++              fadt->flags |= 0x1 << 2;        /* FLAGS.PROC_C1 = 1 */
++              fadt->flags |= 0x1 << 3;        /* FLAGS.P_LVL2_UP = 1 */
++      } else {
++              fadt->cst_cnt = 0;
++      }
++      fadt->pstate_cnt = 0;
++}
+diff --git a/src/include/cpu/amd/powernow.h b/src/include/cpu/amd/powernow.h
+index 85356bd..07817d9 100644
+--- a/src/include/cpu/amd/powernow.h
++++ b/src/include/cpu/amd/powernow.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2009 Rudolf Marek <address@hidden>
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -21,5 +22,6 @@
+ #define POWERNOW_H
+ 
+ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP);
++void amd_powernow_update_fadt(acpi_fadt_t * fadt);
+ 
+ #endif
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index bfd2020..e3eb4fe 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -14,6 +14,7 @@ ecc_scrub_rate = 1.28us
+ interleave_chip_selects = Enable
+ interleave_nodes = Disable
+ interleave_memory_channels = Enable
++cpu_c_states = Enable
+ cpu_cc6_state = Enable
+ ieee1394 = Enable
+ power_on_after_fail = On
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 630219e..7f9f661 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -43,8 +43,9 @@ entries
+ 458          4       e       11       hypertransport_speed_limit
+ 462          2       e       12       minimum_memory_voltage
+ 464          1       e       2        compute_unit_siblings
+-465          1       e       1        cpu_cc6_state
+-466          1       r       0        allow_spd_nvram_cache_restore
++465          1       e       1        cpu_c_states
++466          1       e       1        cpu_cc6_state
++467          1       r       0        allow_spd_nvram_cache_restore
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+diff --git a/src/northbridge/amd/amdfam10/link_control.c 
b/src/northbridge/amd/amdfam10/link_control.c
+index 1091ef4..7fa9f12 100644
+--- a/src/northbridge/amd/amdfam10/link_control.c
++++ b/src/northbridge/amd/amdfam10/link_control.c
+@@ -49,15 +49,94 @@ static inline uint8_t is_fam15h(void)
+ 
+ static void nb_control_init(struct device *dev)
+ {
++      uint8_t enable_c_states;
++      uint8_t enable_cc6;
+       uint32_t dword;
+ 
+       printk(BIOS_DEBUG, "NB: Function 4 Link Control.. ");
+ 
++      /* Configure L3 Power Control */
++      dword = pci_read_config32(dev, 0x1c4);
++      dword |= (0x1 << 8);                    /* L3PwrSavEn = 1 */
++      pci_write_config32(dev, 0x1c4, dword);
++
+       if (is_fam15h()) {
++              /* Configure L3 Control 2 */
++              dword = pci_read_config32(dev, 0x1cc);
++              dword &= ~(0x7 << 6);                   /* 
ImplRdProjDelayThresh = 0x2 */
++              dword |= (0x2 << 6);
++              pci_write_config32(dev, 0x1cc, dword);
++
++              /* Configure TDP Accumulator Divisor Control */
++              dword = pci_read_config32(dev, 0x104);
++              dword &= ~(0xfff << 2);                 /* TdpAccDivRate = 0xc8 
*/
++              dword |= (0xc8 << 2);
++              dword &= ~0x3;                          /* TdpAccDivVal = 0x1 */
++              dword |= 0x1;
++              pci_write_config32(dev, 0x104, dword);
++
++              /* Configure Sample and Residency Timers */
++              dword = pci_read_config32(dev, 0x110);
++              dword &= ~0xfff;                        /* CSampleTimer = 0x1 */
++              dword |= 0x1;
++              pci_write_config32(dev, 0x110, dword);
++
++              /* Configure APM TDP Control */
++              dword = pci_read_config32(dev, 0x16c);
++              dword |= (0x1 << 4);                    /* ApmTdpLimitIntEn = 1 
*/
++              pci_write_config32(dev, 0x16c, dword);
++
+               /* Enable APM */
+               dword = pci_read_config32(dev, 0x15c);
+               dword |= (0x1 << 7);                    /* ApmMasterEn = 1 */
+               pci_write_config32(dev, 0x15c, dword);
++
++              enable_c_states = 0;
++              enable_cc6 = 0;
++#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
++              uint8_t nvram;
++
++              if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
++                      enable_c_states = !!nvram;
++
++              if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
++                      enable_cc6 = !!nvram;
++#endif
++
++              if (enable_c_states) {
++                      /* Configure C-state Control 1 */
++                      dword = pci_read_config32(dev, 0x118);
++                      dword |= (0x1 << 24);           /* PwrGateEnCstAct1 = 1 
*/
++                      dword &= ~(0x7 << 21);          /* ClkDivisorCstAct1 = 
0x0 */
++                      dword &= ~(0x3 << 18);          /* 
CacheFlushTmrSelCstAct1 = 0x1 */
++                      dword |= (0x1 << 18);
++                      dword |= (0x1 << 17);           /* CacheFlushEnCstAct1 
= 1 */
++                      dword |= (0x1 << 16);           /* CpuPrbEnCstAct1 = 1 
*/
++                      dword &= ~(0x1 << 8);           /* PwrGateEnCstAct0 = 0 
*/
++                      dword &= ~(0x7 << 5);           /* ClkDivisorCstAct0 = 
0x0 */
++                      dword &= ~(0x3 << 2);           /* 
CacheFlushTmrSelCstAct0 = 0x2 */
++                      dword |= (0x2 << 2);
++                      dword |= (0x1 << 1);            /* CacheFlushEnCstAct0 
= 1 */
++                      dword |= 0x1;                   /* CpuPrbEnCstAct0 = 1 
*/
++                      pci_write_config32(dev, 0x118, dword);
++
++                      /* Configure C-state Control 2 */
++                      dword = pci_read_config32(dev, 0x11c);
++                      dword &= ~(0x1 << 8);           /* PwrGateEnCstAct2 = 0 
*/
++                      dword &= ~(0x7 << 5);           /* ClkDivisorCstAct2 = 
0x0 */
++                      dword &= ~(0x3 << 2);           /* 
CacheFlushTmrSelCstAct0 = 0x0 */
++                      dword &= ~(0x1 << 1);           /* CacheFlushEnCstAct0 
= 0 */
++                      dword &= ~(0x1);                /* CpuPrbEnCstAct0 = 0 
*/
++                      pci_write_config32(dev, 0x11c, dword);
++
++                      /* Configure C-state Policy Control 1 */
++                      dword = pci_read_config32(dev, 0x128);
++                      dword &= ~(0x7f << 5);          /* CacheFlushTmr = 0x28 
*/
++                      dword |= (0x28 << 5);
++                      dword &= ~0x1;                  /* CoreCstateMode = 
!enable_cc6 */
++                      dword |= ((enable_cc6)?0:1);
++                      pci_write_config32(dev, 0x128, dword);
++              }
+       }
+ 
+       printk(BIOS_DEBUG, "done.\n");
+@@ -83,4 +162,4 @@ static const struct pci_driver mcf4_driver_fam15 
__pci_driver = {
+       .ops    = &mcf4_ops,
+       .vendor = PCI_VENDOR_ID_AMD,
+       .device = 0x1604,
+-};
+\ No newline at end of file
++};
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index e5612fa..9fe0ccb 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -770,53 +770,49 @@ static void amdfam10_domain_read_resources(device_t dev)
+                       uint8_t num_nodes;
+ 
+                       /* Find highest DRAM range (DramLimitAddr) */
++                      num_nodes = 0;
+                       max_node = 0;
+                       max_range = -1;
+                       interleaved = 0;
+                       max_range_limit = 0;
+-                      for (range = 0; range < 8; range++) {
+-                              dword = f1_read_config32(0x40 + (range * 0x8));
+-                              if (!(dword & 0x3))
+-                                      continue;
+-
+-                              if ((dword >> 8) & 0x7)
+-                                      interleaved = 1;
+-
+-                              dword = f1_read_config32(0x44 + (range * 0x8));
+-                              dword2 = f1_read_config32(0x144 + (range * 
0x8));
+-                              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 
24;
+-                              qword |= (((uint64_t)dword2) & 0xff) << 40;
+-
+-                              if (qword > max_range_limit) {
+-                                      max_range = range;
+-                                      max_range_limit = qword;
+-                                      max_node = dword & 0x7;
+-                              }
+-                      }
+-
+-                      num_nodes = 0;
+                       device_t node_dev;
+                       for (node = 0; node < FX_DEVS; node++) {
+                               node_dev = get_node_pci(node, 0);
+                               /* Test for node presence */
+-                              if ((node_dev) && (pci_read_config32(node_dev, 
PCI_VENDOR_ID) != 0xffffffff))
+-                                      num_nodes++;
++                              if ((!node_dev) || (pci_read_config32(node_dev, 
PCI_VENDOR_ID) == 0xffffffff))
++                                      continue;
++
++                              num_nodes++;
++                              for (range = 0; range < 8; range++) {
++                                      dword = 
pci_read_config32(get_node_pci(node, 1), 0x40 + (range * 0x8));
++                                      if (!(dword & 0x3))
++                                              continue;
++
++                                      if ((dword >> 8) & 0x7)
++                                              interleaved = 1;
++
++                                      dword = 
pci_read_config32(get_node_pci(node, 1), 0x44 + (range * 0x8));
++                                      dword2 = 
pci_read_config32(get_node_pci(node, 1), 0x144 + (range * 0x8));
++                                      qword = 0xffffff;
++                                      qword |= ((((uint64_t)dword) >> 16) & 
0xffff) << 24;
++                                      qword |= (((uint64_t)dword2) & 0xff) << 
40;
++
++                                      if (qword > max_range_limit) {
++                                              max_range = range;
++                                              max_range_limit = qword;
++                                              max_node = dword & 0x7;
++                                      }
++                              }
+                       }
+ 
+-                      /* Calculate CC6 sotrage area size */
++                      /* Calculate CC6 storage area size */
+                       if (interleaved)
+                               qword = (0x1000000 * num_nodes);
+                       else
+                               qword = 0x1000000;
+ 
+                       /* Reserve the CC6 save segment */
+-                      reserved_ram_resource(dev, 8, max_range_limit >> 10, 
qword >> 10);
+-
+-                      /* Set up the C-state base address */
+-                      msr_t c_state_addr_msr;
+-                      c_state_addr_msr = rdmsr(0xc0010073);
+-                      c_state_addr_msr.lo = 0xe0e0;           /* CstateAddr = 
0xe0e0 */
+-                      wrmsr(0xc0010073, c_state_addr_msr);
++                      reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 
10, qword >> 10);
+               }
+       }
+ }
+diff --git a/src/northbridge/amd/amdht/AsPsDefs.h 
b/src/northbridge/amd/amdht/AsPsDefs.h
+index caeb9b4..7f29dd1 100644
+--- a/src/northbridge/amd/amdht/AsPsDefs.h
++++ b/src/northbridge/amd/amdht/AsPsDefs.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -254,7 +255,7 @@
+ #define DUAL_PLANE_NB_VID_SHIFT 17/* for CPU rev <= C */
+ 
+ 
+-#define NM_PS_REG 5                   /* number of P-state MSR registers */
++#define NM_PS_REG (is_fam15h()?8:5)   /* number of P-state MSR registers */
+ 
+ /* sFidVidInit.outFlags defines */
+ #define PWR_CK_OK 0                   /* System board check OK */
+diff --git a/src/northbridge/amd/amdmct/amddefs.h 
b/src/northbridge/amd/amdmct/amddefs.h
+index 20a77d3..7aa4698 100644
+--- a/src/northbridge/amd/amdmct/amddefs.h
++++ b/src/northbridge/amd/amdmct/amddefs.h
+@@ -53,32 +53,34 @@
+ /*
+  * Groups - Create as many as you wish, from the above public values
+  */
+-#define       AMD_NPT_F2      (AMD_NPT_F2C | AMD_NPT_F2D | AMD_NPT_F2E | 
AMD_NPT_F2G | AMD_NPT_F2J | AMD_NPT_F2K)
+-#define       AMD_NPT_F3      (AMD_NPT_F3L)
+-#define       AMD_NPT_Fx      (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2 | 
AMD_NPT_F3)
+-#define       AMD_NPT_Gx      (AMD_NPT_G0A | AMD_NPT_G1B)
+-#define       AMD_NPT_ALL     (AMD_NPT_Fx | AMD_NPT_Gx)
+-#define       AMD_FINEDELAY   (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2)
+-#define       AMD_GT_F0       (AMD_NPT_ALL AND NOT AMD_NPT_F0)
+-#define       AMD_DR_Ax       (AMD_DR_A0A + AMD_DR_A1B + AMD_DR_A2)
+-#define       AMD_DR_Bx       (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_B3 
| AMD_DR_BA)
+-#define       AMD_DR_LT_B2    (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)
+-#define       AMD_DR_LT_B3    (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_BA)
+-#define       AMD_DR_GT_B0    (AMD_DR_ALL & ~(AMD_DR_B0))
+-#define       AMD_DR_GT_Bx    (AMD_DR_ALL & ~(AMD_DR_Ax | AMD_DR_Bx))
+-#define       AMD_DR_ALL      (AMD_DR_Bx)
+-#define       AMD_FAM10_ALL   (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | AMD_DA_C3 
| AMD_DA_C2 | AMD_RB_C3 | AMD_HY_D1 | AMD_PH_E0)
+-#define AMD_FAM10_LT_D  (AMD_FAM10_ALL & ~(AMD_HY_D0))
+-#define       AMD_FAM10_GT_B0 (AMD_FAM10_ALL & ~(AMD_DR_B0))
+-#define AMD_FAM10_REV_D       (AMD_HY_D0 | AMD_HY_D1)
+-#define       AMD_DA_Cx       (AMD_DA_C2 | AMD_DA_C3)
+-#define       AMD_DR_Cx       (AMD_RB_C2 | AMD_RB_C3 | AMD_DA_Cx)
+-#define       AMD_FAM10_C3       (AMD_RB_C3 | AMD_DA_C3)
+-#define       AMD_DR_Dx       (AMD_HY_D0 | AMD_HY_D1)
+-#define       AMD_DRBH_Cx     (AMD_DR_Cx | AMD_HY_D0 )
+-#define       AMD_DRBA23_RBC2 (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | AMD_RB_C2 )
++#define       AMD_NPT_F2              (AMD_NPT_F2C | AMD_NPT_F2D | 
AMD_NPT_F2E | AMD_NPT_F2G | AMD_NPT_F2J | AMD_NPT_F2K)
++#define       AMD_NPT_F3              (AMD_NPT_F3L)
++#define       AMD_NPT_Fx              (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2 | 
AMD_NPT_F3)
++#define       AMD_NPT_Gx              (AMD_NPT_G0A | AMD_NPT_G1B)
++#define       AMD_NPT_ALL             (AMD_NPT_Fx | AMD_NPT_Gx)
++#define       AMD_FINEDELAY           (AMD_NPT_F0 | AMD_NPT_F1 | AMD_NPT_F2)
++#define       AMD_GT_F0               (AMD_NPT_ALL AND NOT AMD_NPT_F0)
++#define       AMD_DR_Ax               (AMD_DR_A0A + AMD_DR_A1B + AMD_DR_A2)
++#define       AMD_DR_Bx               (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | 
AMD_DR_B3 | AMD_DR_BA)
++#define       AMD_DR_Cx               (AMD_RB_C2 | AMD_RB_C3 | AMD_DA_Cx)
++#define       AMD_DR_Dx               (AMD_HY_D0 | AMD_HY_D1)
++#define       AMD_DR_Ex               (AMD_PH_E0)
++#define       AMD_DR_LT_B2            (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_BA)
++#define       AMD_DR_LT_B3            (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | 
AMD_DR_BA)
++#define       AMD_DR_GT_B0            (AMD_DR_ALL & ~(AMD_DR_B0))
++#define       AMD_DR_GT_Bx            (AMD_DR_ALL & ~(AMD_DR_Ax | AMD_DR_Bx))
++#define       AMD_DR_GT_D0            ((AMD_DR_Dx & ~(AMD_HY_D0)) | AMD_DR_Ex)
++#define       AMD_DR_ALL              (AMD_DR_Bx)
++#define       AMD_FAM10_ALL           (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | 
AMD_DA_C3 | AMD_DA_C2 | AMD_RB_C3 | AMD_HY_D1 | AMD_PH_E0)
++#define AMD_FAM10_LT_D        (AMD_FAM10_ALL & ~(AMD_HY_D0))
++#define       AMD_FAM10_GT_B0         (AMD_FAM10_ALL & ~(AMD_DR_B0))
++#define AMD_FAM10_REV_D               (AMD_HY_D0 | AMD_HY_D1)
++#define       AMD_DA_Cx               (AMD_DA_C2 | AMD_DA_C3)
++#define       AMD_FAM10_C3            (AMD_RB_C3 | AMD_DA_C3)
++#define       AMD_DRBH_Cx             (AMD_DR_Cx | AMD_HY_D0 )
++#define       AMD_DRBA23_RBC2         (AMD_DR_BA | AMD_DR_B2 | AMD_DR_B3 | 
AMD_RB_C2 )
+ #define       AMD_DR_DAC2_OR_C3       (AMD_DA_C2 | AMD_DA_C3 | AMD_RB_C3)
+-#define       AMD_FAM15_ALL   (AMD_OR_B2 | AMD_OR_C0)
++#define       AMD_FAM15_ALL           (AMD_OR_B2 | AMD_OR_C0)
+ 
+ /*
+  *  Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH 
CPUPLATFORMTYPE RETURN VALUE
+@@ -91,9 +93,9 @@
+ #define       AMD_PTYPE_MC    0x020   /* Multi Core (>2) */
+ #define       AMD_PTYPE_UMA   0x040   /* UMA required */
+ 
+-      /*
+-       * Groups - Create as many as you wish, from the above public values
+-       */
++/*
++ * Groups - Create as many as you wish, from the above public values
++ */
+ #define       AMD_PTYPE_ALL   0xFFFFFFFF      /* A mask for all */
+ 
+ 
+@@ -102,11 +104,11 @@
+  */
+ #define HTPHY_LINKTYPE_HT3            0x00000001
+ #define HTPHY_LINKTYPE_HT1            0x00000002
+-#define HTPHY_LINKTYPE_COHERENT       0x00000004
++#define HTPHY_LINKTYPE_COHERENT               0x00000004
+ #define HTPHY_LINKTYPE_NONCOHERENT    0x00000008
+ #define HTPHY_LINKTYPE_CONNECTED      (HTPHY_LINKTYPE_COHERENT | 
HTPHY_LINKTYPE_NONCOHERENT)
+ #define HTPHY_LINKTYPE_GANGED         0x00000010
+-#define HTPHY_LINKTYPE_UNGANGED       0x00000020
++#define HTPHY_LINKTYPE_UNGANGED               0x00000020
+ #define HTPHY_LINKTYPE_ALL            0x7FFFFFFF
+ 
+ 
+@@ -114,7 +116,7 @@
+  * CPU HT PHY REGISTERS, FIELDS, AND MASKS
+  */
+ #define HTPHY_OFFSET_MASK             0xE00001FF
+-#define HTPHY_WRITE_CMD               0x40000000
++#define HTPHY_WRITE_CMD                       0x40000000
+ #define HTPHY_IS_COMPLETE_MASK                0x80000000
+ #define HTPHY_DIRECT_MAP              0x20000000
+ #define HTPHY_DIRECT_OFFSET_MASK      0xE000FFFF
+@@ -162,4 +164,4 @@
+ #define AMD_PKGTYPE_S1gX 2
+ #define AMD_PKGTYPE_G34 3
+ #define AMD_PKGTYPE_ASB2 4
+-#define AMD_PKGTYPE_C32 5
++#define AMD_PKGTYPE_C32 5
+\ No newline at end of file
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 2798506..4044c36 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1197,6 +1197,7 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
+       int8_t max_range;
+       uint8_t max_node;
+       uint64_t max_range_limit;
++      uint8_t byte;
+       uint32_t dword;
+       uint32_t dword2;
+       uint64_t qword;
+@@ -1216,7 +1217,8 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
+ 
+               dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
+               dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
+-              qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
++              qword = 0xffffff;
++              qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24;
+               qword |= (((uint64_t)dword2) & 0xff) << 40;
+ 
+               if (qword > max_range_limit) {
+@@ -1226,26 +1228,35 @@ static void set_up_cc6_storage_fam15(struct 
MCTStatStruc *pMCTstat,
+               }
+       }
+ 
+-      if (pDCTstat->Node_ID == max_node) {
+-              if (max_range >= 0) {
+-                      if (interleaved)
+-                              /* Move upper limit down by 16M * the number of 
nodes */
+-                              max_range_limit -= (0x1000000 * num_nodes);
+-                      else
+-                              /* Move upper limit down by 16M */
+-                              max_range_limit -= 0x1000000;
+-
+-                      /* Store modified range */
+-                      dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 
0x8));
+-                      dword &= ~(0xffff << 16);               /* 
DramLimit[39:24] = max_range_limit[39:24] */
+-                      dword |= (max_range_limit >> 24) & 0xffff;
+-                      Set_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8), 
dword);
+-
+-                      dword = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 
0x8));
+-                      dword &= ~(0xffff << 16);               /* 
DramLimit[47:40] = max_range_limit[47:40] */
+-                      dword |= (max_range_limit >> 40) & 0xff;
+-                      Set_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8), 
dword);
+-              }
++      if (max_range >= 0) {
++              if (interleaved)
++                      /* Move upper limit down by 16M * the number of nodes */
++                      max_range_limit -= (0x1000000 * num_nodes);
++              else
++                      /* Move upper limit down by 16M */
++                      max_range_limit -= 0x1000000;
++
++              /* Disable the range */
++              dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
++              byte = dword & 0x3;
++              dword &= ~(0x3);
++              Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword);
++
++              /* Store modified range */
++              dword = Get_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8));
++              dword &= ~(0xffff << 16);               /* DramLimit[39:24] = 
max_range_limit[39:24] */
++              dword |= ((max_range_limit >> 24) & 0xffff) << 16;
++              Set_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8), dword);
++
++              dword = Get_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8));
++              dword &= ~0xff;                 /* DramLimit[47:40] = 
max_range_limit[47:40] */
++              dword |= (max_range_limit >> 40) & 0xff;
++              Set_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8), dword);
++
++              /* Reenable the range */
++              dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
++              dword |= byte;
++              Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword);
+       }
+ 
+       /* Determine save state destination node */
+@@ -1531,8 +1542,8 @@ restartinit:
+                                       pDCTstat = pDCTstatA + Node;
+ 
+                                       if (pDCTstat->NodePresent) {
+-                                              lock_dram_config(pMCTstat, 
pDCTstat);
+                                               set_cc6_save_enable(pMCTstat, 
pDCTstat, 1);
++                                              lock_dram_config(pMCTstat, 
pDCTstat);
+                                       }
+                               }
+                       }
+@@ -5110,7 +5121,7 @@ static void mct_HTMemMapExt(struct MCTStatStruc 
*pMCTstat,
+               /* get base/limit from Node0 */
+               reg = 0x40 + (Node << 3);               /* Node0/Dram Base 0 */
+               val = Get_NB32(dev, reg);
+-              Drambase = val >> ( 16 + 3);
++              Drambase = val >> (16 + 3);
+ 
+               reg = 0x44 + (Node << 3);               /* Node0/Dram Base 0 */
+               val = Get_NB32(dev, reg);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+index 11f1b2c..3a9fecc 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+@@ -159,6 +159,14 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                       if (MemClrECC) {
+                               MCTMemClrSync_D(pMCTstat, pDCTstatA);
+                       }
++
++                      if (pDCTstat->LogicalCPUID & (AMD_DR_GT_D0 | 
AMD_FAM15_ALL)) {
++                              /* Set up message triggered C1E */
++                              val = pci_read_config32(pDCTstat->dev_nbmisc, 
0xd4);
++                              val &= ~(0x1 << 15);                    /* 
StutterScrubEn = DRAM scrub enabled */
++                              val |= (mctGet_NVbits(NV_DramBKScrub)?1:0) << 
15;
++                              pci_write_config32(pDCTstat->dev_nbmisc, 0xd4, 
val);
++                      }
+               }       /* if Node present */
+       }
+ 
+diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
+index a6849b0..fd3b099 100644
+--- a/src/southbridge/amd/sb700/early_setup.c
++++ b/src/southbridge/amd/sb700/early_setup.c
+@@ -22,6 +22,7 @@
+ #define _SB700_EARLY_SETUP_C_
+ 
+ #include <stdint.h>
++#include <option.h>
+ #include <arch/acpi.h>
+ #include <arch/cpu.h>
+ #include <arch/io.h>
+@@ -271,10 +272,6 @@ void enable_fid_change_on_sb(u32 sbbusn, u32 sbdn)
+       byte &= ~(1<<6);
+       pmio_write(0x8d, byte);
+ 
+-      byte = pmio_read(0x61);
+-      byte &= ~0x04;
+-      pmio_write(0x61, byte);
+-
+       byte = pmio_read(0x42);
+       byte &= ~0x04;
+       pmio_write(0x42, byte);
+@@ -560,6 +557,13 @@ static void sb700_devices_por_init(void)
+ static void sb700_pmio_por_init(void)
+ {
+       u8 byte;
++      uint8_t enable_c_states;
++
++      enable_c_states = 0;
++#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
++      if (get_option(&byte, "cpu_c_states") == CB_SUCCESS)
++              enable_c_states = !!byte;
++#endif
+ 
+       printk(BIOS_INFO, "sb700_pmio_por_init()\n");
+       /* K8KbRstEn, KB_RST# control for K8 system. */
+@@ -621,6 +625,14 @@ static void sb700_pmio_por_init(void)
+       byte |= 1 << 0;
+       pmio_write(0xB2, byte);
+ 
++      /* Set up IOAPIC and BM_STS monitoring */
++      byte = pmio_read(0x61);
++      if (enable_c_states)
++              byte |= 0x4;
++      else
++              byte &= ~0x04;
++      pmio_write(0x61, byte);
++
+       // FIXME: Enabling this causes boot to hang while initializing 
processors.
+ //    /* Enable automatic C1e state switch */
+ //    byte = pmio_read(0xc9);
+diff --git a/src/southbridge/amd/sb700/fadt.c 
b/src/southbridge/amd/sb700/fadt.c
+index 96996a3..e860016 100644
+--- a/src/southbridge/amd/sb700/fadt.c
++++ b/src/southbridge/amd/sb700/fadt.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -26,6 +27,7 @@
+ #include <arch/acpi.h>
+ #include <arch/io.h>
+ #include <device/device.h>
++#include <cpu/amd/powernow.h>
+ #include "sb700.h"
+ 
+ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
+@@ -156,5 +158,8 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
+       fadt->x_gpe1_blk.addrl = 0;
+       fadt->x_gpe1_blk.addrh = 0x0;
+ 
++      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
++              amd_powernow_update_fadt(fadt);
++
+       header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t));
+ }
+diff --git a/src/southbridge/amd/sb700/sb700.h 
b/src/southbridge/amd/sb700/sb700.h
+index b477091..941a4fd 100644
+--- a/src/southbridge/amd/sb700/sb700.h
++++ b/src/southbridge/amd/sb700/sb700.h
+@@ -36,10 +36,11 @@
+ 
+ #define ACPI_PM_EVT_BLK               (SB700_ACPI_IO_BASE + 0x00) /* 4 bytes 
*/
+ #define ACPI_PM1_CNT_BLK      (SB700_ACPI_IO_BASE + 0x04) /* 2 bytes */
+-#define ACPI_PMA_CNT_BLK      (SB700_ACPI_IO_BASE + 0x0E) /* 1 byte */
+-#define ACPI_PM_TMR_BLK               (SB700_ACPI_IO_BASE + 0x18) /* 4 bytes 
*/
+-#define ACPI_GPE0_BLK         (SB700_ACPI_IO_BASE + 0x10) /* 8 bytes */
++#define ACPI_PMA_CNT_BLK      (SB700_ACPI_IO_BASE + 0x16) /* 1 byte */
++#define ACPI_PM_TMR_BLK               (SB700_ACPI_IO_BASE + 0x20) /* 4 bytes 
*/
++#define ACPI_GPE0_BLK         (SB700_ACPI_IO_BASE + 0x18) /* 8 bytes */
+ #define ACPI_CPU_CONTROL      (SB700_ACPI_IO_BASE + 0x08) /* 6 bytes */
++#define ACPI_CPU_P_LVL2               (ACPI_CPU_CONTROL + 0x4)    /* 1 byte */
+ 
+ extern void pm_iowrite(u8 reg, u8 value);
+ extern u8 pm_ioread(u8 reg);
+diff --git a/src/southbridge/amd/sb700/sm.c b/src/southbridge/amd/sb700/sm.c
+index 71253b5..5bd49c5 100644
+--- a/src/southbridge/amd/sb700/sm.c
++++ b/src/southbridge/amd/sb700/sm.c
+@@ -117,7 +117,10 @@ static void sm_init(device_t dev)
+       pci_write_config8(dev, 0x41, byte);
+ 
+       byte = pm_ioread(0x61);
+-      byte |= 1 << 1;         /* Set to enable NB/SB handshake during IOAPIC 
interrupt for AMD K8/K7 */
++      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
++              byte &= ~(1 << 1);      /* Clear for non-K8 CPUs */
++      else
++              byte |= 1 << 1;         /* Set to enable NB/SB handshake during 
IOAPIC interrupt for AMD K8/K7 */
+       pm_iowrite(0x61, byte);
+ 
+       /* disable SMI */
+diff --git a/src/southbridge/amd/sb800/fadt.c 
b/src/southbridge/amd/sb800/fadt.c
+index fea98f9..30b4496 100644
+--- a/src/southbridge/amd/sb800/fadt.c
++++ b/src/southbridge/amd/sb800/fadt.c
+@@ -26,6 +26,7 @@
+ #include <arch/acpi.h>
+ #include <arch/io.h>
+ #include <device/device.h>
++#include <cpu/amd/powernow.h>
+ #include "sb800.h"
+ 
+ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
+@@ -156,5 +157,8 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
+       fadt->x_gpe1_blk.addrl = 0;
+       fadt->x_gpe1_blk.addrh = 0x0;
+ 
++      if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
++              amd_powernow_update_fadt(fadt);
++
+       header->checksum = acpi_checksum((void *)fadt, sizeof(acpi_fadt_t));
+ }
+diff --git a/src/southbridge/amd/sb800/sb800.h 
b/src/southbridge/amd/sb800/sb800.h
+index 9049182..3e3f077 100644
+--- a/src/southbridge/amd/sb800/sb800.h
++++ b/src/southbridge/amd/sb800/sb800.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -35,10 +36,11 @@
+ 
+ #define ACPI_PM_EVT_BLK               (SB800_ACPI_IO_BASE + 0x00) /* 4 bytes 
*/
+ #define ACPI_PM1_CNT_BLK      (SB800_ACPI_IO_BASE + 0x04) /* 2 bytes */
+-#define ACPI_PMA_CNT_BLK      (SB800_ACPI_IO_BASE + 0x0F) /* 1 byte */
+-#define ACPI_PM_TMR_BLK               (SB800_ACPI_IO_BASE + 0x18) /* 4 bytes 
*/
+-#define ACPI_GPE0_BLK         (SB800_ACPI_IO_BASE + 0x10) /* 8 bytes */
++#define ACPI_PMA_CNT_BLK      (SB800_ACPI_IO_BASE + 0x17) /* 1 byte */
++#define ACPI_PM_TMR_BLK               (SB800_ACPI_IO_BASE + 0x20) /* 4 bytes 
*/
++#define ACPI_GPE0_BLK         (SB800_ACPI_IO_BASE + 0x18) /* 8 bytes */
+ #define ACPI_CPU_CONTROL      (SB800_ACPI_IO_BASE + 0x08) /* 6 bytes */
++#define ACPI_CPU_P_LVL2               (ACPI_CPU_CONTROL + 0x4)    /* 1 byte */
+ 
+ void pm_iowrite(u8 reg, u8 value);
+ u8 pm_ioread(u8 reg);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0047-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
 
b/resources/libreboot/patch/kgpe-d16/0047-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
deleted file mode 100644
index 8bd1471..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0047-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
+++ /dev/null
@@ -1,103 +0,0 @@
-From cac705ed59bc27d7eacdfdc16ed3c762fd41e84f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 8 Jun 2015 19:54:56 -0500
-Subject: [PATCH 047/139] northbridge/amd/amdmct: Skip DCT config write to
- Flash if unchanged
-
-Change-Id: I5fee5f5fdf30ab6e3c4f94ed3e54ea66c1204352
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |  3 +++
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |  1 +
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 21 +++++++++++++++++++--
- 3 files changed, 23 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 4044c36..3edce9e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1361,6 +1361,7 @@ restartinit:
- #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
-               restore_mct_information_from_nvram(0);
-+              pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
- #endif
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-@@ -2087,6 +2088,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
- 
-               if (is_fam15h())
-                       exit_training_mode_fam15(pMCTstat, pDCTstatA);
-+
-+              pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
-       }
- 
-       /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 539ecc3..adf89b2 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -316,6 +316,7 @@ struct MCTStatStruc {
- #define GSB_SpIntRemapHole    16      /* Special condition for Node 
Interleave and HW remapping*/
- #define GSB_EnDIMMSpareNW     17      /* Indicates that DIMM Spare can be 
used without a warm reset */
-                                       /* NOTE: This is a local bit used by 
memory code */
-+#define GSB_ConfigRestored    18      /* Training configuration was restored 
from NVRAM */
- 
- 
/*===============================================================================
-       Local DCT Status structure (a structure for each DCT)
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index 83c7b02..1e5c1a0 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -213,7 +213,7 @@ static uint32_t read_config32_dct_nbpstate(device_t dev, 
uint8_t node, uint8_t d
-       return pci_read_config32(dev, reg);
- }
- 
--static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_data)
-+static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_data, uint8_t * restored)
- {
-       uint8_t node;
-       uint8_t dimm;
-@@ -236,6 +236,13 @@ static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data*
-       for (node = 0; node < MAX_NODES_SUPPORTED; node++)
-               for (channel = 0; channel < 2; channel++)
-                       persistent_data->node[node].memclk[channel] = 
mem_info->dct_stat[node].Speed;
-+
-+      if (restored) {
-+              if (mem_info->mct_stat.GStatus & (1 << GSB_ConfigRestored))
-+                      *restored = 1;
-+              else
-+                      *restored = 0;
-+      }
- }
- 
- void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
-@@ -1034,6 +1041,7 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
- int8_t save_mct_information_to_nvram(void)
- {
-       uint8_t nvram;
-+      uint8_t restored = 0;
- 
-       if (acpi_is_wakeup_s3())
-               return 0;
-@@ -1055,7 +1063,16 @@ int8_t save_mct_information_to_nvram(void)
-       copy_mct_data_to_save_variable(persistent_data);
- 
-       /* Save RAM SPD data at the same time */
--      copy_cbmem_spd_data_to_save_variable(persistent_data);
-+      copy_cbmem_spd_data_to_save_variable(persistent_data, &restored);
-+
-+      if (restored) {
-+              /* Allow training bypass if DIMM configuration is unchanged on 
next boot */
-+              nvram = 1;
-+              set_option("allow_spd_nvram_cache_restore", &nvram);
-+
-+              printk(BIOS_DEBUG, "Hardware configuration unchanged since last 
boot; skipping write\n");
-+              return 0;
-+      }
- 
-       /* Obtain CBFS file offset */
-       s3nv_offset = get_s3nv_file_offset();
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0048-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
 
b/resources/libreboot/patch/kgpe-d16/0048-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
new file mode 100644
index 0000000..a3de30d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0048-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch
@@ -0,0 +1,103 @@
+From e513231d8e07299c740ef0cb8750816d5ac69998 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 8 Jun 2015 19:54:56 -0500
+Subject: [PATCH 048/143] northbridge/amd/amdmct: Skip DCT config write to
+ Flash if unchanged
+
+Change-Id: I5fee5f5fdf30ab6e3c4f94ed3e54ea66c1204352
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |    3 +++
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |    1 +
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c |   21 +++++++++++++++++++--
+ 3 files changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 4044c36..3edce9e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1361,6 +1361,7 @@ restartinit:
+ #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT 
configuration from NVRAM\n");
+               restore_mct_information_from_nvram(0);
++              pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
+ #endif
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+@@ -2087,6 +2088,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+ 
+               if (is_fam15h())
+                       exit_training_mode_fam15(pMCTstat, pDCTstatA);
++
++              pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
+       }
+ 
+       /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 539ecc3..adf89b2 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -316,6 +316,7 @@ struct MCTStatStruc {
+ #define GSB_SpIntRemapHole    16      /* Special condition for Node 
Interleave and HW remapping*/
+ #define GSB_EnDIMMSpareNW     17      /* Indicates that DIMM Spare can be 
used without a warm reset */
+                                       /* NOTE: This is a local bit used by 
memory code */
++#define GSB_ConfigRestored    18      /* Training configuration was restored 
from NVRAM */
+ 
+ 
/*===============================================================================
+       Local DCT Status structure (a structure for each DCT)
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+index 83c7b02..1e5c1a0 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -213,7 +213,7 @@ static uint32_t read_config32_dct_nbpstate(device_t dev, 
uint8_t node, uint8_t d
+       return pci_read_config32(dev, reg);
+ }
+ 
+-static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_data)
++static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_data, uint8_t * restored)
+ {
+       uint8_t node;
+       uint8_t dimm;
+@@ -236,6 +236,13 @@ static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data*
+       for (node = 0; node < MAX_NODES_SUPPORTED; node++)
+               for (channel = 0; channel < 2; channel++)
+                       persistent_data->node[node].memclk[channel] = 
mem_info->dct_stat[node].Speed;
++
++      if (restored) {
++              if (mem_info->mct_stat.GStatus & (1 << GSB_ConfigRestored))
++                      *restored = 1;
++              else
++                      *restored = 0;
++      }
+ }
+ 
+ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* 
persistent_data)
+@@ -1034,6 +1041,7 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+ int8_t save_mct_information_to_nvram(void)
+ {
+       uint8_t nvram;
++      uint8_t restored = 0;
+ 
+       if (acpi_is_wakeup_s3())
+               return 0;
+@@ -1055,7 +1063,16 @@ int8_t save_mct_information_to_nvram(void)
+       copy_mct_data_to_save_variable(persistent_data);
+ 
+       /* Save RAM SPD data at the same time */
+-      copy_cbmem_spd_data_to_save_variable(persistent_data);
++      copy_cbmem_spd_data_to_save_variable(persistent_data, &restored);
++
++      if (restored) {
++              /* Allow training bypass if DIMM configuration is unchanged on 
next boot */
++              nvram = 1;
++              set_option("allow_spd_nvram_cache_restore", &nvram);
++
++              printk(BIOS_DEBUG, "Hardware configuration unchanged since last 
boot; skipping write\n");
++              return 0;
++      }
+ 
+       /* Obtain CBFS file offset */
+       s3nv_offset = get_s3nv_file_offset();
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0048-southbridge-amd-sb700-Add-AHCI-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0048-southbridge-amd-sb700-Add-AHCI-support.patch
deleted file mode 100644
index ed4bd52..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0048-southbridge-amd-sb700-Add-AHCI-support.patch
+++ /dev/null
@@ -1,656 +0,0 @@
-From 5c3cca2a8c938c140d6d217fd3fa9a646713678c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 9 Jun 2015 18:09:50 -0500
-Subject: [PATCH 048/139] southbridge/amd/sb700: Add AHCI support
-
-Change-Id: I147284e6a435f4b96d6821a122c1f4f9ddc2ea33
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/include/device/pci_ids.h             |   2 +
- src/mainboard/asus/kgpe-d16/Kconfig      |   4 +
- src/mainboard/asus/kgpe-d16/cmos.default |   1 +
- src/mainboard/asus/kgpe-d16/cmos.layout  |   3 +-
- src/southbridge/amd/sb700/Kconfig        |   4 +
- src/southbridge/amd/sb700/early_setup.c  |  73 ++++++---
- src/southbridge/amd/sb700/ide.c          |  42 +++--
- src/southbridge/amd/sb700/sata.c         | 256 +++++++++++++++++++++----------
- src/southbridge/amd/sb800/fadt.c         |   1 +
- 9 files changed, 267 insertions(+), 119 deletions(-)
-
-diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
-index fcaf4aa..664ac49 100644
---- a/src/include/device/pci_ids.h
-+++ b/src/include/device/pci_ids.h
-@@ -311,6 +311,8 @@
- 
- #define PCI_DEVICE_ID_ATI_SB700_LPC           0x439D
- #define PCI_DEVICE_ID_ATI_SB700_SATA          0x4390
-+#define PCI_DEVICE_ID_ATI_SB700_SATA_AHCI     0x4391
-+#define PCI_DEVICE_ID_ATI_SB700_SATA_AHCI_AMD 0x4394
- #define PCI_DEVICE_ID_ATI_SB700_IDE           0x439C
- #define PCI_DEVICE_ID_ATI_SB700_HDA           0x4383
- #define PCI_DEVICE_ID_ATI_SB700_PCI           0x4384
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-index 8906dee..75bf0ee 100644
---- a/src/mainboard/asus/kgpe-d16/Kconfig
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -89,6 +89,10 @@ config IRQ_SLOT_COUNT
-       int
-       default 13
- 
-+config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD
-+      hex
-+      default 0x3f
-+
- config ONBOARD_VGA_IS_PRIMARY
-       bool
-       default y
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index e3eb4fe..5bfaadd 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -16,6 +16,7 @@ interleave_nodes = Disable
- interleave_memory_channels = Enable
- cpu_c_states = Enable
- cpu_cc6_state = Enable
-+sata_ahci_mode = Enable
- ieee1394 = Enable
- power_on_after_fail = On
- boot_option = Fallback
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index 7f9f661..247fd7b 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -45,7 +45,8 @@ entries
- 464          1       e       2        compute_unit_siblings
- 465          1       e       1        cpu_c_states
- 466          1       e       1        cpu_cc6_state
--467          1       r       0        allow_spd_nvram_cache_restore
-+467          1       e       1        sata_ahci_mode
-+468          1       r       0        allow_spd_nvram_cache_restore
- 477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
-diff --git a/src/southbridge/amd/sb700/Kconfig 
b/src/southbridge/amd/sb700/Kconfig
-index f56f84a..92fb9ab 100644
---- a/src/southbridge/amd/sb700/Kconfig
-+++ b/src/southbridge/amd/sb700/Kconfig
-@@ -46,6 +46,10 @@ config SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
-       bool
-       default n
- 
-+config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD
-+      hex
-+      default 0xf
-+
- config EHCI_BAR
-       hex
-       default 0xfef00000
-diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
-index fd3b099..a06a72f 100644
---- a/src/southbridge/amd/sb700/early_setup.c
-+++ b/src/southbridge/amd/sb700/early_setup.c
-@@ -354,9 +354,13 @@ static void sb700_devices_por_init(void)
- {
-       device_t dev;
-       u8 byte;
--#if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
--      u32 dword;
--#endif
-+      uint32_t dword;
-+      uint8_t nvram;
-+      uint8_t sata_ahci_mode;
-+
-+      sata_ahci_mode = 0;
-+      if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
-+              sata_ahci_mode = !!nvram;
- 
-       printk(BIOS_INFO, "sb700_devices_por_init()\n");
-       /* SMBus Device, BDF:0-20-0 */
-@@ -517,34 +521,56 @@ static void sb700_devices_por_init(void)
-       /* Enable PCIB_DUAL_EN_UP will fix potential problem with PCI cards. */
-       pci_write_config8(dev, 0x50, 0x01);
- 
-+      if (!sata_ahci_mode){
- #if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
--      /* SP5100 default SATA mode is RAID5 MODE */
--      dev = pci_locate_device(PCI_ID(0x1002, 0x4393), 0);
--      /* Set SATA Operation Mode, Set to IDE mode */
--      byte = pci_read_config8(dev, 0x40);
--      byte |= (1 << 0);
--      pci_write_config8(dev, 0x40, byte);
-+              /* SP5100 default SATA mode is RAID5 MODE */
-+              dev = pci_locate_device(PCI_ID(0x1002, 0x4393), 0);
-+
-+              /* Set SATA Operation Mode, Set to IDE mode */
-+              byte = pci_read_config8(dev, 0x40);
-+              byte |= (1 << 0);
-+              pci_write_config8(dev, 0x40, byte);
- 
--      dword = 0x01018f00;
--      pci_write_config32(dev, 0x8, dword);
-+              dword = 0x01018f00;
-+              pci_write_config32(dev, 0x8, dword);
- 
--      /* set SATA Device ID writable */
--      dword = pci_read_config32(dev, 0x40);
--      dword &= ~(1 << 24);
--      pci_write_config32(dev, 0x40, dword);
-+              /* set SATA Device ID writable */
-+              dword = pci_read_config32(dev, 0x40);
-+              dword &= ~(1 << 24);
-+              pci_write_config32(dev, 0x40, dword);
- 
--      /* set Device ID accommodate with IDE emulation mode configuration*/
--      pci_write_config32(dev, 0x0, 0x43901002);
-+              /* set Device ID consistent with IDE emulation mode 
configuration */
-+              pci_write_config32(dev, 0x0, 0x43901002);
- 
--      /* rpr v2.13 4.17 Reset CPU on Sync Flood */
--      abcfg_reg(0x10050, 1 << 2, 1 << 2);
-+              /* rpr v2.13 4.17 Reset CPU on Sync Flood */
-+              abcfg_reg(0x10050, 1 << 2, 1 << 2);
- #endif
-+      }
- 
-       /* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
--      printk(BIOS_INFO, "sb700_devices_por_init(): SATA Device, 
BDF:0-18-0\n");
-+      printk(BIOS_INFO, "sb700_devices_por_init(): SATA Device, 
BDF:0-17-0\n");
-       dev = pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
- 
--      /*PHY Global Control*/
-+      if (sata_ahci_mode) {
-+              /* Switch to AHCI mode (AMD inbox) */
-+              dword = pci_read_config32(dev, 0x40);
-+              dword |= (0x1 << 24);           /* Lock Flash Device ID = 1 */
-+              pci_write_config32(dev, 0x40, dword);
-+
-+              /* Deactivate Sub-Class Code write protection */
-+              byte = pci_read_config8(dev, 0x40);
-+              byte |= (1 << 0);
-+              pci_write_config8(dev, 0x40, byte);
-+
-+              dword = pci_read_config32(dev, 0x08);
-+              dword &= ~(0xff << 16);         /* Sub-Class Code = 0x6 */
-+              dword |= (0x6 << 16);
-+              dword &= ~(0xff << 8);          /* Operating Mode Selection = 
0x1 */
-+              dword |= (0x1 << 8);
-+              pci_write_config32(dev, 0x08, dword);
-+      }
-+
-+      /* PHY Global Control */
-       pci_write_config16(dev, 0x86, 0x2C00);
- }
- 
-@@ -695,6 +721,11 @@ static void sb700_pci_cfg(void)
- 
-       /* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
-       dev = pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
-+      if (dev == PCI_DEV_INVALID)
-+              dev = pci_locate_device(PCI_ID(0x1002, 0x4391), 0);
-+      if (dev == PCI_DEV_INVALID)
-+              dev = pci_locate_device(PCI_ID(0x1002, 0x4394), 0);
-+
-       /* rpr7.12 SATA MSI and D3 Power State Capability. */
-       byte = pci_read_config8(dev, 0x40);
-       byte |= 1 << 0;
-diff --git a/src/southbridge/amd/sb700/ide.c b/src/southbridge/amd/sb700/ide.c
-index 8803d7f..4e07717 100644
---- a/src/southbridge/amd/sb700/ide.c
-+++ b/src/southbridge/amd/sb700/ide.c
-@@ -1,6 +1,7 @@
- /*
-  * This file is part of the coreboot project.
-  *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-  *
-  * This program is free software; you can redistribute it and/or modify
-@@ -22,6 +23,7 @@
- #include <device/pci.h>
- #include <device/pci_ids.h>
- #include <device/pci_ops.h>
-+#include <option.h>
- #include "sb700.h"
- 
- static void ide_init(struct device *dev)
-@@ -30,6 +32,12 @@ static void ide_init(struct device *dev)
-       /* Enable ide devices so the linux ide driver will work */
-       u32 dword;
-       u8 byte;
-+      uint8_t nvram;
-+      uint8_t sata_ahci_mode;
-+
-+      sata_ahci_mode = 0;
-+      if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
-+              sata_ahci_mode = !!nvram;
- 
-       conf = dev->chip_info;
- 
-@@ -39,25 +47,25 @@ static void ide_init(struct device *dev)
-       dword &= ~(1 << 16);
-       pci_write_config32(dev, 0x70, dword);
- 
--      /* Enable UDMA on all devices, it will become UDMA0 (default PIO is 
PIO0) */
--      byte = pci_read_config8(dev, 0x54);
--      byte |= 0xf;
--      pci_write_config8(dev, 0x54, byte);
--
--      /* Enable I/O Access&& Bus Master */
--      dword = pci_read_config16(dev, 0x4);
--      dword |= 1 << 2;
--      pci_write_config16(dev, 0x4, dword);
--
--      /* set ide as primary, if you want to boot from IDE, you'd better set it
--       * in $vendor/$mainboard/devicetree.cb */
-+      if (!sata_ahci_mode) {
-+              /* Enable UDMA on all devices, it will become UDMA0 (default 
PIO is PIO0) */
-+              byte = pci_read_config8(dev, 0x54);
-+              byte |= 0xf;
-+              pci_write_config8(dev, 0x54, byte);
- 
-+              /* Enable I/O Access&& Bus Master */
-+              dword = pci_read_config16(dev, 0x4);
-+              dword |= 1 << 2;
-+              pci_write_config16(dev, 0x4, dword);
- 
--      if (conf->boot_switch_sata_ide == 1) {
--              struct device *sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
--              byte = pci_read_config8(sm_dev, 0xAD);
--              byte |= 1 << 4;
--              pci_write_config8(sm_dev, 0xAD, byte);
-+              /* set ide as primary, if you want to boot from IDE, you'd 
better set it
-+               * in $vendor/$mainboard/devicetree.cb */
-+              if (conf->boot_switch_sata_ide == 1) {
-+                      struct device *sm_dev = dev_find_slot(0, 
PCI_DEVFN(0x14, 0));
-+                      byte = pci_read_config8(sm_dev, 0xad);
-+                      byte |= 1 << 4;
-+                      pci_write_config8(sm_dev, 0xad, byte);
-+              }
-       }
- }
- 
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index 172ad36..d97288a 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -24,18 +25,19 @@
- #include <device/pci_ids.h>
- #include <device/pci_ops.h>
- #include <arch/io.h>
-+#include <option.h>
- #include "sb700.h"
- 
--static int sata_drive_detect(int portnum, u16 iobar)
-+static int sata_drive_detect(int portnum, uint16_t iobar)
- {
-       u8 byte, byte2;
-       int i = 0;
--      outb(0xA0 + 0x10 * (portnum % 2), iobar + 0x6);
-+      outb(0xa0 + 0x10 * (portnum % 2), iobar + 0x6);
-       while (byte = inb(iobar + 0x6), byte2 = inb(iobar + 0x7),
--              (byte != (0xA0 + 0x10 * (portnum % 2))) ||
-+              (byte != (0xa0 + 0x10 * (portnum % 2))) ||
-               ((byte2 & 0x88) != 0)) {
-               printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
--              if (byte != (0xA0 + 0x10 * (portnum % 2))) {
-+              if (byte != (0xa0 + 0x10 * (portnum % 2))) {
-                       /* This will happen at the first iteration of this loop
-                        * if the first SATA port is unpopulated and the
-                        * second SATA port is populated.
-@@ -65,15 +67,15 @@ void __attribute__((weak)) 
sb7xx_51xx_setup_sata_phys(struct device *dev)
-       pci_write_config32(dev, 0x90, 0x01B48016);
-       pci_write_config32(dev, 0x94, 0x01B48016);
-       pci_write_config32(dev, 0x98, 0x01B48016);
--      pci_write_config32(dev, 0x9C, 0x01B48016);
-+      pci_write_config32(dev, 0x9c, 0x01B48016);
- 
-       /* RPR7.6.3 SATA GEN II PHY port setting for port [0~5]. */
--      pci_write_config16(dev, 0xA0, 0xA09A);
--      pci_write_config16(dev, 0xA2, 0xA09F);
--      pci_write_config16(dev, 0xA4, 0xA07A);
--      pci_write_config16(dev, 0xA6, 0xA07A);
--      pci_write_config16(dev, 0xA8, 0xA07A);
--      pci_write_config16(dev, 0xAA, 0xA07A);
-+      pci_write_config16(dev, 0xa0, 0xA09A);
-+      pci_write_config16(dev, 0xa2, 0xA09F);
-+      pci_write_config16(dev, 0xa4, 0xA07A);
-+      pci_write_config16(dev, 0xa6, 0xA07A);
-+      pci_write_config16(dev, 0xa8, 0xA07A);
-+      pci_write_config16(dev, 0xaa, 0xA07A);
- }
- 
- static void sata_init(struct device *dev)
-@@ -83,8 +85,18 @@ static void sata_init(struct device *dev)
-       u32 dword;
-       u8 rev_id;
-       void *sata_bar5;
--      u16 sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
-+      uint16_t sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
-+      uint16_t ide_bar0, ide_bar1, ide_bar2, ide_bar3;
-+      uint16_t current_bar;
-       int i, j;
-+      uint8_t nvram;
-+      uint8_t sata_ahci_mode;
-+      uint8_t port_count;
-+      uint8_t max_port_count;
-+
-+      sata_ahci_mode = 0;
-+      if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
-+              sata_ahci_mode = !!nvram;
- 
-       device_t sm_dev;
-       /* SATA SMBus Disable */
-@@ -98,21 +110,39 @@ static void sata_init(struct device *dev)
-       byte |= (1 << 5);
-       pci_write_config8(sm_dev, 0xad, byte);
- 
-+      /* get rev_id */
-+      rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
-+
-+      if (sata_ahci_mode) {
-+              /* Enable link latency enhancement on A14 and above */
-+              if (rev_id >= 0x14) {
-+                      byte = pci_read_config8(sm_dev, 0xad);
-+                      byte &= ~(1 << 5);
-+                      pci_write_config8(sm_dev, 0xad, byte);
-+              }
-+      }
-+
-+      /* Disable combined mode */
-+      byte = pci_read_config8(sm_dev, 0xad);
-+      byte &= ~(1 << 3);
-+      pci_write_config8(sm_dev, 0xad, byte);
-+
-+      device_t ide_dev;
-+      /* IDE Device */
-+      ide_dev = dev_find_slot(0, PCI_DEVFN(0x14, 1));
-+
-       /* RPR 7.2 SATA Initialization */
-       /* Set the interrupt Mapping to INTG# */
-       byte = pci_read_config8(sm_dev, 0xaf);
-       byte = 0x6 << 2;
-       pci_write_config8(sm_dev, 0xaf, byte);
- 
--      /* get rev_id */
--      rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
--
-       /* get base address */
-       sata_bar5 = (void *)(pci_read_config32(dev, 0x24) & ~0x3FF);
-       sata_bar0 = pci_read_config16(dev, 0x10) & ~0x7;
-       sata_bar1 = pci_read_config16(dev, 0x14) & ~0x3;
-       sata_bar2 = pci_read_config16(dev, 0x18) & ~0x7;
--      sata_bar3 = pci_read_config16(dev, 0x1C) & ~0x3;
-+      sata_bar3 = pci_read_config16(dev, 0x1c) & ~0x3;
-       sata_bar4 = pci_read_config16(dev, 0x20) & ~0xf;
- 
-       printk(BIOS_SPEW, "sata_bar0=%x\n", sata_bar0); /* 3030 */
-@@ -122,11 +152,16 @@ static void sata_init(struct device *dev)
-       printk(BIOS_SPEW, "sata_bar4=%x\n", sata_bar4); /* 3000 */
-       printk(BIOS_SPEW, "sata_bar5=%p\n", sata_bar5); /* e0309000 */
- 
--      /* disable combined mode */
--      byte = pci_read_config8(sm_dev, 0xAD);
--      byte &= ~(1 << 3);
--      pci_write_config8(sm_dev, 0xAD, byte);
--      /* Program the 2C to 0x43801002 */
-+      ide_bar0 = pci_read_config16(ide_dev, 0x10) & ~0x7;
-+      ide_bar1 = pci_read_config16(ide_dev, 0x14) & ~0x3;
-+      ide_bar2 = pci_read_config16(ide_dev, 0x18) & ~0x7;
-+      ide_bar3 = pci_read_config16(ide_dev, 0x1c) & ~0x3;
-+      printk(BIOS_SPEW, "ide_bar0=%x\n", ide_bar0);
-+      printk(BIOS_SPEW, "ide_bar1=%x\n", ide_bar1);
-+      printk(BIOS_SPEW, "ide_bar2=%x\n", ide_bar2);
-+      printk(BIOS_SPEW, "ide_bar3=%x\n", ide_bar3);
-+
-+      /* Program the Subsystem ID/VID to 0x43801002 */
-       dword = 0x43801002;
-       pci_write_config32(dev, 0x2c, dword);
- 
-@@ -140,15 +175,48 @@ static void sata_init(struct device *dev)
-       byte |= (1 << 2);
-       pci_write_config8(dev, 0x40, byte);
- 
--      /* Set SATA Operation Mode, Set to IDE mode */
-+      /* Unlock subclass and certain BAR R/O registers */
-       byte = pci_read_config8(dev, 0x40);
-       byte |= (1 << 0);
--      byte |= (1 << 4);
-       pci_write_config8(dev, 0x40, byte);
- 
--      dword = 0x01018f00;
--      pci_write_config32(dev, 0x8, dword);
-+      /* Disable AHCI enhancement (AMD SP5100 RPR page 54) */
-+      dword = pci_read_config32(dev, 0x40);
-+      dword |= (1 << 23);
-+      pci_write_config32(dev, 0x40, dword);
-+
-+      if (sata_ahci_mode) {
-+              /* Force number of ports to 6
-+               * NOTE: This is not documented in the register
-+               * reference guide, but CIMX needs to do this
-+               * to activate all 6 ports when IDE is disabled.
-+               */
-+              dword = read32(sata_bar5 + 0x00);
-+              dword &= ~0x7;
-+              dword |= 0x5;
-+              write32(sata_bar5 + 0x00, dword);
-+      } else {
-+              /* Set SATA Operation Mode, Set to IDE mode */
-+              byte = pci_read_config8(dev, 0x40);
-+              byte |= (1 << 4);
-+              pci_write_config8(dev, 0x40, byte);
-+
-+              dword = 0x01018f00;
-+              pci_write_config32(dev, 0x8, dword);
-+      }
-+
-+      /* Get maximum number of ports */
-+      max_port_count = read32(sata_bar5 + 0x00) & 0x1f;
-+      max_port_count++;
-+      printk(BIOS_SPEW, "Maximum SATA port count supported by silicon: %d\n", 
max_port_count);
- 
-+      /* Set number of ports */
-+      dword = CONFIG_SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD;
-+      for (i = max_port_count; i < 32; i++)
-+              dword &= ~(0x1 << i);
-+      write32(sata_bar5 + 0x0c, dword);
-+
-+      /* Write protect Sub-Class Code */
-       byte = pci_read_config8(dev, 0x40);
-       byte &= ~(1 << 0);
-       pci_write_config8(dev, 0x40, byte);
-@@ -181,6 +249,7 @@ static void sata_init(struct device *dev)
-       byte = 0x10;
-       pci_write_config8(dev, 0x46, byte);
-       sb7xx_51xx_setup_sata_phys(dev);
-+
-       /* Enable the I/O, MM, BusMaster access for SATA */
-       byte = pci_read_config8(dev, 0x4);
-       byte |= 7 << 0;
-@@ -191,62 +260,75 @@ static void sata_init(struct device *dev)
-       pci_write_config32(dev, 0xC, 0x00004000);
- #endif
- 
--      /* RPR7.7 SATA drive detection. */
--      /* Use BAR5+0x128,BAR0 for Primary Slave */
--      /* Use BAR5+0x1A8,BAR0 for Primary Slave */
--      /* Use BAR5+0x228,BAR2 for Secondary Master */
--      /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
--      /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary master emulation */
--      /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave emulation */
--
--      /* TODO: port 4,5, which are PATA emulations. What are PATA_BARs? */
--
--      for (i = 0; i < 4; i++) {
--              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
--              printk(BIOS_SPEW, "SATA port %i status = %x\n", i, byte);
--              byte &= 0xF;
--              if( byte == 0x1 ) {
--                      /* If the drive status is 0x1 then we see it but we 
aren't talking to it. */
--                      /* Try to do something about it. */
--                      printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
-+      /* Determine port count */
-+      port_count = 0;
-+      for (i = 0; i < 32; i++) {
-+              if (CONFIG_SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD & 
(0x1 << i))
-+                      port_count = i;
-+      }
-+      port_count++;
-+      if (port_count > max_port_count)
-+              port_count = max_port_count;
-+
-+      if (!sata_ahci_mode) {
-+              /* RPR7.7 SATA drive detection. */
-+              /* Use BAR5+0x128,BAR0 for Primary Slave */
-+              /* Use BAR5+0x1A8,BAR0 for Primary Slave */
-+              /* Use BAR5+0x228,BAR2 for Secondary Master */
-+              /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
-+              /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary Master 
emulation */
-+              /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave 
emulation */
-+              for (i = 0; i < port_count; i++) {
-+                      byte = read8(sata_bar5 + 0x128 + 0x80 * i);
-+                      printk(BIOS_SPEW, "SATA port %i status = %x\n", i, 
byte);
-+                      byte &= 0xF;
-+                      if (byte == 0x1) {
-+                              /* If the drive status is 0x1 then we see it 
but we aren't talking to it. */
-+                              /* Try to do something about it. */
-+                              printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
- 
--                      /* Read in Port-N Serial ATA Control Register */
--                      byte = read8(sata_bar5 + 0x12C + 0x80 * i);
-+                              /* Read in Port-N Serial ATA Control Register */
-+                              byte = read8(sata_bar5 + 0x12C + 0x80 * i);
- 
--                      /* Set Reset Bit and 1.5g bit */
--                      byte |= 0x11;
--                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
-+                              /* Set Reset Bit and 1.5g bit */
-+                              byte |= 0x11;
-+                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
- 
--                      /* Wait 1ms */
--                      mdelay(1);
-+                              /* Wait 1ms */
-+                              mdelay(1);
- 
--                      /* Clear Reset Bit */
--                      byte &= ~0x01;
--                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
-+                              /* Clear Reset Bit */
-+                              byte &= ~0x01;
-+                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
- 
--                      /* Wait 1ms */
--                      mdelay(1);
-+                              /* Wait 1ms */
-+                              mdelay(1);
- 
--                      /* Reread status */
--                      byte = read8(sata_bar5 + 0x128 + 0x80 * i);
--                      printk(BIOS_SPEW, "SATA port %i status = %x\n", i, 
byte);
--                      byte &= 0xF;
--              }
-+                              /* Reread status */
-+                              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
-+                              printk(BIOS_SPEW, "SATA port %i status = %x\n", 
i, byte);
-+                              byte &= 0xF;
-+                      }
- 
--              if (byte == 0x3) {
--                      for (j = 0; j < 10; j++) {
--                              if (!sata_drive_detect(i, ((i / 2) == 0) ? 
sata_bar0 : sata_bar2))
--                                      break;
-+                      if (byte == 0x3) {
-+                              for (j = 0; j < 10; j++) {
-+                                      if (i < 4)
-+                                              current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
-+                                      else
-+                                              current_bar = ide_bar0;
-+                                      if (!sata_drive_detect(i, current_bar))
-+                                              break;
-+                              }
-+                              printk(BIOS_DEBUG, "%s %s device is %sready 
after %i tries\n",
-+                                              (i / 2) ? "Secondary" : 
"Primary",
-+                                              (i % 2 ) ? "Slave" : "Master",
-+                                              (j == 10) ? "not " : "",
-+                                              (j == 10) ? j : j + 1);
-+                      } else {
-+                              printk(BIOS_DEBUG, "No %s %s SATA drive on 
Slot%i\n",
-+                                              (i / 2) ? "Secondary" : 
"Primary",
-+                                              (i % 2 ) ? "Slave" : "Master", 
i);
-                       }
--                      printk(BIOS_DEBUG, "%s %s device is %sready after %i 
tries\n",
--                                      (i / 2) ? "Secondary" : "Primary",
--                                      (i % 2 ) ? "Slave" : "Master",
--                                      (j == 10) ? "not " : "",
--                                      (j == 10) ? j : j + 1);
--              } else {
--                      printk(BIOS_DEBUG, "No %s %s SATA drive on Slot%i\n",
--                                      (i / 2) ? "Secondary" : "Primary",
--                                      (i % 2 ) ? "Slave" : "Master", i);
-               }
-       }
- 
-@@ -256,13 +338,15 @@ static void sata_init(struct device *dev)
-       byte |= 1 << 1;
-       write8((sata_bar5 + 0x4), byte);
- 
--      /* Clear error status */
--      write32((sata_bar5 + 0x130), 0xFFFFFFFF);
--      write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
--      write32((sata_bar5 + 0x230), 0xFFFFFFFF);
--      write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
--      write32((sata_bar5 + 0x330), 0xFFFFFFFF);
--      write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
-+      if (!sata_ahci_mode) {
-+              /* Clear error status */
-+              write32((sata_bar5 + 0x130), 0xFFFFFFFF);
-+              write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
-+              write32((sata_bar5 + 0x230), 0xFFFFFFFF);
-+              write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
-+              write32((sata_bar5 + 0x330), 0xFFFFFFFF);
-+              write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
-+      }
- 
-       /* Clear SATA status,Firstly we get the AcpiGpe0BlkAddr */
-       /* ????? why CIM does not set the AcpiGpe0BlkAddr , but use it??? */
-@@ -293,3 +377,15 @@ static const struct pci_driver sata0_driver __pci_driver 
= {
-       .vendor = PCI_VENDOR_ID_ATI,
-       .device = PCI_DEVICE_ID_ATI_SB700_SATA,
- };
-+
-+static const struct pci_driver sata1_driver __pci_driver = {
-+      .ops = &sata_ops,
-+      .vendor = PCI_VENDOR_ID_ATI,
-+      .device = PCI_DEVICE_ID_ATI_SB700_SATA_AHCI,
-+};
-+
-+static const struct pci_driver sata2_driver __pci_driver = {
-+      .ops = &sata_ops,
-+      .vendor = PCI_VENDOR_ID_ATI,
-+      .device = PCI_DEVICE_ID_ATI_SB700_SATA_AHCI_AMD,
-+};
-diff --git a/src/southbridge/amd/sb800/fadt.c 
b/src/southbridge/amd/sb800/fadt.c
-index 5250e20..95e3354 100644
---- a/src/southbridge/amd/sb800/fadt.c
-+++ b/src/southbridge/amd/sb800/fadt.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0049-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
 
b/resources/libreboot/patch/kgpe-d16/0049-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
deleted file mode 100644
index 28bdf5f..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0049-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 8402270ff9ebd9f118f28daa2eda5d3852843a32 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 9 Jun 2015 18:57:23 -0500
-Subject: [PATCH 049/139] mainboard/asus/kgpe-d16: Properly initialize SB700
- SATA PHYs
-
-Change-Id: I5323462dcb8a4e84786be38cc85070eb48d4a31d
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/mainboard.c | 23 +++++++++++++++++++++++
- 1 file changed, 23 insertions(+)
-
-diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c 
b/src/mainboard/asus/kgpe-d16/mainboard.c
-index 47ede34..8de6f26 100644
---- a/src/mainboard/asus/kgpe-d16/mainboard.c
-+++ b/src/mainboard/asus/kgpe-d16/mainboard.c
-@@ -76,6 +76,29 @@ static void mainboard_enable(device_t dev)
-       /* get_ide_dma66(); */
- }
- 
-+/* override the default SATA PHY setup */
-+void sb7xx_51xx_setup_sata_phys(struct device *dev)
-+{
-+      /* RPR7.6.1 Program the PHY Global Control to 0x2C00 */
-+      pci_write_config16(dev, 0x86, 0x2c00);
-+
-+      /* RPR7.6.2 SATA GENI PHY ports setting */
-+      pci_write_config32(dev, 0x88, 0x01b48016);
-+      pci_write_config32(dev, 0x8c, 0x01b48016);
-+      pci_write_config32(dev, 0x90, 0x01b48016);
-+      pci_write_config32(dev, 0x94, 0x01b48016);
-+      pci_write_config32(dev, 0x98, 0x01b48016);
-+      pci_write_config32(dev, 0x9c, 0x01b48016);
-+
-+      /* RPR7.6.3 SATA GEN II PHY port setting for port [0~5]. */
-+      pci_write_config16(dev, 0xa0, 0xa07a);
-+      pci_write_config16(dev, 0xa2, 0xa07a);
-+      pci_write_config16(dev, 0xa4, 0xa07a);
-+      pci_write_config16(dev, 0xa6, 0xa07a);
-+      pci_write_config16(dev, 0xa8, 0xa07a);
-+      pci_write_config16(dev, 0xaa, 0xa07a);
-+}
-+
- struct chip_operations mainboard_ops = {
-       .enable_dev = mainboard_enable,
- };
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0049-southbridge-amd-sb700-Add-AHCI-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0049-southbridge-amd-sb700-Add-AHCI-support.patch
new file mode 100644
index 0000000..7f5d402
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0049-southbridge-amd-sb700-Add-AHCI-support.patch
@@ -0,0 +1,656 @@
+From 2ddaf32b63d12d630da6726ba6fa46caa0e5940f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 9 Jun 2015 18:09:50 -0500
+Subject: [PATCH 049/143] southbridge/amd/sb700: Add AHCI support
+
+Change-Id: I147284e6a435f4b96d6821a122c1f4f9ddc2ea33
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/include/device/pci_ids.h             |    2 +
+ src/mainboard/asus/kgpe-d16/Kconfig      |    4 +
+ src/mainboard/asus/kgpe-d16/cmos.default |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout  |    3 +-
+ src/southbridge/amd/sb700/Kconfig        |    4 +
+ src/southbridge/amd/sb700/early_setup.c  |   73 ++++++---
+ src/southbridge/amd/sb700/ide.c          |   42 +++--
+ src/southbridge/amd/sb700/sata.c         |  256 ++++++++++++++++++++----------
+ src/southbridge/amd/sb800/fadt.c         |    1 +
+ 9 files changed, 267 insertions(+), 119 deletions(-)
+
+diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
+index fcaf4aa..664ac49 100644
+--- a/src/include/device/pci_ids.h
++++ b/src/include/device/pci_ids.h
+@@ -311,6 +311,8 @@
+ 
+ #define PCI_DEVICE_ID_ATI_SB700_LPC           0x439D
+ #define PCI_DEVICE_ID_ATI_SB700_SATA          0x4390
++#define PCI_DEVICE_ID_ATI_SB700_SATA_AHCI     0x4391
++#define PCI_DEVICE_ID_ATI_SB700_SATA_AHCI_AMD 0x4394
+ #define PCI_DEVICE_ID_ATI_SB700_IDE           0x439C
+ #define PCI_DEVICE_ID_ATI_SB700_HDA           0x4383
+ #define PCI_DEVICE_ID_ATI_SB700_PCI           0x4384
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+index 8906dee..75bf0ee 100644
+--- a/src/mainboard/asus/kgpe-d16/Kconfig
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -89,6 +89,10 @@ config IRQ_SLOT_COUNT
+       int
+       default 13
+ 
++config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD
++      hex
++      default 0x3f
++
+ config ONBOARD_VGA_IS_PRIMARY
+       bool
+       default y
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index e3eb4fe..5bfaadd 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -16,6 +16,7 @@ interleave_nodes = Disable
+ interleave_memory_channels = Enable
+ cpu_c_states = Enable
+ cpu_cc6_state = Enable
++sata_ahci_mode = Enable
+ ieee1394 = Enable
+ power_on_after_fail = On
+ boot_option = Fallback
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 7f9f661..247fd7b 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -45,7 +45,8 @@ entries
+ 464          1       e       2        compute_unit_siblings
+ 465          1       e       1        cpu_c_states
+ 466          1       e       1        cpu_cc6_state
+-467          1       r       0        allow_spd_nvram_cache_restore
++467          1       e       1        sata_ahci_mode
++468          1       r       0        allow_spd_nvram_cache_restore
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+diff --git a/src/southbridge/amd/sb700/Kconfig 
b/src/southbridge/amd/sb700/Kconfig
+index bca74fb..05eac5f 100644
+--- a/src/southbridge/amd/sb700/Kconfig
++++ b/src/southbridge/amd/sb700/Kconfig
+@@ -46,6 +46,10 @@ config SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
+       bool
+       default n
+ 
++config SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD
++      hex
++      default 0xf
++
+ config EHCI_BAR
+       hex
+       default 0xfef00000
+diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
+index fd3b099..a06a72f 100644
+--- a/src/southbridge/amd/sb700/early_setup.c
++++ b/src/southbridge/amd/sb700/early_setup.c
+@@ -354,9 +354,13 @@ static void sb700_devices_por_init(void)
+ {
+       device_t dev;
+       u8 byte;
+-#if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
+-      u32 dword;
+-#endif
++      uint32_t dword;
++      uint8_t nvram;
++      uint8_t sata_ahci_mode;
++
++      sata_ahci_mode = 0;
++      if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
++              sata_ahci_mode = !!nvram;
+ 
+       printk(BIOS_INFO, "sb700_devices_por_init()\n");
+       /* SMBus Device, BDF:0-20-0 */
+@@ -517,34 +521,56 @@ static void sb700_devices_por_init(void)
+       /* Enable PCIB_DUAL_EN_UP will fix potential problem with PCI cards. */
+       pci_write_config8(dev, 0x50, 0x01);
+ 
++      if (!sata_ahci_mode){
+ #if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
+-      /* SP5100 default SATA mode is RAID5 MODE */
+-      dev = pci_locate_device(PCI_ID(0x1002, 0x4393), 0);
+-      /* Set SATA Operation Mode, Set to IDE mode */
+-      byte = pci_read_config8(dev, 0x40);
+-      byte |= (1 << 0);
+-      pci_write_config8(dev, 0x40, byte);
++              /* SP5100 default SATA mode is RAID5 MODE */
++              dev = pci_locate_device(PCI_ID(0x1002, 0x4393), 0);
++
++              /* Set SATA Operation Mode, Set to IDE mode */
++              byte = pci_read_config8(dev, 0x40);
++              byte |= (1 << 0);
++              pci_write_config8(dev, 0x40, byte);
+ 
+-      dword = 0x01018f00;
+-      pci_write_config32(dev, 0x8, dword);
++              dword = 0x01018f00;
++              pci_write_config32(dev, 0x8, dword);
+ 
+-      /* set SATA Device ID writable */
+-      dword = pci_read_config32(dev, 0x40);
+-      dword &= ~(1 << 24);
+-      pci_write_config32(dev, 0x40, dword);
++              /* set SATA Device ID writable */
++              dword = pci_read_config32(dev, 0x40);
++              dword &= ~(1 << 24);
++              pci_write_config32(dev, 0x40, dword);
+ 
+-      /* set Device ID accommodate with IDE emulation mode configuration*/
+-      pci_write_config32(dev, 0x0, 0x43901002);
++              /* set Device ID consistent with IDE emulation mode 
configuration */
++              pci_write_config32(dev, 0x0, 0x43901002);
+ 
+-      /* rpr v2.13 4.17 Reset CPU on Sync Flood */
+-      abcfg_reg(0x10050, 1 << 2, 1 << 2);
++              /* rpr v2.13 4.17 Reset CPU on Sync Flood */
++              abcfg_reg(0x10050, 1 << 2, 1 << 2);
+ #endif
++      }
+ 
+       /* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
+-      printk(BIOS_INFO, "sb700_devices_por_init(): SATA Device, 
BDF:0-18-0\n");
++      printk(BIOS_INFO, "sb700_devices_por_init(): SATA Device, 
BDF:0-17-0\n");
+       dev = pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
+ 
+-      /*PHY Global Control*/
++      if (sata_ahci_mode) {
++              /* Switch to AHCI mode (AMD inbox) */
++              dword = pci_read_config32(dev, 0x40);
++              dword |= (0x1 << 24);           /* Lock Flash Device ID = 1 */
++              pci_write_config32(dev, 0x40, dword);
++
++              /* Deactivate Sub-Class Code write protection */
++              byte = pci_read_config8(dev, 0x40);
++              byte |= (1 << 0);
++              pci_write_config8(dev, 0x40, byte);
++
++              dword = pci_read_config32(dev, 0x08);
++              dword &= ~(0xff << 16);         /* Sub-Class Code = 0x6 */
++              dword |= (0x6 << 16);
++              dword &= ~(0xff << 8);          /* Operating Mode Selection = 
0x1 */
++              dword |= (0x1 << 8);
++              pci_write_config32(dev, 0x08, dword);
++      }
++
++      /* PHY Global Control */
+       pci_write_config16(dev, 0x86, 0x2C00);
+ }
+ 
+@@ -695,6 +721,11 @@ static void sb700_pci_cfg(void)
+ 
+       /* SATA Device, BDF:0-17-0, Non-Raid-5 SATA controller */
+       dev = pci_locate_device(PCI_ID(0x1002, 0x4390), 0);
++      if (dev == PCI_DEV_INVALID)
++              dev = pci_locate_device(PCI_ID(0x1002, 0x4391), 0);
++      if (dev == PCI_DEV_INVALID)
++              dev = pci_locate_device(PCI_ID(0x1002, 0x4394), 0);
++
+       /* rpr7.12 SATA MSI and D3 Power State Capability. */
+       byte = pci_read_config8(dev, 0x40);
+       byte |= 1 << 0;
+diff --git a/src/southbridge/amd/sb700/ide.c b/src/southbridge/amd/sb700/ide.c
+index 8803d7f..4e07717 100644
+--- a/src/southbridge/amd/sb700/ide.c
++++ b/src/southbridge/amd/sb700/ide.c
+@@ -1,6 +1,7 @@
+ /*
+  * This file is part of the coreboot project.
+  *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -22,6 +23,7 @@
+ #include <device/pci.h>
+ #include <device/pci_ids.h>
+ #include <device/pci_ops.h>
++#include <option.h>
+ #include "sb700.h"
+ 
+ static void ide_init(struct device *dev)
+@@ -30,6 +32,12 @@ static void ide_init(struct device *dev)
+       /* Enable ide devices so the linux ide driver will work */
+       u32 dword;
+       u8 byte;
++      uint8_t nvram;
++      uint8_t sata_ahci_mode;
++
++      sata_ahci_mode = 0;
++      if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
++              sata_ahci_mode = !!nvram;
+ 
+       conf = dev->chip_info;
+ 
+@@ -39,25 +47,25 @@ static void ide_init(struct device *dev)
+       dword &= ~(1 << 16);
+       pci_write_config32(dev, 0x70, dword);
+ 
+-      /* Enable UDMA on all devices, it will become UDMA0 (default PIO is 
PIO0) */
+-      byte = pci_read_config8(dev, 0x54);
+-      byte |= 0xf;
+-      pci_write_config8(dev, 0x54, byte);
+-
+-      /* Enable I/O Access&& Bus Master */
+-      dword = pci_read_config16(dev, 0x4);
+-      dword |= 1 << 2;
+-      pci_write_config16(dev, 0x4, dword);
+-
+-      /* set ide as primary, if you want to boot from IDE, you'd better set it
+-       * in $vendor/$mainboard/devicetree.cb */
++      if (!sata_ahci_mode) {
++              /* Enable UDMA on all devices, it will become UDMA0 (default 
PIO is PIO0) */
++              byte = pci_read_config8(dev, 0x54);
++              byte |= 0xf;
++              pci_write_config8(dev, 0x54, byte);
+ 
++              /* Enable I/O Access&& Bus Master */
++              dword = pci_read_config16(dev, 0x4);
++              dword |= 1 << 2;
++              pci_write_config16(dev, 0x4, dword);
+ 
+-      if (conf->boot_switch_sata_ide == 1) {
+-              struct device *sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+-              byte = pci_read_config8(sm_dev, 0xAD);
+-              byte |= 1 << 4;
+-              pci_write_config8(sm_dev, 0xAD, byte);
++              /* set ide as primary, if you want to boot from IDE, you'd 
better set it
++               * in $vendor/$mainboard/devicetree.cb */
++              if (conf->boot_switch_sata_ide == 1) {
++                      struct device *sm_dev = dev_find_slot(0, 
PCI_DEVFN(0x14, 0));
++                      byte = pci_read_config8(sm_dev, 0xad);
++                      byte |= 1 << 4;
++                      pci_write_config8(sm_dev, 0xad, byte);
++              }
+       }
+ }
+ 
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index 172ad36..d97288a 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -24,18 +25,19 @@
+ #include <device/pci_ids.h>
+ #include <device/pci_ops.h>
+ #include <arch/io.h>
++#include <option.h>
+ #include "sb700.h"
+ 
+-static int sata_drive_detect(int portnum, u16 iobar)
++static int sata_drive_detect(int portnum, uint16_t iobar)
+ {
+       u8 byte, byte2;
+       int i = 0;
+-      outb(0xA0 + 0x10 * (portnum % 2), iobar + 0x6);
++      outb(0xa0 + 0x10 * (portnum % 2), iobar + 0x6);
+       while (byte = inb(iobar + 0x6), byte2 = inb(iobar + 0x7),
+-              (byte != (0xA0 + 0x10 * (portnum % 2))) ||
++              (byte != (0xa0 + 0x10 * (portnum % 2))) ||
+               ((byte2 & 0x88) != 0)) {
+               printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
+-              if (byte != (0xA0 + 0x10 * (portnum % 2))) {
++              if (byte != (0xa0 + 0x10 * (portnum % 2))) {
+                       /* This will happen at the first iteration of this loop
+                        * if the first SATA port is unpopulated and the
+                        * second SATA port is populated.
+@@ -65,15 +67,15 @@ void __attribute__((weak)) 
sb7xx_51xx_setup_sata_phys(struct device *dev)
+       pci_write_config32(dev, 0x90, 0x01B48016);
+       pci_write_config32(dev, 0x94, 0x01B48016);
+       pci_write_config32(dev, 0x98, 0x01B48016);
+-      pci_write_config32(dev, 0x9C, 0x01B48016);
++      pci_write_config32(dev, 0x9c, 0x01B48016);
+ 
+       /* RPR7.6.3 SATA GEN II PHY port setting for port [0~5]. */
+-      pci_write_config16(dev, 0xA0, 0xA09A);
+-      pci_write_config16(dev, 0xA2, 0xA09F);
+-      pci_write_config16(dev, 0xA4, 0xA07A);
+-      pci_write_config16(dev, 0xA6, 0xA07A);
+-      pci_write_config16(dev, 0xA8, 0xA07A);
+-      pci_write_config16(dev, 0xAA, 0xA07A);
++      pci_write_config16(dev, 0xa0, 0xA09A);
++      pci_write_config16(dev, 0xa2, 0xA09F);
++      pci_write_config16(dev, 0xa4, 0xA07A);
++      pci_write_config16(dev, 0xa6, 0xA07A);
++      pci_write_config16(dev, 0xa8, 0xA07A);
++      pci_write_config16(dev, 0xaa, 0xA07A);
+ }
+ 
+ static void sata_init(struct device *dev)
+@@ -83,8 +85,18 @@ static void sata_init(struct device *dev)
+       u32 dword;
+       u8 rev_id;
+       void *sata_bar5;
+-      u16 sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
++      uint16_t sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
++      uint16_t ide_bar0, ide_bar1, ide_bar2, ide_bar3;
++      uint16_t current_bar;
+       int i, j;
++      uint8_t nvram;
++      uint8_t sata_ahci_mode;
++      uint8_t port_count;
++      uint8_t max_port_count;
++
++      sata_ahci_mode = 0;
++      if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
++              sata_ahci_mode = !!nvram;
+ 
+       device_t sm_dev;
+       /* SATA SMBus Disable */
+@@ -98,21 +110,39 @@ static void sata_init(struct device *dev)
+       byte |= (1 << 5);
+       pci_write_config8(sm_dev, 0xad, byte);
+ 
++      /* get rev_id */
++      rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
++
++      if (sata_ahci_mode) {
++              /* Enable link latency enhancement on A14 and above */
++              if (rev_id >= 0x14) {
++                      byte = pci_read_config8(sm_dev, 0xad);
++                      byte &= ~(1 << 5);
++                      pci_write_config8(sm_dev, 0xad, byte);
++              }
++      }
++
++      /* Disable combined mode */
++      byte = pci_read_config8(sm_dev, 0xad);
++      byte &= ~(1 << 3);
++      pci_write_config8(sm_dev, 0xad, byte);
++
++      device_t ide_dev;
++      /* IDE Device */
++      ide_dev = dev_find_slot(0, PCI_DEVFN(0x14, 1));
++
+       /* RPR 7.2 SATA Initialization */
+       /* Set the interrupt Mapping to INTG# */
+       byte = pci_read_config8(sm_dev, 0xaf);
+       byte = 0x6 << 2;
+       pci_write_config8(sm_dev, 0xaf, byte);
+ 
+-      /* get rev_id */
+-      rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
+-
+       /* get base address */
+       sata_bar5 = (void *)(pci_read_config32(dev, 0x24) & ~0x3FF);
+       sata_bar0 = pci_read_config16(dev, 0x10) & ~0x7;
+       sata_bar1 = pci_read_config16(dev, 0x14) & ~0x3;
+       sata_bar2 = pci_read_config16(dev, 0x18) & ~0x7;
+-      sata_bar3 = pci_read_config16(dev, 0x1C) & ~0x3;
++      sata_bar3 = pci_read_config16(dev, 0x1c) & ~0x3;
+       sata_bar4 = pci_read_config16(dev, 0x20) & ~0xf;
+ 
+       printk(BIOS_SPEW, "sata_bar0=%x\n", sata_bar0); /* 3030 */
+@@ -122,11 +152,16 @@ static void sata_init(struct device *dev)
+       printk(BIOS_SPEW, "sata_bar4=%x\n", sata_bar4); /* 3000 */
+       printk(BIOS_SPEW, "sata_bar5=%p\n", sata_bar5); /* e0309000 */
+ 
+-      /* disable combined mode */
+-      byte = pci_read_config8(sm_dev, 0xAD);
+-      byte &= ~(1 << 3);
+-      pci_write_config8(sm_dev, 0xAD, byte);
+-      /* Program the 2C to 0x43801002 */
++      ide_bar0 = pci_read_config16(ide_dev, 0x10) & ~0x7;
++      ide_bar1 = pci_read_config16(ide_dev, 0x14) & ~0x3;
++      ide_bar2 = pci_read_config16(ide_dev, 0x18) & ~0x7;
++      ide_bar3 = pci_read_config16(ide_dev, 0x1c) & ~0x3;
++      printk(BIOS_SPEW, "ide_bar0=%x\n", ide_bar0);
++      printk(BIOS_SPEW, "ide_bar1=%x\n", ide_bar1);
++      printk(BIOS_SPEW, "ide_bar2=%x\n", ide_bar2);
++      printk(BIOS_SPEW, "ide_bar3=%x\n", ide_bar3);
++
++      /* Program the Subsystem ID/VID to 0x43801002 */
+       dword = 0x43801002;
+       pci_write_config32(dev, 0x2c, dword);
+ 
+@@ -140,15 +175,48 @@ static void sata_init(struct device *dev)
+       byte |= (1 << 2);
+       pci_write_config8(dev, 0x40, byte);
+ 
+-      /* Set SATA Operation Mode, Set to IDE mode */
++      /* Unlock subclass and certain BAR R/O registers */
+       byte = pci_read_config8(dev, 0x40);
+       byte |= (1 << 0);
+-      byte |= (1 << 4);
+       pci_write_config8(dev, 0x40, byte);
+ 
+-      dword = 0x01018f00;
+-      pci_write_config32(dev, 0x8, dword);
++      /* Disable AHCI enhancement (AMD SP5100 RPR page 54) */
++      dword = pci_read_config32(dev, 0x40);
++      dword |= (1 << 23);
++      pci_write_config32(dev, 0x40, dword);
++
++      if (sata_ahci_mode) {
++              /* Force number of ports to 6
++               * NOTE: This is not documented in the register
++               * reference guide, but CIMX needs to do this
++               * to activate all 6 ports when IDE is disabled.
++               */
++              dword = read32(sata_bar5 + 0x00);
++              dword &= ~0x7;
++              dword |= 0x5;
++              write32(sata_bar5 + 0x00, dword);
++      } else {
++              /* Set SATA Operation Mode, Set to IDE mode */
++              byte = pci_read_config8(dev, 0x40);
++              byte |= (1 << 4);
++              pci_write_config8(dev, 0x40, byte);
++
++              dword = 0x01018f00;
++              pci_write_config32(dev, 0x8, dword);
++      }
++
++      /* Get maximum number of ports */
++      max_port_count = read32(sata_bar5 + 0x00) & 0x1f;
++      max_port_count++;
++      printk(BIOS_SPEW, "Maximum SATA port count supported by silicon: %d\n", 
max_port_count);
+ 
++      /* Set number of ports */
++      dword = CONFIG_SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD;
++      for (i = max_port_count; i < 32; i++)
++              dword &= ~(0x1 << i);
++      write32(sata_bar5 + 0x0c, dword);
++
++      /* Write protect Sub-Class Code */
+       byte = pci_read_config8(dev, 0x40);
+       byte &= ~(1 << 0);
+       pci_write_config8(dev, 0x40, byte);
+@@ -181,6 +249,7 @@ static void sata_init(struct device *dev)
+       byte = 0x10;
+       pci_write_config8(dev, 0x46, byte);
+       sb7xx_51xx_setup_sata_phys(dev);
++
+       /* Enable the I/O, MM, BusMaster access for SATA */
+       byte = pci_read_config8(dev, 0x4);
+       byte |= 7 << 0;
+@@ -191,62 +260,75 @@ static void sata_init(struct device *dev)
+       pci_write_config32(dev, 0xC, 0x00004000);
+ #endif
+ 
+-      /* RPR7.7 SATA drive detection. */
+-      /* Use BAR5+0x128,BAR0 for Primary Slave */
+-      /* Use BAR5+0x1A8,BAR0 for Primary Slave */
+-      /* Use BAR5+0x228,BAR2 for Secondary Master */
+-      /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
+-      /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary master emulation */
+-      /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave emulation */
+-
+-      /* TODO: port 4,5, which are PATA emulations. What are PATA_BARs? */
+-
+-      for (i = 0; i < 4; i++) {
+-              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
+-              printk(BIOS_SPEW, "SATA port %i status = %x\n", i, byte);
+-              byte &= 0xF;
+-              if( byte == 0x1 ) {
+-                      /* If the drive status is 0x1 then we see it but we 
aren't talking to it. */
+-                      /* Try to do something about it. */
+-                      printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
++      /* Determine port count */
++      port_count = 0;
++      for (i = 0; i < 32; i++) {
++              if (CONFIG_SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD & 
(0x1 << i))
++                      port_count = i;
++      }
++      port_count++;
++      if (port_count > max_port_count)
++              port_count = max_port_count;
++
++      if (!sata_ahci_mode) {
++              /* RPR7.7 SATA drive detection. */
++              /* Use BAR5+0x128,BAR0 for Primary Slave */
++              /* Use BAR5+0x1A8,BAR0 for Primary Slave */
++              /* Use BAR5+0x228,BAR2 for Secondary Master */
++              /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
++              /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary Master 
emulation */
++              /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave 
emulation */
++              for (i = 0; i < port_count; i++) {
++                      byte = read8(sata_bar5 + 0x128 + 0x80 * i);
++                      printk(BIOS_SPEW, "SATA port %i status = %x\n", i, 
byte);
++                      byte &= 0xF;
++                      if (byte == 0x1) {
++                              /* If the drive status is 0x1 then we see it 
but we aren't talking to it. */
++                              /* Try to do something about it. */
++                              printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
+ 
+-                      /* Read in Port-N Serial ATA Control Register */
+-                      byte = read8(sata_bar5 + 0x12C + 0x80 * i);
++                              /* Read in Port-N Serial ATA Control Register */
++                              byte = read8(sata_bar5 + 0x12C + 0x80 * i);
+ 
+-                      /* Set Reset Bit and 1.5g bit */
+-                      byte |= 0x11;
+-                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
++                              /* Set Reset Bit and 1.5g bit */
++                              byte |= 0x11;
++                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+ 
+-                      /* Wait 1ms */
+-                      mdelay(1);
++                              /* Wait 1ms */
++                              mdelay(1);
+ 
+-                      /* Clear Reset Bit */
+-                      byte &= ~0x01;
+-                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
++                              /* Clear Reset Bit */
++                              byte &= ~0x01;
++                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+ 
+-                      /* Wait 1ms */
+-                      mdelay(1);
++                              /* Wait 1ms */
++                              mdelay(1);
+ 
+-                      /* Reread status */
+-                      byte = read8(sata_bar5 + 0x128 + 0x80 * i);
+-                      printk(BIOS_SPEW, "SATA port %i status = %x\n", i, 
byte);
+-                      byte &= 0xF;
+-              }
++                              /* Reread status */
++                              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
++                              printk(BIOS_SPEW, "SATA port %i status = %x\n", 
i, byte);
++                              byte &= 0xF;
++                      }
+ 
+-              if (byte == 0x3) {
+-                      for (j = 0; j < 10; j++) {
+-                              if (!sata_drive_detect(i, ((i / 2) == 0) ? 
sata_bar0 : sata_bar2))
+-                                      break;
++                      if (byte == 0x3) {
++                              for (j = 0; j < 10; j++) {
++                                      if (i < 4)
++                                              current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
++                                      else
++                                              current_bar = ide_bar0;
++                                      if (!sata_drive_detect(i, current_bar))
++                                              break;
++                              }
++                              printk(BIOS_DEBUG, "%s %s device is %sready 
after %i tries\n",
++                                              (i / 2) ? "Secondary" : 
"Primary",
++                                              (i % 2 ) ? "Slave" : "Master",
++                                              (j == 10) ? "not " : "",
++                                              (j == 10) ? j : j + 1);
++                      } else {
++                              printk(BIOS_DEBUG, "No %s %s SATA drive on 
Slot%i\n",
++                                              (i / 2) ? "Secondary" : 
"Primary",
++                                              (i % 2 ) ? "Slave" : "Master", 
i);
+                       }
+-                      printk(BIOS_DEBUG, "%s %s device is %sready after %i 
tries\n",
+-                                      (i / 2) ? "Secondary" : "Primary",
+-                                      (i % 2 ) ? "Slave" : "Master",
+-                                      (j == 10) ? "not " : "",
+-                                      (j == 10) ? j : j + 1);
+-              } else {
+-                      printk(BIOS_DEBUG, "No %s %s SATA drive on Slot%i\n",
+-                                      (i / 2) ? "Secondary" : "Primary",
+-                                      (i % 2 ) ? "Slave" : "Master", i);
+               }
+       }
+ 
+@@ -256,13 +338,15 @@ static void sata_init(struct device *dev)
+       byte |= 1 << 1;
+       write8((sata_bar5 + 0x4), byte);
+ 
+-      /* Clear error status */
+-      write32((sata_bar5 + 0x130), 0xFFFFFFFF);
+-      write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
+-      write32((sata_bar5 + 0x230), 0xFFFFFFFF);
+-      write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
+-      write32((sata_bar5 + 0x330), 0xFFFFFFFF);
+-      write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
++      if (!sata_ahci_mode) {
++              /* Clear error status */
++              write32((sata_bar5 + 0x130), 0xFFFFFFFF);
++              write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
++              write32((sata_bar5 + 0x230), 0xFFFFFFFF);
++              write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
++              write32((sata_bar5 + 0x330), 0xFFFFFFFF);
++              write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
++      }
+ 
+       /* Clear SATA status,Firstly we get the AcpiGpe0BlkAddr */
+       /* ????? why CIM does not set the AcpiGpe0BlkAddr , but use it??? */
+@@ -293,3 +377,15 @@ static const struct pci_driver sata0_driver __pci_driver 
= {
+       .vendor = PCI_VENDOR_ID_ATI,
+       .device = PCI_DEVICE_ID_ATI_SB700_SATA,
+ };
++
++static const struct pci_driver sata1_driver __pci_driver = {
++      .ops = &sata_ops,
++      .vendor = PCI_VENDOR_ID_ATI,
++      .device = PCI_DEVICE_ID_ATI_SB700_SATA_AHCI,
++};
++
++static const struct pci_driver sata2_driver __pci_driver = {
++      .ops = &sata_ops,
++      .vendor = PCI_VENDOR_ID_ATI,
++      .device = PCI_DEVICE_ID_ATI_SB700_SATA_AHCI_AMD,
++};
+diff --git a/src/southbridge/amd/sb800/fadt.c 
b/src/southbridge/amd/sb800/fadt.c
+index 30b4496..5eb83d7 100644
+--- a/src/southbridge/amd/sb800/fadt.c
++++ b/src/southbridge/amd/sb800/fadt.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0050-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
 
b/resources/libreboot/patch/kgpe-d16/0050-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
new file mode 100644
index 0000000..6788b6f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0050-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch
@@ -0,0 +1,49 @@
+From b67e436ab3de506fe4421ccd2bd2e50f0e3ad652 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 9 Jun 2015 18:57:23 -0500
+Subject: [PATCH 050/143] mainboard/asus/kgpe-d16: Properly initialize SB700
+ SATA PHYs
+
+Change-Id: I5323462dcb8a4e84786be38cc85070eb48d4a31d
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/mainboard.c |   23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c 
b/src/mainboard/asus/kgpe-d16/mainboard.c
+index 47ede34..8de6f26 100644
+--- a/src/mainboard/asus/kgpe-d16/mainboard.c
++++ b/src/mainboard/asus/kgpe-d16/mainboard.c
+@@ -76,6 +76,29 @@ static void mainboard_enable(device_t dev)
+       /* get_ide_dma66(); */
+ }
+ 
++/* override the default SATA PHY setup */
++void sb7xx_51xx_setup_sata_phys(struct device *dev)
++{
++      /* RPR7.6.1 Program the PHY Global Control to 0x2C00 */
++      pci_write_config16(dev, 0x86, 0x2c00);
++
++      /* RPR7.6.2 SATA GENI PHY ports setting */
++      pci_write_config32(dev, 0x88, 0x01b48016);
++      pci_write_config32(dev, 0x8c, 0x01b48016);
++      pci_write_config32(dev, 0x90, 0x01b48016);
++      pci_write_config32(dev, 0x94, 0x01b48016);
++      pci_write_config32(dev, 0x98, 0x01b48016);
++      pci_write_config32(dev, 0x9c, 0x01b48016);
++
++      /* RPR7.6.3 SATA GEN II PHY port setting for port [0~5]. */
++      pci_write_config16(dev, 0xa0, 0xa07a);
++      pci_write_config16(dev, 0xa2, 0xa07a);
++      pci_write_config16(dev, 0xa4, 0xa07a);
++      pci_write_config16(dev, 0xa6, 0xa07a);
++      pci_write_config16(dev, 0xa8, 0xa07a);
++      pci_write_config16(dev, 0xaa, 0xa07a);
++}
++
+ struct chip_operations mainboard_ops = {
+       .enable_dev = mainboard_enable,
+ };
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0050-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
 
b/resources/libreboot/patch/kgpe-d16/0050-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
deleted file mode 100644
index 8bc23ec..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0050-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From 77b9c8b935e51ba8eb779fcf050f8ac407d0c4f3 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 9 Jun 2015 19:12:35 -0500
-Subject: [PATCH 050/139] southbridge/amd/sb700: Disable broken SATA MSI
- functionality
-
-Change-Id: I4e0a52eb90910604f8640ad7533b5d71be6c8e20
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/early_setup.c | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
-index a06a72f..da03961 100644
---- a/src/southbridge/amd/sb700/early_setup.c
-+++ b/src/southbridge/amd/sb700/early_setup.c
-@@ -678,6 +678,7 @@ static void sb700_pci_cfg(void)
- {
-       device_t dev;
-       u8 byte;
-+      uint8_t acpi_s1_supported = 1;
- 
-       /* SMBus Device, BDF:0-20-0 */
-       dev = pci_locate_device(PCI_ID(0x1002, 0x4385), 0);
-@@ -730,10 +731,10 @@ static void sb700_pci_cfg(void)
-       byte = pci_read_config8(dev, 0x40);
-       byte |= 1 << 0;
-       pci_write_config8(dev, 0x40, byte);
--      if (get_sb700_revision(pci_locate_device(PCI_ID(0x1002, 0x4385), 0)) <= 
0x12)
--              pci_write_config8(dev, 0x34, 0x70); /* set 0x61 to 0x70 if S1 
is not supported. */
-+      if (acpi_s1_supported)
-+              pci_write_config8(dev, 0x34, 0x70);     /* Hide D3 power state 
and MSI capabilities */
-       else
--              pci_write_config8(dev, 0x34, 0x50); /* set 0x61 to 0x50 if S1 
is not supported. */
-+              pci_write_config8(dev, 0x61, 0x70);     /* Hide MSI capability 
*/
-       byte &= ~(1 << 0);
-       pci_write_config8(dev, 0x40, byte);
- }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
 
b/resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
new file mode 100644
index 0000000..98ef19d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch
@@ -0,0 +1,41 @@
+From 178c14e07187ad4315db638af03fb6593f147c4f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 9 Jun 2015 19:12:35 -0500
+Subject: [PATCH 051/143] southbridge/amd/sb700: Disable broken SATA MSI
+ functionality
+
+Change-Id: I4e0a52eb90910604f8640ad7533b5d71be6c8e20
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/early_setup.c |    7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
+index a06a72f..da03961 100644
+--- a/src/southbridge/amd/sb700/early_setup.c
++++ b/src/southbridge/amd/sb700/early_setup.c
+@@ -678,6 +678,7 @@ static void sb700_pci_cfg(void)
+ {
+       device_t dev;
+       u8 byte;
++      uint8_t acpi_s1_supported = 1;
+ 
+       /* SMBus Device, BDF:0-20-0 */
+       dev = pci_locate_device(PCI_ID(0x1002, 0x4385), 0);
+@@ -730,10 +731,10 @@ static void sb700_pci_cfg(void)
+       byte = pci_read_config8(dev, 0x40);
+       byte |= 1 << 0;
+       pci_write_config8(dev, 0x40, byte);
+-      if (get_sb700_revision(pci_locate_device(PCI_ID(0x1002, 0x4385), 0)) <= 
0x12)
+-              pci_write_config8(dev, 0x34, 0x70); /* set 0x61 to 0x70 if S1 
is not supported. */
++      if (acpi_s1_supported)
++              pci_write_config8(dev, 0x34, 0x70);     /* Hide D3 power state 
and MSI capabilities */
+       else
+-              pci_write_config8(dev, 0x34, 0x50); /* set 0x61 to 0x50 if S1 
is not supported. */
++              pci_write_config8(dev, 0x61, 0x70);     /* Hide MSI capability 
*/
+       byte &= ~(1 << 0);
+       pci_write_config8(dev, 0x40, byte);
+ }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
 
b/resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
deleted file mode 100644
index e2dda8b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0051-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
+++ /dev/null
@@ -1,93 +0,0 @@
-From 2480454b78d3ad98e1107f07bcd8175b80b69219 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 9 Jun 2015 19:34:16 -0500
-Subject: [PATCH 051/139] southbridge/amd/sb700: Indicate iSATA/eSATA port type
-
-Change-Id: I8ee757d07c82c151b36def6b709163ff144d244f
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/mainboard.c | 16 ++++++++++++++++
- src/southbridge/amd/sb700/sata.c        | 19 +++++++++++++++++++
- src/southbridge/amd/sb700/sb700.h       |  1 +
- 3 files changed, 36 insertions(+)
-
-diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c 
b/src/mainboard/asus/kgpe-d16/mainboard.c
-index 8de6f26..77e55db 100644
---- a/src/mainboard/asus/kgpe-d16/mainboard.c
-+++ b/src/mainboard/asus/kgpe-d16/mainboard.c
-@@ -99,6 +99,22 @@ void sb7xx_51xx_setup_sata_phys(struct device *dev)
-       pci_write_config16(dev, 0xaa, 0xa07a);
- }
- 
-+/* override the default SATA port setup */
-+void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5)
-+{
-+      uint32_t dword;
-+
-+      /* RPR7.9 Program Port Indication Registers */
-+      dword = read32(sata_bar5 + 0xf8);
-+      dword &= ~(0x3f << 12); /* All ports are iSATA */
-+      dword &= ~0x3f;
-+      write32(sata_bar5 + 0xf8, dword);
-+
-+      dword = read32(sata_bar5 + 0xfc);
-+      dword &= ~(0x1 << 20);  /* No eSATA ports are present */
-+      write32(sata_bar5 + 0xfc, dword);
-+}
-+
- struct chip_operations mainboard_ops = {
-       .enable_dev = mainboard_enable,
- };
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index d97288a..d35f84d 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -78,6 +78,23 @@ void __attribute__((weak)) 
sb7xx_51xx_setup_sata_phys(struct device *dev)
-       pci_write_config16(dev, 0xaa, 0xA07A);
- }
- 
-+/* This function can be overloaded in mainboard.c */
-+void __attribute__((weak)) sb7xx_51xx_setup_sata_port_indication(void 
*sata_bar5)
-+{
-+      uint32_t dword;
-+
-+      /* RPR7.9 Program Port Indication Registers */
-+      dword = read32(sata_bar5 + 0xf8);
-+      dword &= ~(0x3f << 12); /* Ports 0 and 1 are eSATA */
-+      dword |= (0x3 << 12);
-+      dword &= ~0x3f;
-+      write32(sata_bar5 + 0xf8, dword);
-+
-+      dword = read32(sata_bar5 + 0xfc);
-+      dword |= 0x1 << 20;     /* At least one eSATA port is present */
-+      write32(sata_bar5 + 0xfc, dword);
-+}
-+
- static void sata_init(struct device *dev)
- {
-       u8 byte;
-@@ -248,7 +265,9 @@ static void sata_init(struct device *dev)
-       /* Program the watchdog counter to 0x10 */
-       byte = 0x10;
-       pci_write_config8(dev, 0x46, byte);
-+
-       sb7xx_51xx_setup_sata_phys(dev);
-+      sb7xx_51xx_setup_sata_port_indication(sata_bar5);
- 
-       /* Enable the I/O, MM, BusMaster access for SATA */
-       byte = pci_read_config8(dev, 0x4);
-diff --git a/src/southbridge/amd/sb700/sb700.h 
b/src/southbridge/amd/sb700/sb700.h
-index 941a4fd..8f792e7 100644
---- a/src/southbridge/amd/sb700/sb700.h
-+++ b/src/southbridge/amd/sb700/sb700.h
-@@ -74,6 +74,7 @@ void sb7xx_51xx_before_pci_init(void);
- #include <device/pci.h>
- /* allow override in mainboard.c */
- void sb7xx_51xx_setup_sata_phys(struct device *dev);
-+void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5);
- 
- #endif
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0052-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
 
b/resources/libreboot/patch/kgpe-d16/0052-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
deleted file mode 100644
index 909f3df..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0052-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-From f12fffe558a4ffd6ea77eadac08a2292ce2d8c96 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Wed, 10 Jun 2015 00:35:05 -0500
-Subject: [PATCH 052/139] northbridge/amd/amdfam10: Add ability to set maximum
- P-state limit
-
-Change-Id: Ifdbb1ad11a856f855c59702ae0ee99e95b08520e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/cmos.default    |  1 +
- src/mainboard/asus/kgpe-d16/cmos.layout     |  3 ++-
- src/northbridge/amd/amdfam10/misc_control.c | 24 ++++++++++++++++++++----
- 3 files changed, 23 insertions(+), 5 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index 5bfaadd..a52b7fa 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -17,6 +17,7 @@ interleave_memory_channels = Enable
- cpu_c_states = Enable
- cpu_cc6_state = Enable
- sata_ahci_mode = Enable
-+maximum_p_state_limit = 0xf
- ieee1394 = Enable
- power_on_after_fail = On
- boot_option = Fallback
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index 247fd7b..307bddc 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -46,7 +46,8 @@ entries
- 465          1       e       1        cpu_c_states
- 466          1       e       1        cpu_cc6_state
- 467          1       e       1        sata_ahci_mode
--468          1       r       0        allow_spd_nvram_cache_restore
-+468          4       h       0        maximum_p_state_limit
-+473          1       r       0        allow_spd_nvram_cache_restore
- 477          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
-diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
-index 8777e8f..703ae51 100644
---- a/src/northbridge/amd/amdfam10/misc_control.c
-+++ b/src/northbridge/amd/amdfam10/misc_control.c
-@@ -124,16 +124,32 @@ static void mcf3_set_resources(device_t dev)
- 
- static void misc_control_init(struct device *dev)
- {
--      u32 cmd;
-+      uint32_t dword;
-+      uint8_t nvram;
-+      uint8_t boost_limit;
-+      uint8_t current_boost;
- 
-       printk(BIOS_DEBUG, "NB: Function 3 Misc Control.. ");
- 
-       /* Disable Machine checks from Invalid Locations.
-        * This is needed for PC backwards compatibility.
-        */
--      cmd = pci_read_config32(dev, 0x44);
--      cmd |= (1<<6) | (1<<25);
--      pci_write_config32(dev, 0x44, cmd );
-+      dword = pci_read_config32(dev, 0x44);
-+      dword |= (1<<6) | (1<<25);
-+      pci_write_config32(dev, 0x44, dword);
-+
-+      boost_limit = 0xf;
-+      if (get_option(&nvram, "maximum_p_state_limit") == CB_SUCCESS)
-+              boost_limit = nvram & 0xf;
-+
-+      /* Set P-state maximum value */
-+      dword = pci_read_config32(dev, 0xdc);
-+      current_boost = (dword >> 8) & 0x7;
-+      if (boost_limit > current_boost)
-+              boost_limit = current_boost;
-+      dword &= ~(0x7 << 8);
-+      dword |= (boost_limit & 0x7) << 8;
-+      pci_write_config32(dev, 0xdc, dword);
- 
-       printk(BIOS_DEBUG, "done.\n");
- }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0052-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
 
b/resources/libreboot/patch/kgpe-d16/0052-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
new file mode 100644
index 0000000..a53e25e
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0052-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch
@@ -0,0 +1,94 @@
+From 0092df93ab131ead3c4f738e35a8371c603f9f83 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 9 Jun 2015 19:34:16 -0500
+Subject: [PATCH 052/143] southbridge/amd/sb700: Indicate iSATA/eSATA port
+ type
+
+Change-Id: I8ee757d07c82c151b36def6b709163ff144d244f
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/mainboard.c |   16 ++++++++++++++++
+ src/southbridge/amd/sb700/sata.c        |   19 +++++++++++++++++++
+ src/southbridge/amd/sb700/sb700.h       |    1 +
+ 3 files changed, 36 insertions(+)
+
+diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c 
b/src/mainboard/asus/kgpe-d16/mainboard.c
+index 8de6f26..77e55db 100644
+--- a/src/mainboard/asus/kgpe-d16/mainboard.c
++++ b/src/mainboard/asus/kgpe-d16/mainboard.c
+@@ -99,6 +99,22 @@ void sb7xx_51xx_setup_sata_phys(struct device *dev)
+       pci_write_config16(dev, 0xaa, 0xa07a);
+ }
+ 
++/* override the default SATA port setup */
++void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5)
++{
++      uint32_t dword;
++
++      /* RPR7.9 Program Port Indication Registers */
++      dword = read32(sata_bar5 + 0xf8);
++      dword &= ~(0x3f << 12); /* All ports are iSATA */
++      dword &= ~0x3f;
++      write32(sata_bar5 + 0xf8, dword);
++
++      dword = read32(sata_bar5 + 0xfc);
++      dword &= ~(0x1 << 20);  /* No eSATA ports are present */
++      write32(sata_bar5 + 0xfc, dword);
++}
++
+ struct chip_operations mainboard_ops = {
+       .enable_dev = mainboard_enable,
+ };
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index d97288a..d35f84d 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -78,6 +78,23 @@ void __attribute__((weak)) 
sb7xx_51xx_setup_sata_phys(struct device *dev)
+       pci_write_config16(dev, 0xaa, 0xA07A);
+ }
+ 
++/* This function can be overloaded in mainboard.c */
++void __attribute__((weak)) sb7xx_51xx_setup_sata_port_indication(void 
*sata_bar5)
++{
++      uint32_t dword;
++
++      /* RPR7.9 Program Port Indication Registers */
++      dword = read32(sata_bar5 + 0xf8);
++      dword &= ~(0x3f << 12); /* Ports 0 and 1 are eSATA */
++      dword |= (0x3 << 12);
++      dword &= ~0x3f;
++      write32(sata_bar5 + 0xf8, dword);
++
++      dword = read32(sata_bar5 + 0xfc);
++      dword |= 0x1 << 20;     /* At least one eSATA port is present */
++      write32(sata_bar5 + 0xfc, dword);
++}
++
+ static void sata_init(struct device *dev)
+ {
+       u8 byte;
+@@ -248,7 +265,9 @@ static void sata_init(struct device *dev)
+       /* Program the watchdog counter to 0x10 */
+       byte = 0x10;
+       pci_write_config8(dev, 0x46, byte);
++
+       sb7xx_51xx_setup_sata_phys(dev);
++      sb7xx_51xx_setup_sata_port_indication(sata_bar5);
+ 
+       /* Enable the I/O, MM, BusMaster access for SATA */
+       byte = pci_read_config8(dev, 0x4);
+diff --git a/src/southbridge/amd/sb700/sb700.h 
b/src/southbridge/amd/sb700/sb700.h
+index 941a4fd..8f792e7 100644
+--- a/src/southbridge/amd/sb700/sb700.h
++++ b/src/southbridge/amd/sb700/sb700.h
+@@ -74,6 +74,7 @@ void sb7xx_51xx_before_pci_init(void);
+ #include <device/pci.h>
+ /* allow override in mainboard.c */
+ void sb7xx_51xx_setup_sata_phys(struct device *dev);
++void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5);
+ 
+ #endif
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
 
b/resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
new file mode 100644
index 0000000..7f45663
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch
@@ -0,0 +1,84 @@
+From 1103d319eede186dc340a9c1701432f3ff33c468 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Wed, 10 Jun 2015 00:35:05 -0500
+Subject: [PATCH 053/143] northbridge/amd/amdfam10: Add ability to set maximum
+ P-state limit
+
+Change-Id: Ifdbb1ad11a856f855c59702ae0ee99e95b08520e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.default    |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout     |    3 ++-
+ src/northbridge/amd/amdfam10/misc_control.c |   24 ++++++++++++++++++++----
+ 3 files changed, 23 insertions(+), 5 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index 5bfaadd..a52b7fa 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -17,6 +17,7 @@ interleave_memory_channels = Enable
+ cpu_c_states = Enable
+ cpu_cc6_state = Enable
+ sata_ahci_mode = Enable
++maximum_p_state_limit = 0xf
+ ieee1394 = Enable
+ power_on_after_fail = On
+ boot_option = Fallback
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 247fd7b..307bddc 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -46,7 +46,8 @@ entries
+ 465          1       e       1        cpu_c_states
+ 466          1       e       1        cpu_cc6_state
+ 467          1       e       1        sata_ahci_mode
+-468          1       r       0        allow_spd_nvram_cache_restore
++468          4       h       0        maximum_p_state_limit
++473          1       r       0        allow_spd_nvram_cache_restore
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
+index 8777e8f..703ae51 100644
+--- a/src/northbridge/amd/amdfam10/misc_control.c
++++ b/src/northbridge/amd/amdfam10/misc_control.c
+@@ -124,16 +124,32 @@ static void mcf3_set_resources(device_t dev)
+ 
+ static void misc_control_init(struct device *dev)
+ {
+-      u32 cmd;
++      uint32_t dword;
++      uint8_t nvram;
++      uint8_t boost_limit;
++      uint8_t current_boost;
+ 
+       printk(BIOS_DEBUG, "NB: Function 3 Misc Control.. ");
+ 
+       /* Disable Machine checks from Invalid Locations.
+        * This is needed for PC backwards compatibility.
+        */
+-      cmd = pci_read_config32(dev, 0x44);
+-      cmd |= (1<<6) | (1<<25);
+-      pci_write_config32(dev, 0x44, cmd );
++      dword = pci_read_config32(dev, 0x44);
++      dword |= (1<<6) | (1<<25);
++      pci_write_config32(dev, 0x44, dword);
++
++      boost_limit = 0xf;
++      if (get_option(&nvram, "maximum_p_state_limit") == CB_SUCCESS)
++              boost_limit = nvram & 0xf;
++
++      /* Set P-state maximum value */
++      dword = pci_read_config32(dev, 0xdc);
++      current_boost = (dword >> 8) & 0x7;
++      if (boost_limit > current_boost)
++              boost_limit = current_boost;
++      dword &= ~(0x7 << 8);
++      dword |= (boost_limit & 0x7) << 8;
++      pci_write_config32(dev, 0xdc, dword);
+ 
+       printk(BIOS_DEBUG, "done.\n");
+ }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
 
b/resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
deleted file mode 100644
index 2d97530..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0053-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
+++ /dev/null
@@ -1,149 +0,0 @@
-From 5ae82615bbd3e9a7a5f6d7b5c7c203b0a780c554 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Wed, 10 Jun 2015 10:46:17 -0500
-Subject: [PATCH 053/139] northbridge/amd/amdmct: Verify MCT NVRAM options
- before skipping training
-
-Change-Id: If26e5d148a906d63bd1407b8ffa58f08ae6b4275
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |  9 ++++++-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |  2 ++
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 36 ++++++++++++++++++++++++++-
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.h |  3 ++-
- 4 files changed, 47 insertions(+), 3 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 3edce9e..4d7e5aa 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -4126,7 +4126,7 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
- #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-       calculate_and_store_spd_hashes(pMCTstat, pDCTstat);
- 
--      if (load_spd_hashes_from_nvram(pDCTstat) < 0) {
-+      if (load_spd_hashes_from_nvram(pMCTstat, pDCTstat) < 0) {
-               pDCTstat->spd_data.nvram_spd_match = 0;
-       }
-       else {
-@@ -4141,6 +4141,13 @@ static void mct_preInitDCT(struct MCTStatStruc 
*pMCTstat,
-       if (get_option(&nvram, "allow_spd_nvram_cache_restore") == CB_SUCCESS)
-               allow_config_restore = !!nvram;
- 
-+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
-+      if (pMCTstat->nvram_checksum != calculate_nvram_mct_hash())
-+              allow_config_restore = 0;
-+#else
-+      allow_config_restore = 0;
-+#endif
-+
-       if (!allow_config_restore)
-               pDCTstat->spd_data.nvram_spd_match = 0;
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index adf89b2..11555ae 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -301,6 +301,7 @@ struct MCTStatStruc {
-       u32 Sub4GCacheTop;      /* If not zero, the 32-bit top of cacheable 
memory.*/
-       u32 SysLimit;           /* LIMIT[39:8] (system address)*/
-       uint32_t TSCFreq;
-+      uint16_t nvram_checksum;
- } __attribute__((packed));
- 
- 
/*=============================================================================
-@@ -796,6 +797,7 @@ struct amd_s3_persistent_node_data {
- 
- struct amd_s3_persistent_data {
-       struct amd_s3_persistent_node_data node[MAX_NODES_SUPPORTED];
-+      uint16_t nvram_checksum;
- } __attribute__((packed));
- 
- 
/*===============================================================================
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index 1e5c1a0..fe89af1 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -143,6 +143,36 @@ void calculate_spd_hash(uint8_t *spd_data, uint64_t 
*spd_hash)
-       *spd_hash = *spd_hash ^ (*spd_hash << 37);
- }
- 
-+uint16_t calculate_nvram_mct_hash(void)
-+{
-+      uint32_t nvram;
-+      uint16_t ret;
-+
-+      ret = 0;
-+      if (get_option(&nvram, "max_mem_clock") == CB_SUCCESS)
-+              ret |= nvram & 0xf;
-+      if (get_option(&nvram, "minimum_memory_voltage") == CB_SUCCESS)
-+              ret |= (nvram & 0x3) << 4;
-+      if (get_option(&nvram, "ECC_memory") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 6;
-+      if (get_option(&nvram, "ECC_redirection") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 7;
-+      if (get_option(&nvram, "ecc_scrub_rate") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 8;
-+      if (get_option(&nvram, "interleave_chip_selects") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 9;
-+      if (get_option(&nvram, "interleave_nodes") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 10;
-+      if (get_option(&nvram, "interleave_memory_channels") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 11;
-+      if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 12;
-+      if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
-+              ret |= (nvram & 0x1) << 13;
-+
-+      return ret;
-+}
-+
- static struct amd_s3_persistent_data * map_s3nv_in_nvram(void)
- {
-       ssize_t s3nv_offset;
-@@ -173,7 +203,7 @@ static struct amd_s3_persistent_data * 
map_s3nv_in_nvram(void)
- }
- 
- #ifdef __PRE_RAM__
--int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat)
-+int8_t load_spd_hashes_from_nvram(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat)
- {
-       struct amd_s3_persistent_data *persistent_data;
- 
-@@ -184,6 +214,8 @@ int8_t load_spd_hashes_from_nvram(struct DCTStatStruc 
*pDCTstat)
-       memcpy(pDCTstat->spd_data.nvram_spd_hash, 
persistent_data->node[pDCTstat->Node_ID].spd_hash, 
sizeof(pDCTstat->spd_data.nvram_spd_hash));
-       memcpy(pDCTstat->spd_data.nvram_memclk, 
persistent_data->node[pDCTstat->Node_ID].memclk, 
sizeof(pDCTstat->spd_data.nvram_memclk));
- 
-+      pMCTstat->nvram_checksum = persistent_data->nvram_checksum;
-+
-       return 0;
- }
- #endif
-@@ -237,6 +269,8 @@ static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data*
-               for (channel = 0; channel < 2; channel++)
-                       persistent_data->node[node].memclk[channel] = 
mem_info->dct_stat[node].Speed;
- 
-+      persistent_data->nvram_checksum = calculate_nvram_mct_hash();
-+
-       if (restored) {
-               if (mem_info->mct_stat.GStatus & (1 << GSB_ConfigRestored))
-                       *restored = 1;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-index 82f73a7..74922c4 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
-@@ -21,9 +21,10 @@
- #include "mct_d.h"
- 
- void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash);
-+uint16_t calculate_nvram_mct_hash(void);
- 
- #ifdef __PRE_RAM__
--int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat);
-+int8_t load_spd_hashes_from_nvram(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- #endif
- 
- #ifdef __RAMSTAGE__
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0054-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
 
b/resources/libreboot/patch/kgpe-d16/0054-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
new file mode 100644
index 0000000..b7eead1
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0054-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch
@@ -0,0 +1,149 @@
+From fdb1ff9b466c0fb32c019ceeeeefb23e857cf00e Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Wed, 10 Jun 2015 10:46:17 -0500
+Subject: [PATCH 054/143] northbridge/amd/amdmct: Verify MCT NVRAM options
+ before skipping training
+
+Change-Id: If26e5d148a906d63bd1407b8ffa58f08ae6b4275
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |    9 ++++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |    2 ++
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c |   36 ++++++++++++++++++++++++-
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.h |    3 ++-
+ 4 files changed, 47 insertions(+), 3 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 3edce9e..4d7e5aa 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -4126,7 +4126,7 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
+ #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+       calculate_and_store_spd_hashes(pMCTstat, pDCTstat);
+ 
+-      if (load_spd_hashes_from_nvram(pDCTstat) < 0) {
++      if (load_spd_hashes_from_nvram(pMCTstat, pDCTstat) < 0) {
+               pDCTstat->spd_data.nvram_spd_match = 0;
+       }
+       else {
+@@ -4141,6 +4141,13 @@ static void mct_preInitDCT(struct MCTStatStruc 
*pMCTstat,
+       if (get_option(&nvram, "allow_spd_nvram_cache_restore") == CB_SUCCESS)
+               allow_config_restore = !!nvram;
+ 
++#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
++      if (pMCTstat->nvram_checksum != calculate_nvram_mct_hash())
++              allow_config_restore = 0;
++#else
++      allow_config_restore = 0;
++#endif
++
+       if (!allow_config_restore)
+               pDCTstat->spd_data.nvram_spd_match = 0;
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index adf89b2..11555ae 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -301,6 +301,7 @@ struct MCTStatStruc {
+       u32 Sub4GCacheTop;      /* If not zero, the 32-bit top of cacheable 
memory.*/
+       u32 SysLimit;           /* LIMIT[39:8] (system address)*/
+       uint32_t TSCFreq;
++      uint16_t nvram_checksum;
+ } __attribute__((packed));
+ 
+ 
/*=============================================================================
+@@ -796,6 +797,7 @@ struct amd_s3_persistent_node_data {
+ 
+ struct amd_s3_persistent_data {
+       struct amd_s3_persistent_node_data node[MAX_NODES_SUPPORTED];
++      uint16_t nvram_checksum;
+ } __attribute__((packed));
+ 
+ 
/*===============================================================================
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+index 1e5c1a0..fe89af1 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -143,6 +143,36 @@ void calculate_spd_hash(uint8_t *spd_data, uint64_t 
*spd_hash)
+       *spd_hash = *spd_hash ^ (*spd_hash << 37);
+ }
+ 
++uint16_t calculate_nvram_mct_hash(void)
++{
++      uint32_t nvram;
++      uint16_t ret;
++
++      ret = 0;
++      if (get_option(&nvram, "max_mem_clock") == CB_SUCCESS)
++              ret |= nvram & 0xf;
++      if (get_option(&nvram, "minimum_memory_voltage") == CB_SUCCESS)
++              ret |= (nvram & 0x3) << 4;
++      if (get_option(&nvram, "ECC_memory") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 6;
++      if (get_option(&nvram, "ECC_redirection") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 7;
++      if (get_option(&nvram, "ecc_scrub_rate") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 8;
++      if (get_option(&nvram, "interleave_chip_selects") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 9;
++      if (get_option(&nvram, "interleave_nodes") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 10;
++      if (get_option(&nvram, "interleave_memory_channels") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 11;
++      if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 12;
++      if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
++              ret |= (nvram & 0x1) << 13;
++
++      return ret;
++}
++
+ static struct amd_s3_persistent_data * map_s3nv_in_nvram(void)
+ {
+       ssize_t s3nv_offset;
+@@ -173,7 +203,7 @@ static struct amd_s3_persistent_data * 
map_s3nv_in_nvram(void)
+ }
+ 
+ #ifdef __PRE_RAM__
+-int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat)
++int8_t load_spd_hashes_from_nvram(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat)
+ {
+       struct amd_s3_persistent_data *persistent_data;
+ 
+@@ -184,6 +214,8 @@ int8_t load_spd_hashes_from_nvram(struct DCTStatStruc 
*pDCTstat)
+       memcpy(pDCTstat->spd_data.nvram_spd_hash, 
persistent_data->node[pDCTstat->Node_ID].spd_hash, 
sizeof(pDCTstat->spd_data.nvram_spd_hash));
+       memcpy(pDCTstat->spd_data.nvram_memclk, 
persistent_data->node[pDCTstat->Node_ID].memclk, 
sizeof(pDCTstat->spd_data.nvram_memclk));
+ 
++      pMCTstat->nvram_checksum = persistent_data->nvram_checksum;
++
+       return 0;
+ }
+ #endif
+@@ -237,6 +269,8 @@ static void copy_cbmem_spd_data_to_save_variable(struct 
amd_s3_persistent_data*
+               for (channel = 0; channel < 2; channel++)
+                       persistent_data->node[node].memclk[channel] = 
mem_info->dct_stat[node].Speed;
+ 
++      persistent_data->nvram_checksum = calculate_nvram_mct_hash();
++
+       if (restored) {
+               if (mem_info->mct_stat.GStatus & (1 << GSB_ConfigRestored))
+                       *restored = 1;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+index 82f73a7..74922c4 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+@@ -21,9 +21,10 @@
+ #include "mct_d.h"
+ 
+ void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash);
++uint16_t calculate_nvram_mct_hash(void);
+ 
+ #ifdef __PRE_RAM__
+-int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat);
++int8_t load_spd_hashes_from_nvram(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ #endif
+ 
+ #ifdef __RAMSTAGE__
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0054-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
 
b/resources/libreboot/patch/kgpe-d16/0054-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
deleted file mode 100644
index 4bbc1c7..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0054-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
+++ /dev/null
@@ -1,104 +0,0 @@
-From da111dc0736f1101683c5e596fdfed46fd48717d Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 11 Jun 2015 16:14:15 -0500
-Subject: [PATCH 054/139] src/northbridge/amd/amdmct: Add option to override
- bad SPD checksum
-
-Change-Id: Ia743a13348d0a6e5e4dfffa04ed9582e0f7f3dad
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/cmos.default     | 1 +
- src/mainboard/asus/kgpe-d16/cmos.layout      | 7 ++++++-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  | 5 +++--
- src/northbridge/amd/amdmct/wrappers/mcti_d.c | 8 ++++++++
- 4 files changed, 18 insertions(+), 3 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index a52b7fa..73f2a38 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -8,6 +8,7 @@ nmi = Disable
- hypertransport_speed_limit = Auto
- max_mem_clock = DDR3-1600
- minimum_memory_voltage = 1.5V
-+dimm_spd_checksum = Enforce
- ECC_memory = Enable
- ECC_redirection = Enable
- ecc_scrub_rate = 1.28us
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index 307bddc..e91568c 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -47,8 +47,10 @@ entries
- 466          1       e       1        cpu_cc6_state
- 467          1       e       1        sata_ahci_mode
- 468          4       h       0        maximum_p_state_limit
--473          1       r       0        allow_spd_nvram_cache_restore
-+472          2       e       13       dimm_spd_checksum
-+474          1       r       0        allow_spd_nvram_cache_restore
- 477          1       e       1        ieee1394
-+>>>>>>> bed9a97... src/northbridge/amd/amdmct: Add option to override bad SPD 
checksum
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
- # Reserve the extended AMD configuration registers
-@@ -142,6 +144,9 @@ enumerations
- 12    1     1.35V
- 12    2     1.25V
- 12    3     1.15V
-+13    0     Enforce
-+13    1     Ignore
-+13    2     Override
- 
- checksums
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 4d7e5aa..f4859d0 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1449,7 +1449,7 @@ restartinit:
-                       }
-               }
-               if (NodesWmem == 0) {
--                      printk(BIOS_DEBUG, "No Nodes?!\n");
-+                      printk(BIOS_ALERT, "Unable to detect valid memory on 
any nodes.  Halting!\n");
-                       goto fatalexit;
-               }
- 
-@@ -3884,13 +3884,14 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                       read_spd_bytes(pMCTstat, pDCTstat, i);
-                                       crc_status = crcCheck(pDCTstat, i);
-                               }
--                              if (crc_status) { /* CRC is OK */
-+                              if ((crc_status) || (SPDCtrl == 2)) { /* CRC is 
OK */
-                                       byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
-                                       if (byte == JED_DDR3SDRAM) {
-                                               /*Dimm is 'Present'*/
-                                               pDCTstat->DIMMValid |= 1 << i;
-                                       }
-                               } else {
-+                                      printk(BIOS_WARNING, "Node %d DIMM %d: 
SPD checksum invalid\n", pDCTstat->Node_ID, i);
-                                       pDCTstat->DIMMSPDCSE = 1 << i;
-                                       if (SPDCtrl == 0) {
-                                               pDCTstat->ErrStatus |= 1 << 
SB_DIMMChkSum;
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index af34d3b..86a0b14 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -150,6 +150,14 @@ static u16 mctGet_NVbits(u8 index)
-       case NV_SPDCHK_RESTRT:
-               val = 0;        /* Exit current node initialization if any DIMM 
has SPD checksum error */
-               //val = 1;      /* Ignore faulty SPD checksum (DIMM will still 
be disabled), continue current node intialization */
-+              //val = 2;      /* Override faulty SPD checksum (DIMM will be 
enabled), continue current node intialization */
-+
-+              if (get_option(&nvram, "dimm_spd_checksum") == CB_SUCCESS)
-+                      val = nvram & 0x3;
-+
-+              if (val > 2)
-+                      val = 2;
-+
-               break;
-       case NV_DQSTrainCTL:
-               //val = 0;      /*Skip dqs training */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0055-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
 
b/resources/libreboot/patch/kgpe-d16/0055-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
deleted file mode 100644
index 518947d..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0055-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
+++ /dev/null
@@ -1,209 +0,0 @@
-From ffdb5fd36669b7f722d46777f421d4ee37005f1c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 12 Jun 2015 13:32:52 -0500
-Subject: [PATCH 055/139] mainboard/asus/kgpe-d16: Add missing IRQ routing for
- PIKE card
-
-Change-Id: I6eba36dad71a2a2713181382484dc0e0976e1dad
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/dsdt.asl | 74 +++++++++++++++++++++++++++---------
- 1 file changed, 55 insertions(+), 19 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/dsdt.asl 
b/src/mainboard/asus/kgpe-d16/dsdt.asl
-index b6f10d9..bbe445f 100644
---- a/src/mainboard/asus/kgpe-d16/dsdt.asl
-+++ b/src/mainboard/asus/kgpe-d16/dsdt.asl
-@@ -296,13 +296,29 @@ DefinitionBlock (
- 
-                       Name (PR03, Package () {
-                               /* PIC */
-+                              Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x02, LNKG, 0x00 },
-+                              Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 },
-+                      })
-+
-+                      Name (AR03, Package () {
-+                              /* APIC */
-+                              Package (0x04) { 0xFFFF, 0x00, 0x00, 44 },
-+                              Package (0x04) { 0xFFFF, 0x01, 0x00, 45 },
-+                              Package (0x04) { 0xFFFF, 0x02, 0x00, 46 },
-+                              Package (0x04) { 0xFFFF, 0x03, 0x00, 47 },
-+                      })
-+
-+                      Name (PR04, Package () {
-+                              /* PIC */
-                               Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
-                               Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
-                               Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
-                               Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
-                       })
- 
--                      Name (AR03, Package () {
-+                      Name (AR04, Package () {
-                               /* APIC */
-                               Package (0x04) { 0xFFFF, 0x00, 0x00, 48 },
-                               Package (0x04) { 0xFFFF, 0x01, 0x00, 49 },
-@@ -310,7 +326,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, 0x00, 51 },
-                       })
- 
--                      Name (PR04, Package () {
-+                      Name (PR05, Package () {
-                               /* PIC */
-                               Package (0x04) { 0xFFFF, 0x00, LNKH, 0x00 },
-                               Package (0x04) { 0xFFFF, 0x01, LNKE, 0x00 },
-@@ -318,7 +334,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, LNKG, 0x00 },
-                       })
- 
--                      Name (AR04, Package () {
-+                      Name (AR05, Package () {
-                               /* APIC */
-                               Package (0x04) { 0xFFFF, 0x00, 0x00, 47 },
-                               Package (0x04) { 0xFFFF, 0x01, 0x00, 44 },
-@@ -326,7 +342,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, 0x00, 46 },
-                       })
- 
--                      Name (PR05, Package () {
-+                      Name (PR06, Package () {
-                               /* PIC */
-                               Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
-                               Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
-@@ -334,7 +350,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
-                       })
- 
--                      Name (AR05, Package () {
-+                      Name (AR06, Package () {
-                               /* APIC */
-                               Package (0x04) { 0xFFFF, 0x00, 0x00, 32 },
-                               Package (0x04) { 0xFFFF, 0x01, 0x00, 33 },
-@@ -342,7 +358,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, 0x00, 35 },
-                       })
- 
--                      Name (PR06, Package () {
-+                      Name (PR07, Package () {
-                               /* PIC */
-                               Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 },
-                               Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 },
-@@ -350,7 +366,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 },
-                       })
- 
--                      Name (AR06, Package () {
-+                      Name (AR07, Package () {
-                               /* APIC */
-                               Package (0x04) { 0xFFFF, 0x00, 0x00, 36 },
-                               Package (0x04) { 0xFFFF, 0x01, 0x00, 37 },
-@@ -358,7 +374,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, 0x00, 39 },
-                       })
- 
--                      Name (PR07, Package () {
-+                      Name (PR08, Package () {
-                               /* PIC */
-                               Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
-                               Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
-@@ -366,7 +382,7 @@ DefinitionBlock (
-                               Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
-                       })
- 
--                      Name (AR07, Package () {
-+                      Name (AR08, Package () {
-                               /* APIC */
-                               Package (0x04) { 0xFFFF, 0x00, 0x00, 40 },
-                               Package (0x04) { 0xFFFF, 0x01, 0x00, 41 },
-@@ -617,6 +633,26 @@ DefinitionBlock (
-                               }
-                       }
- 
-+                      /* 1:00.0 PIKE */
-+                      Device (PIKE)
-+                      {
-+                              Name (_ADR, 0x00040000)                 // 
_ADR: Address
-+                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
-+                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-+                              {
-+                                      If (PICM) {
-+                                              Return (AR03)
-+                                      } Else {
-+                                              Return (PR03)
-+                                      }
-+                              }
-+                              Device (SLT1)
-+                              {
-+                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
-+                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
-+                              }
-+                      }
-+
-                       /* 3:00.0 PCIe NIC A */
-                       Device (NICA)
-                       {
-@@ -625,9 +661,9 @@ DefinitionBlock (
-                               Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
-                               {
-                                       If (PICM) {
--                                              Return (AR03)
-+                                              Return (AR04)
-                                       } Else {
--                                              Return (PR03)
-+                                              Return (PR04)
-                                       }
-                               }
-                               Device (BDC1)
-@@ -644,9 +680,9 @@ DefinitionBlock (
-                               Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
-                               {
-                                       If (PICM) {
--                                              Return (AR04)
-+                                              Return (AR05)
-                                       } Else {
--                                              Return (PR04)
-+                                              Return (PR05)
-                                       }
-                               }
-                               Device (BDC2)
-@@ -663,9 +699,9 @@ DefinitionBlock (
-                               Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-                               {
-                                       If (PICM) {
--                                              Return (AR05)
-+                                              Return (AR06)
-                                       } Else {
--                                              Return (PR05)
-+                                              Return (PR06)
-                                       }
-                               }
-                               Device (SLT1)
-@@ -683,9 +719,9 @@ DefinitionBlock (
-                               Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-                               {
-                                       If (PICM) {
--                                              Return (AR06)
-+                                              Return (AR07)
-                                       } Else {
--                                              Return (PR06)
-+                                              Return (PR07)
-                                       }
-                               }
-                               Device (SLT1)
-@@ -703,9 +739,9 @@ DefinitionBlock (
-                               Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
-                               {
-                                       If (PICM) {
--                                              Return (AR07)
-+                                              Return (AR08)
-                                       } Else {
--                                              Return (PR07)
-+                                              Return (PR08)
-                                       }
-                               }
-                               Device (SLT1)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0055-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
 
b/resources/libreboot/patch/kgpe-d16/0055-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
new file mode 100644
index 0000000..b41d65e
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0055-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch
@@ -0,0 +1,102 @@
+From 0609ebe6ead8e3024e9ceeba7b46817ff6fc47a8 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 11 Jun 2015 16:14:15 -0500
+Subject: [PATCH 055/143] src/northbridge/amd/amdmct: Add option to override
+ bad SPD checksum
+
+Change-Id: Ia743a13348d0a6e5e4dfffa04ed9582e0f7f3dad
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.default     |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout      |    6 +++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  |    5 +++--
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c |    8 ++++++++
+ 4 files changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index a52b7fa..73f2a38 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -8,6 +8,7 @@ nmi = Disable
+ hypertransport_speed_limit = Auto
+ max_mem_clock = DDR3-1600
+ minimum_memory_voltage = 1.5V
++dimm_spd_checksum = Enforce
+ ECC_memory = Enable
+ ECC_redirection = Enable
+ ecc_scrub_rate = 1.28us
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 307bddc..068eaf4 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -47,7 +47,8 @@ entries
+ 466          1       e       1        cpu_cc6_state
+ 467          1       e       1        sata_ahci_mode
+ 468          4       h       0        maximum_p_state_limit
+-473          1       r       0        allow_spd_nvram_cache_restore
++472          2       e       13       dimm_spd_checksum
++474          1       r       0        allow_spd_nvram_cache_restore
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+@@ -142,6 +143,9 @@ enumerations
+ 12    1     1.35V
+ 12    2     1.25V
+ 12    3     1.15V
++13    0     Enforce
++13    1     Ignore
++13    2     Override
+ 
+ checksums
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 4d7e5aa..f4859d0 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1449,7 +1449,7 @@ restartinit:
+                       }
+               }
+               if (NodesWmem == 0) {
+-                      printk(BIOS_DEBUG, "No Nodes?!\n");
++                      printk(BIOS_ALERT, "Unable to detect valid memory on 
any nodes.  Halting!\n");
+                       goto fatalexit;
+               }
+ 
+@@ -3884,13 +3884,14 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                       read_spd_bytes(pMCTstat, pDCTstat, i);
+                                       crc_status = crcCheck(pDCTstat, i);
+                               }
+-                              if (crc_status) { /* CRC is OK */
++                              if ((crc_status) || (SPDCtrl == 2)) { /* CRC is 
OK */
+                                       byte = 
pDCTstat->spd_data.spd_bytes[i][SPD_TYPE];
+                                       if (byte == JED_DDR3SDRAM) {
+                                               /*Dimm is 'Present'*/
+                                               pDCTstat->DIMMValid |= 1 << i;
+                                       }
+                               } else {
++                                      printk(BIOS_WARNING, "Node %d DIMM %d: 
SPD checksum invalid\n", pDCTstat->Node_ID, i);
+                                       pDCTstat->DIMMSPDCSE = 1 << i;
+                                       if (SPDCtrl == 0) {
+                                               pDCTstat->ErrStatus |= 1 << 
SB_DIMMChkSum;
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index 5ca8eac..3053d58 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -150,6 +150,14 @@ static u16 mctGet_NVbits(u8 index)
+       case NV_SPDCHK_RESTRT:
+               val = 0;        /* Exit current node initialization if any DIMM 
has SPD checksum error */
+               //val = 1;      /* Ignore faulty SPD checksum (DIMM will still 
be disabled), continue current node intialization */
++              //val = 2;      /* Override faulty SPD checksum (DIMM will be 
enabled), continue current node intialization */
++
++              if (get_option(&nvram, "dimm_spd_checksum") == CB_SUCCESS)
++                      val = nvram & 0x3;
++
++              if (val > 2)
++                      val = 2;
++
+               break;
+       case NV_DQSTrainCTL:
+               //val = 0;      /*Skip dqs training */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0056-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
 
b/resources/libreboot/patch/kgpe-d16/0056-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
new file mode 100644
index 0000000..1a0b92a
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0056-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch
@@ -0,0 +1,209 @@
+From a4b96f105cfdefd258e743eebe920b9fc6dd3d24 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 12 Jun 2015 13:32:52 -0500
+Subject: [PATCH 056/143] mainboard/asus/kgpe-d16: Add missing IRQ routing for
+ PIKE card
+
+Change-Id: I6eba36dad71a2a2713181382484dc0e0976e1dad
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/dsdt.asl |   74 +++++++++++++++++++++++++---------
+ 1 file changed, 55 insertions(+), 19 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/dsdt.asl 
b/src/mainboard/asus/kgpe-d16/dsdt.asl
+index b6f10d9..bbe445f 100644
+--- a/src/mainboard/asus/kgpe-d16/dsdt.asl
++++ b/src/mainboard/asus/kgpe-d16/dsdt.asl
+@@ -296,13 +296,29 @@ DefinitionBlock (
+ 
+                       Name (PR03, Package () {
+                               /* PIC */
++                              Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x02, LNKG, 0x00 },
++                              Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 },
++                      })
++
++                      Name (AR03, Package () {
++                              /* APIC */
++                              Package (0x04) { 0xFFFF, 0x00, 0x00, 44 },
++                              Package (0x04) { 0xFFFF, 0x01, 0x00, 45 },
++                              Package (0x04) { 0xFFFF, 0x02, 0x00, 46 },
++                              Package (0x04) { 0xFFFF, 0x03, 0x00, 47 },
++                      })
++
++                      Name (PR04, Package () {
++                              /* PIC */
+                               Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
+                               Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
+                               Package (0x04) { 0xFFFF, 0x02, LNKC, 0x00 },
+                               Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
+                       })
+ 
+-                      Name (AR03, Package () {
++                      Name (AR04, Package () {
+                               /* APIC */
+                               Package (0x04) { 0xFFFF, 0x00, 0x00, 48 },
+                               Package (0x04) { 0xFFFF, 0x01, 0x00, 49 },
+@@ -310,7 +326,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, 0x00, 51 },
+                       })
+ 
+-                      Name (PR04, Package () {
++                      Name (PR05, Package () {
+                               /* PIC */
+                               Package (0x04) { 0xFFFF, 0x00, LNKH, 0x00 },
+                               Package (0x04) { 0xFFFF, 0x01, LNKE, 0x00 },
+@@ -318,7 +334,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, LNKG, 0x00 },
+                       })
+ 
+-                      Name (AR04, Package () {
++                      Name (AR05, Package () {
+                               /* APIC */
+                               Package (0x04) { 0xFFFF, 0x00, 0x00, 47 },
+                               Package (0x04) { 0xFFFF, 0x01, 0x00, 44 },
+@@ -326,7 +342,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, 0x00, 46 },
+                       })
+ 
+-                      Name (PR05, Package () {
++                      Name (PR06, Package () {
+                               /* PIC */
+                               Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
+                               Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
+@@ -334,7 +350,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
+                       })
+ 
+-                      Name (AR05, Package () {
++                      Name (AR06, Package () {
+                               /* APIC */
+                               Package (0x04) { 0xFFFF, 0x00, 0x00, 32 },
+                               Package (0x04) { 0xFFFF, 0x01, 0x00, 33 },
+@@ -342,7 +358,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, 0x00, 35 },
+                       })
+ 
+-                      Name (PR06, Package () {
++                      Name (PR07, Package () {
+                               /* PIC */
+                               Package (0x04) { 0xFFFF, 0x00, LNKE, 0x00 },
+                               Package (0x04) { 0xFFFF, 0x01, LNKF, 0x00 },
+@@ -350,7 +366,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, LNKH, 0x00 },
+                       })
+ 
+-                      Name (AR06, Package () {
++                      Name (AR07, Package () {
+                               /* APIC */
+                               Package (0x04) { 0xFFFF, 0x00, 0x00, 36 },
+                               Package (0x04) { 0xFFFF, 0x01, 0x00, 37 },
+@@ -358,7 +374,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, 0x00, 39 },
+                       })
+ 
+-                      Name (PR07, Package () {
++                      Name (PR08, Package () {
+                               /* PIC */
+                               Package (0x04) { 0xFFFF, 0x00, LNKA, 0x00 },
+                               Package (0x04) { 0xFFFF, 0x01, LNKB, 0x00 },
+@@ -366,7 +382,7 @@ DefinitionBlock (
+                               Package (0x04) { 0xFFFF, 0x03, LNKD, 0x00 },
+                       })
+ 
+-                      Name (AR07, Package () {
++                      Name (AR08, Package () {
+                               /* APIC */
+                               Package (0x04) { 0xFFFF, 0x00, 0x00, 40 },
+                               Package (0x04) { 0xFFFF, 0x01, 0x00, 41 },
+@@ -617,6 +633,26 @@ DefinitionBlock (
+                               }
+                       }
+ 
++                      /* 1:00.0 PIKE */
++                      Device (PIKE)
++                      {
++                              Name (_ADR, 0x00040000)                 // 
_ADR: Address
++                              Name(_PRW, Package () {0x11, 0x04})     // Wake 
from S1-S4
++                              Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
++                              {
++                                      If (PICM) {
++                                              Return (AR03)
++                                      } Else {
++                                              Return (PR03)
++                                      }
++                              }
++                              Device (SLT1)
++                              {
++                                      Name (_ADR, 0xFFFF)                     
// _ADR: Address
++                                      Name(_PRW, Package () {0x0B, 0x04})     
// Wake from S1-S4
++                              }
++                      }
++
+                       /* 3:00.0 PCIe NIC A */
+                       Device (NICA)
+                       {
+@@ -625,9 +661,9 @@ DefinitionBlock (
+                               Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
+                               {
+                                       If (PICM) {
+-                                              Return (AR03)
++                                              Return (AR04)
+                                       } Else {
+-                                              Return (PR03)
++                                              Return (PR04)
+                                       }
+                               }
+                               Device (BDC1)
+@@ -644,9 +680,9 @@ DefinitionBlock (
+                               Method (_PRT, 0, NotSerialized)  // _PRT: PCI 
Routing Table
+                               {
+                                       If (PICM) {
+-                                              Return (AR04)
++                                              Return (AR05)
+                                       } Else {
+-                                              Return (PR04)
++                                              Return (PR05)
+                                       }
+                               }
+                               Device (BDC2)
+@@ -663,9 +699,9 @@ DefinitionBlock (
+                               Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
+                               {
+                                       If (PICM) {
+-                                              Return (AR05)
++                                              Return (AR06)
+                                       } Else {
+-                                              Return (PR05)
++                                              Return (PR06)
+                                       }
+                               }
+                               Device (SLT1)
+@@ -683,9 +719,9 @@ DefinitionBlock (
+                               Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
+                               {
+                                       If (PICM) {
+-                                              Return (AR06)
++                                              Return (AR07)
+                                       } Else {
+-                                              Return (PR06)
++                                              Return (PR07)
+                                       }
+                               }
+                               Device (SLT1)
+@@ -703,9 +739,9 @@ DefinitionBlock (
+                               Method (_PRT, 0, NotSerialized)         // 
_PRT: PCI Routing Table
+                               {
+                                       If (PICM) {
+-                                              Return (AR07)
++                                              Return (AR08)
+                                       } Else {
+-                                              Return (PR07)
++                                              Return (PR08)
+                                       }
+                               }
+                               Device (SLT1)
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0056-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
 
b/resources/libreboot/patch/kgpe-d16/0056-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
deleted file mode 100644
index 6c11daf..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0056-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From b0454d907b46b7d117a8778e18aa01c4258aeb1a Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 12 Jun 2015 19:43:06 -0500
-Subject: [PATCH 056/139] northbridge/amd/amdmct: Fix hang on boot due to
- invalid array access
-
-Change-Id: I47755caf7d2ff59463c817e739f9cb2ddd367c18
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/wrappers/mcti_d.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index 86a0b14..0a31aad 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -344,7 +344,7 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
-       }
- 
- #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
--      for (i = 0; i < 15; i = i + 2) {
-+      for (i = 0; i < MAX_DIMMS_SUPPORTED; i = i + 2) {
-               if (pDCTstat->DIMMValid & (1 << i))
-                       ch1_voltage |= pDCTstat->DimmConfiguredVoltage[i];
-               if (pDCTstat->DIMMValid & (1 << (i + 1)))
-@@ -355,7 +355,7 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
-       for (i = 0; i < 2; i++) {
-               sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[i];
-               highest_rank_count[i] = 0x0;
--              for (dimm = 0; dimm < 8; dimm++) {
-+              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
-                       if (pDCTData->DimmRanks[dimm] > highest_rank_count[i])
-                               highest_rank_count[i] = 
pDCTData->DimmRanks[dimm];
-               }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0057-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
 
b/resources/libreboot/patch/kgpe-d16/0057-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
new file mode 100644
index 0000000..495ee91
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0057-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch
@@ -0,0 +1,37 @@
+From 117171290f9890f7e12f9252bf59e798bc6a8cf3 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 12 Jun 2015 19:43:06 -0500
+Subject: [PATCH 057/143] northbridge/amd/amdmct: Fix hang on boot due to
+ invalid array access
+
+Change-Id: I47755caf7d2ff59463c817e739f9cb2ddd367c18
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index 3053d58..295397a 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -345,7 +345,7 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+ #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
+       uint8_t dimm;
+ 
+-      for (i = 0; i < 15; i = i + 2) {
++      for (i = 0; i < MAX_DIMMS_SUPPORTED; i = i + 2) {
+               if (pDCTstat->DIMMValid & (1 << i))
+                       ch1_voltage |= pDCTstat->DimmConfiguredVoltage[i];
+               if (pDCTstat->DIMMValid & (1 << (i + 1)))
+@@ -355,7 +355,7 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+       for (i = 0; i < 2; i++) {
+               sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[i];
+               highest_rank_count[i] = 0x0;
+-              for (dimm = 0; dimm < 8; dimm++) {
++              for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
+                       if (pDCTData->DimmRanks[dimm] > highest_rank_count[i])
+                               highest_rank_count[i] = 
pDCTData->DimmRanks[dimm];
+               }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0057-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
 
b/resources/libreboot/patch/kgpe-d16/0057-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
deleted file mode 100644
index dc2ad90..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0057-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
+++ /dev/null
@@ -1,85 +0,0 @@
-From c6ad4c2dc41378273147690741de931ca2f292f5 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 12 Jun 2015 19:43:38 -0500
-Subject: [PATCH 057/139] southbridge/amd/sr5650: Fix GPP3a link training in
- higher width modes
-
-Change-Id: I7503ae42eb8bc91411413ef2cc7e7a723df7091a
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sr5650/pcie.c | 51 ++++++++++++++++++++++++++++++++++++---
- 1 file changed, 47 insertions(+), 4 deletions(-)
-
-diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
-index d306b5a..79f2a5f 100644
---- a/src/southbridge/amd/sr5650/pcie.c
-+++ b/src/southbridge/amd/sr5650/pcie.c
-@@ -249,7 +249,7 @@ static void switching_gpp3a_configurations(device_t 
nb_dev, device_t sb_dev)
-               reg |= 0xFF0BAA0;
-               break;
-       default:        /* shouldn't be here. */
--              printk(BIOS_DEBUG, "Warning:gpp3a_configuration is not correct. 
Check you devicetree.cb\n");
-+              printk(BIOS_DEBUG, "Warning:gpp3a_configuration is not correct. 
Check your devicetree.cb\n");
-               break;
-       }
-       nbmisc_write_index(nb_dev, 0x26, reg);
-@@ -722,10 +722,53 @@ void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, 
u32 port)
- 
-               /* check port enable */
-               if (cfg->port_enable & (1 << port)) {
--                      PcieReleasePortTraining(nb_dev, dev, port);
-+                      uint32_t hw_port = port;
-+                      switch (cfg->gpp3a_configuration) {
-+                      case 0x1: /* 4:2:0:0:0:0 */
-+                              if (hw_port == 9)
-+                                      hw_port = 4 + 1;
-+                              break;
-+                      case 0x2: /* 4:1:1:0:0:0 */
-+                              if (hw_port == 9)
-+                                      hw_port = 4 + 1;
-+                              else if (hw_port == 10)
-+                                      hw_port = 4 + 2;
-+                              break;
-+                      case 0xc: /* 2:2:2:0:0:0 */
-+                              if (hw_port == 6)
-+                                      hw_port = 4 + 1;
-+                              else if (hw_port == 9)
-+                                      hw_port = 4 + 2;
-+                              break;
-+                      case 0xa: /* 2:2:1:1:0:0 */
-+                              if (hw_port == 6)
-+                                      hw_port = 4 + 1;
-+                              else if (hw_port == 9)
-+                                      hw_port = 4 + 2;
-+                              else if (hw_port == 10)
-+                                      hw_port = 4 + 3;
-+                              break;
-+                      case 0x4: /* 2:1:1:1:1:0 */
-+                              if (hw_port == 6)
-+                                      hw_port = 4 + 1;
-+                              else if (hw_port == 7)
-+                                      hw_port = 4 + 2;
-+                              else if (hw_port == 9)
-+                                      hw_port = 4 + 3;
-+                              else if (hw_port == 10)
-+                                      hw_port = 4 + 4;
-+                              break;
-+                      case 0xb: /* 1:1:1:1:1:1 */
-+                              break;
-+                      default:  /* shouldn't be here. */
-+                              printk(BIOS_WARNING, "invalid 
gpp3a_configuration\n");
-+                              return;
-+                      }
-+                      PcieReleasePortTraining(nb_dev, dev, hw_port);
-                       if (!(AtiPcieCfg.Config & PCIE_GPP_COMPLIANCE)) {
--                              u8 res = PcieTrainPort(nb_dev, dev, port);
--                              printk(BIOS_DEBUG, "PcieTrainPort port=0x%x 
result=%d\n", port, res);
-+                              u8 res = PcieTrainPort(nb_dev, dev, hw_port);
-+                              printk(BIOS_DEBUG, "PcieTrainPort port=0x%x 
hw_port=0x%x result=%d\n",
-+                                      port, hw_port, res);
-                               if (res) {
-                                       AtiPcieCfg.PortDetect |= 1 << port;
-                               } else {
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
 
b/resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
deleted file mode 100644
index 9466989..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-From fbb842e25841100adff123f3154c3149d241fd30 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 12 Jun 2015 20:08:29 -0500
-Subject: [PATCH 058/139] southbridge/amd/sr5650: Add optional delay after link
- training
-
-Certain devices (such as the LSI SAS 2008 controller) do not
-respond to PCI probes immediately after link training.  If it
-is known that such a device is likely to be installed allow the
-mainboard to insert an appropriate delay.
-
-Change-Id: Ibcd9426628cacd6f88e6e3fcbc2b3eb7e3a92081
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sr5650/chip.h   | 4 ++++
- src/southbridge/amd/sr5650/sr5650.c | 3 +++
- 2 files changed, 7 insertions(+)
-
-diff --git a/src/southbridge/amd/sr5650/chip.h 
b/src/southbridge/amd/sr5650/chip.h
-index 8a68998..d23c614 100644
---- a/src/southbridge/amd/sr5650/chip.h
-+++ b/src/southbridge/amd/sr5650/chip.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -27,6 +28,9 @@ struct southbridge_amd_sr5650_config
-       u8 gpp2_configuration;          /* The configuration of General Purpose 
Port. */
-       u8 gpp3a_configuration;         /* The configuration of General Purpose 
Port. */
-       u16 port_enable;                /* Which port is enabled? 
GPP(2,3,4,5,6,7,9,10,11,12,13) */
-+      uint32_t pcie_settling_time;    /* How long to wait after link training 
for PCI-e devices to
-+                                       * initialize before probing PCI-e 
busses (in microseconds).
-+                                       */
- };
- 
- #endif /* SR5650_CHIP_H */
-diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
-index 75383de..6db1eb1 100644
---- a/src/southbridge/amd/sr5650/sr5650.c
-+++ b/src/southbridge/amd/sr5650/sr5650.c
-@@ -345,6 +345,7 @@ void sr5650_enable(device_t dev)
- {
-       device_t nb_dev = 0, sb_dev = 0;
-       int dev_ind;
-+      struct southbridge_amd_sr5650_config *cfg;
- 
-       printk(BIOS_INFO, "sr5650_enable: dev=%p, VID_DID=0x%x\n", dev, 
get_vid_did(dev));
-       nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-@@ -352,6 +353,7 @@ void sr5650_enable(device_t dev)
-               die("sr5650_enable: CAN NOT FIND SR5650 DEVICE, HALT!\n");
-               /* NOT REACHED */
-       }
-+      cfg = (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
- 
-       /* sb_dev (dev 8) is a bridge that links to southbridge. */
-       sb_dev = dev_find_slot(0, PCI_DEVFN(8, 0));
-@@ -432,6 +434,7 @@ void sr5650_enable(device_t dev)
-       /* Lock HWInit Register after the last device was done */
-       if (dev_ind == 13) {
-               sr56x0_lock_hwinitreg();
-+              udelay(cfg->pcie_settling_time);
-       }
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
 
b/resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
new file mode 100644
index 0000000..dd284cf
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0058-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch
@@ -0,0 +1,85 @@
+From 2b66ecd9eefad11d8f3456784208804f29e53b0b Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 12 Jun 2015 19:43:38 -0500
+Subject: [PATCH 058/143] southbridge/amd/sr5650: Fix GPP3a link training in
+ higher width modes
+
+Change-Id: I7503ae42eb8bc91411413ef2cc7e7a723df7091a
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sr5650/pcie.c |   51 ++++++++++++++++++++++++++++++++++---
+ 1 file changed, 47 insertions(+), 4 deletions(-)
+
+diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
+index d306b5a..79f2a5f 100644
+--- a/src/southbridge/amd/sr5650/pcie.c
++++ b/src/southbridge/amd/sr5650/pcie.c
+@@ -249,7 +249,7 @@ static void switching_gpp3a_configurations(device_t 
nb_dev, device_t sb_dev)
+               reg |= 0xFF0BAA0;
+               break;
+       default:        /* shouldn't be here. */
+-              printk(BIOS_DEBUG, "Warning:gpp3a_configuration is not correct. 
Check you devicetree.cb\n");
++              printk(BIOS_DEBUG, "Warning:gpp3a_configuration is not correct. 
Check your devicetree.cb\n");
+               break;
+       }
+       nbmisc_write_index(nb_dev, 0x26, reg);
+@@ -722,10 +722,53 @@ void sr5650_gpp_sb_init(device_t nb_dev, device_t dev, 
u32 port)
+ 
+               /* check port enable */
+               if (cfg->port_enable & (1 << port)) {
+-                      PcieReleasePortTraining(nb_dev, dev, port);
++                      uint32_t hw_port = port;
++                      switch (cfg->gpp3a_configuration) {
++                      case 0x1: /* 4:2:0:0:0:0 */
++                              if (hw_port == 9)
++                                      hw_port = 4 + 1;
++                              break;
++                      case 0x2: /* 4:1:1:0:0:0 */
++                              if (hw_port == 9)
++                                      hw_port = 4 + 1;
++                              else if (hw_port == 10)
++                                      hw_port = 4 + 2;
++                              break;
++                      case 0xc: /* 2:2:2:0:0:0 */
++                              if (hw_port == 6)
++                                      hw_port = 4 + 1;
++                              else if (hw_port == 9)
++                                      hw_port = 4 + 2;
++                              break;
++                      case 0xa: /* 2:2:1:1:0:0 */
++                              if (hw_port == 6)
++                                      hw_port = 4 + 1;
++                              else if (hw_port == 9)
++                                      hw_port = 4 + 2;
++                              else if (hw_port == 10)
++                                      hw_port = 4 + 3;
++                              break;
++                      case 0x4: /* 2:1:1:1:1:0 */
++                              if (hw_port == 6)
++                                      hw_port = 4 + 1;
++                              else if (hw_port == 7)
++                                      hw_port = 4 + 2;
++                              else if (hw_port == 9)
++                                      hw_port = 4 + 3;
++                              else if (hw_port == 10)
++                                      hw_port = 4 + 4;
++                              break;
++                      case 0xb: /* 1:1:1:1:1:1 */
++                              break;
++                      default:  /* shouldn't be here. */
++                              printk(BIOS_WARNING, "invalid 
gpp3a_configuration\n");
++                              return;
++                      }
++                      PcieReleasePortTraining(nb_dev, dev, hw_port);
+                       if (!(AtiPcieCfg.Config & PCIE_GPP_COMPLIANCE)) {
+-                              u8 res = PcieTrainPort(nb_dev, dev, port);
+-                              printk(BIOS_DEBUG, "PcieTrainPort port=0x%x 
result=%d\n", port, res);
++                              u8 res = PcieTrainPort(nb_dev, dev, hw_port);
++                              printk(BIOS_DEBUG, "PcieTrainPort port=0x%x 
hw_port=0x%x result=%d\n",
++                                      port, hw_port, res);
+                               if (res) {
+                                       AtiPcieCfg.PortDetect |= 1 << port;
+                               } else {
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0059-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
 
b/resources/libreboot/patch/kgpe-d16/0059-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
deleted file mode 100644
index 822d763..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0059-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 64ad6ee510824d3804a38a538f1822e5313eb3a3 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 12 Jun 2015 20:10:58 -0500
-Subject: [PATCH 059/139] mainboard/asus/kgpe-d16: Properly configure SR5690
- southbridge PIKE slot
-
-Change-Id: I2f1373905ffd6460ac3c7c21738e2e2a9aa2e463
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/devicetree.cb | 6 +++---
- 1 file changed, 3 insertions(+), 3 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
-index 18e337e..ada268b 100644
---- a/src/mainboard/asus/kgpe-d16/devicetree.cb
-+++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
-@@ -43,9 +43,9 @@ chip northbridge/amd/amdfam10/root_complex   # Root complex
-                                       end
-                                       register "gpp1_configuration" = "0"     
# Configuration 16:0 default
-                                       register "gpp2_configuration" = "1"     
# Configuration 8:8
--                                      #register "gpp3a_configuration" = "2"   
# Configuration 4:1:1:0:0:0
--                                      register "gpp3a_configuration" = "11"   
# Configuration 1:1:1:1:1:1
--                                      register "port_enable" = "0x3ffc"       
# Enable all ports except 0 and 1
-+                                      register "gpp3a_configuration" = "2"    
# Configuration 4:1:1:0:0:0
-+                                      register "port_enable" = "0x3f1c"       
# Enable all ports except 0, 1, 5, 6, and 7
-+                                      register "pcie_settling_time" = 
"1000000"       # Allow PIKE to be detected / configured
-                               end
-                               chip southbridge/amd/sb700              # 
Secondary southbridge
-                                       device pci 11.0 on end                  
# SATA
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0059-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
 
b/resources/libreboot/patch/kgpe-d16/0059-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
new file mode 100644
index 0000000..e24676d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0059-southbridge-amd-sr5650-Add-optional-delay-after-link.patch
@@ -0,0 +1,71 @@
+From 4e2f99afb90497195aae6491ecf9d931e77dc90d Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 12 Jun 2015 20:08:29 -0500
+Subject: [PATCH 059/143] southbridge/amd/sr5650: Add optional delay after
+ link training
+
+Certain devices (such as the LSI SAS 2008 controller) do not
+respond to PCI probes immediately after link training.  If it
+is known that such a device is likely to be installed allow the
+mainboard to insert an appropriate delay.
+
+Change-Id: Ibcd9426628cacd6f88e6e3fcbc2b3eb7e3a92081
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sr5650/chip.h   |    4 ++++
+ src/southbridge/amd/sr5650/sr5650.c |    3 +++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/src/southbridge/amd/sr5650/chip.h 
b/src/southbridge/amd/sr5650/chip.h
+index 8a68998..d23c614 100644
+--- a/src/southbridge/amd/sr5650/chip.h
++++ b/src/southbridge/amd/sr5650/chip.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -27,6 +28,9 @@ struct southbridge_amd_sr5650_config
+       u8 gpp2_configuration;          /* The configuration of General Purpose 
Port. */
+       u8 gpp3a_configuration;         /* The configuration of General Purpose 
Port. */
+       u16 port_enable;                /* Which port is enabled? 
GPP(2,3,4,5,6,7,9,10,11,12,13) */
++      uint32_t pcie_settling_time;    /* How long to wait after link training 
for PCI-e devices to
++                                       * initialize before probing PCI-e 
busses (in microseconds).
++                                       */
+ };
+ 
+ #endif /* SR5650_CHIP_H */
+diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
+index 75383de..6db1eb1 100644
+--- a/src/southbridge/amd/sr5650/sr5650.c
++++ b/src/southbridge/amd/sr5650/sr5650.c
+@@ -345,6 +345,7 @@ void sr5650_enable(device_t dev)
+ {
+       device_t nb_dev = 0, sb_dev = 0;
+       int dev_ind;
++      struct southbridge_amd_sr5650_config *cfg;
+ 
+       printk(BIOS_INFO, "sr5650_enable: dev=%p, VID_DID=0x%x\n", dev, 
get_vid_did(dev));
+       nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
+@@ -352,6 +353,7 @@ void sr5650_enable(device_t dev)
+               die("sr5650_enable: CAN NOT FIND SR5650 DEVICE, HALT!\n");
+               /* NOT REACHED */
+       }
++      cfg = (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
+ 
+       /* sb_dev (dev 8) is a bridge that links to southbridge. */
+       sb_dev = dev_find_slot(0, PCI_DEVFN(8, 0));
+@@ -432,6 +434,7 @@ void sr5650_enable(device_t dev)
+       /* Lock HWInit Register after the last device was done */
+       if (dev_ind == 13) {
+               sr56x0_lock_hwinitreg();
++              udelay(cfg->pcie_settling_time);
+       }
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0060-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
 
b/resources/libreboot/patch/kgpe-d16/0060-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
new file mode 100644
index 0000000..40a2116
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0060-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch
@@ -0,0 +1,32 @@
+From c3b35b628326f2b6f8b6b8fca8ab744654e8631b Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 12 Jun 2015 20:10:58 -0500
+Subject: [PATCH 060/143] mainboard/asus/kgpe-d16: Properly configure SR5690
+ southbridge PIKE slot
+
+Change-Id: I2f1373905ffd6460ac3c7c21738e2e2a9aa2e463
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/devicetree.cb |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
+index cd22893..8eeb33e 100644
+--- a/src/mainboard/asus/kgpe-d16/devicetree.cb
++++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
+@@ -43,9 +43,9 @@ chip northbridge/amd/amdfam10/root_complex   # Root complex
+                                       end
+                                       register "gpp1_configuration" = "0"     
# Configuration 16:0 default
+                                       register "gpp2_configuration" = "1"     
# Configuration 8:8
+-                                      #register "gpp3a_configuration" = "2"   
# Configuration 4:1:1:0:0:0
+-                                      register "gpp3a_configuration" = "11"   
# Configuration 1:1:1:1:1:1
+-                                      register "port_enable" = "0x3ffc"       
# Enable all ports except 0 and 1
++                                      register "gpp3a_configuration" = "2"    
# Configuration 4:1:1:0:0:0
++                                      register "port_enable" = "0x3f1c"       
# Enable all ports except 0, 1, 5, 6, and 7
++                                      register "pcie_settling_time" = 
"1000000"       # Allow PIKE to be detected / configured
+                               end
+                               chip southbridge/amd/sb700              # 
Secondary southbridge
+                                       device pci 11.0 on end                  
# SATA
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0060-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
 
b/resources/libreboot/patch/kgpe-d16/0060-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
deleted file mode 100644
index 84cd46a..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0060-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
+++ /dev/null
@@ -1,86 +0,0 @@
-From c13f090d6aa84c3537521bdb89cfb8dd10e70006 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 18 Jun 2015 11:48:02 -0500
-Subject: [PATCH 060/139] southbridge/amd/sb700: Add option to disable SATA
- ALPM
-
-Change-Id: I88055cbb4df4d7ba811cef7056c0a6ca2612fcb0
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/cmos.default |  1 +
- src/mainboard/asus/kgpe-d16/cmos.layout  |  8 ++++----
- src/southbridge/amd/sb700/sata.c         | 12 ++++++++++++
- 3 files changed, 17 insertions(+), 4 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index 73f2a38..9b30b00 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -18,6 +18,7 @@ interleave_memory_channels = Enable
- cpu_c_states = Enable
- cpu_cc6_state = Enable
- sata_ahci_mode = Enable
-+sata_alpm = Disable
- maximum_p_state_limit = 0xf
- ieee1394 = Enable
- power_on_after_fail = On
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index e91568c..f705af2 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -46,11 +46,11 @@ entries
- 465          1       e       1        cpu_c_states
- 466          1       e       1        cpu_cc6_state
- 467          1       e       1        sata_ahci_mode
--468          4       h       0        maximum_p_state_limit
--472          2       e       13       dimm_spd_checksum
--474          1       r       0        allow_spd_nvram_cache_restore
-+468          1       e       1        sata_alpm
-+469          4       h       0        maximum_p_state_limit
-+473          2       e       13       dimm_spd_checksum
-+475          1       r       0        allow_spd_nvram_cache_restore
- 477          1       e       1        ieee1394
-->>>>>>> bed9a97... src/northbridge/amd/amdmct: Add option to override bad SPD 
checksum
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
- # Reserve the extended AMD configuration registers
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index d35f84d..b09ae73 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -108,6 +108,7 @@ static void sata_init(struct device *dev)
-       int i, j;
-       uint8_t nvram;
-       uint8_t sata_ahci_mode;
-+      uint8_t sata_alpm_enable;
-       uint8_t port_count;
-       uint8_t max_port_count;
- 
-@@ -115,6 +116,10 @@ static void sata_init(struct device *dev)
-       if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
-               sata_ahci_mode = !!nvram;
- 
-+      sata_alpm_enable = 0;
-+      if (get_option(&nvram, "sata_alpm") == CB_SUCCESS)
-+              sata_alpm_enable = !!nvram;
-+
-       device_t sm_dev;
-       /* SATA SMBus Disable */
-       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
-@@ -233,6 +238,13 @@ static void sata_init(struct device *dev)
-               dword &= ~(0x1 << i);
-       write32(sata_bar5 + 0x0c, dword);
- 
-+      /* Disable ALPM if ALPM support not requested */
-+      if (!sata_alpm_enable) {
-+              dword = read32(sata_bar5 + 0xfc);
-+              dword &= ~(0x1 << 11);  /* Disable ALPM */
-+              write32(sata_bar5 + 0xfc, dword);
-+      }
-+
-       /* Write protect Sub-Class Code */
-       byte = pci_read_config8(dev, 0x40);
-       byte &= ~(1 << 0);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0061-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
 
b/resources/libreboot/patch/kgpe-d16/0061-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
deleted file mode 100644
index d5a3a46..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0061-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 226e682880c316f193d58fc00b31265563c7ac38 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 18 Jun 2015 12:37:08 -0500
-Subject: [PATCH 061/139] mainboard/asus/kgpe-d16: Set SP5100 subtype
-
-Change-Id: If839fd71ed12c1fe27aeab374e242a6855737f5d
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/Kconfig | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-index 75bf0ee..084a412 100644
---- a/src/mainboard/asus/kgpe-d16/Kconfig
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -11,6 +11,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
-       select SOUTHBRIDGE_AMD_SR5650
-       select SOUTHBRIDGE_AMD_SB700
-       select SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
-+      select SOUTHBRIDGE_AMD_SUBTYPE_SP5100
-       select SUPERIO_NUVOTON_NCT5572D
-       select PARALLEL_CPU_INIT
-       select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0061-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
 
b/resources/libreboot/patch/kgpe-d16/0061-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
new file mode 100644
index 0000000..fa54029
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0061-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch
@@ -0,0 +1,84 @@
+From 59fece51e2abd69a5cf5829096d4f2b55ad994bf Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 18 Jun 2015 11:48:02 -0500
+Subject: [PATCH 061/143] southbridge/amd/sb700: Add option to disable SATA
+ ALPM
+
+Change-Id: I88055cbb4df4d7ba811cef7056c0a6ca2612fcb0
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.default |    1 +
+ src/mainboard/asus/kgpe-d16/cmos.layout  |    7 ++++---
+ src/southbridge/amd/sb700/sata.c         |   12 ++++++++++++
+ 3 files changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index 73f2a38..9b30b00 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -18,6 +18,7 @@ interleave_memory_channels = Enable
+ cpu_c_states = Enable
+ cpu_cc6_state = Enable
+ sata_ahci_mode = Enable
++sata_alpm = Disable
+ maximum_p_state_limit = 0xf
+ ieee1394 = Enable
+ power_on_after_fail = On
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 068eaf4..f705af2 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -46,9 +46,10 @@ entries
+ 465          1       e       1        cpu_c_states
+ 466          1       e       1        cpu_cc6_state
+ 467          1       e       1        sata_ahci_mode
+-468          4       h       0        maximum_p_state_limit
+-472          2       e       13       dimm_spd_checksum
+-474          1       r       0        allow_spd_nvram_cache_restore
++468          1       e       1        sata_alpm
++469          4       h       0        maximum_p_state_limit
++473          2       e       13       dimm_spd_checksum
++475          1       r       0        allow_spd_nvram_cache_restore
+ 477          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index d35f84d..b09ae73 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -108,6 +108,7 @@ static void sata_init(struct device *dev)
+       int i, j;
+       uint8_t nvram;
+       uint8_t sata_ahci_mode;
++      uint8_t sata_alpm_enable;
+       uint8_t port_count;
+       uint8_t max_port_count;
+ 
+@@ -115,6 +116,10 @@ static void sata_init(struct device *dev)
+       if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
+               sata_ahci_mode = !!nvram;
+ 
++      sata_alpm_enable = 0;
++      if (get_option(&nvram, "sata_alpm") == CB_SUCCESS)
++              sata_alpm_enable = !!nvram;
++
+       device_t sm_dev;
+       /* SATA SMBus Disable */
+       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+@@ -233,6 +238,13 @@ static void sata_init(struct device *dev)
+               dword &= ~(0x1 << i);
+       write32(sata_bar5 + 0x0c, dword);
+ 
++      /* Disable ALPM if ALPM support not requested */
++      if (!sata_alpm_enable) {
++              dword = read32(sata_bar5 + 0xfc);
++              dword &= ~(0x1 << 11);  /* Disable ALPM */
++              write32(sata_bar5 + 0xfc, dword);
++      }
++
+       /* Write protect Sub-Class Code */
+       byte = pci_read_config8(dev, 0x40);
+       byte &= ~(1 << 0);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0062-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
 
b/resources/libreboot/patch/kgpe-d16/0062-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
new file mode 100644
index 0000000..ceb3f87
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0062-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch
@@ -0,0 +1,26 @@
+From 779dcaaff5ef6b357daa86e1f3f14223f34b9fc3 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 18 Jun 2015 12:37:08 -0500
+Subject: [PATCH 062/143] mainboard/asus/kgpe-d16: Set SP5100 subtype
+
+Change-Id: If839fd71ed12c1fe27aeab374e242a6855737f5d
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/Kconfig |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+index 75bf0ee..084a412 100644
+--- a/src/mainboard/asus/kgpe-d16/Kconfig
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -11,6 +11,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+       select SOUTHBRIDGE_AMD_SR5650
+       select SOUTHBRIDGE_AMD_SB700
+       select SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA
++      select SOUTHBRIDGE_AMD_SUBTYPE_SP5100
+       select SUPERIO_NUVOTON_NCT5572D
+       select PARALLEL_CPU_INIT
+       select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0062-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
 
b/resources/libreboot/patch/kgpe-d16/0062-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
deleted file mode 100644
index 34b14f0..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0062-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 136ca22907a8f16c8cce4d05a208ded2f2f054ac Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 20 Jun 2015 14:40:56 -0500
-Subject: [PATCH 062/139] northbridge/amd/amdmct: Fix crash on startup due to
- NULL pointer access
-
-Change-Id: I47089f2ad886a6fda4e0cd4472efd975bb8e06c5
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/wrappers/mcti_d.c | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index 0a31aad..ce2329d 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -353,11 +353,10 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
- #endif
- 
-       for (i = 0; i < 2; i++) {
--              sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[i];
-               highest_rank_count[i] = 0x0;
-               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
--                      if (pDCTData->DimmRanks[dimm] > highest_rank_count[i])
--                              highest_rank_count[i] = 
pDCTData->DimmRanks[dimm];
-+                      if (pDCTstat->DimmRanks[dimm] > highest_rank_count[i])
-+                              highest_rank_count[i] = 
pDCTstat->DimmRanks[dimm];
-               }
-       }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
 
b/resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
deleted file mode 100644
index da29a67..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
+++ /dev/null
@@ -1,185 +0,0 @@
-From 1900ff138ed07b4cbe30aa4f73cb59b9ec5b4720 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 20 Jun 2015 20:02:49 -0500
-Subject: [PATCH 063/139] northbridge/amd/amdmct: Clear memory before enabling
- ECC
-
-Change-Id: I992e7040520570893ba6a213138dd57bfa14733b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 45 ++++++++------------------
- src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c | 38 +++++++++++++++++++++-
- 2 files changed, 51 insertions(+), 32 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index f4859d0..d8a09f0 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -51,8 +51,6 @@ static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat);
- static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat);
--static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstatA);
- static u8 NodePresent_D(u8 Node);
- static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstatA);
-@@ -1500,10 +1498,11 @@ restartinit:
-               InterleaveChannels_D(pMCTstat, pDCTstatA);
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
--              if (ECCInit_D(pMCTstat, pDCTstatA)) {           /* Setup ECC 
control and ECC check-bits*/
--                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
--                      MCTMemClr_D(pMCTstat,pDCTstatA);
--              }
-+              ECCInit_D(pMCTstat, pDCTstatA);                 /* Setup ECC 
control and ECC check-bits*/
-+
-+              /* mctDoWarmResetMemClr_D(); */
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
-+              MCTMemClr_D(pMCTstat,pDCTstatA);
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-@@ -2094,9 +2093,6 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
- 
-       /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
-       mctHookAfterAnyTraining();
--
--      /* mctDoWarmResetMemClr_D(); */
--      MCTMemClr_D(pMCTstat, pDCTstatA);
- }
- 
- static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
-@@ -2384,26 +2380,6 @@ static void DCTMemClr_Init_D(struct MCTStatStruc 
*pMCTstat,
-       }
- }
- 
--static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstatA)
--{
--      /* Ensures that memory clear has completed on all node.*/
--      u8 Node;
--      struct DCTStatStruc *pDCTstat;
--
--      if (!mctGet_NVbits(NV_DQSTrainCTL)){
--              /* callback to wrapper: mctDoWarmResetMemClr_D */
--      } else {        /* NV_DQSTrainCTL == 1 */
--              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
--                      pDCTstat = pDCTstatA + Node;
--
--                      if (pDCTstat->NodePresent) {
--                              DCTMemClr_Sync_D(pMCTstat, pDCTstat);
--                      }
--              }
--      }
--}
--
- static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat)
- {
-@@ -2424,9 +2400,12 @@ static void DCTMemClr_Sync_D(struct MCTStatStruc 
*pMCTstat,
-               } while (!(val & (1 << Dr_MemClrStatus)));
-       }
- 
--      val = 0x0FE40FC0;               /* BKDG recommended */
-+      if (is_fam15h())
-+              val = 0x0ce00f41;       /* BKDG recommended */
-+      else
-+              val = 0x0fe40fc0;       /* BKDG recommended */
-       val |= MCCH_FlushWrOnStpGnt;    /* Set for S3 */
--      Set_NB32(dev, 0x11C, val);
-+      Set_NB32(dev, 0x11c, val);
- }
- 
- static u8 NodePresent_D(u8 Node)
-@@ -3089,6 +3068,8 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
-       u16 proposedFreq;
-       u16 word;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       /* Get CPU Si Revision defined limit (NPT) */
-       if (is_fam15h())
-               proposedFreq = 933;
-@@ -3113,6 +3094,8 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
-               pDCTstat->PresetmaxFreq = word;
-       }
-       /* Check F3xE8[DdrMaxRate] for maximum DRAM data rate support */
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-index 3a9fecc..918e91e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-@@ -88,6 +88,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-       u32 val;
-       u16 nvbits;
- 
-+      uint32_t dword;
-+      uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED];
-+      uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED];
-+
-       mctHookBeforeECC();
- 
-       /* Construct these booleans, based on setup options, for easy handling
-@@ -111,6 +115,25 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-       nvbits = mctGet_NVbits(NV_DramBKScrub);
-       OF_ScrubCTL |= nvbits;
- 
-+      /* Prevent lockups on DRAM errors during ECC init */
-+      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+              struct DCTStatStruc *pDCTstat;
-+              pDCTstat = pDCTstatA + Node;
-+
-+              if (NodePresent_D(Node)) {
-+                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
-+                      sync_flood_on_dram_err[Node] = (dword >> 30) & 0x1;
-+                      sync_flood_on_any_uc_err[Node] = (dword >> 21) & 0x1;
-+                      dword &= ~(0x1 << 30);
-+                      dword &= ~(0x1 << 21);
-+                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
-+
-+                      /* Clear the RAM before enabling ECC to prevent 
MCE-related lockups */
-+                      DCTMemClr_Init_D(pMCTstat, pDCTstat);
-+                      DCTMemClr_Sync_D(pMCTstat, pDCTstat);
-+              }
-+      }
-+
-       AllECC = 1;
-       MemClrECC = 0;
-       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-@@ -157,7 +180,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                       }       /* Node has Dram */
- 
-                       if (MemClrECC) {
--                              MCTMemClrSync_D(pMCTstat, pDCTstatA);
-+                              DCTMemClr_Sync_D(pMCTstat, pDCTstat);
-                       }
- 
-                       if (pDCTstat->LogicalCPUID & (AMD_DR_GT_D0 | 
AMD_FAM15_ALL)) {
-@@ -170,6 +193,19 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-               }       /* if Node present */
-       }
- 
-+      /* Restore previous MCA error handling settings */
-+      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+              struct DCTStatStruc *pDCTstat;
-+              pDCTstat = pDCTstatA + Node;
-+
-+              if (NodePresent_D(Node)) {
-+                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
-+                      dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
-+                      dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
-+                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
-+              }
-+      }
-+
-       if(AllECC)
-               pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
-       else
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
 
b/resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
new file mode 100644
index 0000000..12f420d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0063-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch
@@ -0,0 +1,33 @@
+From ba0eb2ea4d36eb0ce92b8512c7d5e26dfd2c9bc7 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 20 Jun 2015 14:40:56 -0500
+Subject: [PATCH 063/143] northbridge/amd/amdmct: Fix crash on startup due to
+ NULL pointer access
+
+Change-Id: I47089f2ad886a6fda4e0cd4472efd975bb8e06c5
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c |    5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index 295397a..116fb92 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -353,11 +353,10 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc 
*pDCTstat)
+       }
+ 
+       for (i = 0; i < 2; i++) {
+-              sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[i];
+               highest_rank_count[i] = 0x0;
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
+-                      if (pDCTData->DimmRanks[dimm] > highest_rank_count[i])
+-                              highest_rank_count[i] = 
pDCTData->DimmRanks[dimm];
++                      if (pDCTstat->DimmRanks[dimm] > highest_rank_count[i])
++                              highest_rank_count[i] = 
pDCTstat->DimmRanks[dimm];
+               }
+       }
+ #endif
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0064-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
 
b/resources/libreboot/patch/kgpe-d16/0064-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
new file mode 100644
index 0000000..e444072
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0064-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch
@@ -0,0 +1,185 @@
+From 337818cec631161582a2e65d73cf3e1f9a611bb7 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 20 Jun 2015 20:02:49 -0500
+Subject: [PATCH 064/143] northbridge/amd/amdmct: Clear memory before enabling
+ ECC
+
+Change-Id: I992e7040520570893ba6a213138dd57bfa14733b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |   45 ++++++++----------------
+ src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c |   38 +++++++++++++++++++-
+ 2 files changed, 51 insertions(+), 32 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index f4859d0..d8a09f0 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -51,8 +51,6 @@ static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+ static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat);
+-static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstatA);
+ static u8 NodePresent_D(u8 Node);
+ static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstatA);
+@@ -1500,10 +1498,11 @@ restartinit:
+               InterleaveChannels_D(pMCTstat, pDCTstatA);
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
+-              if (ECCInit_D(pMCTstat, pDCTstatA)) {           /* Setup ECC 
control and ECC check-bits*/
+-                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
+-                      MCTMemClr_D(pMCTstat,pDCTstatA);
+-              }
++              ECCInit_D(pMCTstat, pDCTstatA);                 /* Setup ECC 
control and ECC check-bits*/
++
++              /* mctDoWarmResetMemClr_D(); */
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
++              MCTMemClr_D(pMCTstat,pDCTstatA);
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+@@ -2094,9 +2093,6 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+ 
+       /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+       mctHookAfterAnyTraining();
+-
+-      /* mctDoWarmResetMemClr_D(); */
+-      MCTMemClr_D(pMCTstat, pDCTstatA);
+ }
+ 
+ static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
+@@ -2384,26 +2380,6 @@ static void DCTMemClr_Init_D(struct MCTStatStruc 
*pMCTstat,
+       }
+ }
+ 
+-static void MCTMemClrSync_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstatA)
+-{
+-      /* Ensures that memory clear has completed on all node.*/
+-      u8 Node;
+-      struct DCTStatStruc *pDCTstat;
+-
+-      if (!mctGet_NVbits(NV_DQSTrainCTL)){
+-              /* callback to wrapper: mctDoWarmResetMemClr_D */
+-      } else {        /* NV_DQSTrainCTL == 1 */
+-              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+-                      pDCTstat = pDCTstatA + Node;
+-
+-                      if (pDCTstat->NodePresent) {
+-                              DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+-                      }
+-              }
+-      }
+-}
+-
+ static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+ {
+@@ -2424,9 +2400,12 @@ static void DCTMemClr_Sync_D(struct MCTStatStruc 
*pMCTstat,
+               } while (!(val & (1 << Dr_MemClrStatus)));
+       }
+ 
+-      val = 0x0FE40FC0;               /* BKDG recommended */
++      if (is_fam15h())
++              val = 0x0ce00f41;       /* BKDG recommended */
++      else
++              val = 0x0fe40fc0;       /* BKDG recommended */
+       val |= MCCH_FlushWrOnStpGnt;    /* Set for S3 */
+-      Set_NB32(dev, 0x11C, val);
++      Set_NB32(dev, 0x11c, val);
+ }
+ 
+ static u8 NodePresent_D(u8 Node)
+@@ -3089,6 +3068,8 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
+       u16 proposedFreq;
+       u16 word;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       /* Get CPU Si Revision defined limit (NPT) */
+       if (is_fam15h())
+               proposedFreq = 933;
+@@ -3113,6 +3094,8 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
+               pDCTstat->PresetmaxFreq = word;
+       }
+       /* Check F3xE8[DdrMaxRate] for maximum DRAM data rate support */
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+index 3a9fecc..918e91e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+@@ -88,6 +88,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+       u32 val;
+       u16 nvbits;
+ 
++      uint32_t dword;
++      uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED];
++      uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED];
++
+       mctHookBeforeECC();
+ 
+       /* Construct these booleans, based on setup options, for easy handling
+@@ -111,6 +115,25 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+       nvbits = mctGet_NVbits(NV_DramBKScrub);
+       OF_ScrubCTL |= nvbits;
+ 
++      /* Prevent lockups on DRAM errors during ECC init */
++      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++              struct DCTStatStruc *pDCTstat;
++              pDCTstat = pDCTstatA + Node;
++
++              if (NodePresent_D(Node)) {
++                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
++                      sync_flood_on_dram_err[Node] = (dword >> 30) & 0x1;
++                      sync_flood_on_any_uc_err[Node] = (dword >> 21) & 0x1;
++                      dword &= ~(0x1 << 30);
++                      dword &= ~(0x1 << 21);
++                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
++
++                      /* Clear the RAM before enabling ECC to prevent 
MCE-related lockups */
++                      DCTMemClr_Init_D(pMCTstat, pDCTstat);
++                      DCTMemClr_Sync_D(pMCTstat, pDCTstat);
++              }
++      }
++
+       AllECC = 1;
+       MemClrECC = 0;
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+@@ -157,7 +180,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                       }       /* Node has Dram */
+ 
+                       if (MemClrECC) {
+-                              MCTMemClrSync_D(pMCTstat, pDCTstatA);
++                              DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+                       }
+ 
+                       if (pDCTstat->LogicalCPUID & (AMD_DR_GT_D0 | 
AMD_FAM15_ALL)) {
+@@ -170,6 +193,19 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+               }       /* if Node present */
+       }
+ 
++      /* Restore previous MCA error handling settings */
++      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++              struct DCTStatStruc *pDCTstat;
++              pDCTstat = pDCTstatA + Node;
++
++              if (NodePresent_D(Node)) {
++                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
++                      dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
++                      dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
++                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
++              }
++      }
++
+       if(AllECC)
+               pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
+       else
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0064-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
 
b/resources/libreboot/patch/kgpe-d16/0064-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
deleted file mode 100644
index 17871d0..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0064-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
+++ /dev/null
@@ -1,142 +0,0 @@
-From 8e2c343cbbca40d27e0f50b7d563c5c44020d1da Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 20 Jun 2015 21:31:15 -0500
-Subject: [PATCH 064/139] southbridge/amd/sb700: Do drive detection even in
- AHCI mode
-
-SeaBIOS AHCI drive detection randomly fails for drives present
-on the secondary channel of each AHCI SATA BAR.  Forcing native
-drive detection in AHCI mode resolves this issue.
-
-Change-Id: I34eb1d5d3f2f8aefb749a4eeb911c1373d184938
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/sata.c | 99 +++++++++++++++++++++-------------------
- 1 file changed, 53 insertions(+), 46 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index b09ae73..24f78dd 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -301,65 +301,72 @@ static void sata_init(struct device *dev)
-       if (port_count > max_port_count)
-               port_count = max_port_count;
- 
--      if (!sata_ahci_mode) {
--              /* RPR7.7 SATA drive detection. */
--              /* Use BAR5+0x128,BAR0 for Primary Slave */
--              /* Use BAR5+0x1A8,BAR0 for Primary Slave */
--              /* Use BAR5+0x228,BAR2 for Secondary Master */
--              /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
--              /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary Master 
emulation */
--              /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave 
emulation */
--              for (i = 0; i < port_count; i++) {
-+      /* RPR7.7 SATA drive detection. */
-+      /* Use BAR5+0x128,BAR0 for Primary Slave */
-+      /* Use BAR5+0x1A8,BAR0 for Primary Slave */
-+      /* Use BAR5+0x228,BAR2 for Secondary Master */
-+      /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
-+      /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary Master emulation */
-+      /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave emulation */
-+      for (i = 0; i < port_count; i++) {
-+              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
-+              printk(BIOS_SPEW, "SATA port %i status = %x\n", i, byte);
-+              byte &= 0xF;
-+              if (byte == 0x1) {
-+                      /* If the drive status is 0x1 then we see it but we 
aren't talking to it. */
-+                      /* Try to do something about it. */
-+                      printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
-+
-+                      /* Read in Port-N Serial ATA Control Register */
-+                      byte = read8(sata_bar5 + 0x12C + 0x80 * i);
-+
-+                      /* Set Reset Bit and 1.5g bit */
-+                      byte |= 0x11;
-+                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
-+
-+                      /* Wait 1ms */
-+                      mdelay(1);
-+
-+                      /* Clear Reset Bit */
-+                      byte &= ~0x01;
-+                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
-+
-+                      /* Wait 1ms */
-+                      mdelay(1);
-+
-+                      /* Reread status */
-                       byte = read8(sata_bar5 + 0x128 + 0x80 * i);
-                       printk(BIOS_SPEW, "SATA port %i status = %x\n", i, 
byte);
-                       byte &= 0xF;
--                      if (byte == 0x1) {
--                              /* If the drive status is 0x1 then we see it 
but we aren't talking to it. */
--                              /* Try to do something about it. */
--                              printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
--
--                              /* Read in Port-N Serial ATA Control Register */
--                              byte = read8(sata_bar5 + 0x12C + 0x80 * i);
--
--                              /* Set Reset Bit and 1.5g bit */
--                              byte |= 0x11;
--                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
--
--                              /* Wait 1ms */
--                              mdelay(1);
--
--                              /* Clear Reset Bit */
--                              byte &= ~0x01;
--                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
--
--                              /* Wait 1ms */
--                              mdelay(1);
-+              }
- 
--                              /* Reread status */
--                              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
--                              printk(BIOS_SPEW, "SATA port %i status = %x\n", 
i, byte);
--                              byte &= 0xF;
-+              if (byte == 0x3) {
-+                      for (j = 0; j < 10; j++) {
-+                              if (i < 4)
-+                                      current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
-+                              else
-+                                      current_bar = ide_bar0;
-+                              if (!sata_drive_detect(i, current_bar))
-+                                      break;
-                       }
--
--                      if (byte == 0x3) {
--                              for (j = 0; j < 10; j++) {
--                                      if (i < 4)
--                                              current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
--                                      else
--                                              current_bar = ide_bar0;
--                                      if (!sata_drive_detect(i, current_bar))
--                                              break;
--                              }
-+                      if (sata_ahci_mode)
-+                              printk(BIOS_DEBUG, "AHCI device %d is %sready 
after %i tries\n",
-+                                              i,
-+                                              (j == 10) ? "not " : "",
-+                                              (j == 10) ? j : j + 1);
-+                      else
-                               printk(BIOS_DEBUG, "%s %s device is %sready 
after %i tries\n",
-                                               (i / 2) ? "Secondary" : 
"Primary",
-                                               (i % 2 ) ? "Slave" : "Master",
-                                               (j == 10) ? "not " : "",
-                                               (j == 10) ? j : j + 1);
--                      } else {
-+              } else {
-+                      if (sata_ahci_mode)
-+                              printk(BIOS_DEBUG, "No AHCI SATA drive on 
Slot%i\n", i);
-+                      else
-                               printk(BIOS_DEBUG, "No %s %s SATA drive on 
Slot%i\n",
-                                               (i / 2) ? "Secondary" : 
"Primary",
-                                               (i % 2 ) ? "Slave" : "Master", 
i);
--                      }
-               }
-       }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0065-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
 
b/resources/libreboot/patch/kgpe-d16/0065-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
new file mode 100644
index 0000000..84404e5
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0065-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch
@@ -0,0 +1,142 @@
+From 9f702a6ac2a4106d3e1f88a27f61052ad4b99925 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 20 Jun 2015 21:31:15 -0500
+Subject: [PATCH 065/143] southbridge/amd/sb700: Do drive detection even in
+ AHCI mode
+
+SeaBIOS AHCI drive detection randomly fails for drives present
+on the secondary channel of each AHCI SATA BAR.  Forcing native
+drive detection in AHCI mode resolves this issue.
+
+Change-Id: I34eb1d5d3f2f8aefb749a4eeb911c1373d184938
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/sata.c |   99 ++++++++++++++++++++------------------
+ 1 file changed, 53 insertions(+), 46 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index b09ae73..24f78dd 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -301,65 +301,72 @@ static void sata_init(struct device *dev)
+       if (port_count > max_port_count)
+               port_count = max_port_count;
+ 
+-      if (!sata_ahci_mode) {
+-              /* RPR7.7 SATA drive detection. */
+-              /* Use BAR5+0x128,BAR0 for Primary Slave */
+-              /* Use BAR5+0x1A8,BAR0 for Primary Slave */
+-              /* Use BAR5+0x228,BAR2 for Secondary Master */
+-              /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
+-              /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary Master 
emulation */
+-              /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave 
emulation */
+-              for (i = 0; i < port_count; i++) {
++      /* RPR7.7 SATA drive detection. */
++      /* Use BAR5+0x128,BAR0 for Primary Slave */
++      /* Use BAR5+0x1A8,BAR0 for Primary Slave */
++      /* Use BAR5+0x228,BAR2 for Secondary Master */
++      /* Use BAR5+0x2A8,BAR2 for Secondary Slave */
++      /* Use BAR5+0x328,PATA_BAR0/2 for Primary/Secondary Master emulation */
++      /* Use BAR5+0x3A8,PATA_BAR0/2 for Primary/Secondary Slave emulation */
++      for (i = 0; i < port_count; i++) {
++              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
++              printk(BIOS_SPEW, "SATA port %i status = %x\n", i, byte);
++              byte &= 0xF;
++              if (byte == 0x1) {
++                      /* If the drive status is 0x1 then we see it but we 
aren't talking to it. */
++                      /* Try to do something about it. */
++                      printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
++
++                      /* Read in Port-N Serial ATA Control Register */
++                      byte = read8(sata_bar5 + 0x12C + 0x80 * i);
++
++                      /* Set Reset Bit and 1.5g bit */
++                      byte |= 0x11;
++                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
++
++                      /* Wait 1ms */
++                      mdelay(1);
++
++                      /* Clear Reset Bit */
++                      byte &= ~0x01;
++                      write8((sata_bar5 + 0x12C + 0x80 * i), byte);
++
++                      /* Wait 1ms */
++                      mdelay(1);
++
++                      /* Reread status */
+                       byte = read8(sata_bar5 + 0x128 + 0x80 * i);
+                       printk(BIOS_SPEW, "SATA port %i status = %x\n", i, 
byte);
+                       byte &= 0xF;
+-                      if (byte == 0x1) {
+-                              /* If the drive status is 0x1 then we see it 
but we aren't talking to it. */
+-                              /* Try to do something about it. */
+-                              printk(BIOS_SPEW, "SATA device detected but not 
talking. Trying lower speed.\n");
+-
+-                              /* Read in Port-N Serial ATA Control Register */
+-                              byte = read8(sata_bar5 + 0x12C + 0x80 * i);
+-
+-                              /* Set Reset Bit and 1.5g bit */
+-                              byte |= 0x11;
+-                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+-
+-                              /* Wait 1ms */
+-                              mdelay(1);
+-
+-                              /* Clear Reset Bit */
+-                              byte &= ~0x01;
+-                              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
+-
+-                              /* Wait 1ms */
+-                              mdelay(1);
++              }
+ 
+-                              /* Reread status */
+-                              byte = read8(sata_bar5 + 0x128 + 0x80 * i);
+-                              printk(BIOS_SPEW, "SATA port %i status = %x\n", 
i, byte);
+-                              byte &= 0xF;
++              if (byte == 0x3) {
++                      for (j = 0; j < 10; j++) {
++                              if (i < 4)
++                                      current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
++                              else
++                                      current_bar = ide_bar0;
++                              if (!sata_drive_detect(i, current_bar))
++                                      break;
+                       }
+-
+-                      if (byte == 0x3) {
+-                              for (j = 0; j < 10; j++) {
+-                                      if (i < 4)
+-                                              current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
+-                                      else
+-                                              current_bar = ide_bar0;
+-                                      if (!sata_drive_detect(i, current_bar))
+-                                              break;
+-                              }
++                      if (sata_ahci_mode)
++                              printk(BIOS_DEBUG, "AHCI device %d is %sready 
after %i tries\n",
++                                              i,
++                                              (j == 10) ? "not " : "",
++                                              (j == 10) ? j : j + 1);
++                      else
+                               printk(BIOS_DEBUG, "%s %s device is %sready 
after %i tries\n",
+                                               (i / 2) ? "Secondary" : 
"Primary",
+                                               (i % 2 ) ? "Slave" : "Master",
+                                               (j == 10) ? "not " : "",
+                                               (j == 10) ? j : j + 1);
+-                      } else {
++              } else {
++                      if (sata_ahci_mode)
++                              printk(BIOS_DEBUG, "No AHCI SATA drive on 
Slot%i\n", i);
++                      else
+                               printk(BIOS_DEBUG, "No %s %s SATA drive on 
Slot%i\n",
+                                               (i / 2) ? "Secondary" : 
"Primary",
+                                               (i % 2 ) ? "Slave" : "Master", 
i);
+-                      }
+               }
+       }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0065-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
 
b/resources/libreboot/patch/kgpe-d16/0065-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
deleted file mode 100644
index f63be47..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0065-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 15a27b612b1da36173017dd671763ce455f319ad Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 21 Jun 2015 16:27:03 -0500
-Subject: [PATCH 065/139] src/southbridge/amd/sb700: Reset SATA controller in
- AHCI mode during startup
-
-In AHCI mode SeaBIOS randomly fails to detect disks (AHCI timeouts),
-with the probability of a failure increasing with the number of disks
-connected to the controller.  Resetting the SATA controller appears to
-show the true state of the underlying hardware, allowing the drive
-detection code to attempt link renegotiation as needed.
-
-Change-Id: Ib1f7c5f830a0cdba41cb6f5b05d759adee5ce369
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/sata.c | 47 ++++++++++++++++++++++++++++++----------
- 1 file changed, 35 insertions(+), 12 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index 24f78dd..d51baa1 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -135,6 +135,8 @@ static void sata_init(struct device *dev)
-       /* get rev_id */
-       rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
- 
-+      printk(BIOS_SPEW, "rev_id=%x\n", rev_id);
-+
-       if (sata_ahci_mode) {
-               /* Enable link latency enhancement on A14 and above */
-               if (rev_id >= 0x14) {
-@@ -245,6 +247,27 @@ static void sata_init(struct device *dev)
-               write32(sata_bar5 + 0xfc, dword);
-       }
- 
-+      if (sata_ahci_mode) {
-+              /* FIXME
-+              * SeaBIOS does not know how to spin
-+              * up the drives and therefore hangs
-+              * in AHCI init if this is enabled...
-+              */
-+              /* Enable staggered spin-up */
-+              dword = read32(sata_bar5 + 0x00);
-+#if 0
-+              dword |= 0x1 << 27;
-+#else
-+              dword &= ~(0x1 << 27);
-+#endif
-+              write32(sata_bar5 + 0x00, dword);
-+
-+              /* Reset the HBA to avoid stuck drives in SeaBIOS */
-+              dword = read32(sata_bar5 + 0x04);
-+              dword |= 0x1;
-+              write32(sata_bar5 + 0x04, dword);
-+      }
-+
-       /* Write protect Sub-Class Code */
-       byte = pci_read_config8(dev, 0x40);
-       byte &= ~(1 << 0);
-@@ -371,21 +394,21 @@ static void sata_init(struct device *dev)
-       }
- 
-       /* Below is CIM InitSataLateFar */
--      /* Enable interrupts from the HBA  */
--      byte = read8(sata_bar5 + 0x4);
--      byte |= 1 << 1;
--      write8((sata_bar5 + 0x4), byte);
--
-       if (!sata_ahci_mode) {
--              /* Clear error status */
--              write32((sata_bar5 + 0x130), 0xFFFFFFFF);
--              write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
--              write32((sata_bar5 + 0x230), 0xFFFFFFFF);
--              write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
--              write32((sata_bar5 + 0x330), 0xFFFFFFFF);
--              write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
-+              /* Enable interrupts from the HBA  */
-+              byte = read8(sata_bar5 + 0x4);
-+              byte |= 1 << 1;
-+              write8((sata_bar5 + 0x4), byte);
-       }
- 
-+      /* Clear error status */
-+      write32((sata_bar5 + 0x130), 0xFFFFFFFF);
-+      write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
-+      write32((sata_bar5 + 0x230), 0xFFFFFFFF);
-+      write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
-+      write32((sata_bar5 + 0x330), 0xFFFFFFFF);
-+      write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
-+
-       /* Clear SATA status,Firstly we get the AcpiGpe0BlkAddr */
-       /* ????? why CIM does not set the AcpiGpe0BlkAddr , but use it??? */
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0066-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0066-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
deleted file mode 100644
index 68138ca..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0066-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
+++ /dev/null
@@ -1,163 +0,0 @@
-From c1413dd2277df0bd10fd2faf94302232889e95d8 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 22 Jun 2015 02:21:29 -0500
-Subject: [PATCH 066/139] southbridge/amd/sb700: Recover if AHCI disk detection
- fails
-
-Change-Id: I29051af5eca5d31b6aecc261e9a48028380eccb3
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/sata.c | 83 ++++++++++++++++++++++++++++++++++++----
- 1 file changed, 75 insertions(+), 8 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index d51baa1..ce242c1 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -31,12 +31,15 @@
- static int sata_drive_detect(int portnum, uint16_t iobar)
- {
-       u8 byte, byte2;
-+      u8 byte_prev, byte2_prev;
-       int i = 0;
-+      byte_prev = byte2_prev = 0;
-       outb(0xa0 + 0x10 * (portnum % 2), iobar + 0x6);
-       while (byte = inb(iobar + 0x6), byte2 = inb(iobar + 0x7),
-               (byte != (0xa0 + 0x10 * (portnum % 2))) ||
-               ((byte2 & 0x88) != 0)) {
--              printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
-+              if ((byte != byte_prev) || (byte2 != byte2_prev))
-+                      printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
-               if (byte != (0xa0 + 0x10 * (portnum % 2))) {
-                       /* This will happen at the first iteration of this loop
-                        * if the first SATA port is unpopulated and the
-@@ -45,11 +48,22 @@ static int sata_drive_detect(int portnum, uint16_t iobar)
-                       printk(BIOS_DEBUG, "drive no longer selected after %i 
ms, "
-                               "retrying init\n", i * 10);
-                       return 1;
--              } else
--                      printk(BIOS_SPEW, "drive detection not yet completed, "
--                              "waiting...\n");
-+              } else {
-+                      if (i == 0)
-+                              printk(BIOS_SPEW, "drive detection not yet 
completed, "
-+                                      "waiting...\n");
-+              }
-               mdelay(10);
-               i++;
-+              byte_prev = byte;
-+              byte2_prev = byte2;
-+
-+              /* Detect stuck SATA controller and attempt reset */
-+              if (i > 1024) {
-+                      printk(BIOS_DEBUG, "drive detection not done after %i 
ms, "
-+                              "resetting HBA and retrying init\n", i * 10);
-+                      return 2;
-+              }
-       }
-       printk(BIOS_SPEW, "drive detection done after %i ms\n", i * 10);
-       return 0;
-@@ -105,12 +119,13 @@ static void sata_init(struct device *dev)
-       uint16_t sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
-       uint16_t ide_bar0, ide_bar1, ide_bar2, ide_bar3;
-       uint16_t current_bar;
--      int i, j;
-+      int i, j, ret;
-       uint8_t nvram;
-       uint8_t sata_ahci_mode;
-       uint8_t sata_alpm_enable;
-       uint8_t port_count;
-       uint8_t max_port_count;
-+      uint8_t hba_reset_count;
- 
-       sata_ahci_mode = 0;
-       if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
-@@ -124,14 +139,23 @@ static void sata_init(struct device *dev)
-       /* SATA SMBus Disable */
-       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
- 
-+      hba_reset_count = 0;
-+
-+retry_init:
-       byte = pci_read_config8(sm_dev, 0xad);
-       /* Disable SATA SMBUS */
--      byte |= (1 << 0);
--      /* Enable SATA and power saving */
-       byte |= (1 << 1);
-+      /* Enable SATA and power saving */
-+      byte |= (1 << 0);
-       byte |= (1 << 5);
-       pci_write_config8(sm_dev, 0xad, byte);
- 
-+      /* Take the PHY logic out of reset */
-+      word = pci_read_config16(dev, 0x84);
-+      word |= 0x1 << 2;
-+      word &= ~0x1f8;
-+      pci_write_config16(dev, 0x84, word);
-+
-       /* get rev_id */
-       rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
- 
-@@ -324,6 +348,26 @@ static void sata_init(struct device *dev)
-       if (port_count > max_port_count)
-               port_count = max_port_count;
- 
-+      /* Send COMRESET to all ports */
-+      for (i = 0; i < port_count; i++) {
-+              /* Read in Port-N Serial ATA Control Register */
-+              byte = read8(sata_bar5 + 0x12C + 0x80 * i);
-+
-+              /* Set Reset Bit */
-+              byte |= 0x1;
-+              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
-+
-+              /* Wait 1ms */
-+              mdelay(1);
-+
-+              /* Clear Reset Bit */
-+              byte &= ~0x01;
-+              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
-+
-+              /* Wait 1ms */
-+              mdelay(1);
-+      }
-+
-       /* RPR7.7 SATA drive detection. */
-       /* Use BAR5+0x128,BAR0 for Primary Slave */
-       /* Use BAR5+0x1A8,BAR0 for Primary Slave */
-@@ -369,8 +413,31 @@ static void sata_init(struct device *dev)
-                                       current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
-                               else
-                                       current_bar = ide_bar0;
--                              if (!sata_drive_detect(i, current_bar))
-+                              ret = sata_drive_detect(i, current_bar);
-+                              if (ret == 0) {
-                                       break;
-+                              } else if (ret == 2) {
-+                                      /* Reset PHY logic */
-+                                      word = pci_read_config16(dev, 0x84);
-+                                      word &= ~(0x1 << 2);
-+                                      word |= 0x1f8;
-+                                      pci_write_config16(dev, 0x84, word);
-+
-+                                      /* Disable SATA controller */
-+                                      byte = pci_read_config8(sm_dev, 0xad);
-+                                      byte &= ~(0x1);
-+                                      pci_write_config8(sm_dev, 0xad, byte);
-+
-+                                      mdelay(100);
-+
-+                                      /* Retry initialization */
-+                                      hba_reset_count++;
-+                                      if (hba_reset_count < 16)
-+                                              goto retry_init;
-+                                      else
-+                                              printk(BIOS_WARNING, "HBA reset 
count exceeded, "
-+                                                      "continuing but AHCI 
drives may not function\n");
-+                              }
-                       }
-                       if (sata_ahci_mode)
-                               printk(BIOS_DEBUG, "AHCI device %d is %sready 
after %i tries\n",
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0066-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
 
b/resources/libreboot/patch/kgpe-d16/0066-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
new file mode 100644
index 0000000..b414899
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0066-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch
@@ -0,0 +1,96 @@
+From f2d97b4ed0b0594b8983dbe4d551aca7f9e6a32e Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 21 Jun 2015 16:27:03 -0500
+Subject: [PATCH 066/143] src/southbridge/amd/sb700: Reset SATA controller in
+ AHCI mode during startup
+
+In AHCI mode SeaBIOS randomly fails to detect disks (AHCI timeouts),
+with the probability of a failure increasing with the number of disks
+connected to the controller.  Resetting the SATA controller appears to
+show the true state of the underlying hardware, allowing the drive
+detection code to attempt link renegotiation as needed.
+
+Change-Id: Ib1f7c5f830a0cdba41cb6f5b05d759adee5ce369
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/sata.c |   47 ++++++++++++++++++++++++++++----------
+ 1 file changed, 35 insertions(+), 12 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index 24f78dd..d51baa1 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -135,6 +135,8 @@ static void sata_init(struct device *dev)
+       /* get rev_id */
+       rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
+ 
++      printk(BIOS_SPEW, "rev_id=%x\n", rev_id);
++
+       if (sata_ahci_mode) {
+               /* Enable link latency enhancement on A14 and above */
+               if (rev_id >= 0x14) {
+@@ -245,6 +247,27 @@ static void sata_init(struct device *dev)
+               write32(sata_bar5 + 0xfc, dword);
+       }
+ 
++      if (sata_ahci_mode) {
++              /* FIXME
++              * SeaBIOS does not know how to spin
++              * up the drives and therefore hangs
++              * in AHCI init if this is enabled...
++              */
++              /* Enable staggered spin-up */
++              dword = read32(sata_bar5 + 0x00);
++#if 0
++              dword |= 0x1 << 27;
++#else
++              dword &= ~(0x1 << 27);
++#endif
++              write32(sata_bar5 + 0x00, dword);
++
++              /* Reset the HBA to avoid stuck drives in SeaBIOS */
++              dword = read32(sata_bar5 + 0x04);
++              dword |= 0x1;
++              write32(sata_bar5 + 0x04, dword);
++      }
++
+       /* Write protect Sub-Class Code */
+       byte = pci_read_config8(dev, 0x40);
+       byte &= ~(1 << 0);
+@@ -371,21 +394,21 @@ static void sata_init(struct device *dev)
+       }
+ 
+       /* Below is CIM InitSataLateFar */
+-      /* Enable interrupts from the HBA  */
+-      byte = read8(sata_bar5 + 0x4);
+-      byte |= 1 << 1;
+-      write8((sata_bar5 + 0x4), byte);
+-
+       if (!sata_ahci_mode) {
+-              /* Clear error status */
+-              write32((sata_bar5 + 0x130), 0xFFFFFFFF);
+-              write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
+-              write32((sata_bar5 + 0x230), 0xFFFFFFFF);
+-              write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
+-              write32((sata_bar5 + 0x330), 0xFFFFFFFF);
+-              write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
++              /* Enable interrupts from the HBA  */
++              byte = read8(sata_bar5 + 0x4);
++              byte |= 1 << 1;
++              write8((sata_bar5 + 0x4), byte);
+       }
+ 
++      /* Clear error status */
++      write32((sata_bar5 + 0x130), 0xFFFFFFFF);
++      write32((sata_bar5 + 0x1b0), 0xFFFFFFFF);
++      write32((sata_bar5 + 0x230), 0xFFFFFFFF);
++      write32((sata_bar5 + 0x2b0), 0xFFFFFFFF);
++      write32((sata_bar5 + 0x330), 0xFFFFFFFF);
++      write32((sata_bar5 + 0x3b0), 0xFFFFFFFF);
++
+       /* Clear SATA status,Firstly we get the AcpiGpe0BlkAddr */
+       /* ????? why CIM does not set the AcpiGpe0BlkAddr , but use it??? */
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
 
b/resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
deleted file mode 100644
index 6466354..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From 0785e1c4b21ee56c6265df7b6c7f95ad94a43fbb Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 22 Jun 2015 02:56:10 -0500
-Subject: [PATCH 067/139] southbridge/amd/sb700: Fix SATA port 4/5 drive
- detection
-
-Change-Id: I01481f25189d01b6f4ed778902b2ecc4d39c7912
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/sata.c | 42 ++++++++++++++++++++++++++++++++++++----
- 1 file changed, 38 insertions(+), 4 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index ce242c1..dc64082 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -126,6 +126,8 @@ static void sata_init(struct device *dev)
-       uint8_t port_count;
-       uint8_t max_port_count;
-       uint8_t hba_reset_count;
-+      uint8_t ide_io_enabled;
-+      uint8_t ide_legacy_io_enabled;
- 
-       sata_ahci_mode = 0;
-       if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
-@@ -170,15 +172,27 @@ retry_init:
-               }
-       }
- 
--      /* Disable combined mode */
-+      /* Enable combined mode */
-       byte = pci_read_config8(sm_dev, 0xad);
--      byte &= ~(1 << 3);
-+      byte |= (1 << 3);
-       pci_write_config8(sm_dev, 0xad, byte);
- 
-       device_t ide_dev;
-       /* IDE Device */
-       ide_dev = dev_find_slot(0, PCI_DEVFN(0x14, 1));
- 
-+      /* Disable legacy IDE mode (enable PATA_BAR0/2) */
-+      byte = pci_read_config8(ide_dev, 0x09);
-+      ide_legacy_io_enabled = !(byte & 0x1);
-+      byte |= 0x1;
-+      pci_write_config8(ide_dev, 0x09, byte);
-+
-+      /* Enable IDE I/O access (enable PATA_BAR0/2) */
-+      byte = pci_read_config8(ide_dev, 0x04);
-+      ide_io_enabled = byte & 0x1;
-+      byte |= 0x1;
-+      pci_write_config8(ide_dev, 0x04, byte);
-+
-       /* RPR 7.2 SATA Initialization */
-       /* Set the interrupt Mapping to INTG# */
-       byte = pci_read_config8(sm_dev, 0xaf);
-@@ -425,7 +439,8 @@ retry_init:
- 
-                                       /* Disable SATA controller */
-                                       byte = pci_read_config8(sm_dev, 0xad);
--                                      byte &= ~(0x1);
-+                                      byte &= ~(1 << 0);
-+                                      byte &= ~(1 << 3);
-                                       pci_write_config8(sm_dev, 0xad, byte);
- 
-                                       mdelay(100);
-@@ -460,8 +475,27 @@ retry_init:
-               }
-       }
- 
-+      /* Restore IDE I/O access */
-+      if (!ide_io_enabled) {
-+              byte = pci_read_config8(ide_dev, 0x04);
-+              byte &= ~0x1;
-+              pci_write_config8(ide_dev, 0x04, byte);
-+      }
-+
-+      /* Re-enable legacy IDE mode */
-+      if (ide_legacy_io_enabled) {
-+              byte = pci_read_config8(ide_dev, 0x09);
-+              byte &= ~0x1;
-+              pci_write_config8(ide_dev, 0x09, byte);
-+      }
-+
-       /* Below is CIM InitSataLateFar */
--      if (!sata_ahci_mode) {
-+      if (sata_ahci_mode) {
-+              /* Disable combined mode */
-+              byte = pci_read_config8(sm_dev, 0xad);
-+              byte &= ~(1 << 3);
-+              pci_write_config8(sm_dev, 0xad, byte);
-+      } else {
-               /* Enable interrupts from the HBA  */
-               byte = read8(sata_bar5 + 0x4);
-               byte |= 1 << 1;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
new file mode 100644
index 0000000..407952e
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0067-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch
@@ -0,0 +1,163 @@
+From e80d2ec15e83fe1e6bb1ee4c8b3d4dad196e023f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 22 Jun 2015 02:21:29 -0500
+Subject: [PATCH 067/143] southbridge/amd/sb700: Recover if AHCI disk
+ detection fails
+
+Change-Id: I29051af5eca5d31b6aecc261e9a48028380eccb3
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/sata.c |   83 ++++++++++++++++++++++++++++++++++----
+ 1 file changed, 75 insertions(+), 8 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index d51baa1..ce242c1 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -31,12 +31,15 @@
+ static int sata_drive_detect(int portnum, uint16_t iobar)
+ {
+       u8 byte, byte2;
++      u8 byte_prev, byte2_prev;
+       int i = 0;
++      byte_prev = byte2_prev = 0;
+       outb(0xa0 + 0x10 * (portnum % 2), iobar + 0x6);
+       while (byte = inb(iobar + 0x6), byte2 = inb(iobar + 0x7),
+               (byte != (0xa0 + 0x10 * (portnum % 2))) ||
+               ((byte2 & 0x88) != 0)) {
+-              printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
++              if ((byte != byte_prev) || (byte2 != byte2_prev))
++                      printk(BIOS_SPEW, "0x6=%x, 0x7=%x\n", byte, byte2);
+               if (byte != (0xa0 + 0x10 * (portnum % 2))) {
+                       /* This will happen at the first iteration of this loop
+                        * if the first SATA port is unpopulated and the
+@@ -45,11 +48,22 @@ static int sata_drive_detect(int portnum, uint16_t iobar)
+                       printk(BIOS_DEBUG, "drive no longer selected after %i 
ms, "
+                               "retrying init\n", i * 10);
+                       return 1;
+-              } else
+-                      printk(BIOS_SPEW, "drive detection not yet completed, "
+-                              "waiting...\n");
++              } else {
++                      if (i == 0)
++                              printk(BIOS_SPEW, "drive detection not yet 
completed, "
++                                      "waiting...\n");
++              }
+               mdelay(10);
+               i++;
++              byte_prev = byte;
++              byte2_prev = byte2;
++
++              /* Detect stuck SATA controller and attempt reset */
++              if (i > 1024) {
++                      printk(BIOS_DEBUG, "drive detection not done after %i 
ms, "
++                              "resetting HBA and retrying init\n", i * 10);
++                      return 2;
++              }
+       }
+       printk(BIOS_SPEW, "drive detection done after %i ms\n", i * 10);
+       return 0;
+@@ -105,12 +119,13 @@ static void sata_init(struct device *dev)
+       uint16_t sata_bar0, sata_bar1, sata_bar2, sata_bar3, sata_bar4;
+       uint16_t ide_bar0, ide_bar1, ide_bar2, ide_bar3;
+       uint16_t current_bar;
+-      int i, j;
++      int i, j, ret;
+       uint8_t nvram;
+       uint8_t sata_ahci_mode;
+       uint8_t sata_alpm_enable;
+       uint8_t port_count;
+       uint8_t max_port_count;
++      uint8_t hba_reset_count;
+ 
+       sata_ahci_mode = 0;
+       if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
+@@ -124,14 +139,23 @@ static void sata_init(struct device *dev)
+       /* SATA SMBus Disable */
+       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+ 
++      hba_reset_count = 0;
++
++retry_init:
+       byte = pci_read_config8(sm_dev, 0xad);
+       /* Disable SATA SMBUS */
+-      byte |= (1 << 0);
+-      /* Enable SATA and power saving */
+       byte |= (1 << 1);
++      /* Enable SATA and power saving */
++      byte |= (1 << 0);
+       byte |= (1 << 5);
+       pci_write_config8(sm_dev, 0xad, byte);
+ 
++      /* Take the PHY logic out of reset */
++      word = pci_read_config16(dev, 0x84);
++      word |= 0x1 << 2;
++      word &= ~0x1f8;
++      pci_write_config16(dev, 0x84, word);
++
+       /* get rev_id */
+       rev_id = pci_read_config8(sm_dev, 0x08) - 0x28;
+ 
+@@ -324,6 +348,26 @@ static void sata_init(struct device *dev)
+       if (port_count > max_port_count)
+               port_count = max_port_count;
+ 
++      /* Send COMRESET to all ports */
++      for (i = 0; i < port_count; i++) {
++              /* Read in Port-N Serial ATA Control Register */
++              byte = read8(sata_bar5 + 0x12C + 0x80 * i);
++
++              /* Set Reset Bit */
++              byte |= 0x1;
++              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
++
++              /* Wait 1ms */
++              mdelay(1);
++
++              /* Clear Reset Bit */
++              byte &= ~0x01;
++              write8((sata_bar5 + 0x12C + 0x80 * i), byte);
++
++              /* Wait 1ms */
++              mdelay(1);
++      }
++
+       /* RPR7.7 SATA drive detection. */
+       /* Use BAR5+0x128,BAR0 for Primary Slave */
+       /* Use BAR5+0x1A8,BAR0 for Primary Slave */
+@@ -369,8 +413,31 @@ static void sata_init(struct device *dev)
+                                       current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
+                               else
+                                       current_bar = ide_bar0;
+-                              if (!sata_drive_detect(i, current_bar))
++                              ret = sata_drive_detect(i, current_bar);
++                              if (ret == 0) {
+                                       break;
++                              } else if (ret == 2) {
++                                      /* Reset PHY logic */
++                                      word = pci_read_config16(dev, 0x84);
++                                      word &= ~(0x1 << 2);
++                                      word |= 0x1f8;
++                                      pci_write_config16(dev, 0x84, word);
++
++                                      /* Disable SATA controller */
++                                      byte = pci_read_config8(sm_dev, 0xad);
++                                      byte &= ~(0x1);
++                                      pci_write_config8(sm_dev, 0xad, byte);
++
++                                      mdelay(100);
++
++                                      /* Retry initialization */
++                                      hba_reset_count++;
++                                      if (hba_reset_count < 16)
++                                              goto retry_init;
++                                      else
++                                              printk(BIOS_WARNING, "HBA reset 
count exceeded, "
++                                                      "continuing but AHCI 
drives may not function\n");
++                              }
+                       }
+                       if (sata_ahci_mode)
+                               printk(BIOS_DEBUG, "AHCI device %d is %sready 
after %i tries\n",
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
 
b/resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
new file mode 100644
index 0000000..2db0453
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch
@@ -0,0 +1,97 @@
+From 20cecb2ba215a7c8021cc76631d388cbf63fb8b5 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 22 Jun 2015 02:56:10 -0500
+Subject: [PATCH 068/143] southbridge/amd/sb700: Fix SATA port 4/5 drive
+ detection
+
+Change-Id: I01481f25189d01b6f4ed778902b2ecc4d39c7912
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/sata.c |   42 ++++++++++++++++++++++++++++++++++----
+ 1 file changed, 38 insertions(+), 4 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index ce242c1..dc64082 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -126,6 +126,8 @@ static void sata_init(struct device *dev)
+       uint8_t port_count;
+       uint8_t max_port_count;
+       uint8_t hba_reset_count;
++      uint8_t ide_io_enabled;
++      uint8_t ide_legacy_io_enabled;
+ 
+       sata_ahci_mode = 0;
+       if (get_option(&nvram, "sata_ahci_mode") == CB_SUCCESS)
+@@ -170,15 +172,27 @@ retry_init:
+               }
+       }
+ 
+-      /* Disable combined mode */
++      /* Enable combined mode */
+       byte = pci_read_config8(sm_dev, 0xad);
+-      byte &= ~(1 << 3);
++      byte |= (1 << 3);
+       pci_write_config8(sm_dev, 0xad, byte);
+ 
+       device_t ide_dev;
+       /* IDE Device */
+       ide_dev = dev_find_slot(0, PCI_DEVFN(0x14, 1));
+ 
++      /* Disable legacy IDE mode (enable PATA_BAR0/2) */
++      byte = pci_read_config8(ide_dev, 0x09);
++      ide_legacy_io_enabled = !(byte & 0x1);
++      byte |= 0x1;
++      pci_write_config8(ide_dev, 0x09, byte);
++
++      /* Enable IDE I/O access (enable PATA_BAR0/2) */
++      byte = pci_read_config8(ide_dev, 0x04);
++      ide_io_enabled = byte & 0x1;
++      byte |= 0x1;
++      pci_write_config8(ide_dev, 0x04, byte);
++
+       /* RPR 7.2 SATA Initialization */
+       /* Set the interrupt Mapping to INTG# */
+       byte = pci_read_config8(sm_dev, 0xaf);
+@@ -425,7 +439,8 @@ retry_init:
+ 
+                                       /* Disable SATA controller */
+                                       byte = pci_read_config8(sm_dev, 0xad);
+-                                      byte &= ~(0x1);
++                                      byte &= ~(1 << 0);
++                                      byte &= ~(1 << 3);
+                                       pci_write_config8(sm_dev, 0xad, byte);
+ 
+                                       mdelay(100);
+@@ -460,8 +475,27 @@ retry_init:
+               }
+       }
+ 
++      /* Restore IDE I/O access */
++      if (!ide_io_enabled) {
++              byte = pci_read_config8(ide_dev, 0x04);
++              byte &= ~0x1;
++              pci_write_config8(ide_dev, 0x04, byte);
++      }
++
++      /* Re-enable legacy IDE mode */
++      if (ide_legacy_io_enabled) {
++              byte = pci_read_config8(ide_dev, 0x09);
++              byte &= ~0x1;
++              pci_write_config8(ide_dev, 0x09, byte);
++      }
++
+       /* Below is CIM InitSataLateFar */
+-      if (!sata_ahci_mode) {
++      if (sata_ahci_mode) {
++              /* Disable combined mode */
++              byte = pci_read_config8(sm_dev, 0xad);
++              byte &= ~(1 << 3);
++              pci_write_config8(sm_dev, 0xad, byte);
++      } else {
+               /* Enable interrupts from the HBA  */
+               byte = read8(sata_bar5 + 0x4);
+               byte |= 1 << 1;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
 
b/resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
deleted file mode 100644
index 0d16a01..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
+++ /dev/null
@@ -1,165 +0,0 @@
-From 6b5ae665f42bf04cb5dd54d719a18f5f1e670c63 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 22 Jun 2015 20:57:39 -0500
-Subject: [PATCH 068/139] southbridge/amd/sb700: Fix random persistent SATA
- AHCI drive detection failure
-
-Change-Id: I4202a62217a7aaeaba07e4b994a350e83e064c9c
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/sata.c | 81 +++++++++++++++++++++-------------------
- 1 file changed, 42 insertions(+), 39 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
-index dc64082..9d354bb 100644
---- a/src/southbridge/amd/sb700/sata.c
-+++ b/src/southbridge/amd/sb700/sata.c
-@@ -125,7 +125,6 @@ static void sata_init(struct device *dev)
-       uint8_t sata_alpm_enable;
-       uint8_t port_count;
-       uint8_t max_port_count;
--      uint8_t hba_reset_count;
-       uint8_t ide_io_enabled;
-       uint8_t ide_legacy_io_enabled;
- 
-@@ -141,14 +140,20 @@ static void sata_init(struct device *dev)
-       /* SATA SMBus Disable */
-       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
- 
--      hba_reset_count = 0;
--
--retry_init:
-+      /* WARNING
-+       * Enabling the SATA link latency enhancement (SMBUS 0xAD bit 5)
-+       * causes random persistent drive detection failures until it is 
cleared,
-+       * with the probabability of detection failure rising exponentially with
-+       * the number of drives attached to the controller!
-+       * This happens on Rev15 H/W.
-+       * Do NOT follow the RPR advice; leave this bit set at all times...
-+       */
-       byte = pci_read_config8(sm_dev, 0xad);
-       /* Disable SATA SMBUS */
-       byte |= (1 << 1);
-       /* Enable SATA and power saving */
-       byte |= (1 << 0);
-+      /* Disable link latency enhancement */
-       byte |= (1 << 5);
-       pci_write_config8(sm_dev, 0xad, byte);
- 
-@@ -163,15 +168,6 @@ retry_init:
- 
-       printk(BIOS_SPEW, "rev_id=%x\n", rev_id);
- 
--      if (sata_ahci_mode) {
--              /* Enable link latency enhancement on A14 and above */
--              if (rev_id >= 0x14) {
--                      byte = pci_read_config8(sm_dev, 0xad);
--                      byte &= ~(1 << 5);
--                      pci_write_config8(sm_dev, 0xad, byte);
--              }
--      }
--
-       /* Enable combined mode */
-       byte = pci_read_config8(sm_dev, 0xad);
-       byte |= (1 << 3);
-@@ -285,6 +281,17 @@ retry_init:
-               write32(sata_bar5 + 0xfc, dword);
-       }
- 
-+      /* Enable SATA ports */
-+      byte = pci_read_config8(dev, 0x42);
-+      if (max_port_count <= 6) {
-+              byte |= 0x3f;
-+              for (i = 0; i < max_port_count; i++)
-+                      byte &= ~(0x1 << i);
-+      } else {
-+              byte &= ~0x3f;
-+      }
-+      pci_write_config8(dev, 0x42, byte);
-+
-       if (sata_ahci_mode) {
-               /* FIXME
-               * SeaBIOS does not know how to spin
-@@ -306,6 +313,9 @@ retry_init:
-               write32(sata_bar5 + 0x04, dword);
-       }
- 
-+      sb7xx_51xx_setup_sata_phys(dev);
-+      sb7xx_51xx_setup_sata_port_indication(sata_bar5);
-+
-       /* Write protect Sub-Class Code */
-       byte = pci_read_config8(dev, 0x40);
-       byte &= ~(1 << 0);
-@@ -331,7 +341,7 @@ retry_init:
-       else {
-               dword &= ~(1 << 24 | 1 << 21); /* A14 and above */
-               dword &= ~0xFF80; /* 15:7 */
--              dword |= 1 << 15 | 0x7F << 7;
-+              dword |= 1 << 15 | 0x7F << 7 | 1 << 6;
-       }
-       pci_write_config32(dev, 0x48, dword);
- 
-@@ -339,9 +349,6 @@ retry_init:
-       byte = 0x10;
-       pci_write_config8(dev, 0x46, byte);
- 
--      sb7xx_51xx_setup_sata_phys(dev);
--      sb7xx_51xx_setup_sata_port_indication(sata_bar5);
--
-       /* Enable the I/O, MM, BusMaster access for SATA */
-       byte = pci_read_config8(dev, 0x4);
-       byte |= 7 << 0;
-@@ -426,32 +433,28 @@ retry_init:
-                               if (i < 4)
-                                       current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
-                               else
--                                      current_bar = ide_bar0;
-+                                      current_bar = (pci_read_config8(sm_dev, 
0xad) & (0x1 << 4))
-+                                              ? ide_bar2 : ide_bar0;
-                               ret = sata_drive_detect(i, current_bar);
-                               if (ret == 0) {
-                                       break;
-                               } else if (ret == 2) {
--                                      /* Reset PHY logic */
--                                      word = pci_read_config16(dev, 0x84);
--                                      word &= ~(0x1 << 2);
--                                      word |= 0x1f8;
--                                      pci_write_config16(dev, 0x84, word);
--
--                                      /* Disable SATA controller */
--                                      byte = pci_read_config8(sm_dev, 0xad);
--                                      byte &= ~(1 << 0);
--                                      byte &= ~(1 << 3);
--                                      pci_write_config8(sm_dev, 0xad, byte);
--
--                                      mdelay(100);
--
--                                      /* Retry initialization */
--                                      hba_reset_count++;
--                                      if (hba_reset_count < 16)
--                                              goto retry_init;
--                                      else
--                                              printk(BIOS_WARNING, "HBA reset 
count exceeded, "
--                                                      "continuing but AHCI 
drives may not function\n");
-+                                      /* Read in Port-N Serial ATA Control 
Register */
-+                                      byte = read8(sata_bar5 + 0x12C + 0x80 * 
i);
-+
-+                                      /* Set Reset Bit */
-+                                      byte |= 0x1;
-+                                      write8((sata_bar5 + 0x12C + 0x80 * i), 
byte);
-+
-+                                      /* Wait 1000ms */
-+                                      mdelay(1000);
-+
-+                                      /* Clear Reset Bit */
-+                                      byte &= ~0x01;
-+                                      write8((sata_bar5 + 0x12C + 0x80 * i), 
byte);
-+
-+                                      /* Wait 1ms */
-+                                      mdelay(1);
-                               }
-                       }
-                       if (sata_ahci_mode)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0069-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
 
b/resources/libreboot/patch/kgpe-d16/0069-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
deleted file mode 100644
index 4b7392b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0069-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
+++ /dev/null
@@ -1,407 +0,0 @@
-From c942d174cfc1a0ba6e91e0131c0a105addddbbd4 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Wed, 24 Jun 2015 19:15:09 -0500
-Subject: [PATCH 069/139] northbridge/amd/amdmct/mct_ddr3: Fix lockups and
- wasted time during ECC init
-
-Change-Id: I09a8ea83024186b7ece7d78a4bef1201ab34ff8a
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 142 +++++++++++++++----------
- src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c |  39 ++++++-
- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c  |  22 +++-
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |   3 +-
- 4 files changed, 145 insertions(+), 61 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index d8a09f0..68957f5 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1498,11 +1498,12 @@ restartinit:
-               InterleaveChannels_D(pMCTstat, pDCTstatA);
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
--              ECCInit_D(pMCTstat, pDCTstatA);                 /* Setup ECC 
control and ECC check-bits*/
--
--              /* mctDoWarmResetMemClr_D(); */
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
--              MCTMemClr_D(pMCTstat,pDCTstatA);
-+              if (!ECCInit_D(pMCTstat, pDCTstatA)) {                  /* 
Setup ECC control and ECC check-bits*/
-+                      /* Memory was not cleared during ECC setup */
-+                      /* mctDoWarmResetMemClr_D(); */
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
-+                      MCTMemClr_D(pMCTstat,pDCTstatA);
-+              }
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-@@ -1695,7 +1696,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               uint8_t x8_present = 0;
-               uint8_t memclk_index;
-               uint8_t interleave_channels = 0;
--              uint8_t redirect_ecc_scrub = 0;
-               uint16_t trdrdsddc;
-               uint16_t trdrddd;
-               uint16_t cdd_trdrddd;
-@@ -1733,9 +1733,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               if (pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1] && 
mctGet_NVbits(NV_Unganged))
-                       interleave_channels = 1;
- 
--              if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
--                      redirect_ecc_scrub = 1;
--
-               dword = (Get_NB32_DCT(dev, dct, 0x240) >> 4) & 0xf;
-               if (dword > 6)
-                       read_odt_delay = dword - 6;
-@@ -1927,21 +1924,10 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
-               dword |= (interleave_channels & 0x1) << 2;
-               Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
- 
--              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58);  /* 
Scrub Rate Control */
--              dword &= ~(0x1f << 24);                                 /* 
L3Scrub = NV_L3BKScrub */
--              dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
--              dword &= ~(0x1f);                                       /* 
DramScrub = NV_DramBKScrub */
--              dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f;
--              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* 
Scrub Rate Control */
--
--              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM 
Scrub Address Low */
--              dword &= ~(0x1);                                        /* 
ScrubReDirEn = redirect_ecc_scrub */
--              dword |= redirect_ecc_scrub & 0x1;
--              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM 
Scrub Address Low */
--
--              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 
Control 1 */
--              dword &= ~(0x1 << 4);                                   /* 
L3ScrbRedirDis = 0 */
--              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 
Control 1 */
-+              /* NOTE
-+               * ECC-related setup is performed as part of ECCInit_D and must 
not be located here,
-+               * otherwise semi-random lockups will occur due to 
misconfigured scrubbing hardware!
-+               */
- 
-               /* FIXME
-                * The BKDG-recommended settings cause memory corruption on the 
ASUS KGPE-D16.
-@@ -1983,11 +1969,17 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
-               dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
-               Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
- 
-+              /* Configure partial power down delay */
-+              dword = Get_NB32(dev, 0x244);                           /* DRAM 
Controller Miscellaneous 3 */
-+              dword &= ~0xf;                                          /* 
PrtlChPDDynDly = 0x2 */
-+              dword |= 0x2;
-+              Set_NB32(dev, 0x244, dword);                            /* DRAM 
Controller Miscellaneous 3 */
-+
-               /* Enable prefetchers */
--              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* 
Memory Controller Configuration High */
-+              dword = Get_NB32(dev, 0x11c);                           /* 
Memory Controller Configuration High */
-               dword &= ~(0x1 << 13);                                  /* 
PrefIoDis = 0 */
-               dword &= ~(0x1 << 12);                                  /* 
PrefCpuDis = 0 */
--              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* 
Memory Controller Configuration High */
-+              Set_NB32(dev, 0x11c, dword);                            /* 
Memory Controller Configuration High */
-       }
- }
- 
-@@ -2091,6 +2083,19 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-               pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
-       }
- 
-+      if (is_fam15h()) {
-+              uint8_t Node;
-+              struct DCTStatStruc *pDCTstat;
-+
-+              /* Switch DCT control register to DCT 0 per Erratum 505 */
-+              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                      pDCTstat = pDCTstatA + Node;
-+                      if (pDCTstat->NodePresent) {
-+                              fam15h_switch_dct(pDCTstat->dev_map, 0);
-+                      }
-+              }
-+      }
-+
-       /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
-       mctHookAfterAnyTraining();
- }
-@@ -2337,6 +2342,7 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
-        * status are checked to ensure that memclr has completed.
-        */
-       u8 Node;
-+      uint32_t dword;
-       struct DCTStatStruc *pDCTstat;
- 
-       if (!mctGet_NVbits(NV_DQSTrainCTL)){
-@@ -2357,6 +2363,16 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
-                       }
-               }
-       }
-+
-+      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+              /* Configure and enable prefetchers */
-+              if (is_fam15h())
-+                      dword = 0x0ce00f41;     /* BKDG recommended */
-+              else
-+                      dword = 0x0fe40fc0;     /* BKDG recommended */
-+              dword |= MCCH_FlushWrOnStpGnt;  /* Set for S3 */
-+              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);
-+      }
- }
- 
- static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
-@@ -2364,48 +2380,59 @@ static void DCTMemClr_Init_D(struct MCTStatStruc 
*pMCTstat,
- {
-       u32 val;
-       u32 dev;
--      u32 reg;
-+      uint32_t dword;
- 
-       /* Initiates a memory clear operation on one node */
-       if (pDCTstat->DCTSysLimit) {
-               dev = pDCTstat->dev_dct;
--              reg = 0x110;
-+
-+              /* Disable prefetchers */
-+              dword = Get_NB32(dev, 0x11c);           /* Memory Controller 
Configuration High */
-+              dword |= 0x1 << 13;                     /* PrefIoDis = 1 */
-+              dword |= 0x1 << 12;                     /* PrefCpuDis = 1 */
-+              Set_NB32(dev, 0x11c, dword);            /* Memory Controller 
Configuration High */
- 
-               do {
--                      val = Get_NB32(dev, reg);
-+                      val = Get_NB32(dev, 0x110);
-               } while (val & (1 << MemClrBusy));
- 
-               val |= (1 << MemClrInit);
--              Set_NB32(dev, reg, val);
-+              Set_NB32(dev, 0x110, val);
-       }
- }
- 
- static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat)
- {
--      u32 val;
--      u32 dev = pDCTstat->dev_dct;
--      u32 reg;
-+      uint32_t dword;
-+      uint32_t dev = pDCTstat->dev_dct;
-+
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
- 
-       /* Ensure that a memory clear operation has completed on one node */
-       if (pDCTstat->DCTSysLimit){
--              reg = 0x110;
--
-+              printk(BIOS_DEBUG, "%s: Waiting for memory clear to complete", 
__func__);
-               do {
--                      val = Get_NB32(dev, reg);
--              } while (val & (1 << MemClrBusy));
-+                      dword = Get_NB32(dev, 0x110);
- 
-+                      printk(BIOS_DEBUG, ".");
-+              } while (dword & (1 << MemClrBusy));
-+
-+              printk(BIOS_DEBUG, "\n");
-               do {
--                      val = Get_NB32(dev, reg);
--              } while (!(val & (1 << Dr_MemClrStatus)));
-+                      printk(BIOS_DEBUG, ".");
-+                      dword = Get_NB32(dev, 0x110);
-+              } while (!(dword & (1 << Dr_MemClrStatus)));
-+              printk(BIOS_DEBUG, "\n");
-       }
- 
--      if (is_fam15h())
--              val = 0x0ce00f41;       /* BKDG recommended */
--      else
--              val = 0x0fe40fc0;       /* BKDG recommended */
--      val |= MCCH_FlushWrOnStpGnt;    /* Set for S3 */
--      Set_NB32(dev, 0x11c, val);
-+      /* Enable prefetchers */
-+      dword = Get_NB32(dev, 0x11c);           /* Memory Controller 
Configuration High */
-+      dword &= ~(0x1 << 13);                  /* PrefIoDis = 0 */
-+      dword &= ~(0x1 << 12);                  /* PrefCpuDis = 0 */
-+      Set_NB32(dev, 0x11c, dword);            /* Memory Controller 
Configuration High */
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static u8 NodePresent_D(u8 Node)
-@@ -3346,8 +3373,8 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-       dev = pDCTstat->dev_dct;
- 
-       /* Build Dram Control Register Value */
--      DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xA8);         /* Dram 
Control*/
--      DramControl = Get_NB32_DCT(dev, dct, 0x78);             /* Dram 
Control*/
-+      DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xa8);         /* Dram 
Miscellaneous 2 */
-+      DramControl = Get_NB32_DCT(dev, dct, 0x78);             /* Dram Control 
*/
- 
-       /* FIXME: Skip mct_checkForDxSupport */
-       /* REV_CALL mct_DoRdPtrInit if not Dx */
-@@ -3402,9 +3429,15 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-                       /* set only if x8 Registered DIMMs in System*/
-                       DramConfigHi |= 1 << RDqsEn;
- 
--      if (mctGet_NVbits(NV_CKE_CTL))
--              /*Chip Select control of CKE*/
--              DramConfigHi |= 1 << 16;
-+      if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
-+              DramConfigLo |= 1 << 25;        /* PendRefPaybackS3En = 1 */
-+              DramConfigLo |= 1 << 24;        /* StagRefEn = 1 */
-+              DramConfigHi |= 1 << 16;        /* PowerDownMode = 1 */
-+      } else {
-+              if (mctGet_NVbits(NV_CKE_CTL))
-+                      /*Chip Select control of CKE*/
-+                      DramConfigHi |= 1 << 16;
-+      }
- 
-       /* Control Bank Swizzle */
-       if (0) /* call back not needed mctBankSwizzleControl_D()) */
-@@ -4112,8 +4145,7 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
- 
-       if (load_spd_hashes_from_nvram(pMCTstat, pDCTstat) < 0) {
-               pDCTstat->spd_data.nvram_spd_match = 0;
--      }
--      else {
-+      } else {
-               compare_nvram_spd_hashes(pMCTstat, pDCTstat);
-       }
- #else
-@@ -4311,8 +4343,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
-       }
-       for (i=i_start; i<i_end; i++) {
-               index_reg = 0x98;
--              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
--              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
-+              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */
-+              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */
-       }
- 
-       return pDCTstat->ErrCode;
-@@ -6102,11 +6134,11 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
-               DramMRS |= 1 << 1;
- 
-       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
-+      dword |= DramMRS;
-       if (is_fam15h())
-               dword &= ~0x00800003;
-       else
-               dword &= ~0x00fc2f8f;
--      dword |= DramMRS;
-       Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword);
- }
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-index 918e91e..a0482e8 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-@@ -92,8 +92,13 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-       uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED];
-       uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED];
- 
-+      uint8_t redirect_ecc_scrub = 0;
-+
-       mctHookBeforeECC();
- 
-+      if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
-+              redirect_ecc_scrub = 1;
-+
-       /* Construct these booleans, based on setup options, for easy handling
-       later in this procedure */
-       OB_NBECC = mctGet_NVbits(NV_NBECC);                     /* MCA ECC 
(MCE) enable bit */
-@@ -230,12 +235,12 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                                       }
-                                       dev = pDCTstat->dev_nbmisc;
-                                       val = curBase << 8;
--                                      if(OB_ECCRedir) {
--                                              val |= (1<<0); /* enable 
redirection */
-+                                      if (OB_ECCRedir) {
-+                                              val |= (1<<0);                  
/* enable redirection */
-                                       }
--                                      Set_NB32(dev, 0x5C, val); /* Dram Scrub 
Addr Low */
-+                                      Set_NB32(dev, 0x5c, val);               
/* Dram Scrub Addr Low */
-                                       val = curBase>>24;
--                                      Set_NB32(dev, 0x60, val); /* Dram Scrub 
Addr High */
-+                                      Set_NB32(dev, 0x60, val);               
/* Dram Scrub Addr High */
-                                       Set_NB32(dev, 0x58, OF_ScrubCTL);       
/*Scrub Control */
- 
-                                       if (!is_fam15h()) {
-@@ -252,6 +257,32 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                                                       }
-                                               }
-                                       }
-+
-+                                      if (is_fam15h()) {
-+                                              uint8_t dct;
-+
-+                                              /* Disable training mode
-+                                               * See fam15EnableTrainingMode 
for the non-ECC training mode tear-down code
-+                                               */
-+                                              for (dct = 0; dct < 2; dct++) {
-+                                                      /* NOTE: Reads use DCT 
0 and writes use the current DCT per Erratum 505 */
-+                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, 0, 0x58);    /* Scrub Rate Control */
-+                                                      dword &= ~(0x1f << 24); 
                                /* L3Scrub = NV_L3BKScrub */
-+                                                      dword |= 
(mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
-+                                                      dword &= ~(0x1f);       
                                /* DramScrub = NV_DramBKScrub */
-+                                                      dword |= 
mctGet_NVbits(NV_DramBKScrub) & 0x1f;
-+                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* Scrub Rate Control */
-+
-+                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM Scrub Address Low */
-+                                                      dword &= ~(0x1);        
                                /* ScrubReDirEn = redirect_ecc_scrub */
-+                                                      dword |= 
redirect_ecc_scrub & 0x1;
-+                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM Scrub Address 
Low */
-+
-+                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */
-+                                                      dword &= ~(0x1 << 4);   
                                /* L3ScrbRedirDis = 0 */
-+                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 Control 1 */
-+                                              }
-+                                      }
-                               }       /* this node has ECC enabled dram */
-                       }       /*Node has Dram */
-               }       /*if Node present */
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-index 5ef4a2c..32b447f 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-@@ -23,7 +23,27 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
- {
-       u32 val;
- 
--      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
-+      /* FIXME
-+       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-+       * For now assume a maximum of 2 DIMMs per channel can be installed
-+       */
-+      uint8_t MaxDimmsInstallable = 2;
-+
-+      if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
-+              uint8_t cs_mux_45;
-+              uint8_t cs_mux_67;
-+
-+              /* BKDG v3.14 Table 200 / Table 201 */
-+              if (MaxDimmsInstallable < 3) {
-+                      cs_mux_45 = 1;
-+                      cs_mux_67 = 1;
-+              } else {
-+                      cs_mux_45 = 0;
-+                      cs_mux_67 = 0;
-+              }
-+              misc2 |= (cs_mux_45 & 0x1) << 26;
-+              misc2 |= (cs_mux_67 & 0x1) << 27;
-+      } else if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
-               if (pDCTstat->Status & (1 << SB_Registered)) {
-                       misc2 |= 1 << SubMemclkRegDly;
-                       if (mctGet_NVbits(NV_MAX_DIMMS) == 8)
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index 7ea7901..c760bac 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -209,7 +209,8 @@ void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTsta
-                       uint16_t total_delay_seed = 
((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
-                       uint16_t total_delay_phy = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
-                       if (abs(total_delay_phy - total_delay_seed) > 0x20) {
--                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value\n", __func__);
-+                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value (seed: %04x phy: %04x step: %04x)\n", __func__,
-+                                      total_delay_seed, total_delay_phy, 
abs(total_delay_phy - total_delay_seed));
-                               pDCTData->WLGrossDelay[index+ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane];
-                               pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
-                       }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0069-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
 
b/resources/libreboot/patch/kgpe-d16/0069-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
new file mode 100644
index 0000000..7b92fab
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0069-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch
@@ -0,0 +1,165 @@
+From f4472e05253e15f9324e3a9b669e0cb1f4dce5cb Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 22 Jun 2015 20:57:39 -0500
+Subject: [PATCH 069/143] southbridge/amd/sb700: Fix random persistent SATA
+ AHCI drive detection failure
+
+Change-Id: I4202a62217a7aaeaba07e4b994a350e83e064c9c
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/sata.c |   81 ++++++++++++++++++++------------------
+ 1 file changed, 42 insertions(+), 39 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/sata.c 
b/src/southbridge/amd/sb700/sata.c
+index dc64082..9d354bb 100644
+--- a/src/southbridge/amd/sb700/sata.c
++++ b/src/southbridge/amd/sb700/sata.c
+@@ -125,7 +125,6 @@ static void sata_init(struct device *dev)
+       uint8_t sata_alpm_enable;
+       uint8_t port_count;
+       uint8_t max_port_count;
+-      uint8_t hba_reset_count;
+       uint8_t ide_io_enabled;
+       uint8_t ide_legacy_io_enabled;
+ 
+@@ -141,14 +140,20 @@ static void sata_init(struct device *dev)
+       /* SATA SMBus Disable */
+       sm_dev = dev_find_slot(0, PCI_DEVFN(0x14, 0));
+ 
+-      hba_reset_count = 0;
+-
+-retry_init:
++      /* WARNING
++       * Enabling the SATA link latency enhancement (SMBUS 0xAD bit 5)
++       * causes random persistent drive detection failures until it is 
cleared,
++       * with the probabability of detection failure rising exponentially with
++       * the number of drives attached to the controller!
++       * This happens on Rev15 H/W.
++       * Do NOT follow the RPR advice; leave this bit set at all times...
++       */
+       byte = pci_read_config8(sm_dev, 0xad);
+       /* Disable SATA SMBUS */
+       byte |= (1 << 1);
+       /* Enable SATA and power saving */
+       byte |= (1 << 0);
++      /* Disable link latency enhancement */
+       byte |= (1 << 5);
+       pci_write_config8(sm_dev, 0xad, byte);
+ 
+@@ -163,15 +168,6 @@ retry_init:
+ 
+       printk(BIOS_SPEW, "rev_id=%x\n", rev_id);
+ 
+-      if (sata_ahci_mode) {
+-              /* Enable link latency enhancement on A14 and above */
+-              if (rev_id >= 0x14) {
+-                      byte = pci_read_config8(sm_dev, 0xad);
+-                      byte &= ~(1 << 5);
+-                      pci_write_config8(sm_dev, 0xad, byte);
+-              }
+-      }
+-
+       /* Enable combined mode */
+       byte = pci_read_config8(sm_dev, 0xad);
+       byte |= (1 << 3);
+@@ -285,6 +281,17 @@ retry_init:
+               write32(sata_bar5 + 0xfc, dword);
+       }
+ 
++      /* Enable SATA ports */
++      byte = pci_read_config8(dev, 0x42);
++      if (max_port_count <= 6) {
++              byte |= 0x3f;
++              for (i = 0; i < max_port_count; i++)
++                      byte &= ~(0x1 << i);
++      } else {
++              byte &= ~0x3f;
++      }
++      pci_write_config8(dev, 0x42, byte);
++
+       if (sata_ahci_mode) {
+               /* FIXME
+               * SeaBIOS does not know how to spin
+@@ -306,6 +313,9 @@ retry_init:
+               write32(sata_bar5 + 0x04, dword);
+       }
+ 
++      sb7xx_51xx_setup_sata_phys(dev);
++      sb7xx_51xx_setup_sata_port_indication(sata_bar5);
++
+       /* Write protect Sub-Class Code */
+       byte = pci_read_config8(dev, 0x40);
+       byte &= ~(1 << 0);
+@@ -331,7 +341,7 @@ retry_init:
+       else {
+               dword &= ~(1 << 24 | 1 << 21); /* A14 and above */
+               dword &= ~0xFF80; /* 15:7 */
+-              dword |= 1 << 15 | 0x7F << 7;
++              dword |= 1 << 15 | 0x7F << 7 | 1 << 6;
+       }
+       pci_write_config32(dev, 0x48, dword);
+ 
+@@ -339,9 +349,6 @@ retry_init:
+       byte = 0x10;
+       pci_write_config8(dev, 0x46, byte);
+ 
+-      sb7xx_51xx_setup_sata_phys(dev);
+-      sb7xx_51xx_setup_sata_port_indication(sata_bar5);
+-
+       /* Enable the I/O, MM, BusMaster access for SATA */
+       byte = pci_read_config8(dev, 0x4);
+       byte |= 7 << 0;
+@@ -426,32 +433,28 @@ retry_init:
+                               if (i < 4)
+                                       current_bar = ((i / 2) == 0) ? 
sata_bar0 : sata_bar2;
+                               else
+-                                      current_bar = ide_bar0;
++                                      current_bar = (pci_read_config8(sm_dev, 
0xad) & (0x1 << 4))
++                                              ? ide_bar2 : ide_bar0;
+                               ret = sata_drive_detect(i, current_bar);
+                               if (ret == 0) {
+                                       break;
+                               } else if (ret == 2) {
+-                                      /* Reset PHY logic */
+-                                      word = pci_read_config16(dev, 0x84);
+-                                      word &= ~(0x1 << 2);
+-                                      word |= 0x1f8;
+-                                      pci_write_config16(dev, 0x84, word);
+-
+-                                      /* Disable SATA controller */
+-                                      byte = pci_read_config8(sm_dev, 0xad);
+-                                      byte &= ~(1 << 0);
+-                                      byte &= ~(1 << 3);
+-                                      pci_write_config8(sm_dev, 0xad, byte);
+-
+-                                      mdelay(100);
+-
+-                                      /* Retry initialization */
+-                                      hba_reset_count++;
+-                                      if (hba_reset_count < 16)
+-                                              goto retry_init;
+-                                      else
+-                                              printk(BIOS_WARNING, "HBA reset 
count exceeded, "
+-                                                      "continuing but AHCI 
drives may not function\n");
++                                      /* Read in Port-N Serial ATA Control 
Register */
++                                      byte = read8(sata_bar5 + 0x12C + 0x80 * 
i);
++
++                                      /* Set Reset Bit */
++                                      byte |= 0x1;
++                                      write8((sata_bar5 + 0x12C + 0x80 * i), 
byte);
++
++                                      /* Wait 1000ms */
++                                      mdelay(1000);
++
++                                      /* Clear Reset Bit */
++                                      byte &= ~0x01;
++                                      write8((sata_bar5 + 0x12C + 0x80 * i), 
byte);
++
++                                      /* Wait 1ms */
++                                      mdelay(1);
+                               }
+                       }
+                       if (sata_ahci_mode)
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0070-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
 
b/resources/libreboot/patch/kgpe-d16/0070-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
deleted file mode 100644
index 0b55b83..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0070-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
+++ /dev/null
@@ -1,474 +0,0 @@
-From 589c0f7e4f80b82bdf8e604f0a7ded82cc9c09fe Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 25 Jun 2015 15:07:34 -0500
-Subject: [PATCH 070/139] cpu/amd: Fix AMD Family 15h ECC initialization
- reliability issues
-
-Change-Id: I7f009b655f8500aeb22981f7020f1db74cdd6925
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/car/cache_as_ram.inc               |   4 +
- src/cpu/amd/family_10h-family_15h/init_cpus.c  |  16 ++++
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  12 +--
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |   6 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |  21 ++++-
- src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c | 110 +++++++++++--------------
- src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c |   6 +-
- src/northbridge/amd/amdmct/mct_ddr3/s3utils.c  |  57 ++++++++-----
- 8 files changed, 136 insertions(+), 96 deletions(-)
-
-diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
-index 9edc41f..5db9224 100644
---- a/src/cpu/amd/car/cache_as_ram.inc
-+++ b/src/cpu/amd/car/cache_as_ram.inc
-@@ -362,12 +362,16 @@ clear_fixed_var_mtrr_out:
-       simplemask CacheSize, 0
-       wrmsr
- 
-+      jmp_if_fam15h(fam15_skip_dram_mtrr_setup)
-+
-       /* Enable memory access for first MBs using top_mem. */
-       movl    $TOP_MEM, %ecx
-       xorl    %edx, %edx
-       movl    $(((CONFIG_RAMTOP) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax
-       wrmsr
- 
-+fam15_skip_dram_mtrr_setup:
-+
- #if CONFIG_XIP_ROM_SIZE
- 
-       /* Enable write base caching so we can do execute in place (XIP)
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 818431b..0044dc6 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -317,6 +317,22 @@ static void STOP_CAR_AND_CPU(uint8_t skip_sharedc_config, 
uint32_t apicid)
-               msr = rdmsr(BU_CFG2);
-               msr.lo &= ~(1 << ClLinesToNbDis);
-               wrmsr(BU_CFG2, msr);
-+      } else {
-+              /* Family 15h or later
-+               * DRAM setup is delayed on Fam15 in order to prevent
-+               * any DRAM access before ECC check bits are initialized.
-+               * Each core also needs to have its initial DRAM map initialized
-+               * before it is put to sleep, otherwise it will fail to wake
-+               * in ramstage.  To meet both of these goals, delay DRAM map
-+               * setup until the last possible moment, where speculative
-+               * memory access is highly unlikely before core halt...
-+               */
-+              if (!skip_sharedc_config) {
-+                      /* Enable memory access for first MBs using top_mem */
-+                      msr.hi = 0;
-+                      msr.lo = (CONFIG_RAMTOP + TOP_MEM_MASK) & 
(~TOP_MEM_MASK);
-+                      wrmsr(TOP_MEM, msr);
-+              }
-       }
- 
-       disable_cache_as_ram(skip_sharedc_config);      // inline
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 68957f5..fadb353 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1458,8 +1458,7 @@ restartinit:
-               HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory 
into system address space.*/
-               mctHookAfterHTMap();
- 
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
--              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctHookAfterCPU\n");
-               mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
- 
-               /* FIXME
-@@ -1482,9 +1481,6 @@ restartinit:
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
-               DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get 
Receiver Enable and DQS signal timing*/
- 
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
--              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
--
-               if (!allow_config_restore) {
-                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
-                       mct_OtherTiming(pMCTstat, pDCTstatA);
-@@ -1505,6 +1501,12 @@ restartinit:
-                       MCTMemClr_D(pMCTstat,pDCTstatA);
-               }
- 
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
-+              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
-+
-+              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
-+              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
-+
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-                       struct DCTStatStruc *pDCTstat;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 11555ae..ac8c934 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -725,8 +725,10 @@ struct amd_s3_persistent_mct_channel_data {
-       uint32_t f2x9cx30[12];
-       uint32_t f2x9cx40[12];
- 
--      /* Other (1 dword) */
-+      /* Other (3 dwords) */
-       uint32_t f3x58;
-+      uint32_t f3x5c;
-+      uint32_t f3x60;
- 
-       /* Family 15h-specific registers (90 dwords) */
-       uint32_t f2x200;
-@@ -785,7 +787,7 @@ struct amd_s3_persistent_mct_channel_data {
-       uint32_t f2x9cx0d0f0_0_f_31[9];         /* [lane] */
-       uint32_t f2x9cx0d0f8021;
- 
--      /* TOTAL: 340 dwords */
-+      /* TOTAL: 342 dwords */
- } __attribute__((packed));
- 
- struct amd_s3_persistent_node_data {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index 740edae..b0ad54b 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -902,6 +902,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-       uint32_t dev = pDCTstat->dev_dct;
-       uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
- 
-+#if DQS_TRAIN_DEBUG > 0
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+#endif
-+
-+      mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
-+      if (fam15h_freq_tab[mem_clk] == 0) {
-+              pDCTstat->CH_MaxRdLat[dct] = 0x55;
-+              return;
-+      }
-+
-       /* P is specified in PhyCLKs (1/2 MEMCLKs) */
-       for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
-               /* 2.10.5.8.5 (2) */
-@@ -949,7 +959,6 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-               t += 800;
- 
-               /* 2.10.5.8.5 (10) */
--              mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
-               dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 
4)));               /* Retrieve NbDid, NbFid */
-               nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) 
& 0x1)?2:1);
-               n = (((((uint64_t)p * 
1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + 
((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
-@@ -964,8 +973,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-               Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
- 
-               /* Save result for later use */
--              pDCTstat->CH_MaxRdLat[dct] = n;
-+              pDCTstat->CH_MaxRdLat[dct] = n - 1;
-+
-+#if DQS_TRAIN_DEBUG > 0
-+      printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, 
pDCTstat->CH_MaxRdLat[dct]);
-+#endif
-       }
-+
-+#if DQS_TRAIN_DEBUG > 0
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
-+#endif
- }
- 
- static void start_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-index a0482e8..d25ed53 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
-@@ -92,13 +92,8 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-       uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED];
-       uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED];
- 
--      uint8_t redirect_ecc_scrub = 0;
--
-       mctHookBeforeECC();
- 
--      if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
--              redirect_ecc_scrub = 1;
--
-       /* Construct these booleans, based on setup options, for easy handling
-       later in this procedure */
-       OB_NBECC = mctGet_NVbits(NV_NBECC);                     /* MCA ECC 
(MCE) enable bit */
-@@ -117,8 +112,11 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-               OF_ScrubCTL |= (u32) nvbits << 8;
-       }
- 
-+      nvbits = mctGet_NVbits(NV_L3BKScrub);
-+      OF_ScrubCTL |= (nvbits & 0x1f) << 24;                   /* L3Scrub = 
NV_L3BKScrub */
-+
-       nvbits = mctGet_NVbits(NV_DramBKScrub);
--      OF_ScrubCTL |= nvbits;
-+      OF_ScrubCTL |= nvbits;                                  /* DramScrub = 
NV_DramBKScrub */
- 
-       /* Prevent lockups on DRAM errors during ECC init */
-       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-@@ -133,6 +131,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                       dword &= ~(0x1 << 21);
-                       Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
- 
-+                      /* Clear MC4 error status */
-+                      pci_write_config32(pDCTstat->dev_nbmisc, 0x48, 0x0);
-+                      pci_write_config32(pDCTstat->dev_nbmisc, 0x4c, 0x0);
-+
-                       /* Clear the RAM before enabling ECC to prevent 
MCE-related lockups */
-                       DCTMemClr_Init_D(pMCTstat, pDCTstat);
-                       DCTMemClr_Sync_D(pMCTstat, pDCTstat);
-@@ -170,6 +172,9 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                               if(LDramECC) {  /* if ECC is enabled on this 
dram */
-                                       if (OB_NBECC) {
-                                               mct_EnableDatIntlv_D(pMCTstat, 
pDCTstat);
-+                                              val = 
Get_NB32(pDCTstat->dev_dct, 0x110);
-+                                              val |= 1 << 5;  /* DctDatIntLv 
= 1 */
-+                                              Set_NB32(pDCTstat->dev_dct, 
0x110, val);
-                                               dev = pDCTstat->dev_nbmisc;
-                                               reg = 0x44;     /* MCA NB 
Configuration */
-                                               val = Get_NB32(dev, reg);
-@@ -180,37 +185,16 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                                               printk(BIOS_DEBUG, "  ECC 
enabled on node: %02x\n", Node);
-                                       }
-                               }       /* this node has ECC enabled dram */
-+
-+                              if (MemClrECC) {
-+                                      DCTMemClr_Sync_D(pMCTstat, pDCTstat);
-+                              }
-                       } else {
-                               LDramECC = 0;
-                       }       /* Node has Dram */
--
--                      if (MemClrECC) {
--                              DCTMemClr_Sync_D(pMCTstat, pDCTstat);
--                      }
--
--                      if (pDCTstat->LogicalCPUID & (AMD_DR_GT_D0 | 
AMD_FAM15_ALL)) {
--                              /* Set up message triggered C1E */
--                              val = pci_read_config32(pDCTstat->dev_nbmisc, 
0xd4);
--                              val &= ~(0x1 << 15);                    /* 
StutterScrubEn = DRAM scrub enabled */
--                              val |= (mctGet_NVbits(NV_DramBKScrub)?1:0) << 
15;
--                              pci_write_config32(pDCTstat->dev_nbmisc, 0xd4, 
val);
--                      }
-               }       /* if Node present */
-       }
- 
--      /* Restore previous MCA error handling settings */
--      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
--              struct DCTStatStruc *pDCTstat;
--              pDCTstat = pDCTstatA + Node;
--
--              if (NodePresent_D(Node)) {
--                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
--                      dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
--                      dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
--                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
--              }
--      }
--
-       if(AllECC)
-               pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
-       else
-@@ -229,19 +213,26 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                       /*WE/RE is checked because memory config may have been 
*/
-                       if((val & 3)==3) {      /* Node has dram populated */
-                               if (isDramECCEn_D(pDCTstat)) {  /* if ECC is 
enabled on this dram */
--                                      if (is_fam15h()) {
--                                              /* Erratum 505 */
--                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);
--                                      }
-                                       dev = pDCTstat->dev_nbmisc;
-                                       val = curBase << 8;
-                                       if (OB_ECCRedir) {
--                                              val |= (1<<0);                  
/* enable redirection */
-+                                              val |= (1 << 0);                
/* Enable redirection */
-                                       }
-                                       Set_NB32(dev, 0x5c, val);               
/* Dram Scrub Addr Low */
--                                      val = curBase>>24;
-+                                      val = curBase >> 24;
-                                       Set_NB32(dev, 0x60, val);               
/* Dram Scrub Addr High */
--                                      Set_NB32(dev, 0x58, OF_ScrubCTL);       
/*Scrub Control */
-+
-+                                      /* Set scrub rate controls */
-+                                      if (is_fam15h()) {
-+                                              /* Erratum 505 */
-+                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);
-+                                      }
-+                                      Set_NB32(dev, 0x58, OF_ScrubCTL);       
/* Scrub Control */
-+                                      if (is_fam15h()) {
-+                                              
fam15h_switch_dct(pDCTstat->dev_map, 1);        /* Erratum 505 */
-+                                              Set_NB32(dev, 0x58, 
OF_ScrubCTL);               /* Scrub Control */
-+                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);        /* Erratum 505 */
-+                                      }
- 
-                                       if (!is_fam15h()) {
-                                               /* Divisor should not be set 
deeper than
-@@ -258,36 +249,31 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
-                                               }
-                                       }
- 
--                                      if (is_fam15h()) {
--                                              uint8_t dct;
--
--                                              /* Disable training mode
--                                               * See fam15EnableTrainingMode 
for the non-ECC training mode tear-down code
--                                               */
--                                              for (dct = 0; dct < 2; dct++) {
--                                                      /* NOTE: Reads use DCT 
0 and writes use the current DCT per Erratum 505 */
--                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, 0, 0x58);    /* Scrub Rate Control */
--                                                      dword &= ~(0x1f << 24); 
                                /* L3Scrub = NV_L3BKScrub */
--                                                      dword |= 
(mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
--                                                      dword &= ~(0x1f);       
                                /* DramScrub = NV_DramBKScrub */
--                                                      dword |= 
mctGet_NVbits(NV_DramBKScrub) & 0x1f;
--                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* Scrub Rate Control */
--
--                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM Scrub Address Low */
--                                                      dword &= ~(0x1);        
                                /* ScrubReDirEn = redirect_ecc_scrub */
--                                                      dword |= 
redirect_ecc_scrub & 0x1;
--                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM Scrub Address 
Low */
--
--                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */
--                                                      dword &= ~(0x1 << 4);   
                                /* L3ScrbRedirDis = 0 */
--                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 Control 1 */
--                                              }
-+                                      if (pDCTstat->LogicalCPUID & 
(AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
-+                                              /* Set up message triggered C1E 
*/
-+                                              val = 
pci_read_config32(pDCTstat->dev_nbmisc, 0xd4);
-+                                              val &= ~(0x1 << 15);            
        /* StutterScrubEn = DRAM scrub enabled */
-+                                              val |= 
(mctGet_NVbits(NV_DramBKScrub)?1:0) << 15;
-+                                              
pci_write_config32(pDCTstat->dev_nbmisc, 0xd4, val);
-                                       }
-                               }       /* this node has ECC enabled dram */
-                       }       /*Node has Dram */
-               }       /*if Node present */
-       }
- 
-+      /* Restore previous MCA error handling settings */
-+      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+              struct DCTStatStruc *pDCTstat;
-+              pDCTstat = pDCTstatA + Node;
-+
-+              if (NodePresent_D(Node)) {
-+                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
-+                      dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
-+                      dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
-+                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
-+              }
-+      }
-+
-       if(mctGet_NVbits(NV_SyncOnUnEccEn))
-               setSyncOnUnEccEn_D(pMCTstat, pDCTstatA);
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
-index 596fb23..abc8ae3 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
-@@ -232,9 +232,9 @@ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat
-               Cache32bTOP = val;
-               pMCTstat->Sub4GCacheTop = val;
- 
--      /*======================================================================
--       * Clear variable MTRR values
--       
*======================================================================*/
-+              
/*======================================================================
-+               * Clear variable MTRR values
-+               
*======================================================================*/
-               addr = 0x200;
-               lo = 0;
-               hi = lo;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-index fe89af1..b4a084c 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
-@@ -89,6 +89,28 @@ static uint32_t read_config32_dct(device_t dev, uint8_t 
node, uint8_t dct, uint3
-       return pci_read_config32(dev, reg);
- }
- 
-+static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg, uint32_t value) {
-+      if (is_fam15h()) {
-+              uint32_t dword;
-+#ifdef __PRE_RAM__
-+              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-+#else
-+              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
-+#endif
-+
-+              /* Select DCT */
-+              dword = pci_read_config32(dev_fn1, 0x10c);
-+              dword &= ~0x1;
-+              dword |= (dct & 0x1);
-+              pci_write_config32(dev_fn1, 0x10c, dword);
-+      } else {
-+              /* Apply offset */
-+              reg += dct * 0x100;
-+      }
-+
-+      pci_write_config32(dev, reg, value);
-+}
-+
- static uint32_t read_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index)
- {
-       uint32_t dword;
-@@ -489,29 +511,17 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
- 
-                       /* Other */
-                       /* ECC scrub rate control */
--                      data->f3x58 = pci_read_config32(dev_fn3, 0x58);
-+                      data->f3x58 = read_config32_dct(dev_fn3, node, 0, 0x58);
-+
-+                      /* ECC scrub location */
-+                      write_config32_dct(dev_fn3, node, 0, 0x58, 0x0);        
        /* Disable sequential scrub to work around non-atomic location read */
-+                      data->f3x5c = read_config32_dct(dev_fn3, node, 0, 0x5c);
-+                      data->f3x60 = read_config32_dct(dev_fn3, node, 0, 0x60);
-+                      write_config32_dct(dev_fn3, node, 0, 0x58, 
data->f3x58);        /* Re-enable sequential scrub */
-               }
-       }
- }
- #else
--static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg, uint32_t value) {
--      if (is_fam15h()) {
--              uint32_t dword;
--              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
--
--              /* Select DCT */
--              dword = pci_read_config32(dev_fn1, 0x10c);
--              dword &= ~0x1;
--              dword |= (dct & 0x1);
--              pci_write_config32(dev_fn1, 0x10c, dword);
--      } else {
--              /* Apply offset */
--              reg += dct * 0x100;
--      }
--
--      pci_write_config32(dev, reg, value);
--}
--
- static void write_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t 
dct, uint8_t nb_pstate, uint32_t reg, uint32_t value) {
-       uint32_t dword;
-       device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-@@ -613,8 +623,7 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                               if (is_fam15h()) {
-                                       for (i=0; i<4; i++)
-                                               
write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 
0x210, data->f2x210[i]);
--                              }
--                              else {
-+                              } else {
-                                       write_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x78, data->f2x78);
-                               }
- 
-@@ -1060,8 +1069,12 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
-                       if (!persistent_data->node[node].node_present)
-                               continue;
- 
-+                      /* ECC scrub location */
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 
0x5c, data->f3x5c);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 
0x60, data->f3x60);
-+
-                       /* ECC scrub rate control */
--                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x58, 
data->f3x58);
-+                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 
0x58, data->f3x58);
- 
-                       if (is_fam15h())
-                               /* Set LockDramCfg and CC6SaveEn */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0070-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
 
b/resources/libreboot/patch/kgpe-d16/0070-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
new file mode 100644
index 0000000..6a95d9d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0070-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch
@@ -0,0 +1,409 @@
+From e37c51fbf56695813ee545da5507eb465c688241 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Wed, 24 Jun 2015 19:15:09 -0500
+Subject: [PATCH 070/143] northbridge/amd/amdmct/mct_ddr3: Fix lockups and
+ wasted time during ECC init
+
+Change-Id: I09a8ea83024186b7ece7d78a4bef1201ab34ff8a
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  144 +++++++++++++++---------
+ src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c |   39 ++++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctproc.c  |   22 +++-
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |    3 +-
+ 4 files changed, 147 insertions(+), 61 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index d8a09f0..78bc8b3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1498,11 +1498,12 @@ restartinit:
+               InterleaveChannels_D(pMCTstat, pDCTstatA);
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n");
+-              ECCInit_D(pMCTstat, pDCTstatA);                 /* Setup ECC 
control and ECC check-bits*/
+-
+-              /* mctDoWarmResetMemClr_D(); */
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
+-              MCTMemClr_D(pMCTstat,pDCTstatA);
++              if (!ECCInit_D(pMCTstat, pDCTstatA)) {                  /* 
Setup ECC control and ECC check-bits*/
++                      /* Memory was not cleared during ECC setup */
++                      /* mctDoWarmResetMemClr_D(); */
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n");
++                      MCTMemClr_D(pMCTstat,pDCTstatA);
++              }
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+@@ -1695,7 +1696,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               uint8_t x8_present = 0;
+               uint8_t memclk_index;
+               uint8_t interleave_channels = 0;
+-              uint8_t redirect_ecc_scrub = 0;
+               uint16_t trdrdsddc;
+               uint16_t trdrddd;
+               uint16_t cdd_trdrddd;
+@@ -1733,9 +1733,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               if (pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1] && 
mctGet_NVbits(NV_Unganged))
+                       interleave_channels = 1;
+ 
+-              if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
+-                      redirect_ecc_scrub = 1;
+-
+               dword = (Get_NB32_DCT(dev, dct, 0x240) >> 4) & 0xf;
+               if (dword > 6)
+                       read_odt_delay = dword - 6;
+@@ -1927,21 +1924,10 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
+               dword |= (interleave_channels & 0x1) << 2;
+               Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
+ 
+-              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58);  /* 
Scrub Rate Control */
+-              dword &= ~(0x1f << 24);                                 /* 
L3Scrub = NV_L3BKScrub */
+-              dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
+-              dword &= ~(0x1f);                                       /* 
DramScrub = NV_DramBKScrub */
+-              dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f;
+-              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* 
Scrub Rate Control */
+-
+-              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM 
Scrub Address Low */
+-              dword &= ~(0x1);                                        /* 
ScrubReDirEn = redirect_ecc_scrub */
+-              dword |= redirect_ecc_scrub & 0x1;
+-              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM 
Scrub Address Low */
+-
+-              dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 
Control 1 */
+-              dword &= ~(0x1 << 4);                                   /* 
L3ScrbRedirDis = 0 */
+-              Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 
Control 1 */
++              /* NOTE
++               * ECC-related setup is performed as part of ECCInit_D and must 
not be located here,
++               * otherwise semi-random lockups will occur due to 
misconfigured scrubbing hardware!
++               */
+ 
+               /* FIXME
+                * The BKDG-recommended settings cause memory corruption on the 
ASUS KGPE-D16.
+@@ -1983,11 +1969,17 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
+               dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
+               Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
+ 
++              /* Configure partial power down delay */
++              dword = Get_NB32(dev, 0x244);                           /* DRAM 
Controller Miscellaneous 3 */
++              dword &= ~0xf;                                          /* 
PrtlChPDDynDly = 0x2 */
++              dword |= 0x2;
++              Set_NB32(dev, 0x244, dword);                            /* DRAM 
Controller Miscellaneous 3 */
++
+               /* Enable prefetchers */
+-              dword = Get_NB32_DCT(dev, dct, 0x110);                  /* 
Memory Controller Configuration High */
++              dword = Get_NB32(dev, 0x11c);                           /* 
Memory Controller Configuration High */
+               dword &= ~(0x1 << 13);                                  /* 
PrefIoDis = 0 */
+               dword &= ~(0x1 << 12);                                  /* 
PrefCpuDis = 0 */
+-              Set_NB32_DCT(dev, dct, 0x110, dword);                   /* 
Memory Controller Configuration High */
++              Set_NB32(dev, 0x11c, dword);                            /* 
Memory Controller Configuration High */
+       }
+ }
+ 
+@@ -2091,6 +2083,19 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+               pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
+       }
+ 
++      if (is_fam15h()) {
++              uint8_t Node;
++              struct DCTStatStruc *pDCTstat;
++
++              /* Switch DCT control register to DCT 0 per Erratum 505 */
++              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                      pDCTstat = pDCTstatA + Node;
++                      if (pDCTstat->NodePresent) {
++                              fam15h_switch_dct(pDCTstat->dev_map, 0);
++                      }
++              }
++      }
++
+       /* FIXME - currently uses calculated value      
TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+       mctHookAfterAnyTraining();
+ }
+@@ -2337,6 +2342,7 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
+        * status are checked to ensure that memclr has completed.
+        */
+       u8 Node;
++      uint32_t dword;
+       struct DCTStatStruc *pDCTstat;
+ 
+       if (!mctGet_NVbits(NV_DQSTrainCTL)){
+@@ -2357,6 +2363,18 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
+                       }
+               }
+       }
++
++      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++              pDCTstat = pDCTstatA + Node;
++
++              /* Configure and enable prefetchers */
++              if (is_fam15h())
++                      dword = 0x0ce00f41;     /* BKDG recommended */
++              else
++                      dword = 0x0fe40fc0;     /* BKDG recommended */
++              dword |= MCCH_FlushWrOnStpGnt;  /* Set for S3 */
++              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);
++      }
+ }
+ 
+ static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat,
+@@ -2364,48 +2382,59 @@ static void DCTMemClr_Init_D(struct MCTStatStruc 
*pMCTstat,
+ {
+       u32 val;
+       u32 dev;
+-      u32 reg;
++      uint32_t dword;
+ 
+       /* Initiates a memory clear operation on one node */
+       if (pDCTstat->DCTSysLimit) {
+               dev = pDCTstat->dev_dct;
+-              reg = 0x110;
++
++              /* Disable prefetchers */
++              dword = Get_NB32(dev, 0x11c);           /* Memory Controller 
Configuration High */
++              dword |= 0x1 << 13;                     /* PrefIoDis = 1 */
++              dword |= 0x1 << 12;                     /* PrefCpuDis = 1 */
++              Set_NB32(dev, 0x11c, dword);            /* Memory Controller 
Configuration High */
+ 
+               do {
+-                      val = Get_NB32(dev, reg);
++                      val = Get_NB32(dev, 0x110);
+               } while (val & (1 << MemClrBusy));
+ 
+               val |= (1 << MemClrInit);
+-              Set_NB32(dev, reg, val);
++              Set_NB32(dev, 0x110, val);
+       }
+ }
+ 
+ static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+ {
+-      u32 val;
+-      u32 dev = pDCTstat->dev_dct;
+-      u32 reg;
++      uint32_t dword;
++      uint32_t dev = pDCTstat->dev_dct;
++
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
+ 
+       /* Ensure that a memory clear operation has completed on one node */
+       if (pDCTstat->DCTSysLimit){
+-              reg = 0x110;
+-
++              printk(BIOS_DEBUG, "%s: Waiting for memory clear to complete", 
__func__);
+               do {
+-                      val = Get_NB32(dev, reg);
+-              } while (val & (1 << MemClrBusy));
++                      dword = Get_NB32(dev, 0x110);
++
++                      printk(BIOS_DEBUG, ".");
++              } while (dword & (1 << MemClrBusy));
+ 
++              printk(BIOS_DEBUG, "\n");
+               do {
+-                      val = Get_NB32(dev, reg);
+-              } while (!(val & (1 << Dr_MemClrStatus)));
++                      printk(BIOS_DEBUG, ".");
++                      dword = Get_NB32(dev, 0x110);
++              } while (!(dword & (1 << Dr_MemClrStatus)));
++              printk(BIOS_DEBUG, "\n");
+       }
+ 
+-      if (is_fam15h())
+-              val = 0x0ce00f41;       /* BKDG recommended */
+-      else
+-              val = 0x0fe40fc0;       /* BKDG recommended */
+-      val |= MCCH_FlushWrOnStpGnt;    /* Set for S3 */
+-      Set_NB32(dev, 0x11c, val);
++      /* Enable prefetchers */
++      dword = Get_NB32(dev, 0x11c);           /* Memory Controller 
Configuration High */
++      dword &= ~(0x1 << 13);                  /* PrefIoDis = 0 */
++      dword &= ~(0x1 << 12);                  /* PrefCpuDis = 0 */
++      Set_NB32(dev, 0x11c, dword);            /* Memory Controller 
Configuration High */
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static u8 NodePresent_D(u8 Node)
+@@ -3346,8 +3375,8 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+       dev = pDCTstat->dev_dct;
+ 
+       /* Build Dram Control Register Value */
+-      DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xA8);         /* Dram 
Control*/
+-      DramControl = Get_NB32_DCT(dev, dct, 0x78);             /* Dram 
Control*/
++      DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xa8);         /* Dram 
Miscellaneous 2 */
++      DramControl = Get_NB32_DCT(dev, dct, 0x78);             /* Dram Control 
*/
+ 
+       /* FIXME: Skip mct_checkForDxSupport */
+       /* REV_CALL mct_DoRdPtrInit if not Dx */
+@@ -3402,9 +3431,15 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+                       /* set only if x8 Registered DIMMs in System*/
+                       DramConfigHi |= 1 << RDqsEn;
+ 
+-      if (mctGet_NVbits(NV_CKE_CTL))
+-              /*Chip Select control of CKE*/
+-              DramConfigHi |= 1 << 16;
++      if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
++              DramConfigLo |= 1 << 25;        /* PendRefPaybackS3En = 1 */
++              DramConfigLo |= 1 << 24;        /* StagRefEn = 1 */
++              DramConfigHi |= 1 << 16;        /* PowerDownMode = 1 */
++      } else {
++              if (mctGet_NVbits(NV_CKE_CTL))
++                      /*Chip Select control of CKE*/
++                      DramConfigHi |= 1 << 16;
++      }
+ 
+       /* Control Bank Swizzle */
+       if (0) /* call back not needed mctBankSwizzleControl_D()) */
+@@ -4112,8 +4147,7 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
+ 
+       if (load_spd_hashes_from_nvram(pMCTstat, pDCTstat) < 0) {
+               pDCTstat->spd_data.nvram_spd_match = 0;
+-      }
+-      else {
++      } else {
+               compare_nvram_spd_hashes(pMCTstat, pDCTstat);
+       }
+ #else
+@@ -4311,8 +4345,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+       }
+       for (i=i_start; i<i_end; i++) {
+               index_reg = 0x98;
+-              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */
+-              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */
++              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */
++              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */
+       }
+ 
+       return pDCTstat->ErrCode;
+@@ -6102,11 +6136,11 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+               DramMRS |= 1 << 1;
+ 
+       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
++      dword |= DramMRS;
+       if (is_fam15h())
+               dword &= ~0x00800003;
+       else
+               dword &= ~0x00fc2f8f;
+-      dword |= DramMRS;
+       Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword);
+ }
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+index 918e91e..a0482e8 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+@@ -92,8 +92,13 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+       uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED];
+       uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED];
+ 
++      uint8_t redirect_ecc_scrub = 0;
++
+       mctHookBeforeECC();
+ 
++      if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
++              redirect_ecc_scrub = 1;
++
+       /* Construct these booleans, based on setup options, for easy handling
+       later in this procedure */
+       OB_NBECC = mctGet_NVbits(NV_NBECC);                     /* MCA ECC 
(MCE) enable bit */
+@@ -230,12 +235,12 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                                       }
+                                       dev = pDCTstat->dev_nbmisc;
+                                       val = curBase << 8;
+-                                      if(OB_ECCRedir) {
+-                                              val |= (1<<0); /* enable 
redirection */
++                                      if (OB_ECCRedir) {
++                                              val |= (1<<0);                  
/* enable redirection */
+                                       }
+-                                      Set_NB32(dev, 0x5C, val); /* Dram Scrub 
Addr Low */
++                                      Set_NB32(dev, 0x5c, val);               
/* Dram Scrub Addr Low */
+                                       val = curBase>>24;
+-                                      Set_NB32(dev, 0x60, val); /* Dram Scrub 
Addr High */
++                                      Set_NB32(dev, 0x60, val);               
/* Dram Scrub Addr High */
+                                       Set_NB32(dev, 0x58, OF_ScrubCTL);       
/*Scrub Control */
+ 
+                                       if (!is_fam15h()) {
+@@ -252,6 +257,32 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                                                       }
+                                               }
+                                       }
++
++                                      if (is_fam15h()) {
++                                              uint8_t dct;
++
++                                              /* Disable training mode
++                                               * See fam15EnableTrainingMode 
for the non-ECC training mode tear-down code
++                                               */
++                                              for (dct = 0; dct < 2; dct++) {
++                                                      /* NOTE: Reads use DCT 
0 and writes use the current DCT per Erratum 505 */
++                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, 0, 0x58);    /* Scrub Rate Control */
++                                                      dword &= ~(0x1f << 24); 
                                /* L3Scrub = NV_L3BKScrub */
++                                                      dword |= 
(mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
++                                                      dword &= ~(0x1f);       
                                /* DramScrub = NV_DramBKScrub */
++                                                      dword |= 
mctGet_NVbits(NV_DramBKScrub) & 0x1f;
++                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* Scrub Rate Control */
++
++                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM Scrub Address Low */
++                                                      dword &= ~(0x1);        
                                /* ScrubReDirEn = redirect_ecc_scrub */
++                                                      dword |= 
redirect_ecc_scrub & 0x1;
++                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM Scrub Address 
Low */
++
++                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */
++                                                      dword &= ~(0x1 << 4);   
                                /* L3ScrbRedirDis = 0 */
++                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 Control 1 */
++                                              }
++                                      }
+                               }       /* this node has ECC enabled dram */
+                       }       /*Node has Dram */
+               }       /*if Node present */
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+index 5ef4a2c..32b447f 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+@@ -23,7 +23,27 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
+ {
+       u32 val;
+ 
+-      if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
++      /* FIXME
++       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
++       * For now assume a maximum of 2 DIMMs per channel can be installed
++       */
++      uint8_t MaxDimmsInstallable = 2;
++
++      if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
++              uint8_t cs_mux_45;
++              uint8_t cs_mux_67;
++
++              /* BKDG v3.14 Table 200 / Table 201 */
++              if (MaxDimmsInstallable < 3) {
++                      cs_mux_45 = 1;
++                      cs_mux_67 = 1;
++              } else {
++                      cs_mux_45 = 0;
++                      cs_mux_67 = 0;
++              }
++              misc2 |= (cs_mux_45 & 0x1) << 26;
++              misc2 |= (cs_mux_67 & 0x1) << 27;
++      } else if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
+               if (pDCTstat->Status & (1 << SB_Registered)) {
+                       misc2 |= 1 << SubMemclkRegDly;
+                       if (mctGet_NVbits(NV_MAX_DIMMS) == 8)
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 35378c8..0e626fa 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -209,7 +209,8 @@ void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTsta
+                       uint16_t total_delay_seed = 
((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
+                       uint16_t total_delay_phy = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
+                       if (abs(total_delay_phy - total_delay_seed) > 0x20) {
+-                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value\n", __func__);
++                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value (seed: %04x phy: %04x step: %04x)\n", __func__,
++                                      total_delay_seed, total_delay_phy, 
abs(total_delay_phy - total_delay_seed));
+                               pDCTData->WLGrossDelay[index+ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane];
+                               pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
+                       }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0071-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
 
b/resources/libreboot/patch/kgpe-d16/0071-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
new file mode 100644
index 0000000..7a84e72
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0071-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch
@@ -0,0 +1,474 @@
+From b2b65511ad56a90e2f206d99d348854d379a719b Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 25 Jun 2015 15:07:34 -0500
+Subject: [PATCH 071/143] cpu/amd: Fix AMD Family 15h ECC initialization
+ reliability issues
+
+Change-Id: I7f009b655f8500aeb22981f7020f1db74cdd6925
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/car/cache_as_ram.inc               |    4 +
+ src/cpu/amd/family_10h-family_15h/init_cpus.c  |   16 ++++
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |   12 +--
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |    6 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   21 ++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c |  110 +++++++++++-------------
+ src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c |    6 +-
+ src/northbridge/amd/amdmct/mct_ddr3/s3utils.c  |   57 +++++++-----
+ 8 files changed, 136 insertions(+), 96 deletions(-)
+
+diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
+index 9edc41f..5db9224 100644
+--- a/src/cpu/amd/car/cache_as_ram.inc
++++ b/src/cpu/amd/car/cache_as_ram.inc
+@@ -362,12 +362,16 @@ clear_fixed_var_mtrr_out:
+       simplemask CacheSize, 0
+       wrmsr
+ 
++      jmp_if_fam15h(fam15_skip_dram_mtrr_setup)
++
+       /* Enable memory access for first MBs using top_mem. */
+       movl    $TOP_MEM, %ecx
+       xorl    %edx, %edx
+       movl    $(((CONFIG_RAMTOP) + TOP_MEM_MASK) & ~TOP_MEM_MASK) , %eax
+       wrmsr
+ 
++fam15_skip_dram_mtrr_setup:
++
+ #if CONFIG_XIP_ROM_SIZE
+ 
+       /* Enable write base caching so we can do execute in place (XIP)
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index 061bba2..d45671c 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -317,6 +317,22 @@ static void STOP_CAR_AND_CPU(uint8_t skip_sharedc_config, 
uint32_t apicid)
+               msr = rdmsr(BU_CFG2);
+               msr.lo &= ~(1 << ClLinesToNbDis);
+               wrmsr(BU_CFG2, msr);
++      } else {
++              /* Family 15h or later
++               * DRAM setup is delayed on Fam15 in order to prevent
++               * any DRAM access before ECC check bits are initialized.
++               * Each core also needs to have its initial DRAM map initialized
++               * before it is put to sleep, otherwise it will fail to wake
++               * in ramstage.  To meet both of these goals, delay DRAM map
++               * setup until the last possible moment, where speculative
++               * memory access is highly unlikely before core halt...
++               */
++              if (!skip_sharedc_config) {
++                      /* Enable memory access for first MBs using top_mem */
++                      msr.hi = 0;
++                      msr.lo = (CONFIG_RAMTOP + TOP_MEM_MASK) & 
(~TOP_MEM_MASK);
++                      wrmsr(TOP_MEM, msr);
++              }
+       }
+ 
+       disable_cache_as_ram(skip_sharedc_config);      // inline
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 78bc8b3..dda997e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1458,8 +1458,7 @@ restartinit:
+               HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory 
into system address space.*/
+               mctHookAfterHTMap();
+ 
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
+-              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctHookAfterCPU\n");
+               mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
+ 
+               /* FIXME
+@@ -1482,9 +1481,6 @@ restartinit:
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
+               DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get 
Receiver Enable and DQS signal timing*/
+ 
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
+-              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
+-
+               if (!allow_config_restore) {
+                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+                       mct_OtherTiming(pMCTstat, pDCTstatA);
+@@ -1505,6 +1501,12 @@ restartinit:
+                       MCTMemClr_D(pMCTstat,pDCTstatA);
+               }
+ 
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
++              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
++
++              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
++              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
++
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+                       struct DCTStatStruc *pDCTstat;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 11555ae..ac8c934 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -725,8 +725,10 @@ struct amd_s3_persistent_mct_channel_data {
+       uint32_t f2x9cx30[12];
+       uint32_t f2x9cx40[12];
+ 
+-      /* Other (1 dword) */
++      /* Other (3 dwords) */
+       uint32_t f3x58;
++      uint32_t f3x5c;
++      uint32_t f3x60;
+ 
+       /* Family 15h-specific registers (90 dwords) */
+       uint32_t f2x200;
+@@ -785,7 +787,7 @@ struct amd_s3_persistent_mct_channel_data {
+       uint32_t f2x9cx0d0f0_0_f_31[9];         /* [lane] */
+       uint32_t f2x9cx0d0f8021;
+ 
+-      /* TOTAL: 340 dwords */
++      /* TOTAL: 342 dwords */
+ } __attribute__((packed));
+ 
+ struct amd_s3_persistent_node_data {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index 740edae..b0ad54b 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -902,6 +902,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+       uint32_t dev = pDCTstat->dev_dct;
+       uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+ 
++#if DQS_TRAIN_DEBUG > 0
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++#endif
++
++      mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
++      if (fam15h_freq_tab[mem_clk] == 0) {
++              pDCTstat->CH_MaxRdLat[dct] = 0x55;
++              return;
++      }
++
+       /* P is specified in PhyCLKs (1/2 MEMCLKs) */
+       for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
+               /* 2.10.5.8.5 (2) */
+@@ -949,7 +959,6 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+               t += 800;
+ 
+               /* 2.10.5.8.5 (10) */
+-              mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f;
+               dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 
4)));               /* Retrieve NbDid, NbFid */
+               nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) 
& 0x1)?2:1);
+               n = (((((uint64_t)p * 
1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + 
((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
+@@ -964,8 +973,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+               Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
+ 
+               /* Save result for later use */
+-              pDCTstat->CH_MaxRdLat[dct] = n;
++              pDCTstat->CH_MaxRdLat[dct] = n - 1;
++
++#if DQS_TRAIN_DEBUG > 0
++      printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, 
pDCTstat->CH_MaxRdLat[dct]);
++#endif
+       }
++
++#if DQS_TRAIN_DEBUG > 0
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
++#endif
+ }
+ 
+ static void start_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+index a0482e8..d25ed53 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
+@@ -92,13 +92,8 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+       uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED];
+       uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED];
+ 
+-      uint8_t redirect_ecc_scrub = 0;
+-
+       mctHookBeforeECC();
+ 
+-      if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && 
mctGet_NVbits(NV_ECCRedir))
+-              redirect_ecc_scrub = 1;
+-
+       /* Construct these booleans, based on setup options, for easy handling
+       later in this procedure */
+       OB_NBECC = mctGet_NVbits(NV_NBECC);                     /* MCA ECC 
(MCE) enable bit */
+@@ -117,8 +112,11 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+               OF_ScrubCTL |= (u32) nvbits << 8;
+       }
+ 
++      nvbits = mctGet_NVbits(NV_L3BKScrub);
++      OF_ScrubCTL |= (nvbits & 0x1f) << 24;                   /* L3Scrub = 
NV_L3BKScrub */
++
+       nvbits = mctGet_NVbits(NV_DramBKScrub);
+-      OF_ScrubCTL |= nvbits;
++      OF_ScrubCTL |= nvbits;                                  /* DramScrub = 
NV_DramBKScrub */
+ 
+       /* Prevent lockups on DRAM errors during ECC init */
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+@@ -133,6 +131,10 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                       dword &= ~(0x1 << 21);
+                       Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
+ 
++                      /* Clear MC4 error status */
++                      pci_write_config32(pDCTstat->dev_nbmisc, 0x48, 0x0);
++                      pci_write_config32(pDCTstat->dev_nbmisc, 0x4c, 0x0);
++
+                       /* Clear the RAM before enabling ECC to prevent 
MCE-related lockups */
+                       DCTMemClr_Init_D(pMCTstat, pDCTstat);
+                       DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+@@ -170,6 +172,9 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                               if(LDramECC) {  /* if ECC is enabled on this 
dram */
+                                       if (OB_NBECC) {
+                                               mct_EnableDatIntlv_D(pMCTstat, 
pDCTstat);
++                                              val = 
Get_NB32(pDCTstat->dev_dct, 0x110);
++                                              val |= 1 << 5;  /* DctDatIntLv 
= 1 */
++                                              Set_NB32(pDCTstat->dev_dct, 
0x110, val);
+                                               dev = pDCTstat->dev_nbmisc;
+                                               reg = 0x44;     /* MCA NB 
Configuration */
+                                               val = Get_NB32(dev, reg);
+@@ -180,37 +185,16 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                                               printk(BIOS_DEBUG, "  ECC 
enabled on node: %02x\n", Node);
+                                       }
+                               }       /* this node has ECC enabled dram */
++
++                              if (MemClrECC) {
++                                      DCTMemClr_Sync_D(pMCTstat, pDCTstat);
++                              }
+                       } else {
+                               LDramECC = 0;
+                       }       /* Node has Dram */
+-
+-                      if (MemClrECC) {
+-                              DCTMemClr_Sync_D(pMCTstat, pDCTstat);
+-                      }
+-
+-                      if (pDCTstat->LogicalCPUID & (AMD_DR_GT_D0 | 
AMD_FAM15_ALL)) {
+-                              /* Set up message triggered C1E */
+-                              val = pci_read_config32(pDCTstat->dev_nbmisc, 
0xd4);
+-                              val &= ~(0x1 << 15);                    /* 
StutterScrubEn = DRAM scrub enabled */
+-                              val |= (mctGet_NVbits(NV_DramBKScrub)?1:0) << 
15;
+-                              pci_write_config32(pDCTstat->dev_nbmisc, 0xd4, 
val);
+-                      }
+               }       /* if Node present */
+       }
+ 
+-      /* Restore previous MCA error handling settings */
+-      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+-              struct DCTStatStruc *pDCTstat;
+-              pDCTstat = pDCTstatA + Node;
+-
+-              if (NodePresent_D(Node)) {
+-                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
+-                      dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
+-                      dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
+-                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
+-              }
+-      }
+-
+       if(AllECC)
+               pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
+       else
+@@ -229,19 +213,26 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                       /*WE/RE is checked because memory config may have been 
*/
+                       if((val & 3)==3) {      /* Node has dram populated */
+                               if (isDramECCEn_D(pDCTstat)) {  /* if ECC is 
enabled on this dram */
+-                                      if (is_fam15h()) {
+-                                              /* Erratum 505 */
+-                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);
+-                                      }
+                                       dev = pDCTstat->dev_nbmisc;
+                                       val = curBase << 8;
+                                       if (OB_ECCRedir) {
+-                                              val |= (1<<0);                  
/* enable redirection */
++                                              val |= (1 << 0);                
/* Enable redirection */
+                                       }
+                                       Set_NB32(dev, 0x5c, val);               
/* Dram Scrub Addr Low */
+-                                      val = curBase>>24;
++                                      val = curBase >> 24;
+                                       Set_NB32(dev, 0x60, val);               
/* Dram Scrub Addr High */
+-                                      Set_NB32(dev, 0x58, OF_ScrubCTL);       
/*Scrub Control */
++
++                                      /* Set scrub rate controls */
++                                      if (is_fam15h()) {
++                                              /* Erratum 505 */
++                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);
++                                      }
++                                      Set_NB32(dev, 0x58, OF_ScrubCTL);       
/* Scrub Control */
++                                      if (is_fam15h()) {
++                                              
fam15h_switch_dct(pDCTstat->dev_map, 1);        /* Erratum 505 */
++                                              Set_NB32(dev, 0x58, 
OF_ScrubCTL);               /* Scrub Control */
++                                              
fam15h_switch_dct(pDCTstat->dev_map, 0);        /* Erratum 505 */
++                                      }
+ 
+                                       if (!is_fam15h()) {
+                                               /* Divisor should not be set 
deeper than
+@@ -258,36 +249,31 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA)
+                                               }
+                                       }
+ 
+-                                      if (is_fam15h()) {
+-                                              uint8_t dct;
+-
+-                                              /* Disable training mode
+-                                               * See fam15EnableTrainingMode 
for the non-ECC training mode tear-down code
+-                                               */
+-                                              for (dct = 0; dct < 2; dct++) {
+-                                                      /* NOTE: Reads use DCT 
0 and writes use the current DCT per Erratum 505 */
+-                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, 0, 0x58);    /* Scrub Rate Control */
+-                                                      dword &= ~(0x1f << 24); 
                                /* L3Scrub = NV_L3BKScrub */
+-                                                      dword |= 
(mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24;
+-                                                      dword &= ~(0x1f);       
                                /* DramScrub = NV_DramBKScrub */
+-                                                      dword |= 
mctGet_NVbits(NV_DramBKScrub) & 0x1f;
+-                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword);   /* Scrub Rate Control */
+-
+-                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c);  /* DRAM Scrub Address Low */
+-                                                      dword &= ~(0x1);        
                                /* ScrubReDirEn = redirect_ecc_scrub */
+-                                                      dword |= 
redirect_ecc_scrub & 0x1;
+-                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword);   /* DRAM Scrub Address 
Low */
+-
+-                                                      dword = 
Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */
+-                                                      dword &= ~(0x1 << 4);   
                                /* L3ScrbRedirDis = 0 */
+-                                                      
Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword);  /* L3 Control 1 */
+-                                              }
++                                      if (pDCTstat->LogicalCPUID & 
(AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
++                                              /* Set up message triggered C1E 
*/
++                                              val = 
pci_read_config32(pDCTstat->dev_nbmisc, 0xd4);
++                                              val &= ~(0x1 << 15);            
        /* StutterScrubEn = DRAM scrub enabled */
++                                              val |= 
(mctGet_NVbits(NV_DramBKScrub)?1:0) << 15;
++                                              
pci_write_config32(pDCTstat->dev_nbmisc, 0xd4, val);
+                                       }
+                               }       /* this node has ECC enabled dram */
+                       }       /*Node has Dram */
+               }       /*if Node present */
+       }
+ 
++      /* Restore previous MCA error handling settings */
++      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++              struct DCTStatStruc *pDCTstat;
++              pDCTstat = pDCTstatA + Node;
++
++              if (NodePresent_D(Node)) {
++                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0x44);
++                      dword |= (sync_flood_on_dram_err[Node] & 0x1) << 30;
++                      dword |= (sync_flood_on_any_uc_err[Node] & 0x1) << 21;
++                      Set_NB32(pDCTstat->dev_nbmisc, 0x44, dword);
++              }
++      }
++
+       if(mctGet_NVbits(NV_SyncOnUnEccEn))
+               setSyncOnUnEccEn_D(pMCTstat, pDCTstatA);
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
+index 596fb23..abc8ae3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
+@@ -232,9 +232,9 @@ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat
+               Cache32bTOP = val;
+               pMCTstat->Sub4GCacheTop = val;
+ 
+-      /*======================================================================
+-       * Clear variable MTRR values
+-       
*======================================================================*/
++              
/*======================================================================
++               * Clear variable MTRR values
++               
*======================================================================*/
+               addr = 0x200;
+               lo = 0;
+               hi = lo;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c 
b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+index fe89af1..b4a084c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+@@ -89,6 +89,28 @@ static uint32_t read_config32_dct(device_t dev, uint8_t 
node, uint8_t dct, uint3
+       return pci_read_config32(dev, reg);
+ }
+ 
++static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg, uint32_t value) {
++      if (is_fam15h()) {
++              uint32_t dword;
++#ifdef __PRE_RAM__
++              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
++#else
++              device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1));
++#endif
++
++              /* Select DCT */
++              dword = pci_read_config32(dev_fn1, 0x10c);
++              dword &= ~0x1;
++              dword |= (dct & 0x1);
++              pci_write_config32(dev_fn1, 0x10c, dword);
++      } else {
++              /* Apply offset */
++              reg += dct * 0x100;
++      }
++
++      pci_write_config32(dev, reg, value);
++}
++
+ static uint32_t read_amd_dct_index_register(device_t dev, uint32_t 
index_ctl_reg, uint32_t index)
+ {
+       uint32_t dword;
+@@ -489,29 +511,17 @@ void copy_mct_data_to_save_variable(struct 
amd_s3_persistent_data* persistent_da
+ 
+                       /* Other */
+                       /* ECC scrub rate control */
+-                      data->f3x58 = pci_read_config32(dev_fn3, 0x58);
++                      data->f3x58 = read_config32_dct(dev_fn3, node, 0, 0x58);
++
++                      /* ECC scrub location */
++                      write_config32_dct(dev_fn3, node, 0, 0x58, 0x0);        
        /* Disable sequential scrub to work around non-atomic location read */
++                      data->f3x5c = read_config32_dct(dev_fn3, node, 0, 0x5c);
++                      data->f3x60 = read_config32_dct(dev_fn3, node, 0, 0x60);
++                      write_config32_dct(dev_fn3, node, 0, 0x58, 
data->f3x58);        /* Re-enable sequential scrub */
+               }
+       }
+ }
+ #else
+-static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, 
uint32_t reg, uint32_t value) {
+-      if (is_fam15h()) {
+-              uint32_t dword;
+-              device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+-
+-              /* Select DCT */
+-              dword = pci_read_config32(dev_fn1, 0x10c);
+-              dword &= ~0x1;
+-              dword |= (dct & 0x1);
+-              pci_write_config32(dev_fn1, 0x10c, dword);
+-      } else {
+-              /* Apply offset */
+-              reg += dct * 0x100;
+-      }
+-
+-      pci_write_config32(dev, reg, value);
+-}
+-
+ static void write_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t 
dct, uint8_t nb_pstate, uint32_t reg, uint32_t value) {
+       uint32_t dword;
+       device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
+@@ -613,8 +623,7 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                               if (is_fam15h()) {
+                                       for (i=0; i<4; i++)
+                                               
write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 
0x210, data->f2x210[i]);
+-                              }
+-                              else {
++                              } else {
+                                       write_config32_dct(PCI_DEV(0, 0x18 + 
node, 2), node, channel, 0x78, data->f2x78);
+                               }
+ 
+@@ -1060,8 +1069,12 @@ void restore_mct_data_from_save_variable(struct 
amd_s3_persistent_data* persiste
+                       if (!persistent_data->node[node].node_present)
+                               continue;
+ 
++                      /* ECC scrub location */
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 
0x5c, data->f3x5c);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 
0x60, data->f3x60);
++
+                       /* ECC scrub rate control */
+-                      pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x58, 
data->f3x58);
++                      write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 
0x58, data->f3x58);
+ 
+                       if (is_fam15h())
+                               /* Set LockDramCfg and CC6SaveEn */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0071-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
 
b/resources/libreboot/patch/kgpe-d16/0071-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
deleted file mode 100644
index 460ea7d..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0071-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
+++ /dev/null
@@ -1,120 +0,0 @@
-From ad1418509321ae8765b2e4692f10e5becc28073e Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 25 Jun 2015 15:28:23 -0500
-Subject: [PATCH 071/139] northbridge/amd/amdfam10: Properly indicate node and
- channel in SMBIOS tables
-
-Change-Id: Ie7278745358daf0c78cdb9c579db5291a1a2a0cb
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/northbridge.c  |  7 ++++++-
- src/northbridge/amd/amdmct/mct/mct_d.c      | 12 ++++++++++++
- src/northbridge/amd/amdmct/mct/mct_d.h      |  7 +++++--
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 12 ++++++++++++
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |  8 +++++---
- 5 files changed, 40 insertions(+), 6 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 3fc31c0..95e902d 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -1207,7 +1207,12 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
-                               t->attributes = 0;
-                               t->attributes |= ranks & 0xf;   /* rank number 
is stored in the lowest 4 bits of the attributes field */
-                               t->form_factor = MEMORY_FORMFACTOR_DIMM;
--                              snprintf(string_buffer, sizeof (string_buffer), 
"NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1);
-+                              if (mem_info->dct_stat[node].Dual_Node_Package) 
{
-+                                      snprintf(string_buffer, sizeof 
(string_buffer), "NODE %d DIMM_%s%d", node >> 1,
-+                                              
(mem_info->dct_stat[node].Internal_Node_ID)?((slot & 0x1)?"D":"C"):((slot & 
0x1)?"B":"A"), (slot >> 1) + 1);
-+                              } else {
-+                                      snprintf(string_buffer, sizeof 
(string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 
1);
-+                              }
-                               t->device_locator = smbios_add_string(t->eos, 
string_buffer);
-                               if (IS_ENABLED(CONFIG_DIMM_DDR2))
-                                       t->memory_type = MEMORY_TYPE_DDR2;
-diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c 
b/src/northbridge/amd/amdmct/mct/mct_d.c
-index be0af65..c805d41 100644
---- a/src/northbridge/amd/amdmct/mct/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct/mct_d.c
-@@ -236,6 +236,18 @@ restartinit:
-               pDCTstat->dev_nbmisc = PA_NBMISC(Node);
-               pDCTstat->NodeSysBase = node_sys_base;
- 
-+              if (mctGet_NVbits(NV_PACK_TYPE) == PT_GR) {
-+                      uint32_t dword;
-+                      pDCTstat->Dual_Node_Package = 1;
-+
-+                      /* Get the internal node number */
-+                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
-+                      dword = (dword >> 30) & 0x3;
-+                      pDCTstat->Internal_Node_ID = dword;
-+              } else {
-+                      pDCTstat->Dual_Node_Package = 0;
-+              }
-+
-               print_tx("mctAutoInitMCT_D: mct_init Node ", Node);
-               mct_init(pMCTstat, pDCTstat);
-               mctNodeIDDebugPort_D();
-diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h 
b/src/northbridge/amd/amdmct/mct/mct_d.h
-index 6b6194d..7569300 100644
---- a/src/northbridge/amd/amdmct/mct/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct/mct_d.h
-@@ -291,8 +291,11 @@ struct MCTStatStruc {
- 
- struct DCTStatStruc {         /* A per Node structure*/
- /* DCTStatStruct_F -  start */
--      u8 Node_ID;             /* Node ID of current controller*/
--      u8 ErrCode;             /* Current error condition of Node
-+      u8 Node_ID;                     /* Node ID of current controller*/
-+      uint8_t Internal_Node_ID;       /* Internal Node ID of the current 
controller */
-+      uint8_t Dual_Node_Package;      /* 1=Dual node package (G34) */
-+      uint8_t stopDCT;                /* Set if the DCT will be stopped */
-+      u8 ErrCode;                     /* Current error condition of Node
-               0= no error
-               1= Variance Error, DCT is running but not in an optimal 
configuration.
-               2= Stop Error, DCT is NOT running
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index fadb353..573c0af 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1389,6 +1389,18 @@ restartinit:
-                       pDCTstat->dev_nbctl = PA_NBCTL(Node);
-                       pDCTstat->NodeSysBase = node_sys_base;
- 
-+                      if (mctGet_NVbits(NV_PACK_TYPE) == PT_GR) {
-+                              uint32_t dword;
-+                              pDCTstat->Dual_Node_Package = 1;
-+
-+                              /* Get the internal node number */
-+                              dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
-+                              dword = (dword >> 30) & 0x3;
-+                              pDCTstat->Internal_Node_ID = dword;
-+                      } else {
-+                              pDCTstat->Dual_Node_Package = 0;
-+                      }
-+
-                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node 
%d\n", Node);
-                       mct_init(pMCTstat, pDCTstat);
-                       mctNodeIDDebugPort_D();
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index ac8c934..8c9da47 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -335,9 +335,11 @@ struct amd_spd_node_data {
- 
- struct DCTStatStruc {         /* A per Node structure*/
- /* DCTStatStruct_F -  start */
--      u8 Node_ID;             /* Node ID of current controller */
--      uint8_t stopDCT;        /* Set if the DCT will be stopped */
--      u8 ErrCode;             /* Current error condition of Node
-+      u8 Node_ID;                     /* Node ID of current controller */
-+      uint8_t Internal_Node_ID;       /* Internal Node ID of the current 
controller */
-+      uint8_t Dual_Node_Package;      /* 1=Dual node package (G34) */
-+      uint8_t stopDCT;                /* Set if the DCT will be stopped */
-+      u8 ErrCode;                     /* Current error condition of Node
-               0= no error
-               1= Variance Error, DCT is running but not in an optimal 
configuration.
-               2= Stop Error, DCT is NOT running
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0072-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
 
b/resources/libreboot/patch/kgpe-d16/0072-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
deleted file mode 100644
index 682326b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0072-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
+++ /dev/null
@@ -1,508 +0,0 @@
-From e2624058dba93cd3820dffbf7964cd84b3ddd973 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 25 Jun 2015 17:07:57 -0500
-Subject: [PATCH 072/139] amd/amdmct/mct_ddr3: Add Family 15h RDIMM timing and
- ODT values
-
-Change-Id: Ia9ee770d9f9c22e18c12e38b5bb4a7bae0a99062
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 422 +++++++++++++++++++---------
- 1 file changed, 290 insertions(+), 132 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 573c0af..643fa39 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -822,28 +822,12 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
- 
-       if (package_type == PT_GR) {
-               /* Socket G34 */
--              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
--              if (MaxDimmsInstallable == 1) {
--                      if (MemClkFreq == 0x4) {
--                              /* DDR3-667 */
--                              calibration_code = 0x00112222;
--                      }
--                      else if (MemClkFreq == 0x6) {
--                              /* DDR3-800 */
--                              calibration_code = 0x10112222;
--                      } else if (MemClkFreq == 0xa) {
--                              /* DDR3-1066 */
--                              calibration_code = 0x20112222;
--                      } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) 
{
--                              /* DDR3-1333 - DDR3-1600 */
--                              calibration_code = 0x30112222;
--                      } else if (MemClkFreq == 0x16) {
--                              /* DDR3-1866 */
--                              calibration_code = 0x30332222;
--                      }
--              } else if (MaxDimmsInstallable == 2) {
--                      if (dimm_count == 1) {
--                              /* 1 DIMM detected */
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* RDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
-+                      if (MaxDimmsInstallable == 1) {
-+                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-                               if (MemClkFreq == 0x4) {
-                                       /* DDR3-667 */
-                                       calibration_code = 0x00112222;
-@@ -856,36 +840,137 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                               } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
-                                       /* DDR3-1333 - DDR3-1600 */
-                                       calibration_code = 0x30112222;
-+                              } else if (MemClkFreq == 0x16) {
-+                                      /* DDR3-1866 */
-+                                      calibration_code = 0x30332222;
-                               }
--                      } else if (dimm_count == 2) {
--                              /* 2 DIMMs detected */
-+
-+                              if (rank_count_dimm0 == 4) {
-+                                      calibration_code &= ~(0xff << 16);
-+                                      calibration_code |= 0x22 << 16;
-+                              }
-+                      } else if (MaxDimmsInstallable == 2) {
-                               rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-                               rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
- 
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-667 */
-+                                              calibration_code = 0x00112222;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-800 */
-+                                              calibration_code = 0x10112222;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x20112222;
-+                                      } else if ((MemClkFreq == 0xe) || 
(MemClkFreq == 0x12)) {
-+                                              /* DDR3-1333 - DDR3-1600 */
-+                                              calibration_code = 0x30112222;
-+                                      }
-+
-+                                      if ((rank_count_dimm0 == 4) || 
(rank_count_dimm1 == 4)) {
-+                                              calibration_code &= ~(0xff << 
16);
-+                                              calibration_code |= 0x22 << 16;
-+                                      }
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-667 */
-+                                              calibration_code = 0x10222222;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-800 */
-+                                              calibration_code = 0x20222222;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x30222222;
-+                                      } else if (MemClkFreq == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x30222222;
-+                                      } else if (MemClkFreq == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              calibration_code = 0x30222222;
-+                                      }
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                              * 3 DIMM/channel support unimplemented
-+                              */
-+                      }
-+              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* LRDIMM */
-+                      /* TODO
-+                       * LRDIMM support unimplemented
-+                       */
-+              } else {
-+                      /* UDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-+                      if (MaxDimmsInstallable == 1) {
-                               if (MemClkFreq == 0x4) {
-                                       /* DDR3-667 */
--                                      calibration_code = 0x10222222;
-+                                      calibration_code = 0x00112222;
-                               } else if (MemClkFreq == 0x6) {
-                                       /* DDR3-800 */
--                                      calibration_code = 0x20222222;
-+                                      calibration_code = 0x10112222;
-                               } else if (MemClkFreq == 0xa) {
-                                       /* DDR3-1066 */
--                                      calibration_code = 0x30222222;
--                              } else if (MemClkFreq == 0xe) {
--                                      /* DDR3-1333 */
--                                      calibration_code = 0x30222222;
--                              } else if (MemClkFreq == 0x12) {
--                                      /* DDR3-1600 */
--                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
--                                              calibration_code = 0x30222222;
--                                      else
--                                              calibration_code = 0x30112222;
-+                                      calibration_code = 0x20112222;
-+                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
-+                                      /* DDR3-1333 - DDR3-1600 */
-+                                      calibration_code = 0x30112222;
-+                              } else if (MemClkFreq == 0x16) {
-+                                      /* DDR3-1866 */
-+                                      calibration_code = 0x30332222;
-                               }
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-667 */
-+                                              calibration_code = 0x00112222;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-800 */
-+                                              calibration_code = 0x10112222;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x20112222;
-+                                      } else if ((MemClkFreq == 0xe) || 
(MemClkFreq == 0x12)) {
-+                                              /* DDR3-1333 - DDR3-1600 */
-+                                              calibration_code = 0x30112222;
-+                                      }
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-667 */
-+                                              calibration_code = 0x10222222;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-800 */
-+                                              calibration_code = 0x20222222;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x30222222;
-+                                      } else if (MemClkFreq == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x30222222;
-+                                      } else if (MemClkFreq == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-+                                                      calibration_code = 
0x30222222;
-+                                              else
-+                                                      calibration_code = 
0x30112222;
-+                                      }
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-                       }
--              } else if (MaxDimmsInstallable == 3) {
--                      /* TODO
--                       * 3 DIMM/channel support unimplemented
--                       */
-               }
-       } else {
-               /* TODO
-@@ -917,41 +1002,69 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
- 
-       if (package_type == PT_GR) {
-               /* Socket G34 */
--              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
--              if (MaxDimmsInstallable == 1) {
--                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
--
--                      if (MemClkFreq == 0x4) {
--                              /* DDR3-667 */
--                              if (rank_count_dimm0 == 1)
--                                      calibration_code = 0x00000000;
--                              else
--                                      calibration_code = 0x003b0000;
--                      } else if (MemClkFreq == 0x6) {
--                              /* DDR3-800 */
--                              if (rank_count_dimm0 == 1)
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* RDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
-+                      if (MaxDimmsInstallable == 1) {
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800*/
-                                       calibration_code = 0x00000000;
--                              else
--                                      calibration_code = 0x003b0000;
--                      } else if (MemClkFreq == 0xa) {
--                              /* DDR3-1066 */
--                              calibration_code = 0x00383837;
--                      } else if (MemClkFreq == 0xe) {
--                              /* DDR3-1333 */
--                              calibration_code = 0x00363635;
--                      } else if (MemClkFreq == 0x12) {
--                              /* DDR3-1600 */
--                              if (rank_count_dimm0 == 1)
--                                      calibration_code = 0x00353533;
--                              else
--                                      calibration_code = 0x00003533;
--                      } else if (MemClkFreq == 0x16) {
--                              /* DDR3-1866 */
--                              calibration_code = 0x00333330;
-+                              } else if (MemClkFreq == 0xa) {
-+                                      /* DDR3-1066 */
-+                                      calibration_code = 0x003c3c3c;
-+                              } else if (MemClkFreq == 0xe) {
-+                                      /* DDR3-1333 */
-+                                      calibration_code = 0x003a3a3a;
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-+                                      calibration_code = 0x00393939;
-+                              }
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
-+                                              /* DDR3-667 - DDR3-800*/
-+                                              calibration_code = 0x00000000;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x00393c39;
-+                                      } else if (MemClkFreq == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x00373a37;
-+                                      } else if (MemClkFreq == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              calibration_code = 0x00363936;
-+                                      }
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
-+                                              /* DDR3-667 - DDR3-800*/
-+                                              calibration_code = 0x00000000;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x003a3c3a;
-+                                      } else if (MemClkFreq == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x00383a38;
-+                                      } else if (MemClkFreq == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              calibration_code = 0x00353935;
-+                                      }
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-                       }
--              } else if (MaxDimmsInstallable == 2) {
--                      if (dimm_count == 1) {
--                              /* 1 DIMM detected */
-+              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* LRDIMM */
-+                      /* TODO
-+                       * LRDIMM support unimplemented
-+                       */
-+              } else {
-+                      /* UDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-+                      if (MaxDimmsInstallable == 1) {
-                               rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
- 
-                               if (MemClkFreq == 0x4) {
-@@ -978,34 +1091,68 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
-                                               calibration_code = 0x00353533;
-                                       else
-                                               calibration_code = 0x00003533;
-+                              } else if (MemClkFreq == 0x16) {
-+                                      /* DDR3-1866 */
-+                                      calibration_code = 0x00333330;
-                               }
--                      } else if (dimm_count == 2) {
--                              /* 2 DIMMs detected */
--                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-667 */
-+                                              if (rank_count_dimm0 == 1)
-+                                                      calibration_code = 
0x00000000;
-+                                              else
-+                                                      calibration_code = 
0x003b0000;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-800 */
-+                                              if (rank_count_dimm0 == 1)
-+                                                      calibration_code = 
0x00000000;
-+                                              else
-+                                                      calibration_code = 
0x003b0000;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x00383837;
-+                                      } else if (MemClkFreq == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x00363635;
-+                                      } else if (MemClkFreq == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              if (rank_count_dimm0 == 1)
-+                                                      calibration_code = 
0x00353533;
-+                                              else
-+                                                      calibration_code = 
0x00003533;
-+                                      }
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
- 
--                              if (MemClkFreq == 0x4) {
--                                      /* DDR3-667 */
--                                      calibration_code = 0x00390039;
--                              } else if (MemClkFreq == 0x6) {
--                                      /* DDR3-800 */
--                                      calibration_code = 0x00390039;
--                              } else if (MemClkFreq == 0xa) {
--                                      /* DDR3-1066 */
--                                      calibration_code = 0x003a3a3a;
--                              } else if (MemClkFreq == 0xe) {
--                                      /* DDR3-1333 */
--                                      calibration_code = 0x00003939;
--                              } else if (MemClkFreq == 0x12) {
--                                      /* DDR3-1600 */
--                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
--                                              calibration_code = 0x00003738;
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-667 */
-+                                              calibration_code = 0x00390039;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-800 */
-+                                              calibration_code = 0x00390039;
-+                                      } else if (MemClkFreq == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x003a3a3a;
-+                                      } else if (MemClkFreq == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x00003939;
-+                                      } else if (MemClkFreq == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-+                                                      calibration_code = 
0x00003738;
-+                                      }
-                               }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-                       }
--              } else if (MaxDimmsInstallable == 3) {
--                      /* TODO
--                       * 3 DIMM/channel support unimplemented
--                       */
-               }
-       } else {
-               /* TODO
-@@ -1037,55 +1184,66 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
- 
-       if (package_type == PT_GR) {
-               /* Socket G34 */
--              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
--              if (MaxDimmsInstallable == 1) {
--                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
--
--                      if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
--                              || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) {
--                              /* DDR3-667 - DDR3-1333 */
--                              slow_access = 0;
--                      } else if ((MemClkFreq == 0x12) || (MemClkFreq == 
0x16)) {
--                              /* DDR3-1600 - DDR3-1866 */
--                              if (rank_count_dimm0 == 1)
--                                      slow_access = 0;
--                              else
--                                      slow_access = 1;
--                      }
--              } else if (MaxDimmsInstallable == 2) {
--                      if (dimm_count == 1) {
--                              /* 1 DIMM detected */
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* RDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
-+                      slow_access = 0;
-+              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* LRDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 75 */
-+                      slow_access = 0;
-+              } else {
-+                      /* UDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-+                      if (MaxDimmsInstallable == 1) {
-                               rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
- 
-                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
-                                       || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
-                                       /* DDR3-667 - DDR3-1333 */
-                                       slow_access = 0;
--                              } else if (MemClkFreq == 0x12) {
--                                      /* DDR3-1600 */
-+                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
-+                                      /* DDR3-1600 - DDR3-1866 */
-                                       if (rank_count_dimm0 == 1)
-                                               slow_access = 0;
-                                       else
-                                               slow_access = 1;
-                               }
--                      } else if (dimm_count == 2) {
--                              /* 2 DIMMs detected */
--                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
- 
--                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
--                                      || (MemClkFreq == 0xa)) {
--                                      /* DDR3-667 - DDR3-1066 */
--                                      slow_access = 0;
--                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
--                                      /* DDR3-1333 - DDR3-1600 */
--                                      slow_access = 1;
-+                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
-+                                              || (MemClkFreq == 0xa) | 
(MemClkFreq == 0xe)) {
-+                                              /* DDR3-667 - DDR3-1333 */
-+                                              slow_access = 0;
-+                                      } else if (MemClkFreq == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              if (rank_count_dimm0 == 1)
-+                                                      slow_access = 0;
-+                                              else
-+                                                      slow_access = 1;
-+                                      }
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
-+                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+
-+                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
-+                                              || (MemClkFreq == 0xa)) {
-+                                              /* DDR3-667 - DDR3-1066 */
-+                                              slow_access = 0;
-+                                      } else if ((MemClkFreq == 0xe) || 
(MemClkFreq == 0x12)) {
-+                                              /* DDR3-1333 - DDR3-1600 */
-+                                              slow_access = 1;
-+                                      }
-                               }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-                       }
--              } else if (MaxDimmsInstallable == 3) {
--                      /* TODO
--                       * 3 DIMM/channel support unimplemented
--                       */
-               }
-       } else {
-               /* TODO
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0072-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
 
b/resources/libreboot/patch/kgpe-d16/0072-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
new file mode 100644
index 0000000..4b628b1
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0072-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch
@@ -0,0 +1,120 @@
+From a00183866e0083ead7735ef5dcb974a98cd0de98 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 25 Jun 2015 15:28:23 -0500
+Subject: [PATCH 072/143] northbridge/amd/amdfam10: Properly indicate node and
+ channel in SMBIOS tables
+
+Change-Id: Ie7278745358daf0c78cdb9c579db5291a1a2a0cb
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/northbridge.c  |    7 ++++++-
+ src/northbridge/amd/amdmct/mct/mct_d.c      |   12 ++++++++++++
+ src/northbridge/amd/amdmct/mct/mct_d.h      |    7 +++++--
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |   12 ++++++++++++
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |    8 +++++---
+ 5 files changed, 40 insertions(+), 6 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 9fe0ccb..52b5ffb 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -1207,7 +1207,12 @@ static int amdfam10_get_smbios_data17(int* count, int 
handle, int parent_handle,
+                               t->attributes = 0;
+                               t->attributes |= ranks & 0xf;   /* rank number 
is stored in the lowest 4 bits of the attributes field */
+                               t->form_factor = MEMORY_FORMFACTOR_DIMM;
+-                              snprintf(string_buffer, sizeof (string_buffer), 
"NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 1);
++                              if (mem_info->dct_stat[node].Dual_Node_Package) 
{
++                                      snprintf(string_buffer, sizeof 
(string_buffer), "NODE %d DIMM_%s%d", node >> 1,
++                                              
(mem_info->dct_stat[node].Internal_Node_ID)?((slot & 0x1)?"D":"C"):((slot & 
0x1)?"B":"A"), (slot >> 1) + 1);
++                              } else {
++                                      snprintf(string_buffer, sizeof 
(string_buffer), "NODE %d DIMM_%s%d", node, (slot & 0x1)?"B":"A", (slot >> 1) + 
1);
++                              }
+                               t->device_locator = smbios_add_string(t->eos, 
string_buffer);
+                               if (IS_ENABLED(CONFIG_DIMM_DDR2))
+                                       t->memory_type = MEMORY_TYPE_DDR2;
+diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c 
b/src/northbridge/amd/amdmct/mct/mct_d.c
+index be0af65..c805d41 100644
+--- a/src/northbridge/amd/amdmct/mct/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct/mct_d.c
+@@ -236,6 +236,18 @@ restartinit:
+               pDCTstat->dev_nbmisc = PA_NBMISC(Node);
+               pDCTstat->NodeSysBase = node_sys_base;
+ 
++              if (mctGet_NVbits(NV_PACK_TYPE) == PT_GR) {
++                      uint32_t dword;
++                      pDCTstat->Dual_Node_Package = 1;
++
++                      /* Get the internal node number */
++                      dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
++                      dword = (dword >> 30) & 0x3;
++                      pDCTstat->Internal_Node_ID = dword;
++              } else {
++                      pDCTstat->Dual_Node_Package = 0;
++              }
++
+               print_tx("mctAutoInitMCT_D: mct_init Node ", Node);
+               mct_init(pMCTstat, pDCTstat);
+               mctNodeIDDebugPort_D();
+diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h 
b/src/northbridge/amd/amdmct/mct/mct_d.h
+index 6b6194d..7569300 100644
+--- a/src/northbridge/amd/amdmct/mct/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct/mct_d.h
+@@ -291,8 +291,11 @@ struct MCTStatStruc {
+ 
+ struct DCTStatStruc {         /* A per Node structure*/
+ /* DCTStatStruct_F -  start */
+-      u8 Node_ID;             /* Node ID of current controller*/
+-      u8 ErrCode;             /* Current error condition of Node
++      u8 Node_ID;                     /* Node ID of current controller*/
++      uint8_t Internal_Node_ID;       /* Internal Node ID of the current 
controller */
++      uint8_t Dual_Node_Package;      /* 1=Dual node package (G34) */
++      uint8_t stopDCT;                /* Set if the DCT will be stopped */
++      u8 ErrCode;                     /* Current error condition of Node
+               0= no error
+               1= Variance Error, DCT is running but not in an optimal 
configuration.
+               2= Stop Error, DCT is NOT running
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index dda997e..571e18d 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1389,6 +1389,18 @@ restartinit:
+                       pDCTstat->dev_nbctl = PA_NBCTL(Node);
+                       pDCTstat->NodeSysBase = node_sys_base;
+ 
++                      if (mctGet_NVbits(NV_PACK_TYPE) == PT_GR) {
++                              uint32_t dword;
++                              pDCTstat->Dual_Node_Package = 1;
++
++                              /* Get the internal node number */
++                              dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
++                              dword = (dword >> 30) & 0x3;
++                              pDCTstat->Internal_Node_ID = dword;
++                      } else {
++                              pDCTstat->Dual_Node_Package = 0;
++                      }
++
+                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node 
%d\n", Node);
+                       mct_init(pMCTstat, pDCTstat);
+                       mctNodeIDDebugPort_D();
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index ac8c934..8c9da47 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -335,9 +335,11 @@ struct amd_spd_node_data {
+ 
+ struct DCTStatStruc {         /* A per Node structure*/
+ /* DCTStatStruct_F -  start */
+-      u8 Node_ID;             /* Node ID of current controller */
+-      uint8_t stopDCT;        /* Set if the DCT will be stopped */
+-      u8 ErrCode;             /* Current error condition of Node
++      u8 Node_ID;                     /* Node ID of current controller */
++      uint8_t Internal_Node_ID;       /* Internal Node ID of the current 
controller */
++      uint8_t Dual_Node_Package;      /* 1=Dual node package (G34) */
++      uint8_t stopDCT;                /* Set if the DCT will be stopped */
++      u8 ErrCode;                     /* Current error condition of Node
+               0= no error
+               1= Variance Error, DCT is running but not in an optimal 
configuration.
+               2= Stop Error, DCT is NOT running
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0073-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
 
b/resources/libreboot/patch/kgpe-d16/0073-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
new file mode 100644
index 0000000..6f2398e
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0073-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch
@@ -0,0 +1,508 @@
+From 88204b8dc65003163e2f02ea14b4d8513a6d16bc Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 25 Jun 2015 17:07:57 -0500
+Subject: [PATCH 073/143] amd/amdmct/mct_ddr3: Add Family 15h RDIMM timing and
+ ODT values
+
+Change-Id: Ia9ee770d9f9c22e18c12e38b5bb4a7bae0a99062
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |  422 ++++++++++++++++++---------
+ 1 file changed, 290 insertions(+), 132 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 571e18d..999e4ae 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -822,28 +822,12 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+ 
+       if (package_type == PT_GR) {
+               /* Socket G34 */
+-              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+-              if (MaxDimmsInstallable == 1) {
+-                      if (MemClkFreq == 0x4) {
+-                              /* DDR3-667 */
+-                              calibration_code = 0x00112222;
+-                      }
+-                      else if (MemClkFreq == 0x6) {
+-                              /* DDR3-800 */
+-                              calibration_code = 0x10112222;
+-                      } else if (MemClkFreq == 0xa) {
+-                              /* DDR3-1066 */
+-                              calibration_code = 0x20112222;
+-                      } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) 
{
+-                              /* DDR3-1333 - DDR3-1600 */
+-                              calibration_code = 0x30112222;
+-                      } else if (MemClkFreq == 0x16) {
+-                              /* DDR3-1866 */
+-                              calibration_code = 0x30332222;
+-                      }
+-              } else if (MaxDimmsInstallable == 2) {
+-                      if (dimm_count == 1) {
+-                              /* 1 DIMM detected */
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* RDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
++                      if (MaxDimmsInstallable == 1) {
++                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
+                               if (MemClkFreq == 0x4) {
+                                       /* DDR3-667 */
+                                       calibration_code = 0x00112222;
+@@ -856,36 +840,137 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                               } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
+                                       /* DDR3-1333 - DDR3-1600 */
+                                       calibration_code = 0x30112222;
++                              } else if (MemClkFreq == 0x16) {
++                                      /* DDR3-1866 */
++                                      calibration_code = 0x30332222;
+                               }
+-                      } else if (dimm_count == 2) {
+-                              /* 2 DIMMs detected */
++
++                              if (rank_count_dimm0 == 4) {
++                                      calibration_code &= ~(0xff << 16);
++                                      calibration_code |= 0x22 << 16;
++                              }
++                      } else if (MaxDimmsInstallable == 2) {
+                               rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+                               rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ 
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-667 */
++                                              calibration_code = 0x00112222;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-800 */
++                                              calibration_code = 0x10112222;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x20112222;
++                                      } else if ((MemClkFreq == 0xe) || 
(MemClkFreq == 0x12)) {
++                                              /* DDR3-1333 - DDR3-1600 */
++                                              calibration_code = 0x30112222;
++                                      }
++
++                                      if ((rank_count_dimm0 == 4) || 
(rank_count_dimm1 == 4)) {
++                                              calibration_code &= ~(0xff << 
16);
++                                              calibration_code |= 0x22 << 16;
++                                      }
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-667 */
++                                              calibration_code = 0x10222222;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-800 */
++                                              calibration_code = 0x20222222;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x30222222;
++                                      } else if (MemClkFreq == 0xe) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x30222222;
++                                      } else if (MemClkFreq == 0x12) {
++                                              /* DDR3-1600 */
++                                              calibration_code = 0x30222222;
++                                      }
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                              * 3 DIMM/channel support unimplemented
++                              */
++                      }
++              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* LRDIMM */
++                      /* TODO
++                       * LRDIMM support unimplemented
++                       */
++              } else {
++                      /* UDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
++                      if (MaxDimmsInstallable == 1) {
+                               if (MemClkFreq == 0x4) {
+                                       /* DDR3-667 */
+-                                      calibration_code = 0x10222222;
++                                      calibration_code = 0x00112222;
+                               } else if (MemClkFreq == 0x6) {
+                                       /* DDR3-800 */
+-                                      calibration_code = 0x20222222;
++                                      calibration_code = 0x10112222;
+                               } else if (MemClkFreq == 0xa) {
+                                       /* DDR3-1066 */
+-                                      calibration_code = 0x30222222;
+-                              } else if (MemClkFreq == 0xe) {
+-                                      /* DDR3-1333 */
+-                                      calibration_code = 0x30222222;
+-                              } else if (MemClkFreq == 0x12) {
+-                                      /* DDR3-1600 */
+-                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
+-                                              calibration_code = 0x30222222;
+-                                      else
+-                                              calibration_code = 0x30112222;
++                                      calibration_code = 0x20112222;
++                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
++                                      /* DDR3-1333 - DDR3-1600 */
++                                      calibration_code = 0x30112222;
++                              } else if (MemClkFreq == 0x16) {
++                                      /* DDR3-1866 */
++                                      calibration_code = 0x30332222;
+                               }
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-667 */
++                                              calibration_code = 0x00112222;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-800 */
++                                              calibration_code = 0x10112222;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x20112222;
++                                      } else if ((MemClkFreq == 0xe) || 
(MemClkFreq == 0x12)) {
++                                              /* DDR3-1333 - DDR3-1600 */
++                                              calibration_code = 0x30112222;
++                                      }
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-667 */
++                                              calibration_code = 0x10222222;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-800 */
++                                              calibration_code = 0x20222222;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x30222222;
++                                      } else if (MemClkFreq == 0xe) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x30222222;
++                                      } else if (MemClkFreq == 0x12) {
++                                              /* DDR3-1600 */
++                                              if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
++                                                      calibration_code = 
0x30222222;
++                                              else
++                                                      calibration_code = 
0x30112222;
++                                      }
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
+                       }
+-              } else if (MaxDimmsInstallable == 3) {
+-                      /* TODO
+-                       * 3 DIMM/channel support unimplemented
+-                       */
+               }
+       } else {
+               /* TODO
+@@ -917,41 +1002,69 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+ 
+       if (package_type == PT_GR) {
+               /* Socket G34 */
+-              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+-              if (MaxDimmsInstallable == 1) {
+-                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+-
+-                      if (MemClkFreq == 0x4) {
+-                              /* DDR3-667 */
+-                              if (rank_count_dimm0 == 1)
+-                                      calibration_code = 0x00000000;
+-                              else
+-                                      calibration_code = 0x003b0000;
+-                      } else if (MemClkFreq == 0x6) {
+-                              /* DDR3-800 */
+-                              if (rank_count_dimm0 == 1)
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* RDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
++                      if (MaxDimmsInstallable == 1) {
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800*/
+                                       calibration_code = 0x00000000;
+-                              else
+-                                      calibration_code = 0x003b0000;
+-                      } else if (MemClkFreq == 0xa) {
+-                              /* DDR3-1066 */
+-                              calibration_code = 0x00383837;
+-                      } else if (MemClkFreq == 0xe) {
+-                              /* DDR3-1333 */
+-                              calibration_code = 0x00363635;
+-                      } else if (MemClkFreq == 0x12) {
+-                              /* DDR3-1600 */
+-                              if (rank_count_dimm0 == 1)
+-                                      calibration_code = 0x00353533;
+-                              else
+-                                      calibration_code = 0x00003533;
+-                      } else if (MemClkFreq == 0x16) {
+-                              /* DDR3-1866 */
+-                              calibration_code = 0x00333330;
++                              } else if (MemClkFreq == 0xa) {
++                                      /* DDR3-1066 */
++                                      calibration_code = 0x003c3c3c;
++                              } else if (MemClkFreq == 0xe) {
++                                      /* DDR3-1333 */
++                                      calibration_code = 0x003a3a3a;
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
++                                      calibration_code = 0x00393939;
++                              }
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
++                                              /* DDR3-667 - DDR3-800*/
++                                              calibration_code = 0x00000000;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x00393c39;
++                                      } else if (MemClkFreq == 0xe) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x00373a37;
++                                      } else if (MemClkFreq == 0x12) {
++                                              /* DDR3-1600 */
++                                              calibration_code = 0x00363936;
++                                      }
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
++                                              /* DDR3-667 - DDR3-800*/
++                                              calibration_code = 0x00000000;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x003a3c3a;
++                                      } else if (MemClkFreq == 0xe) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x00383a38;
++                                      } else if (MemClkFreq == 0x12) {
++                                              /* DDR3-1600 */
++                                              calibration_code = 0x00353935;
++                                      }
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
+                       }
+-              } else if (MaxDimmsInstallable == 2) {
+-                      if (dimm_count == 1) {
+-                              /* 1 DIMM detected */
++              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* LRDIMM */
++                      /* TODO
++                       * LRDIMM support unimplemented
++                       */
++              } else {
++                      /* UDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
++                      if (MaxDimmsInstallable == 1) {
+                               rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ 
+                               if (MemClkFreq == 0x4) {
+@@ -978,34 +1091,68 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+                                               calibration_code = 0x00353533;
+                                       else
+                                               calibration_code = 0x00003533;
++                              } else if (MemClkFreq == 0x16) {
++                                      /* DDR3-1866 */
++                                      calibration_code = 0x00333330;
+                               }
+-                      } else if (dimm_count == 2) {
+-                              /* 2 DIMMs detected */
+-                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-667 */
++                                              if (rank_count_dimm0 == 1)
++                                                      calibration_code = 
0x00000000;
++                                              else
++                                                      calibration_code = 
0x003b0000;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-800 */
++                                              if (rank_count_dimm0 == 1)
++                                                      calibration_code = 
0x00000000;
++                                              else
++                                                      calibration_code = 
0x003b0000;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x00383837;
++                                      } else if (MemClkFreq == 0xe) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x00363635;
++                                      } else if (MemClkFreq == 0x12) {
++                                              /* DDR3-1600 */
++                                              if (rank_count_dimm0 == 1)
++                                                      calibration_code = 
0x00353533;
++                                              else
++                                                      calibration_code = 
0x00003533;
++                                      }
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ 
+-                              if (MemClkFreq == 0x4) {
+-                                      /* DDR3-667 */
+-                                      calibration_code = 0x00390039;
+-                              } else if (MemClkFreq == 0x6) {
+-                                      /* DDR3-800 */
+-                                      calibration_code = 0x00390039;
+-                              } else if (MemClkFreq == 0xa) {
+-                                      /* DDR3-1066 */
+-                                      calibration_code = 0x003a3a3a;
+-                              } else if (MemClkFreq == 0xe) {
+-                                      /* DDR3-1333 */
+-                                      calibration_code = 0x00003939;
+-                              } else if (MemClkFreq == 0x12) {
+-                                      /* DDR3-1600 */
+-                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
+-                                              calibration_code = 0x00003738;
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-667 */
++                                              calibration_code = 0x00390039;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-800 */
++                                              calibration_code = 0x00390039;
++                                      } else if (MemClkFreq == 0xa) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x003a3a3a;
++                                      } else if (MemClkFreq == 0xe) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x00003939;
++                                      } else if (MemClkFreq == 0x12) {
++                                              /* DDR3-1600 */
++                                              if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
++                                                      calibration_code = 
0x00003738;
++                                      }
+                               }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
+                       }
+-              } else if (MaxDimmsInstallable == 3) {
+-                      /* TODO
+-                       * 3 DIMM/channel support unimplemented
+-                       */
+               }
+       } else {
+               /* TODO
+@@ -1037,55 +1184,66 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+ 
+       if (package_type == PT_GR) {
+               /* Socket G34 */
+-              /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+-              if (MaxDimmsInstallable == 1) {
+-                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+-
+-                      if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
+-                              || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) {
+-                              /* DDR3-667 - DDR3-1333 */
+-                              slow_access = 0;
+-                      } else if ((MemClkFreq == 0x12) || (MemClkFreq == 
0x16)) {
+-                              /* DDR3-1600 - DDR3-1866 */
+-                              if (rank_count_dimm0 == 1)
+-                                      slow_access = 0;
+-                              else
+-                                      slow_access = 1;
+-                      }
+-              } else if (MaxDimmsInstallable == 2) {
+-                      if (dimm_count == 1) {
+-                              /* 1 DIMM detected */
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* RDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
++                      slow_access = 0;
++              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* LRDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 75 */
++                      slow_access = 0;
++              } else {
++                      /* UDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
++                      if (MaxDimmsInstallable == 1) {
+                               rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ 
+                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
+                                       || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
+                                       /* DDR3-667 - DDR3-1333 */
+                                       slow_access = 0;
+-                              } else if (MemClkFreq == 0x12) {
+-                                      /* DDR3-1600 */
++                              } else if ((MemClkFreq == 0x12) || (MemClkFreq 
== 0x16)) {
++                                      /* DDR3-1600 - DDR3-1866 */
+                                       if (rank_count_dimm0 == 1)
+                                               slow_access = 0;
+                                       else
+                                               slow_access = 1;
+                               }
+-                      } else if (dimm_count == 2) {
+-                              /* 2 DIMMs detected */
+-                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
+ 
+-                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
+-                                      || (MemClkFreq == 0xa)) {
+-                                      /* DDR3-667 - DDR3-1066 */
+-                                      slow_access = 0;
+-                              } else if ((MemClkFreq == 0xe) || (MemClkFreq 
== 0x12)) {
+-                                      /* DDR3-1333 - DDR3-1600 */
+-                                      slow_access = 1;
++                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
++                                              || (MemClkFreq == 0xa) | 
(MemClkFreq == 0xe)) {
++                                              /* DDR3-667 - DDR3-1333 */
++                                              slow_access = 0;
++                                      } else if (MemClkFreq == 0x12) {
++                                              /* DDR3-1600 */
++                                              if (rank_count_dimm0 == 1)
++                                                      slow_access = 0;
++                                              else
++                                                      slow_access = 1;
++                                      }
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
++                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++
++                                      if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
++                                              || (MemClkFreq == 0xa)) {
++                                              /* DDR3-667 - DDR3-1066 */
++                                              slow_access = 0;
++                                      } else if ((MemClkFreq == 0xe) || 
(MemClkFreq == 0x12)) {
++                                              /* DDR3-1333 - DDR3-1600 */
++                                              slow_access = 1;
++                                      }
+                               }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
+                       }
+-              } else if (MaxDimmsInstallable == 3) {
+-                      /* TODO
+-                       * 3 DIMM/channel support unimplemented
+-                       */
+               }
+       } else {
+               /* TODO
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0073-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
 
b/resources/libreboot/patch/kgpe-d16/0073-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
deleted file mode 100644
index 43ba5d1..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0073-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
+++ /dev/null
@@ -1,256 +0,0 @@
-From 15e1fd712629a70457b1dfd76fe46c539e7c64e5 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 25 Jun 2015 18:08:53 -0500
-Subject: [PATCH 073/139] northbridge/amd/amdmct/mct_ddr3: Attempt to recover
- from phy training errors
-
-Change-Id: Ia2c3022534c9ad44714eef6e118869f054bd9f6b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c  | 68 +++++++++++++++++++++------
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 36 +++++++++++---
- 2 files changed, 83 insertions(+), 21 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-index 5e81808..539cb0d 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-@@ -18,11 +18,11 @@
-  * Foundation, Inc.
-  */
- 
--static void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
-+static uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
--static void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
-+static uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
--static void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
-+static uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
- static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
-@@ -100,11 +100,12 @@ static void DisableAutoRefresh_D(struct MCTStatStruc 
*pMCTstat,
- }
- 
- 
--static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
-+static uint8_t PhyWLPass1(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-       u8 dimm;
-       u16 DIMMValid;
-+      uint8_t status = 0;
-       void *DCTPtr;
- 
-       dct &= 1;
-@@ -121,19 +122,22 @@ static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
-               PrepareC_DCT(pMCTstat, pDCTstat, dct);
-               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
-                       if (DIMMValid & (1 << (dimm << 1))) {
--                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
--                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
--                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
-+                              status |= AgesaHwWlPhase1(pMCTstat, pDCTstat, 
dct, dimm, FirstPass);
-+                              status |= AgesaHwWlPhase2(pMCTstat, pDCTstat, 
dct, dimm, FirstPass);
-+                              status |= AgesaHwWlPhase3(pMCTstat, pDCTstat, 
dct, dimm, FirstPass);
-                       }
-               }
-       }
-+
-+      return status;
- }
- 
--static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
-+static uint8_t PhyWLPass2(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-       u8 dimm;
-       u16 DIMMValid;
-+      uint8_t status = 0;
-       void *DCTPtr;
- 
-       dct &= 1;
-@@ -163,12 +167,14 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
-               DisableAutoRefresh_D(pMCTstat, pDCTstat);
-               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
-                       if (DIMMValid & (1 << (dimm << 1))) {
--                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
--                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
--                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
-+                              status |= AgesaHwWlPhase1(pMCTstat, pDCTstat, 
dct, dimm, SecondPass);
-+                              status |= AgesaHwWlPhase2(pMCTstat, pDCTstat, 
dct, dimm, SecondPass);
-+                              status |= AgesaHwWlPhase3(pMCTstat, pDCTstat, 
dct, dimm, SecondPass);
-                       }
-               }
-       }
-+
-+      return status;
- }
- 
- static uint16_t fam15h_next_highest_memclk_freq(uint16_t memclk_freq)
-@@ -183,6 +189,8 @@ static uint16_t fam15h_next_highest_memclk_freq(uint16_t 
memclk_freq)
- static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, uint8_t 
Pass)
- {
-+      uint8_t status;
-+      uint8_t timeout;
-       uint16_t final_target_freq;
- 
-       pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
-@@ -201,8 +209,21 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
-       }
- 
-       if (Pass == FirstPass) {
--              PhyWLPass1(pMCTstat, pDCTstat, 0);
--              PhyWLPass1(pMCTstat, pDCTstat, 1);
-+              timeout = 0;
-+              do {
-+                      status = 0;
-+                      timeout++;
-+                      status |= PhyWLPass1(pMCTstat, pDCTstat, 0);
-+                      status |= PhyWLPass1(pMCTstat, pDCTstat, 1);
-+                      if (status)
-+                              printk(BIOS_INFO,
-+                                      "%s: Retrying write levelling due to 
invalid value(s) detected in first phase\n",
-+                                      __func__);
-+              } while (status && (timeout < 8));
-+              if (status)
-+                      printk(BIOS_INFO,
-+                              "%s: Uncorrectable invalid value(s) detected in 
first phase of write levelling\n",
-+                              __func__);
-       }
- 
-       if (Pass == SecondPass) {
-@@ -211,6 +232,7 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
-                        * NOTE: BIOS must program both DCTs to the same 
frequency.
-                        * NOTE: Fam15h steps the frequency, Fam10h slams the 
frequency.
-                        */
-+                      uint8_t global_phy_training_status = 0;
-                       final_target_freq = pDCTstat->TargetFreq;
- 
-                       while (pDCTstat->Speed != final_target_freq) {
-@@ -219,12 +241,28 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
-                               else
-                                       pDCTstat->TargetFreq = 
final_target_freq;
-                               SetTargetFreq(pMCTstat, pDCTstat);
--                              PhyWLPass2(pMCTstat, pDCTstat, 0);
--                              PhyWLPass2(pMCTstat, pDCTstat, 1);
-+                              timeout = 0;
-+                              do {
-+                                      status = 0;
-+                                      timeout++;
-+                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 0);
-+                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 1);
-+                                      if (status)
-+                                              printk(BIOS_INFO,
-+                                                      "%s: Retrying write 
levelling due to invalid value(s) detected in last phase\n",
-+                                                      __func__);
-+                              } while (status && (timeout < 8));
-+                              global_phy_training_status |= status;
-                       }
- 
-                       pDCTstat->TargetFreq = final_target_freq;
- 
-+                      if (global_phy_training_status)
-+                              printk(BIOS_WARNING,
-+                                      "%s: Uncorrectable invalid value(s) 
detected in second phase of write levelling; "
-+                                      "continuing but system may be 
unstable!\n",
-+                                      __func__);
-+
-                       uint8_t dct;
-                       for (dct = 0; dct < 2; dct++) {
-                               sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index c760bac..bb076cb 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -54,7 +54,7 @@ static int32_t abs(int32_t val) {
-  */
- 
- 
/*-----------------------------------------------------------------------------
-- * void AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct 
*DCTData,
-+ * uint8_t AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct 
*DCTData,
-  *                  u8 Dimm, u8 Pass)
-  *
-  *  Description:
-@@ -71,7 +71,7 @@ static int32_t abs(int32_t val) {
-  *       OUT
-  
*-----------------------------------------------------------------------------
-  */
--void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-               u8 dct, u8 dimm, u8 pass)
- {
-       u8 ByteLane;
-@@ -174,12 +174,15 @@ void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTsta
-       }
- 
-       pDCTData->WLCriticalGrossDelayPrevPass = 0x1f;
-+
-+      return 0;
- }
- 
--void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-               u8 dct, u8 dimm, u8 pass)
- {
-       u8 ByteLane;
-+      uint8_t status = 0;
-       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- 
-       if (is_fam15h()) {
-@@ -206,19 +209,38 @@ void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTsta
- 
-               /* Compensate for occasional noise/instability causing sporadic 
training failure */
-               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-+                      uint8_t faulty_value_detected = 0;
-                       uint16_t total_delay_seed = 
((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
-                       uint16_t total_delay_phy = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
--                      if (abs(total_delay_phy - total_delay_seed) > 0x20) {
--                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value (seed: %04x phy: %04x step: %04x)\n", __func__,
-+                      if (pass == FirstPass) {
-+                              /* Allow a somewhat higher step threshold on 
the first pass
-+                               * For the most part, as long as the phy isn't 
stepping
-+                               * several clocks at once the values are 
probably valid.
-+                               */
-+                              if (abs(total_delay_phy - total_delay_seed) > 
0x30)
-+                                      faulty_value_detected = 1;
-+                      } else {
-+                              /* Stepping memory clocks between adjacent 
allowed frequencies
-+                               *  should not yield large phy value 
differences...
-+                               */
-+
-+                              if (abs(total_delay_phy - total_delay_seed) > 
0x20)
-+                                      faulty_value_detected = 1;
-+                      }
-+                      if (faulty_value_detected) {
-+                              printk(BIOS_INFO, "%s: overriding faulty phy 
value (seed: %04x phy: %04x step: %04x)\n", __func__,
-                                       total_delay_seed, total_delay_phy, 
abs(total_delay_phy - total_delay_seed));
-                               pDCTData->WLGrossDelay[index+ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane];
-                               pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
-+                              status = 1;
-                       }
-               }
-       }
-+
-+      return status;
- }
- 
--void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-+uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-               u8 dct, u8 dimm, u8 pass)
- {
-       u8 ByteLane;
-@@ -285,6 +307,8 @@ void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTsta
-        * to the normal operating termination:
-        */
-       prepareDimms(pMCTstat, pDCTstat, dct, dimm, FALSE);
-+
-+      return 0;
- }
- 
- /*----------------------------------------------------------------------------
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
 
b/resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
new file mode 100644
index 0000000..d054245
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch
@@ -0,0 +1,256 @@
+From 42807626761e52746fd88b39c76223bc85e49e50 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 25 Jun 2015 18:08:53 -0500
+Subject: [PATCH 074/143] northbridge/amd/amdmct/mct_ddr3: Attempt to recover
+ from phy training errors
+
+Change-Id: Ia2c3022534c9ad44714eef6e118869f054bd9f6b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c  |   68 +++++++++++++++++++------
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c |   36 ++++++++++---
+ 2 files changed, 83 insertions(+), 21 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+index 5e81808..539cb0d 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+@@ -18,11 +18,11 @@
+  * Foundation, Inc.
+  */
+ 
+-static void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
++static uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
+-static void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
++static uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
+-static void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
++static uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
+ static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+@@ -100,11 +100,12 @@ static void DisableAutoRefresh_D(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ 
+-static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
++static uint8_t PhyWLPass1(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+       u8 dimm;
+       u16 DIMMValid;
++      uint8_t status = 0;
+       void *DCTPtr;
+ 
+       dct &= 1;
+@@ -121,19 +122,22 @@ static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
+               PrepareC_DCT(pMCTstat, pDCTstat, dct);
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
+                       if (DIMMValid & (1 << (dimm << 1))) {
+-                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
+-                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
+-                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
FirstPass);
++                              status |= AgesaHwWlPhase1(pMCTstat, pDCTstat, 
dct, dimm, FirstPass);
++                              status |= AgesaHwWlPhase2(pMCTstat, pDCTstat, 
dct, dimm, FirstPass);
++                              status |= AgesaHwWlPhase3(pMCTstat, pDCTstat, 
dct, dimm, FirstPass);
+                       }
+               }
+       }
++
++      return status;
+ }
+ 
+-static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
++static uint8_t PhyWLPass2(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+       u8 dimm;
+       u16 DIMMValid;
++      uint8_t status = 0;
+       void *DCTPtr;
+ 
+       dct &= 1;
+@@ -163,12 +167,14 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
+               DisableAutoRefresh_D(pMCTstat, pDCTstat);
+               for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
+                       if (DIMMValid & (1 << (dimm << 1))) {
+-                              AgesaHwWlPhase1(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
+-                              AgesaHwWlPhase2(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
+-                              AgesaHwWlPhase3(pMCTstat, pDCTstat, dct, dimm, 
SecondPass);
++                              status |= AgesaHwWlPhase1(pMCTstat, pDCTstat, 
dct, dimm, SecondPass);
++                              status |= AgesaHwWlPhase2(pMCTstat, pDCTstat, 
dct, dimm, SecondPass);
++                              status |= AgesaHwWlPhase3(pMCTstat, pDCTstat, 
dct, dimm, SecondPass);
+                       }
+               }
+       }
++
++      return status;
+ }
+ 
+ static uint16_t fam15h_next_highest_memclk_freq(uint16_t memclk_freq)
+@@ -183,6 +189,8 @@ static uint16_t fam15h_next_highest_memclk_freq(uint16_t 
memclk_freq)
+ static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, uint8_t 
Pass)
+ {
++      uint8_t status;
++      uint8_t timeout;
+       uint16_t final_target_freq;
+ 
+       pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
+@@ -201,8 +209,21 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+       }
+ 
+       if (Pass == FirstPass) {
+-              PhyWLPass1(pMCTstat, pDCTstat, 0);
+-              PhyWLPass1(pMCTstat, pDCTstat, 1);
++              timeout = 0;
++              do {
++                      status = 0;
++                      timeout++;
++                      status |= PhyWLPass1(pMCTstat, pDCTstat, 0);
++                      status |= PhyWLPass1(pMCTstat, pDCTstat, 1);
++                      if (status)
++                              printk(BIOS_INFO,
++                                      "%s: Retrying write levelling due to 
invalid value(s) detected in first phase\n",
++                                      __func__);
++              } while (status && (timeout < 8));
++              if (status)
++                      printk(BIOS_INFO,
++                              "%s: Uncorrectable invalid value(s) detected in 
first phase of write levelling\n",
++                              __func__);
+       }
+ 
+       if (Pass == SecondPass) {
+@@ -211,6 +232,7 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+                        * NOTE: BIOS must program both DCTs to the same 
frequency.
+                        * NOTE: Fam15h steps the frequency, Fam10h slams the 
frequency.
+                        */
++                      uint8_t global_phy_training_status = 0;
+                       final_target_freq = pDCTstat->TargetFreq;
+ 
+                       while (pDCTstat->Speed != final_target_freq) {
+@@ -219,12 +241,28 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+                               else
+                                       pDCTstat->TargetFreq = 
final_target_freq;
+                               SetTargetFreq(pMCTstat, pDCTstat);
+-                              PhyWLPass2(pMCTstat, pDCTstat, 0);
+-                              PhyWLPass2(pMCTstat, pDCTstat, 1);
++                              timeout = 0;
++                              do {
++                                      status = 0;
++                                      timeout++;
++                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 0);
++                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 1);
++                                      if (status)
++                                              printk(BIOS_INFO,
++                                                      "%s: Retrying write 
levelling due to invalid value(s) detected in last phase\n",
++                                                      __func__);
++                              } while (status && (timeout < 8));
++                              global_phy_training_status |= status;
+                       }
+ 
+                       pDCTstat->TargetFreq = final_target_freq;
+ 
++                      if (global_phy_training_status)
++                              printk(BIOS_WARNING,
++                                      "%s: Uncorrectable invalid value(s) 
detected in second phase of write levelling; "
++                                      "continuing but system may be 
unstable!\n",
++                                      __func__);
++
+                       uint8_t dct;
+                       for (dct = 0; dct < 2; dct++) {
+                               sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 0e626fa..403c87c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -54,7 +54,7 @@ static int32_t abs(int32_t val) {
+  */
+ 
+ 
/*-----------------------------------------------------------------------------
+- * void AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct 
*DCTData,
++ * uint8_t AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct 
*DCTData,
+  *                  u8 Dimm, u8 Pass)
+  *
+  *  Description:
+@@ -71,7 +71,7 @@ static int32_t abs(int32_t val) {
+  *       OUT
+  
*-----------------------------------------------------------------------------
+  */
+-void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
+               u8 dct, u8 dimm, u8 pass)
+ {
+       u8 ByteLane;
+@@ -174,12 +174,15 @@ void AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTsta
+       }
+ 
+       pDCTData->WLCriticalGrossDelayPrevPass = 0x1f;
++
++      return 0;
+ }
+ 
+-void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
+               u8 dct, u8 dimm, u8 pass)
+ {
+       u8 ByteLane;
++      uint8_t status = 0;
+       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+ 
+       if (is_fam15h()) {
+@@ -206,19 +209,38 @@ void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTsta
+ 
+               /* Compensate for occasional noise/instability causing sporadic 
training failure */
+               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
++                      uint8_t faulty_value_detected = 0;
+                       uint16_t total_delay_seed = 
((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
+                       uint16_t total_delay_phy = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
+-                      if (abs(total_delay_phy - total_delay_seed) > 0x20) {
+-                              printk(BIOS_DEBUG, "%s: overriding faulty phy 
value (seed: %04x phy: %04x step: %04x)\n", __func__,
++                      if (pass == FirstPass) {
++                              /* Allow a somewhat higher step threshold on 
the first pass
++                               * For the most part, as long as the phy isn't 
stepping
++                               * several clocks at once the values are 
probably valid.
++                               */
++                              if (abs(total_delay_phy - total_delay_seed) > 
0x30)
++                                      faulty_value_detected = 1;
++                      } else {
++                              /* Stepping memory clocks between adjacent 
allowed frequencies
++                               *  should not yield large phy value 
differences...
++                               */
++
++                              if (abs(total_delay_phy - total_delay_seed) > 
0x20)
++                                      faulty_value_detected = 1;
++                      }
++                      if (faulty_value_detected) {
++                              printk(BIOS_INFO, "%s: overriding faulty phy 
value (seed: %04x phy: %04x step: %04x)\n", __func__,
+                                       total_delay_seed, total_delay_phy, 
abs(total_delay_phy - total_delay_seed));
+                               pDCTData->WLGrossDelay[index+ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane];
+                               pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
++                              status = 1;
+                       }
+               }
+       }
++
++      return status;
+ }
+ 
+-void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
++uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
+               u8 dct, u8 dimm, u8 pass)
+ {
+       u8 ByteLane;
+@@ -285,6 +307,8 @@ void AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTsta
+        * to the normal operating termination:
+        */
+       prepareDimms(pMCTstat, pDCTstat, dct, dimm, FALSE);
++
++      return 0;
+ }
+ 
+ /*----------------------------------------------------------------------------
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
 
b/resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
deleted file mode 100644
index 5703442..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0074-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 91caf442aef8c846b9d860bf3e8d2954a2a5e21b Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 25 Jun 2015 18:37:45 -0500
-Subject: [PATCH 074/139] northbridge/amd/amdmct/mct_ddr3: Work around strange
- phy training issue
-
-Change-Id: Ic7a19d24954f47c922126e3da7be1f7e85f7396f
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 16 ++++++++++++++++
- 1 file changed, 16 insertions(+)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index bb076cb..bd37ba7 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -207,6 +207,22 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
- 
-               pDCTData->WLCriticalGrossDelayPrevPass = cgd;
- 
-+              if (pDCTstat->Speed != pDCTstat->TargetFreq) {
-+                      /* FIXME
-+                       * Using the Pass 1 training values causes major phy 
training problems on
-+                       * all Family 15h processors I tested (Pass 1 values 
are randomly too high,
-+                       * and Pass 2 cannot lock).
-+                       * Figure out why this is and fix it, then remove the 
bypass code below...
-+                       */
-+                      if (pass == FirstPass) {
-+                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                                      pDCTData->WLGrossDelay[index+ByteLane] 
= pDCTData->WLSeedGrossDelay[index+ByteLane];
-+                                      pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
-+                              }
-+                              return 0;
-+                      }
-+              }
-+
-               /* Compensate for occasional noise/instability causing sporadic 
training failure */
-               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-                       uint8_t faulty_value_detected = 0;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
 
b/resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
deleted file mode 100644
index 728e747..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
+++ /dev/null
@@ -1,120 +0,0 @@
-From feb85d8596ae2447a8ec82e370350e30cfefbc90 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 26 Jun 2015 00:17:10 -0500
-Subject: [PATCH 075/139] northbridge/amd/amdmct/mct_ddr3: Add additional debug
- trace statements
-
-Change-Id: Iacd789b3572dc8ee85e76d56c46685e6df31d1a6
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  |  8 ++++++++
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c | 16 ++++++++++++++++
- 2 files changed, 24 insertions(+)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 643fa39..f9a7934 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -5815,7 +5815,11 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc 
*pMCTstat,
- static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       mct_ProgramODT_D(pMCTstat, pDCTstat, dct);
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
-@@ -5825,6 +5829,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-       u32 dword;
-       u32 dev = pDCTstat->dev_dct;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       /* FIXME
-        * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
-        * For now assume a maximum of 2 DIMMs per channel can be installed
-@@ -6139,6 +6145,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, 
odt_pattern_2);
-               }
-       }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index 51cbf16..380c5f2 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -192,9 +192,13 @@ static void mct_DCTAccessDone(struct DCTStatStruc 
*pDCTstat, u8 dct)
-       u32 dev = pDCTstat->dev_dct;
-       u32 val;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       do {
-               val = Get_NB32_DCT(dev, dct, 0x98);
-       } while (!(val & (1 << DctAccessDone)));
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 
MR_register_setting, u8 MrsChipSel, u8 dct)
-@@ -239,6 +243,8 @@ static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 EMRS)
-       u32 dev = pDCTstat->dev_dct;
-       u32 val;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       val = Get_NB32_DCT(dev, dct, 0x7c);
-       val &= ~0x00ffffff;
-       val |= EMRS;
-@@ -248,6 +254,8 @@ static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 EMRS)
-       do {
-               val = Get_NB32_DCT(dev, dct, 0x7c);
-       } while (val & (1 << SendMrsCmd));
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
-@@ -557,6 +565,8 @@ static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, 
u8 dct)
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       /*1.Program MrsAddress[10]=1
-         2.Set SendZQCmd=1
-        */
-@@ -573,6 +583,8 @@ static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, 
u8 dct)
- 
-       /* 4.Wait 512 MEMCLKs */
-       mct_Wait(300);
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-@@ -582,6 +594,8 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-       u32 dword;
-       u32 dev = pDCTstat->dev_dct;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-               /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
-               dword = Get_NB32_DCT(dev, dct, 0x7c);
-@@ -663,4 +677,6 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-               Set_NB32_DCT(dev, dct, 0x7C, dword);
-               mct_DCTAccessDone(pDCTstat, dct);
-       }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
 
b/resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
new file mode 100644
index 0000000..ed90d9f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch
@@ -0,0 +1,42 @@
+From 557954beb8c452750f9ffdd176896b2afb764f27 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 25 Jun 2015 18:37:45 -0500
+Subject: [PATCH 075/143] northbridge/amd/amdmct/mct_ddr3: Work around strange
+ phy training issue
+
+Change-Id: Ic7a19d24954f47c922126e3da7be1f7e85f7396f
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c |   16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 403c87c..85b8378 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -207,6 +207,22 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
+ 
+               pDCTData->WLCriticalGrossDelayPrevPass = cgd;
+ 
++              if (pDCTstat->Speed != pDCTstat->TargetFreq) {
++                      /* FIXME
++                       * Using the Pass 1 training values causes major phy 
training problems on
++                       * all Family 15h processors I tested (Pass 1 values 
are randomly too high,
++                       * and Pass 2 cannot lock).
++                       * Figure out why this is and fix it, then remove the 
bypass code below...
++                       */
++                      if (pass == FirstPass) {
++                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                                      pDCTData->WLGrossDelay[index+ByteLane] 
= pDCTData->WLSeedGrossDelay[index+ByteLane];
++                                      pDCTData->WLFineDelay[index+ByteLane] = 
pDCTData->WLSeedFineDelay[index+ByteLane];
++                              }
++                              return 0;
++                      }
++              }
++
+               /* Compensate for occasional noise/instability causing sporadic 
training failure */
+               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+                       uint8_t faulty_value_detected = 0;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
 
b/resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
new file mode 100644
index 0000000..e233545
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch
@@ -0,0 +1,120 @@
+From 2d90214ad2153d723398d5c1175a7dc1769f86a4 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 26 Jun 2015 00:17:10 -0500
+Subject: [PATCH 076/143] northbridge/amd/amdmct/mct_ddr3: Add additional
+ debug trace statements
+
+Change-Id: Iacd789b3572dc8ee85e76d56c46685e6df31d1a6
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  |    8 ++++++++
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c |   16 ++++++++++++++++
+ 2 files changed, 24 insertions(+)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 999e4ae..6448eb4 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -5817,7 +5817,11 @@ static void mct_ResetDataStruct_D(struct MCTStatStruc 
*pMCTstat,
+ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       mct_ProgramODT_D(pMCTstat, pDCTstat, dct);
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
+@@ -5827,6 +5831,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+       u32 dword;
+       u32 dev = pDCTstat->dev_dct;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       /* FIXME
+        * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+        * For now assume a maximum of 2 DIMMs per channel can be installed
+@@ -6141,6 +6147,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, 
odt_pattern_2);
+               }
+       }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat,
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 51cbf16..380c5f2 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -192,9 +192,13 @@ static void mct_DCTAccessDone(struct DCTStatStruc 
*pDCTstat, u8 dct)
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       do {
+               val = Get_NB32_DCT(dev, dct, 0x98);
+       } while (!(val & (1 << DctAccessDone)));
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 
MR_register_setting, u8 MrsChipSel, u8 dct)
+@@ -239,6 +243,8 @@ static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 EMRS)
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       val = Get_NB32_DCT(dev, dct, 0x7c);
+       val &= ~0x00ffffff;
+       val |= EMRS;
+@@ -248,6 +254,8 @@ static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 EMRS)
+       do {
+               val = Get_NB32_DCT(dev, dct, 0x7c);
+       } while (val & (1 << SendMrsCmd));
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+@@ -557,6 +565,8 @@ static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, 
u8 dct)
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       /*1.Program MrsAddress[10]=1
+         2.Set SendZQCmd=1
+        */
+@@ -573,6 +583,8 @@ static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, 
u8 dct)
+ 
+       /* 4.Wait 512 MEMCLKs */
+       mct_Wait(300);
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+@@ -582,6 +594,8 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+       u32 dword;
+       u32 dev = pDCTstat->dev_dct;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       if (pDCTstat->DIMMAutoSpeed == 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+               /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
+               dword = Get_NB32_DCT(dev, dct, 0x7c);
+@@ -663,4 +677,6 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+               Set_NB32_DCT(dev, dct, 0x7C, dword);
+               mct_DCTAccessDone(pDCTstat, dct);
+       }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
 
b/resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
deleted file mode 100644
index 73d5696..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
+++ /dev/null
@@ -1,240 +0,0 @@
-From 55d9af79adf271287c8cf9091da53b707f67e02f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 26 Jun 2015 12:17:48 -0500
-Subject: [PATCH 076/139] northbridge/amd/amdmct/mct_ddr3: Fix null pointer
- access and related hangs
-
-Change-Id: Iaf826b6a0c8e929372519f6d97933515a80f0b39
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  | 58 +++++++++++++++-------------
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c |  8 ++--
- 2 files changed, 34 insertions(+), 32 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index f9a7934..e859c54 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -826,7 +826,7 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                       /* RDIMM */
-                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
-                       if (MaxDimmsInstallable == 1) {
--                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
- 
-                               if (MemClkFreq == 0x4) {
-                                       /* DDR3-667 */
-@@ -850,8 +850,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                                       calibration_code |= 0x22 << 16;
-                               }
-                       } else if (MaxDimmsInstallable == 2) {
--                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) 
+ dct];
-+                              rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
- 
-                               if (dimm_count == 1) {
-                                       /* 1 DIMM detected */
-@@ -875,8 +875,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                                       }
-                               } else if (dimm_count == 2) {
-                                       /* 2 DIMMs detected */
--                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
- 
-                                       if (MemClkFreq == 0x4) {
-                                               /* DDR3-667 */
-@@ -943,8 +943,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                                       }
-                               } else if (dimm_count == 2) {
-                                       /* 2 DIMMs detected */
--                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
- 
-                                       if (MemClkFreq == 0x4) {
-                                               /* DDR3-667 */
-@@ -1065,7 +1065,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
-                       /* UDIMM */
-                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-                       if (MaxDimmsInstallable == 1) {
--                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
- 
-                               if (MemClkFreq == 0x4) {
-                                       /* DDR3-667 */
-@@ -1098,7 +1098,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
-                       } else if (MaxDimmsInstallable == 2) {
-                               if (dimm_count == 1) {
-                                       /* 1 DIMM detected */
--                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
- 
-                                       if (MemClkFreq == 0x4) {
-                                               /* DDR3-667 */
-@@ -1127,8 +1127,8 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
-                                       }
-                               } else if (dimm_count == 2) {
-                                       /* 2 DIMMs detected */
--                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
- 
-                                       if (MemClkFreq == 0x4) {
-                                               /* DDR3-667 */
-@@ -1196,7 +1196,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
-                       /* UDIMM */
-                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
-                       if (MaxDimmsInstallable == 1) {
--                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
- 
-                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
-                                       || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
-@@ -1212,7 +1212,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
-                       } else if (MaxDimmsInstallable == 2) {
-                               if (dimm_count == 1) {
-                                       /* 1 DIMM detected */
--                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
- 
-                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
-                                               || (MemClkFreq == 0xa) | 
(MemClkFreq == 0xe)) {
-@@ -1227,8 +1227,8 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
-                                       }
-                               } else if (dimm_count == 2) {
-                                       /* 2 DIMMs detected */
--                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
- 
-                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
-                                               || (MemClkFreq == 0xa)) {
-@@ -5851,14 +5851,18 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-               uint8_t write_odt_delay;
-               uint8_t read_odt_delay;
- 
-+              /* NOTE
-+               * Rank count per DIMM and DCT is encoded by 
pDCTstat->DimmRanks[(<dimm number> * 2) + dct]
-+               */
-+
-               /* Select appropriate ODT pattern for installed DIMMs
-                * Refer to the Fam15h BKDG Rev. 3.14, page 149 onwards
-                */
--              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED]) {
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-                       if (MaxDimmsInstallable == 2) {
-                               if (dimm_count == 1) {
-                                       /* 1 DIMM detected */
--                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-                                       if (rank_count_dimm1 == 1) {
-                                               odt_pattern_0 = 0x00000000;
-                                               odt_pattern_1 = 0x00000000;
-@@ -5883,8 +5887,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                                       }
-                               } else {
-                                       /* 2 DIMMs detected */
--                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
--                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-                                       if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
-                                               odt_pattern_0 = 0x00000000;
-                                               odt_pattern_1 = 0x01010202;
-@@ -5922,7 +5926,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                               odt_pattern_2 = 0x00000000;
-                               odt_pattern_3 = 0x00000000;
-                       }
--              } else if 
(pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
-+              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-                       /* TODO
-                        * Load reduced dimms UNIMPLEMENTED
-                        */
-@@ -5934,7 +5938,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                       if (MaxDimmsInstallable == 2) {
-                               if (dimm_count == 1) {
-                                       /* 1 DIMM detected */
--                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-                                       if (rank_count_dimm1 == 1) {
-                                               odt_pattern_0 = 0x00000000;
-                                               odt_pattern_1 = 0x00000000;
-@@ -5970,7 +5974,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                       }
-               }
- 
--              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
-+              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-                       /* TODO
-                        * Load reduced dimms UNIMPLEMENTED
-                        */
-@@ -6030,11 +6034,11 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                       /* Select appropriate ODT pattern for installed DIMMs
-                        * Refer to the Fam10h BKDG Rev. 3.62, page 120 onwards
-                        */
--                      if 
(pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) {
-+                      if (pDCTstat->Status & (1 << SB_Registered)) {
-                               if (MaxDimmsInstallable == 2) {
-                                       if (dimm_count == 1) {
-                                               /* 1 DIMM detected */
--                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
-+                                              rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + i];
-                                               if (rank_count_dimm1 == 1) {
-                                                       odt_pattern_0 = 
0x00000000;
-                                                       odt_pattern_1 = 
0x00000000;
-@@ -6059,8 +6063,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                                               }
-                                       } else {
-                                               /* 2 DIMMs detected */
--                                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[0];
--                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
-+                                              rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + i];
-+                                              rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + i];
-                                               if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
-                                                       odt_pattern_0 = 
0x00000000;
-                                                       odt_pattern_1 = 
0x01010202;
-@@ -6102,7 +6106,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                               if (MaxDimmsInstallable == 2) {
-                                       if (dimm_count == 1) {
-                                               /* 1 DIMM detected */
--                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
-+                                              rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + i];
-                                               if (rank_count_dimm1 == 1) {
-                                                       odt_pattern_0 = 
0x00000000;
-                                                       odt_pattern_1 = 
0x00000000;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index 380c5f2..c7d7463 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -38,10 +38,9 @@ static uint8_t fam15_dimm_dic(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_
- static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
- {
-       uint8_t term = 0;
--      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
--      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
-+      uint8_t number_of_dimms = pDCTstat->MAdimms[dct];
-       uint8_t frequency_index;
--      uint8_t rank_count = pDCTData->DimmRanks[dimm];
-+      uint8_t rank_count = pDCTstat->DimmRanks[(dimm * 2) + dct];
- 
-       if (is_fam15h())
-               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
-@@ -101,8 +100,7 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
- static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
- {
-       uint8_t term = 0;
--      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
--      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
-+      uint8_t number_of_dimms = pDCTstat->MAdimms[dct];
-       uint8_t frequency_index;
- 
-       if (is_fam15h())
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
deleted file mode 100644
index b406fc9..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
+++ /dev/null
@@ -1,268 +0,0 @@
-From bc99fcbab8c0bd2851216a34f3d72fddbe790332 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 26 Jun 2015 14:15:57 -0500
-Subject: [PATCH 077/139] northbridge/amd/amdmct/mct_ddr3: Add missing Family
- 15h RDIMM Rtt values
-
-Change-Id: I80cd7f8aec12951611d802f33e5e167a41dd532e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  |   4 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c | 201 ++++++++++++++++++++++++++-
- 2 files changed, 198 insertions(+), 7 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index e859c54..8ca2c25 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -897,8 +897,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
-                               }
-                       } else if (MaxDimmsInstallable == 3) {
-                               /* TODO
--                              * 3 DIMM/channel support unimplemented
--                              */
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-                       }
-               } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-                       /* LRDIMM */
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index c7d7463..dfbd2d9 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -42,6 +42,10 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
-       uint8_t frequency_index;
-       uint8_t rank_count = pDCTstat->DimmRanks[(dimm * 2) + dct];
- 
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+      uint8_t rank_count_dimm2;
-+
-       if (is_fam15h())
-               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
-       else
-@@ -54,11 +58,80 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
-       uint8_t MaxDimmsInstallable = 2;
- 
-       if (is_fam15h()) {
--              if (pDCTstat->Status & (1 << SB_Registered)) {
-+              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-                       /* TODO
--                       * RDIMM unimplemented
-+                       * LRDIMM unimplemented
-                        */
-+              } else if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* RDIMM */
-+                      if (package_type == PT_GR) {
-+                              /* Socket G34: Fam15h BKDG v3.14 Table 57 */
-+                              if (MaxDimmsInstallable == 1) {
-+                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)
-+                                              || (frequency_index == 0xa) || 
(frequency_index == 0xe)) {
-+                                              /* DDR3-667 - DDR3-1333 */
-+                                              if (rank_count < 3)
-+                                                      term = 0x0;
-+                                              else
-+                                                      term = 0x2;
-+                                      } else {
-+                                              /* DDR3-1600 */
-+                                              term = 0x0;
-+                                      }
-+                              } else if (MaxDimmsInstallable == 2) {
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)) {
-+                                              /* DDR3-667 - DDR3-800 */
-+                                              if ((number_of_dimms == 1) && 
((rank_count_dimm0 < 4)
-+                                                      && (rank_count_dimm1 < 
4)))
-+                                                      term = 0x0;
-+                                              else
-+                                                      term = 0x2;
-+                                      } else if (frequency_index == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              if (number_of_dimms == 1) {
-+                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
-+                                                              term = 0x0;
-+                                                      else
-+                                                              term = 0x2;
-+                                              } else {
-+                                                      term = 0x1;
-+                                              }
-+                                      } else if (frequency_index == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              term = 0x2;
-+                                      } else {
-+                                              /* DDR3-1600 */
-+                                              if (number_of_dimms == 1)
-+                                                      term = 0x0;
-+                                              else
-+                                                      term = 0x1;
-+                                      }
-+                              } else if (MaxDimmsInstallable == 3) {
-+                                      rank_count_dimm2 = 
pDCTstat->DimmRanks[(2 * 2) + dct];
-+
-+                                      if ((frequency_index == 0xa) || 
(frequency_index == 0xe)) {
-+                                              /* DDR3-1066 - DDR3-1333 */
-+                                              if (rank_count_dimm2 < 4)
-+                                                      term = 0x1;
-+                                              else
-+                                                      term = 0x2;
-+                                      } else if (frequency_index == 0x12) {
-+                                              /* DDR3-1600 */
-+                                              term = 0x1;
-+                                      } else {
-+                                              term = 0x2;
-+                                      }
-+                              }
-+                      } else {
-+                              /* TODO
-+                               * Other sockets unimplemented
-+                               */
-+                      }
-               } else {
-+                      /* UDIMM */
-                       if (package_type == PT_GR) {
-                               /* Socket G34: Fam15h BKDG v3.14 Table 56 */
-                               if (MaxDimmsInstallable == 1) {
-@@ -103,6 +176,9 @@ static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t
-       uint8_t number_of_dimms = pDCTstat->MAdimms[dct];
-       uint8_t frequency_index;
- 
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+
-       if (is_fam15h())
-               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
-       else
-@@ -120,10 +196,125 @@ static uint8_t fam15_rttnom(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t
-                        * LRDIMM unimplemented
-                        */
-               } else if (pDCTstat->Status & (1 << SB_Registered)) {
--                      /* TODO
--                       * RDIMM unimplemented
--                       */
-+                      /* RDIMM */
-+                      if (package_type == PT_GR) {
-+                              /* Socket G34: Fam15h BKDG v3.14 Table 57 */
-+                              if (MaxDimmsInstallable == 1) {
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+
-+                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)) {
-+                                              /* DDR3-667 - DDR3-800 */
-+                                              if (rank_count_dimm0 < 4) {
-+                                                      term = 0x2;
-+                                              } else {
-+                                                      if (!rank)
-+                                                              term = 0x2;
-+                                                      else
-+                                                              term = 0x0;
-+                                              }
-+                                      } else if (frequency_index == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              term = 0x1;
-+                                      } else if (frequency_index == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              if (rank_count_dimm0 < 4) {
-+                                                      term = 0x1;
-+                                              } else {
-+                                                      if (!rank)
-+                                                              term = 0x3;
-+                                                      else
-+                                                              term = 0x0;
-+                                              }
-+                                      } else {
-+                                              term = 0x3;
-+                                      }
-+                              } else if (MaxDimmsInstallable == 2) {
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)) {
-+                                              /* DDR3-667 - DDR3-800 */
-+                                              if (number_of_dimms == 1) {
-+                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
-+                                                              term = 0x2;
-+                                                      else if (rank)
-+                                                              term = 0x0;
-+                                                      else
-+                                                              term = 0x2;
-+                                              } else {
-+                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4)) {
-+                                                              term = 0x3;
-+                                                      } else {
-+                                                              if 
(rank_count_dimm0 == 4) {
-+                                                                      if 
(rank_count_dimm1 == 1)
-+                                                                              
term = 0x5;
-+                                                                      else
-+                                                                              
term = 0x1;
-+                                                              } else if 
(rank_count_dimm1 == 4) {
-+                                                                      if 
(rank_count_dimm0 == 1)
-+                                                                              
term = 0x5;
-+                                                                      else
-+                                                                              
term = 0x1;
-+                                                              }
-+                                                              if (rank)
-+                                                                      term = 
0x0;
-+                                                      }
-+                                              }
-+                                      } else if (frequency_index == 0xa) {
-+                                              /* DDR3-1066 */
-+                                              if (number_of_dimms == 1) {
-+                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
-+                                                              term = 0x1;
-+                                                      else if (rank)
-+                                                              term = 0x0;
-+                                                      else
-+                                                              term = 0x1;
-+                                              } else {
-+                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4)) {
-+                                                              term = 0x3;
-+                                                      } else {
-+                                                              if 
(rank_count_dimm0 == 4) {
-+                                                                      if 
(rank_count_dimm1 == 1)
-+                                                                              
term = 0x5;
-+                                                                      else
-+                                                                              
term = 0x1;
-+                                                              } else if 
(rank_count_dimm1 == 4) {
-+                                                                      if 
(rank_count_dimm0 == 1)
-+                                                                              
term = 0x5;
-+                                                                      else
-+                                                                              
term = 0x1;
-+                                                              }
-+                                                              if (rank)
-+                                                                      term = 
0x0;
-+                                                      }
-+                                              }
-+                                      } else if (frequency_index == 0xe) {
-+                                              /* DDR3-1333 */
-+                                              if (number_of_dimms == 1) {
-+                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
-+                                                              term = 0x1;
-+                                                      else if (rank)
-+                                                              term = 0x0;
-+                                                      else
-+                                                              term = 0x3;
-+                                              } else {
-+                                                      term = 0x5;
-+                                              }
-+                                      } else {
-+                                              /* DDR3-1600 */
-+                                              if (number_of_dimms == 1)
-+                                                      term = 0x3;
-+                                              else
-+                                                      term = 0x4;
-+                                      }
-+                              } else if (MaxDimmsInstallable == 3) {
-+                                      /* TODO
-+                                       * 3 DIMM/channel support unimplemented
-+                                       */
-+                              }
-+                      }
-               } else {
-+                      /* UDIMM */
-                       if (package_type == PT_GR) {
-                               /* Socket G34: Fam15h BKDG v3.14 Table 56 */
-                               if (MaxDimmsInstallable == 1) {
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
 
b/resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
new file mode 100644
index 0000000..cdfa99b
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch
@@ -0,0 +1,240 @@
+From fd59dbd74e335c9337f4c2fedf76575a454f4e19 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 26 Jun 2015 12:17:48 -0500
+Subject: [PATCH 077/143] northbridge/amd/amdmct/mct_ddr3: Fix null pointer
+ access and related hangs
+
+Change-Id: Iaf826b6a0c8e929372519f6d97933515a80f0b39
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  |   58 ++++++++++++++------------
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c |    8 ++--
+ 2 files changed, 34 insertions(+), 32 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 6448eb4..2009fd3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -826,7 +826,7 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                       /* RDIMM */
+                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
+                       if (MaxDimmsInstallable == 1) {
+-                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
+ 
+                               if (MemClkFreq == 0x4) {
+                                       /* DDR3-667 */
+@@ -850,8 +850,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                                       calibration_code |= 0x22 << 16;
+                               }
+                       } else if (MaxDimmsInstallable == 2) {
+-                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) 
+ dct];
++                              rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
+ 
+                               if (dimm_count == 1) {
+                                       /* 1 DIMM detected */
+@@ -875,8 +875,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                                       }
+                               } else if (dimm_count == 2) {
+                                       /* 2 DIMMs detected */
+-                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+ 
+                                       if (MemClkFreq == 0x4) {
+                                               /* DDR3-667 */
+@@ -943,8 +943,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                                       }
+                               } else if (dimm_count == 2) {
+                                       /* 2 DIMMs detected */
+-                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+ 
+                                       if (MemClkFreq == 0x4) {
+                                               /* DDR3-667 */
+@@ -1065,7 +1065,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+                       /* UDIMM */
+                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+                       if (MaxDimmsInstallable == 1) {
+-                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
+ 
+                               if (MemClkFreq == 0x4) {
+                                       /* DDR3-667 */
+@@ -1098,7 +1098,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+                       } else if (MaxDimmsInstallable == 2) {
+                               if (dimm_count == 1) {
+                                       /* 1 DIMM detected */
+-                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+ 
+                                       if (MemClkFreq == 0x4) {
+                                               /* DDR3-667 */
+@@ -1127,8 +1127,8 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+                                       }
+                               } else if (dimm_count == 2) {
+                                       /* 2 DIMMs detected */
+-                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+ 
+                                       if (MemClkFreq == 0x4) {
+                                               /* DDR3-667 */
+@@ -1196,7 +1196,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+                       /* UDIMM */
+                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */
+                       if (MaxDimmsInstallable == 1) {
+-                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
+ 
+                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)
+                                       || (MemClkFreq == 0xa) | (MemClkFreq == 
0xe)) {
+@@ -1212,7 +1212,7 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+                       } else if (MaxDimmsInstallable == 2) {
+                               if (dimm_count == 1) {
+                                       /* 1 DIMM detected */
+-                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+ 
+                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
+                                               || (MemClkFreq == 0xa) | 
(MemClkFreq == 0xe)) {
+@@ -1227,8 +1227,8 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+                                       }
+                               } else if (dimm_count == 2) {
+                                       /* 2 DIMMs detected */
+-                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+ 
+                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)
+                                               || (MemClkFreq == 0xa)) {
+@@ -5853,14 +5853,18 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+               uint8_t write_odt_delay;
+               uint8_t read_odt_delay;
+ 
++              /* NOTE
++               * Rank count per DIMM and DCT is encoded by 
pDCTstat->DimmRanks[(<dimm number> * 2) + dct]
++               */
++
+               /* Select appropriate ODT pattern for installed DIMMs
+                * Refer to the Fam15h BKDG Rev. 3.14, page 149 onwards
+                */
+-              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED]) {
++              if (pDCTstat->Status & (1 << SB_Registered)) {
+                       if (MaxDimmsInstallable == 2) {
+                               if (dimm_count == 1) {
+                                       /* 1 DIMM detected */
+-                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+                                       if (rank_count_dimm1 == 1) {
+                                               odt_pattern_0 = 0x00000000;
+                                               odt_pattern_1 = 0x00000000;
+@@ -5885,8 +5889,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                                       }
+                               } else {
+                                       /* 2 DIMMs detected */
+-                                      rank_count_dimm0 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[0];
+-                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+                                       if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
+                                               odt_pattern_0 = 0x00000000;
+                                               odt_pattern_1 = 0x01010202;
+@@ -5924,7 +5928,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                               odt_pattern_2 = 0x00000000;
+                               odt_pattern_3 = 0x00000000;
+                       }
+-              } else if 
(pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
++              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+                       /* TODO
+                        * Load reduced dimms UNIMPLEMENTED
+                        */
+@@ -5936,7 +5940,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                       if (MaxDimmsInstallable == 2) {
+                               if (dimm_count == 1) {
+                                       /* 1 DIMM detected */
+-                                      rank_count_dimm1 = 
pDCTstat->C_DCTPtr[dct]->DimmRanks[1];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
+                                       if (rank_count_dimm1 == 1) {
+                                               odt_pattern_0 = 0x00000000;
+                                               odt_pattern_1 = 0x00000000;
+@@ -5972,7 +5976,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                       }
+               }
+ 
+-              if (pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_LOAD_REDUCED]) {
++              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+                       /* TODO
+                        * Load reduced dimms UNIMPLEMENTED
+                        */
+@@ -6032,11 +6036,11 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                       /* Select appropriate ODT pattern for installed DIMMs
+                        * Refer to the Fam10h BKDG Rev. 3.62, page 120 onwards
+                        */
+-                      if 
(pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) {
++                      if (pDCTstat->Status & (1 << SB_Registered)) {
+                               if (MaxDimmsInstallable == 2) {
+                                       if (dimm_count == 1) {
+                                               /* 1 DIMM detected */
+-                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
++                                              rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + i];
+                                               if (rank_count_dimm1 == 1) {
+                                                       odt_pattern_0 = 
0x00000000;
+                                                       odt_pattern_1 = 
0x00000000;
+@@ -6061,8 +6065,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                                               }
+                                       } else {
+                                               /* 2 DIMMs detected */
+-                                              rank_count_dimm0 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[0];
+-                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
++                                              rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + i];
++                                              rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + i];
+                                               if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4)) {
+                                                       odt_pattern_0 = 
0x00000000;
+                                                       odt_pattern_1 = 
0x01010202;
+@@ -6104,7 +6108,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                               if (MaxDimmsInstallable == 2) {
+                                       if (dimm_count == 1) {
+                                               /* 1 DIMM detected */
+-                                              rank_count_dimm1 = 
pDCTstat->C_DCTPtr[i]->DimmRanks[1];
++                                              rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + i];
+                                               if (rank_count_dimm1 == 1) {
+                                                       odt_pattern_0 = 
0x00000000;
+                                                       odt_pattern_1 = 
0x00000000;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 380c5f2..c7d7463 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -38,10 +38,9 @@ static uint8_t fam15_dimm_dic(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_
+ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
+ {
+       uint8_t term = 0;
+-      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+-      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
++      uint8_t number_of_dimms = pDCTstat->MAdimms[dct];
+       uint8_t frequency_index;
+-      uint8_t rank_count = pDCTData->DimmRanks[dimm];
++      uint8_t rank_count = pDCTstat->DimmRanks[(dimm * 2) + dct];
+ 
+       if (is_fam15h())
+               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
+@@ -101,8 +100,7 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
+ static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t dimm, uint8_t rank, uint8_t package_type)
+ {
+       uint8_t term = 0;
+-      sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+-      uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
++      uint8_t number_of_dimms = pDCTstat->MAdimms[dct];
+       uint8_t frequency_index;
+ 
+       if (is_fam15h())
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
new file mode 100644
index 0000000..cb40f86
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch
@@ -0,0 +1,268 @@
+From 85be24f8b0bbe7ddea842457438837c48ca0ae13 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 26 Jun 2015 14:15:57 -0500
+Subject: [PATCH 078/143] northbridge/amd/amdmct/mct_ddr3: Add missing Family
+ 15h RDIMM Rtt values
+
+Change-Id: I80cd7f8aec12951611d802f33e5e167a41dd532e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  |    4 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c |  201 +++++++++++++++++++++++++-
+ 2 files changed, 198 insertions(+), 7 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 2009fd3..bb5593d 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -897,8 +897,8 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+                               }
+                       } else if (MaxDimmsInstallable == 3) {
+                               /* TODO
+-                              * 3 DIMM/channel support unimplemented
+-                              */
++                               * 3 DIMM/channel support unimplemented
++                               */
+                       }
+               } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+                       /* LRDIMM */
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index c7d7463..dfbd2d9 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -42,6 +42,10 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
+       uint8_t frequency_index;
+       uint8_t rank_count = pDCTstat->DimmRanks[(dimm * 2) + dct];
+ 
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++      uint8_t rank_count_dimm2;
++
+       if (is_fam15h())
+               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
+       else
+@@ -54,11 +58,80 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
+       uint8_t MaxDimmsInstallable = 2;
+ 
+       if (is_fam15h()) {
+-              if (pDCTstat->Status & (1 << SB_Registered)) {
++              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+                       /* TODO
+-                       * RDIMM unimplemented
++                       * LRDIMM unimplemented
+                        */
++              } else if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* RDIMM */
++                      if (package_type == PT_GR) {
++                              /* Socket G34: Fam15h BKDG v3.14 Table 57 */
++                              if (MaxDimmsInstallable == 1) {
++                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)
++                                              || (frequency_index == 0xa) || 
(frequency_index == 0xe)) {
++                                              /* DDR3-667 - DDR3-1333 */
++                                              if (rank_count < 3)
++                                                      term = 0x0;
++                                              else
++                                                      term = 0x2;
++                                      } else {
++                                              /* DDR3-1600 */
++                                              term = 0x0;
++                                      }
++                              } else if (MaxDimmsInstallable == 2) {
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)) {
++                                              /* DDR3-667 - DDR3-800 */
++                                              if ((number_of_dimms == 1) && 
((rank_count_dimm0 < 4)
++                                                      && (rank_count_dimm1 < 
4)))
++                                                      term = 0x0;
++                                              else
++                                                      term = 0x2;
++                                      } else if (frequency_index == 0xa) {
++                                              /* DDR3-1066 */
++                                              if (number_of_dimms == 1) {
++                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
++                                                              term = 0x0;
++                                                      else
++                                                              term = 0x2;
++                                              } else {
++                                                      term = 0x1;
++                                              }
++                                      } else if (frequency_index == 0xe) {
++                                              /* DDR3-1333 */
++                                              term = 0x2;
++                                      } else {
++                                              /* DDR3-1600 */
++                                              if (number_of_dimms == 1)
++                                                      term = 0x0;
++                                              else
++                                                      term = 0x1;
++                                      }
++                              } else if (MaxDimmsInstallable == 3) {
++                                      rank_count_dimm2 = 
pDCTstat->DimmRanks[(2 * 2) + dct];
++
++                                      if ((frequency_index == 0xa) || 
(frequency_index == 0xe)) {
++                                              /* DDR3-1066 - DDR3-1333 */
++                                              if (rank_count_dimm2 < 4)
++                                                      term = 0x1;
++                                              else
++                                                      term = 0x2;
++                                      } else if (frequency_index == 0x12) {
++                                              /* DDR3-1600 */
++                                              term = 0x1;
++                                      } else {
++                                              term = 0x2;
++                                      }
++                              }
++                      } else {
++                              /* TODO
++                               * Other sockets unimplemented
++                               */
++                      }
+               } else {
++                      /* UDIMM */
+                       if (package_type == PT_GR) {
+                               /* Socket G34: Fam15h BKDG v3.14 Table 56 */
+                               if (MaxDimmsInstallable == 1) {
+@@ -103,6 +176,9 @@ static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t
+       uint8_t number_of_dimms = pDCTstat->MAdimms[dct];
+       uint8_t frequency_index;
+ 
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++
+       if (is_fam15h())
+               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x1f;
+       else
+@@ -120,10 +196,125 @@ static uint8_t fam15_rttnom(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t
+                        * LRDIMM unimplemented
+                        */
+               } else if (pDCTstat->Status & (1 << SB_Registered)) {
+-                      /* TODO
+-                       * RDIMM unimplemented
+-                       */
++                      /* RDIMM */
++                      if (package_type == PT_GR) {
++                              /* Socket G34: Fam15h BKDG v3.14 Table 57 */
++                              if (MaxDimmsInstallable == 1) {
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++
++                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)) {
++                                              /* DDR3-667 - DDR3-800 */
++                                              if (rank_count_dimm0 < 4) {
++                                                      term = 0x2;
++                                              } else {
++                                                      if (!rank)
++                                                              term = 0x2;
++                                                      else
++                                                              term = 0x0;
++                                              }
++                                      } else if (frequency_index == 0xa) {
++                                              /* DDR3-1066 */
++                                              term = 0x1;
++                                      } else if (frequency_index == 0xe) {
++                                              /* DDR3-1333 */
++                                              if (rank_count_dimm0 < 4) {
++                                                      term = 0x1;
++                                              } else {
++                                                      if (!rank)
++                                                              term = 0x3;
++                                                      else
++                                                              term = 0x0;
++                                              }
++                                      } else {
++                                              term = 0x3;
++                                      }
++                              } else if (MaxDimmsInstallable == 2) {
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if ((frequency_index == 0x4) || 
(frequency_index == 0x6)) {
++                                              /* DDR3-667 - DDR3-800 */
++                                              if (number_of_dimms == 1) {
++                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
++                                                              term = 0x2;
++                                                      else if (rank)
++                                                              term = 0x0;
++                                                      else
++                                                              term = 0x2;
++                                              } else {
++                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4)) {
++                                                              term = 0x3;
++                                                      } else {
++                                                              if 
(rank_count_dimm0 == 4) {
++                                                                      if 
(rank_count_dimm1 == 1)
++                                                                              
term = 0x5;
++                                                                      else
++                                                                              
term = 0x1;
++                                                              } else if 
(rank_count_dimm1 == 4) {
++                                                                      if 
(rank_count_dimm0 == 1)
++                                                                              
term = 0x5;
++                                                                      else
++                                                                              
term = 0x1;
++                                                              }
++                                                              if (rank)
++                                                                      term = 
0x0;
++                                                      }
++                                              }
++                                      } else if (frequency_index == 0xa) {
++                                              /* DDR3-1066 */
++                                              if (number_of_dimms == 1) {
++                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
++                                                              term = 0x1;
++                                                      else if (rank)
++                                                              term = 0x0;
++                                                      else
++                                                              term = 0x1;
++                                              } else {
++                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4)) {
++                                                              term = 0x3;
++                                                      } else {
++                                                              if 
(rank_count_dimm0 == 4) {
++                                                                      if 
(rank_count_dimm1 == 1)
++                                                                              
term = 0x5;
++                                                                      else
++                                                                              
term = 0x1;
++                                                              } else if 
(rank_count_dimm1 == 4) {
++                                                                      if 
(rank_count_dimm0 == 1)
++                                                                              
term = 0x5;
++                                                                      else
++                                                                              
term = 0x1;
++                                                              }
++                                                              if (rank)
++                                                                      term = 
0x0;
++                                                      }
++                                              }
++                                      } else if (frequency_index == 0xe) {
++                                              /* DDR3-1333 */
++                                              if (number_of_dimms == 1) {
++                                                      if ((rank_count_dimm0 < 
4) && (rank_count_dimm1 < 4))
++                                                              term = 0x1;
++                                                      else if (rank)
++                                                              term = 0x0;
++                                                      else
++                                                              term = 0x3;
++                                              } else {
++                                                      term = 0x5;
++                                              }
++                                      } else {
++                                              /* DDR3-1600 */
++                                              if (number_of_dimms == 1)
++                                                      term = 0x3;
++                                              else
++                                                      term = 0x4;
++                                      }
++                              } else if (MaxDimmsInstallable == 3) {
++                                      /* TODO
++                                       * 3 DIMM/channel support unimplemented
++                                       */
++                              }
++                      }
+               } else {
++                      /* UDIMM */
+                       if (package_type == PT_GR) {
+                               /* Socket G34: Fam15h BKDG v3.14 Table 56 */
+                               if (MaxDimmsInstallable == 1) {
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
 
b/resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
deleted file mode 100644
index 7b3d0f1..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From e8926cb6ee7046c3b4ceacb1ca8c885a2ec1c037 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 26 Jun 2015 17:49:25 -0500
-Subject: [PATCH 078/139] northbridge/amd/amdmct/mct_ddr3: Set SkewMemClk when
- both DCTs are in use
-
-Change-Id: Ibcce54fc53b79beba2f790994bcf87cc0354213a
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 41 +++++++++++++++++++++++------
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |  2 +-
- 2 files changed, 34 insertions(+), 9 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 8ca2c25..aea17a1 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -2643,7 +2643,7 @@ static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDC
- 
-       /* Reset DCT registers */
-       ClearDCT_D(pMCTstat, pDCTstat, dct);
--      pDCTstat->stopDCT = 1;          /*preload flag with 'disable' */
-+      pDCTstat->stopDCT[dct] = 1;     /* preload flag with 'disable' */
- 
-       if (!is_fam15h()) {
-               /* Enable DDR3 support */
-@@ -2654,7 +2654,7 @@ static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDC
- 
-       /* Read the SPD information into the data structures */
-       if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
--              printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_DIMMPresence Done\n");
-+              printk(BIOS_DEBUG, "\t\tDCTPreInit_D: mct_DIMMPresence Done\n");
-       }
- }
- 
-@@ -2680,17 +2680,40 @@ static void DCTInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTst
-                               printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D 
Done\n");
-                               if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
-                                       printk(BIOS_DEBUG, "\t\tDCTInit_D: 
PlatformSpec_D Done\n");
--                                      pDCTstat->stopDCT = 0;
--                                      if (!(pMCTstat->GStatus & (1 << 
GSB_EnDIMMSpareNW))) {
--                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: StartupDCT_D\n");
--                                              StartupDCT_D(pMCTstat, 
pDCTstat, dct);   /*yeaahhh! */
--                                      }
-+                                      pDCTstat->stopDCT[dct] = 0;
-                               }
-                       }
-               }
-       }
- 
--      if (pDCTstat->stopDCT) {
-+
-+}
-+
-+static void DCTFinalInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
-+{
-+      uint32_t dword;
-+
-+      /* Finalize DRAM init on a single node */
-+      if (is_fam15h()) {
-+              /* Set memory clock skew if needed */
-+              if (dct == 0) {
-+                      if (!pDCTstat->stopDCT[0] && !pDCTstat->stopDCT[1]) {
-+                              dword = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0d0fe00a);
-+                              dword |= (0x1 << 4);                            
/* SkewMemClk = 1 */
-+                              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
0x98, 0x0d0fe00a, dword);
-+                      }
-+              }
-+      }
-+
-+      if (!pDCTstat->stopDCT[dct]) {
-+              if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
-+                      printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D 
Start\n");
-+                      StartupDCT_D(pMCTstat, pDCTstat, dct);
-+                      printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D 
Done\n");
-+              }
-+      }
-+
-+      if (pDCTstat->stopDCT[dct]) {
-               dword = 1 << DisDramInterface;
-               Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
- 
-@@ -4348,6 +4371,7 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
- 
-       /* Config. DCT0 for Ganged or unganged mode */
-       DCTInit_D(pMCTstat, pDCTstat, 0);
-+      DCTFinalInit_D(pMCTstat, pDCTstat, 0);
-       if (pDCTstat->ErrCode == SC_FatalErr) {
-               /* Do nothing goto exitDCTInit; any fatal errors? */
-       } else {
-@@ -4357,6 +4381,7 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
-                               err_code = pDCTstat->ErrCode;           /* save 
DCT0 errors */
-                               pDCTstat->ErrCode = 0;
-                               DCTInit_D(pMCTstat, pDCTstat, 1);
-+                              DCTFinalInit_D(pMCTstat, pDCTstat, 1);
-                               if (pDCTstat->ErrCode == 2)             /* DCT1 
is not Running */
-                                       pDCTstat->ErrCode = err_code;   /* 
Using DCT0 Error code to update pDCTstat.ErrCode */
-                       } else {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 8c9da47..7bc392b 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -338,7 +338,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-       u8 Node_ID;                     /* Node ID of current controller */
-       uint8_t Internal_Node_ID;       /* Internal Node ID of the current 
controller */
-       uint8_t Dual_Node_Package;      /* 1=Dual node package (G34) */
--      uint8_t stopDCT;                /* Set if the DCT will be stopped */
-+      uint8_t stopDCT[2];             /* Set if the DCT will be stopped */
-       u8 ErrCode;                     /* Current error condition of Node
-               0= no error
-               1= Variance Error, DCT is running but not in an optimal 
configuration.
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
 
b/resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
deleted file mode 100644
index 2f8a513..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 146d781ece056408e0ba28b4c8d7a46df6d0257a Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 27 Jun 2015 17:52:18 -0500
-Subject: [PATCH 079/139] northbridge/amd/amdmct/mct_ddr3: Properly indicate
- clobbered registers
-
-Change-Id: Icb2754143762bd64ee1df5674fa071de1c595eaf
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h | 11 +++++++++--
- 1 file changed, 9 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-index f6aa755..cc8d971 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
-@@ -123,6 +123,9 @@ static void proc_CLFLUSH(u32 addr_hi)
- 
- static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 line_num)
- {
-+      uint32_t step = 16;
-+      uint32_t count = line_num * 4;
-+
-       __asm__ volatile (
-               /*prevent speculative execution of following instructions*/
-               /* FIXME: needed ? */
-@@ -135,7 +138,7 @@ static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 
line_num)
-               "loop 1b\n\t"
-               "mfence\n\t"
- 
--               :: "a" (addr_lo), "d" (16), "c" (line_num * 4), "b"(buf_a)
-+               : "+a" (addr_lo), "+d" (step), "+c" (count), "+b" (buf_a) : :
-       );
- 
- }
-@@ -255,6 +258,10 @@ static void ReadMaxRdLat1CLTestPattern_D(u32 addr)
- 
- static void WriteMaxRdLat1CLTestPattern_D(u32 buf, u32 addr)
- {
-+      uint32_t addr_phys = addr << 8;
-+      uint32_t step = 16;
-+      uint32_t count = 3 * 4;
-+
-       SetUpperFSbase(addr);
- 
-       __asm__ volatile (
-@@ -267,7 +274,7 @@ static void WriteMaxRdLat1CLTestPattern_D(u32 buf, u32 
addr)
-               "loop 1b\n\t"
-               "mfence\n\t"
- 
--               :: "a" (addr<<8), "d" (16), "c" (3 * 4), "b"(buf)
-+               : "+a" (addr_phys), "+d" (step), "+c" (count), "+b" (buf) : :
-       );
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
 
b/resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
new file mode 100644
index 0000000..d06c447
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch
@@ -0,0 +1,114 @@
+From 77935659fbe9426e7a65ecc5506beb4491171e7f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 26 Jun 2015 17:49:25 -0500
+Subject: [PATCH 079/143] northbridge/amd/amdmct/mct_ddr3: Set SkewMemClk when
+ both DCTs are in use
+
+Change-Id: Ibcce54fc53b79beba2f790994bcf87cc0354213a
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |   41 +++++++++++++++++++++------
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |    2 +-
+ 2 files changed, 34 insertions(+), 9 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index bb5593d..f3d5cb8 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -2645,7 +2645,7 @@ static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDC
+ 
+       /* Reset DCT registers */
+       ClearDCT_D(pMCTstat, pDCTstat, dct);
+-      pDCTstat->stopDCT = 1;          /*preload flag with 'disable' */
++      pDCTstat->stopDCT[dct] = 1;     /* preload flag with 'disable' */
+ 
+       if (!is_fam15h()) {
+               /* Enable DDR3 support */
+@@ -2656,7 +2656,7 @@ static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDC
+ 
+       /* Read the SPD information into the data structures */
+       if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) {
+-              printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_DIMMPresence Done\n");
++              printk(BIOS_DEBUG, "\t\tDCTPreInit_D: mct_DIMMPresence Done\n");
+       }
+ }
+ 
+@@ -2682,17 +2682,40 @@ static void DCTInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTst
+                               printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D 
Done\n");
+                               if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
+                                       printk(BIOS_DEBUG, "\t\tDCTInit_D: 
PlatformSpec_D Done\n");
+-                                      pDCTstat->stopDCT = 0;
+-                                      if (!(pMCTstat->GStatus & (1 << 
GSB_EnDIMMSpareNW))) {
+-                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: StartupDCT_D\n");
+-                                              StartupDCT_D(pMCTstat, 
pDCTstat, dct);   /*yeaahhh! */
+-                                      }
++                                      pDCTstat->stopDCT[dct] = 0;
+                               }
+                       }
+               }
+       }
+ 
+-      if (pDCTstat->stopDCT) {
++
++}
++
++static void DCTFinalInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
++{
++      uint32_t dword;
++
++      /* Finalize DRAM init on a single node */
++      if (is_fam15h()) {
++              /* Set memory clock skew if needed */
++              if (dct == 0) {
++                      if (!pDCTstat->stopDCT[0] && !pDCTstat->stopDCT[1]) {
++                              dword = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0d0fe00a);
++                              dword |= (0x1 << 4);                            
/* SkewMemClk = 1 */
++                              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
0x98, 0x0d0fe00a, dword);
++                      }
++              }
++      }
++
++      if (!pDCTstat->stopDCT[dct]) {
++              if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
++                      printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D 
Start\n");
++                      StartupDCT_D(pMCTstat, pDCTstat, dct);
++                      printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D 
Done\n");
++              }
++      }
++
++      if (pDCTstat->stopDCT[dct]) {
+               dword = 1 << DisDramInterface;
+               Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
+ 
+@@ -4350,6 +4373,7 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+ 
+       /* Config. DCT0 for Ganged or unganged mode */
+       DCTInit_D(pMCTstat, pDCTstat, 0);
++      DCTFinalInit_D(pMCTstat, pDCTstat, 0);
+       if (pDCTstat->ErrCode == SC_FatalErr) {
+               /* Do nothing goto exitDCTInit; any fatal errors? */
+       } else {
+@@ -4359,6 +4383,7 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+                               err_code = pDCTstat->ErrCode;           /* save 
DCT0 errors */
+                               pDCTstat->ErrCode = 0;
+                               DCTInit_D(pMCTstat, pDCTstat, 1);
++                              DCTFinalInit_D(pMCTstat, pDCTstat, 1);
+                               if (pDCTstat->ErrCode == 2)             /* DCT1 
is not Running */
+                                       pDCTstat->ErrCode = err_code;   /* 
Using DCT0 Error code to update pDCTstat.ErrCode */
+                       } else {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 8c9da47..7bc392b 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -338,7 +338,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+       u8 Node_ID;                     /* Node ID of current controller */
+       uint8_t Internal_Node_ID;       /* Internal Node ID of the current 
controller */
+       uint8_t Dual_Node_Package;      /* 1=Dual node package (G34) */
+-      uint8_t stopDCT;                /* Set if the DCT will be stopped */
++      uint8_t stopDCT[2];             /* Set if the DCT will be stopped */
+       u8 ErrCode;                     /* Current error condition of Node
+               0= no error
+               1= Variance Error, DCT is running but not in an optimal 
configuration.
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
 
b/resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
deleted file mode 100644
index 4f7af96..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From ddbdb1b748edc2f8a8c453d93a36f28e7d26f2e5 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 27 Jun 2015 17:52:45 -0500
-Subject: [PATCH 080/139] northbridge/amd/amdmct/mct_ddr3: Fix Family 10h boot
- failure
-
-Change-Id: I5dcb333d3a5a49318fe7bddd4c386642205c343e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  | 28 +++++++++++++++++++++-------
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c |  8 +++++++-
- 2 files changed, 28 insertions(+), 8 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index aea17a1..1758bd6 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1628,6 +1628,11 @@ restartinit:
-               HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory 
into system address space.*/
-               mctHookAfterHTMap();
- 
-+              if (!is_fam15h()) {
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
CPUMemTyping_D\n");
-+                      CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram 
into WB/UC CPU cacheability */
-+              }
-+
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctHookAfterCPU\n");
-               mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
- 
-@@ -1651,6 +1656,11 @@ restartinit:
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
-               DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get 
Receiver Enable and DQS signal timing*/
- 
-+              if (!is_fam15h()) {
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
UMAMemTyping_D\n");
-+                      UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for 
UMA sizing */
-+              }
-+
-               if (!allow_config_restore) {
-                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
-                       mct_OtherTiming(pMCTstat, pDCTstatA);
-@@ -1671,11 +1681,13 @@ restartinit:
-                       MCTMemClr_D(pMCTstat,pDCTstatA);
-               }
- 
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
--              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
-+              if (is_fam15h()) {
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
CPUMemTyping_D\n");
-+                      CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram 
into WB/UC CPU cacheability */
- 
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
--              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
UMAMemTyping_D\n");
-+                      UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for 
UMA sizing */
-+              }
- 
-               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-@@ -6343,11 +6355,13 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
-               DramMRS |= 1 << 1;
- 
-       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
--      dword |= DramMRS;
--      if (is_fam15h())
-+      if (is_fam15h()) {
-+              dword |= DramMRS;
-               dword &= ~0x00800003;
--      else
-+      } else {
-               dword &= ~0x00fc2f8f;
-+              dword |= DramMRS;
-+      }
-       Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword);
- }
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 011a94f..57641a1 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -908,9 +908,15 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc 
*pMCTstat,
-                        * Flush the receiver FIFO
-                        * Write one full cache line of non-0x55/0xaa data to 
one of the test addresses, then read it back to flush the FIFO
-                        */
--
-+                      /* FIXME
-+                       * This does not seem to be needed, and has a tendency 
to lock up the
-+                       * boot process while attempting to write the test 
pattern.
-+                       */
-+#if 0
-+                      SetUpperFSbase(TestAddr0);
-                       WriteLNTestPattern(TestAddr0 << 8, (uint8_t 
*)TestPattern2_D, 1);
-                       mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0);
-+#endif
-               }
-               MaxDelay_CH[Channel] = CTLRMaxDelay;
-       }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
 
b/resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
new file mode 100644
index 0000000..da17100
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch
@@ -0,0 +1,58 @@
+From e4cb65c6451563032f027e526250ac5e4bd614bb Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 27 Jun 2015 17:52:18 -0500
+Subject: [PATCH 080/143] northbridge/amd/amdmct/mct_ddr3: Properly indicate
+ clobbered registers
+
+Change-Id: Icb2754143762bd64ee1df5674fa071de1c595eaf
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h |   11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
+index f6aa755..cc8d971 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
+@@ -123,6 +123,9 @@ static void proc_CLFLUSH(u32 addr_hi)
+ 
+ static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 line_num)
+ {
++      uint32_t step = 16;
++      uint32_t count = line_num * 4;
++
+       __asm__ volatile (
+               /*prevent speculative execution of following instructions*/
+               /* FIXME: needed ? */
+@@ -135,7 +138,7 @@ static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 
line_num)
+               "loop 1b\n\t"
+               "mfence\n\t"
+ 
+-               :: "a" (addr_lo), "d" (16), "c" (line_num * 4), "b"(buf_a)
++               : "+a" (addr_lo), "+d" (step), "+c" (count), "+b" (buf_a) : :
+       );
+ 
+ }
+@@ -255,6 +258,10 @@ static void ReadMaxRdLat1CLTestPattern_D(u32 addr)
+ 
+ static void WriteMaxRdLat1CLTestPattern_D(u32 buf, u32 addr)
+ {
++      uint32_t addr_phys = addr << 8;
++      uint32_t step = 16;
++      uint32_t count = 3 * 4;
++
+       SetUpperFSbase(addr);
+ 
+       __asm__ volatile (
+@@ -267,7 +274,7 @@ static void WriteMaxRdLat1CLTestPattern_D(u32 buf, u32 
addr)
+               "loop 1b\n\t"
+               "mfence\n\t"
+ 
+-               :: "a" (addr<<8), "d" (16), "c" (3 * 4), "b"(buf)
++               : "+a" (addr_phys), "+d" (step), "+c" (count), "+b" (buf) : :
+       );
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0081-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
 
b/resources/libreboot/patch/kgpe-d16/0081-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
new file mode 100644
index 0000000..5d2b74f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0081-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch
@@ -0,0 +1,100 @@
+From 5045c1b894492d4e818c41861d2c21e4eef242b4 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 27 Jun 2015 17:52:45 -0500
+Subject: [PATCH 081/143] northbridge/amd/amdmct/mct_ddr3: Fix Family 10h boot
+ failure
+
+Change-Id: I5dcb333d3a5a49318fe7bddd4c386642205c343e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c  |   28 +++++++++++++++++++-------
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c |    8 +++++++-
+ 2 files changed, 28 insertions(+), 8 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index f3d5cb8..cfdfd43 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1628,6 +1628,11 @@ restartinit:
+               HTMemMapInit_D(pMCTstat, pDCTstatA);    /* Map local memory 
into system address space.*/
+               mctHookAfterHTMap();
+ 
++              if (!is_fam15h()) {
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
CPUMemTyping_D\n");
++                      CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram 
into WB/UC CPU cacheability */
++              }
++
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctHookAfterCPU\n");
+               mctHookAfterCPU();                      /* Setup external 
northbridge(s) */
+ 
+@@ -1651,6 +1656,11 @@ restartinit:
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
+               DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get 
Receiver Enable and DQS signal timing*/
+ 
++              if (!is_fam15h()) {
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
UMAMemTyping_D\n");
++                      UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for 
UMA sizing */
++              }
++
+               if (!allow_config_restore) {
+                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+                       mct_OtherTiming(pMCTstat, pDCTstatA);
+@@ -1671,11 +1681,13 @@ restartinit:
+                       MCTMemClr_D(pMCTstat,pDCTstatA);
+               }
+ 
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n");
+-              CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram into WB/UC 
CPU cacheability */
++              if (is_fam15h()) {
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
CPUMemTyping_D\n");
++                      CPUMemTyping_D(pMCTstat, pDCTstatA);    /* Map dram 
into WB/UC CPU cacheability */
+ 
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
+-              UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for UMA 
sizing */
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
UMAMemTyping_D\n");
++                      UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for 
UMA sizing */
++              }
+ 
+               printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+@@ -6345,11 +6357,13 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+               DramMRS |= 1 << 1;
+ 
+       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
+-      dword |= DramMRS;
+-      if (is_fam15h())
++      if (is_fam15h()) {
++              dword |= DramMRS;
+               dword &= ~0x00800003;
+-      else
++      } else {
+               dword &= ~0x00fc2f8f;
++              dword |= DramMRS;
++      }
+       Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword);
+ }
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 011a94f..57641a1 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -908,9 +908,15 @@ static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc 
*pMCTstat,
+                        * Flush the receiver FIFO
+                        * Write one full cache line of non-0x55/0xaa data to 
one of the test addresses, then read it back to flush the FIFO
+                        */
+-
++                      /* FIXME
++                       * This does not seem to be needed, and has a tendency 
to lock up the
++                       * boot process while attempting to write the test 
pattern.
++                       */
++#if 0
++                      SetUpperFSbase(TestAddr0);
+                       WriteLNTestPattern(TestAddr0 << 8, (uint8_t 
*)TestPattern2_D, 1);
+                       mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0);
++#endif
+               }
+               MaxDelay_CH[Channel] = CTLRMaxDelay;
+       }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0081-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
 
b/resources/libreboot/patch/kgpe-d16/0081-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
deleted file mode 100644
index 32a1e8a..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0081-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From 789bac438e1ab4c10ec6bbeb9f62a78d0abcd156 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 3 Jul 2015 17:16:22 -0500
-Subject: [PATCH 081/139] src/southbridge/amd/sr5650: Always configure lane
- director on startup
-
-On the ASUS KGPE-D16 it was noted that the pin straps did not properly
-configure the lane director hardware, causing link training failure
-on NIC B.  Forcing coreboot to always reconfigure the lane director
-on startup resolves this problem.
-
-Change-Id: I5b78cef84960e0f42cc3e0406a7031d12d21f3ad
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sr5650/pcie.c | 13 +++----------
- 1 file changed, 3 insertions(+), 10 deletions(-)
-
-diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
-index 79f2a5f..09ce217 100644
---- a/src/southbridge/amd/sr5650/pcie.c
-+++ b/src/southbridge/amd/sr5650/pcie.c
-@@ -862,8 +862,6 @@ void sr56x0_lock_hwinitreg(void)
- void config_gpp_core(device_t nb_dev, device_t sb_dev)
- {
-       u32 reg;
--      struct southbridge_amd_sr5650_config *cfg =
--              (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
- 
-       reg = nbmisc_read_index(nb_dev, 0x20);
-       if (AtiPcieCfg.Config & PCIE_ENABLE_STATIC_DEV_REMAP)
-@@ -879,14 +877,9 @@ void config_gpp_core(device_t nb_dev, device_t sb_dev)
-       reg &= ~((1 << 31) | (1 << 15) | (1 << 13));    //De-asserts
-       nbmisc_write_index(nb_dev, 0x8, reg);
- 
--      reg = nbmisc_read_index(nb_dev, 0x67); /* get STRAP_BIF_LINK_CONFIG at 
bit 0-4 */
--      if (cfg->gpp3a_configuration != (reg & 0x1F))
--              switching_gpp3a_configurations(nb_dev, sb_dev);
--      reg = nbmisc_read_index(nb_dev, 0x8);  /* get MULTIPORT_CONFIG_GPP1 
MULTIPORT_CONFIG_CONFIG_GPP2 at bit 8,9 */
--      if ((cfg->gpp1_configuration << 8) != (reg & (1 << 8)))
--              switching_gpp1_configurations(nb_dev, sb_dev);
--      if ((cfg->gpp2_configuration << 9) != (reg & (1 << 9)))
--              switching_gpp2_configurations(nb_dev, sb_dev);
-+      switching_gpp3a_configurations(nb_dev, sb_dev);
-+      switching_gpp1_configurations(nb_dev, sb_dev);
-+      switching_gpp2_configurations(nb_dev, sb_dev);
-       ValidatePortEn(nb_dev);
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0082-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
 
b/resources/libreboot/patch/kgpe-d16/0082-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
deleted file mode 100644
index 72f6948..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0082-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 170af60b6ef005f40458f7d55d370dbc083a9a8b Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 24 Jul 2015 17:34:29 -0500
-Subject: [PATCH 082/139] cpu/amd/family_10h-family_15h: Fix BSP stack
- corruption on 32-core Fam10 systems
-
-Change-Id: I72ae8f7abeb9a83b57505469922818f9ec5bdf3f
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/Kconfig | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/Kconfig 
b/src/cpu/amd/family_10h-family_15h/Kconfig
-index 81b1d1e..b95943f 100644
---- a/src/cpu/amd/family_10h-family_15h/Kconfig
-+++ b/src/cpu/amd/family_10h-family_15h/Kconfig
-@@ -37,7 +37,7 @@ config DCACHE_BSP_STACK_SIZE
- 
- config DCACHE_BSP_STACK_SLUSH
-       hex
--      default 0x1000
-+      default 0x4000
- 
- config DCACHE_AP_STACK_SIZE
-       hex
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0082-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
 
b/resources/libreboot/patch/kgpe-d16/0082-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
new file mode 100644
index 0000000..8d4fc4a
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0082-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch
@@ -0,0 +1,51 @@
+From 841de11861037d80ef651107d2be0f7fb31c8cf1 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 3 Jul 2015 17:16:22 -0500
+Subject: [PATCH 082/143] src/southbridge/amd/sr5650: Always configure lane
+ director on startup
+
+On the ASUS KGPE-D16 it was noted that the pin straps did not properly
+configure the lane director hardware, causing link training failure
+on NIC B.  Forcing coreboot to always reconfigure the lane director
+on startup resolves this problem.
+
+Change-Id: I5b78cef84960e0f42cc3e0406a7031d12d21f3ad
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sr5650/pcie.c |   13 +++----------
+ 1 file changed, 3 insertions(+), 10 deletions(-)
+
+diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
+index 79f2a5f..09ce217 100644
+--- a/src/southbridge/amd/sr5650/pcie.c
++++ b/src/southbridge/amd/sr5650/pcie.c
+@@ -862,8 +862,6 @@ void sr56x0_lock_hwinitreg(void)
+ void config_gpp_core(device_t nb_dev, device_t sb_dev)
+ {
+       u32 reg;
+-      struct southbridge_amd_sr5650_config *cfg =
+-              (struct southbridge_amd_sr5650_config *)nb_dev->chip_info;
+ 
+       reg = nbmisc_read_index(nb_dev, 0x20);
+       if (AtiPcieCfg.Config & PCIE_ENABLE_STATIC_DEV_REMAP)
+@@ -879,14 +877,9 @@ void config_gpp_core(device_t nb_dev, device_t sb_dev)
+       reg &= ~((1 << 31) | (1 << 15) | (1 << 13));    //De-asserts
+       nbmisc_write_index(nb_dev, 0x8, reg);
+ 
+-      reg = nbmisc_read_index(nb_dev, 0x67); /* get STRAP_BIF_LINK_CONFIG at 
bit 0-4 */
+-      if (cfg->gpp3a_configuration != (reg & 0x1F))
+-              switching_gpp3a_configurations(nb_dev, sb_dev);
+-      reg = nbmisc_read_index(nb_dev, 0x8);  /* get MULTIPORT_CONFIG_GPP1 
MULTIPORT_CONFIG_CONFIG_GPP2 at bit 8,9 */
+-      if ((cfg->gpp1_configuration << 8) != (reg & (1 << 8)))
+-              switching_gpp1_configurations(nb_dev, sb_dev);
+-      if ((cfg->gpp2_configuration << 9) != (reg & (1 << 9)))
+-              switching_gpp2_configurations(nb_dev, sb_dev);
++      switching_gpp3a_configurations(nb_dev, sb_dev);
++      switching_gpp1_configurations(nb_dev, sb_dev);
++      switching_gpp2_configurations(nb_dev, sb_dev);
+       ValidatePortEn(nb_dev);
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0083-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
 
b/resources/libreboot/patch/kgpe-d16/0083-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
new file mode 100644
index 0000000..284750c
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0083-cpu-amd-family_10h-family_15h-Fix-BSP-stack-corrupti.patch
@@ -0,0 +1,40 @@
+From dbc09e431b4023385d3733a1b157053ff6e8c9f0 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 24 Jul 2015 17:34:29 -0500
+Subject: [PATCH 083/143] cpu/amd/family_10h-family_15h: Fix BSP stack
+ corruption on 32-core Fam10 systems
+
+Change-Id: I72ae8f7abeb9a83b57505469922818f9ec5bdf3f
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/Kconfig |    7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/Kconfig 
b/src/cpu/amd/family_10h-family_15h/Kconfig
+index 81b1d1e..bfb6751 100644
+--- a/src/cpu/amd/family_10h-family_15h/Kconfig
++++ b/src/cpu/amd/family_10h-family_15h/Kconfig
+@@ -15,6 +15,12 @@ config CPU_AMD_MODEL_10XXX
+ 
+ if CPU_AMD_MODEL_10XXX
+ 
++config USE_LARGE_DCACHE
++      bool
++      default y if CPU_AMD_SOCKET_G34_NON_AGESA
++      default y if CPU_AMD_SOCKET_C32_NON_AGESA
++      default n
++
+ config NUM_IPI_STARTS
+       int
+       default 1
+@@ -37,6 +43,7 @@ config DCACHE_BSP_STACK_SIZE
+ 
+ config DCACHE_BSP_STACK_SLUSH
+       hex
++      default 0x4000 if USE_LARGE_DCACHE
+       default 0x1000
+ 
+ config DCACHE_AP_STACK_SIZE
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0083-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
 
b/resources/libreboot/patch/kgpe-d16/0083-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
deleted file mode 100644
index 6bf6885..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0083-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
+++ /dev/null
@@ -1,330 +0,0 @@
-From 34c8a0f868d298f787713a2dd3ba6852c794ae86 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 25 Jul 2015 01:23:17 -0500
-Subject: [PATCH 083/139] northbridge/amd/amdmct/mct_ddr3: Fix RDIMM errors due
- to undefined number of slots
-
-Change-Id: I488511d6262ffa8207c442d133314aed0f75acfb
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct/mct_d.h         |  2 ++
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 24 ++++--------------------
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |  2 ++
- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c  |  6 +-----
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   | 12 ++----------
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |  6 +-----
- src/northbridge/amd/amdmct/mct_ddr3/mctwl.c    |  2 --
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  | 20 ++++++--------------
- src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c | 11 ++++++-----
- src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h   |  4 ----
- src/northbridge/amd/amdmct/wrappers/mcti_d.c   |  7 +++++++
- 11 files changed, 31 insertions(+), 65 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h 
b/src/northbridge/amd/amdmct/mct/mct_d.h
-index 7569300..296f3f0 100644
---- a/src/northbridge/amd/amdmct/mct/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct/mct_d.h
-@@ -691,6 +691,8 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-                                       xx0b = disable
-                                       yy1b = enable with DctSelIntLvAddr set 
to yyb */
- 
-+#define NV_MAX_DIMMS_PER_CH   64      /* Maximum number of DIMMs per channel 
*/
-+
- 
/*===============================================================================
-       CBMEM storage
- 
===============================================================================*/
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 1758bd6..b616c2d 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -803,11 +803,7 @@ static uint32_t 
fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *p
- 
- static uint32_t fam15h_output_driver_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
- {
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       uint8_t package_type;
-       uint32_t calibration_code = 0;
-@@ -983,11 +979,7 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
- 
- static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
- {
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       uint8_t package_type;
-       uint32_t calibration_code = 0;
-@@ -1165,11 +1157,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
- 
- static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t 
dct)
- {
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       uint8_t package_type;
-       uint32_t slow_access = 0;
-@@ -5868,11 +5856,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
- 
-       printk(BIOS_DEBUG, "%s: Start\n", __func__);
- 
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       if (is_fam15h()) {
-               /* Obtain number of DIMMs on channel */
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 7bc392b..6b5d8c1 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -957,6 +957,8 @@ struct amd_s3_persistent_data {
-                                       xx0b = disable
-                                       yy1b = enable with DctSelIntLvAddr set 
to yyb */
- 
-+#define NV_MAX_DIMMS_PER_CH   64      /* Maximum number of DIMMs per channel 
*/
-+
- 
/*===============================================================================
-         CBMEM storage
- 
===============================================================================*/
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-index 32b447f..738304e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-@@ -23,11 +23,7 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
- {
-       u32 val;
- 
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
-               uint8_t cs_mux_45;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index dfbd2d9..6a2c2a7 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -51,11 +51,7 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
-       else
-               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
- 
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       if (is_fam15h()) {
-               if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-@@ -184,11 +180,7 @@ static uint8_t fam15_rttnom(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t
-       else
-               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
- 
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       if (is_fam15h()) {
-               if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 57641a1..9313673 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -105,11 +105,7 @@ static uint16_t 
fam15_receiver_enable_training_seed(struct DCTStatStruc *pDCTsta
-       uint32_t dword;
-       uint16_t seed = 0;
- 
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       uint8_t channel = dct;
-       if (package_type == PT_GR) {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-index 0ff4484..6b63ba0 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-@@ -31,8 +31,6 @@ void PrepareC_MCT(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat)
- {
-       pDCTstat->C_MCTPtr->AgesaDelay = AgesaDelay;
--      pDCTstat->C_MCTPtr->PlatMaxTotalDimms = mctGet_NVbits(NV_MAX_DIMMS);
--      pDCTstat->C_MCTPtr->PlatMaxDimmsDct = 
pDCTstat->C_MCTPtr->PlatMaxTotalDimms >> 1;
- }
- 
- void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index bd37ba7..47ad152 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -419,11 +419,7 @@ static uint16_t 
unbuffered_dimm_nominal_termination_emrs(uint8_t number_of_dimms
- {
-       uint16_t term;
- 
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       if (number_of_dimms == 1) {
-               if (MaxDimmsInstallable < 3) {
-@@ -452,11 +448,7 @@ static uint16_t 
unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms
- {
-       uint16_t term;
- 
--      /* FIXME
--       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
--       * For now assume a maximum of 2 DIMMs per channel can be installed
--       */
--      uint8_t MaxDimmsInstallable = 2;
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       if (number_of_dimms == 1) {
-               if (MaxDimmsInstallable < 3) {
-@@ -574,7 +566,7 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat,
-                                       if (number_of_dimms > 1) {
-                                               if (rank == 0) {
-                                                       /* Get Rtt_WR for the 
current DIMM and rank */
--                                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm]);
-+                                                      uint16_t dynamic_term = 
unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm]);
- 
-                                                       /* Convert dynamic 
termination code to corresponding nominal termination code */
-                                                       if (dynamic_term == 
0x200)
-@@ -584,13 +576,13 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat,
-                                                       else
-                                                               tempW1 = 0x0;
-                                               } else {
--                                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
-                                               }
-                                       } else {
--                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                              tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
-                                       }
-                               } else {
--                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
-+                                      tempW1 = 
unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, 
MemClkFreq, pDCTData->DimmRanks[dimm], rank);
-                               }
-                       }
-               }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c 
b/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
-index c92143c..bb4c3c0 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -57,7 +58,7 @@ static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, 
sDCTStruct *pDCTData, u8 d
-       u32 tempW1;
-       tempW1 = 0;
-       if (wl) {
--              switch (pMCTData->PlatMaxDimmsDct) {
-+              switch (mctGet_NVbits(NV_MAX_DIMMS_PER_CH)) {
-               case 2:
-                       /* 2 dimms per channel */
-                       if (pDCTData->MaxDimmsInstalled == 1) {
-@@ -111,7 +112,7 @@ static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, 
sDCTStruct *pDCTData, u8 d
-                       ASSERT (FALSE);
-               }
-       } else {
--              switch (pMCTData->PlatMaxDimmsDct) {
-+              switch (mctGet_NVbits(NV_MAX_DIMMS_PER_CH)) {
-               case 2:
-                       /* 2 dimms per channel */
-                       if ((pDCTData->DimmRanks[dimm] == 4) && (rank == 1)) {
-@@ -167,7 +168,7 @@ static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, 
sDCTStruct *pDCTData, u8 d
-  */
- static u32 RttNomNonTargetRegDimm (sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
- {
--      if ((wl) && (pMCTData->PlatMaxDimmsDct == 2) && 
(pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
-+      if ((wl) && (mctGet_NVbits(NV_MAX_DIMMS_PER_CH) == 2) && 
(pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
-               return 0x00;    /* for non-target dimm during WL, the second 
rank of a DR dimm need to have Rtt_Nom = OFF */
-       } else {
-               return RttNomTargetRegDimm (pMCTData, pDCTData, dimm, FALSE, 
MemClkFreq, rank); /* otherwise, the same as target dimm in normal mode. */
-@@ -197,7 +198,7 @@ static u32 RttWrRegDimm (sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BO
-       if (wl) {
-               tempW1 = 0x00;  /* Rtt_WR = OFF */
-       } else {
--              switch (pMCTData->PlatMaxDimmsDct) {
-+              switch (mctGet_NVbits(NV_MAX_DIMMS_PER_CH)) {
-               case 2:
-                       if (pDCTData->MaxDimmsInstalled == 1) {
-                               if (pDCTData->DimmRanks[dimm] != 4) {
-@@ -262,7 +263,7 @@ static u8 WrLvOdtRegDimm (sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm)
-               }
-               i += 2;
-       }
--      if (pMCTData->PlatMaxDimmsDct == 2) {
-+      if (mctGet_NVbits(NV_MAX_DIMMS_PER_CH) == 2) {
-               if ((pDCTData->DimmRanks[dimm] == 4) && 
(pDCTData->MaxDimmsInstalled != 1)) {
-                       if (dimm >= 2) {
-                               WrLvOdt1 = (u8)bitTestReset (WrLvOdt1, (dimm - 
2));
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-index 162340e..12e7c4a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-@@ -109,10 +109,6 @@
- 
- typedef struct _sMCTStruct
- {
--      u8 PlatMaxTotalDimms;                   /* IBV defined total number of 
DIMMs */
--                                              /* on a particular node */
--      u8 PlatMaxDimmsDct;                     /* IBV defined maximum number 
of */
--                                              /* DIMMs on a DCT */
-       void (*AgesaDelay)(u32 delayval);       /* IBV defined Delay Function */
- } sMCTStruct;
- 
-diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-index ce2329d..28d298f 100644
---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
-@@ -74,6 +74,13 @@ static u16 mctGet_NVbits(u8 index)
-               val = MAX_DIMMS_SUPPORTED;
-               //val = 8;
-               break;
-+      case NV_MAX_DIMMS_PER_CH:
-+              /* FIXME
-+               * Mainboards need to be able to specify the maximum number of 
DIMMs installable per channel
-+               * For now assume a maximum of 2 DIMMs per channel can be 
installed
-+               */
-+              val = 2;
-+              break;
-       case NV_MAX_MEMCLK:
-               /* Maximum platform supported memclk */
-               val =  MEM_MAX_LOAD_FREQ;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0084-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
 
b/resources/libreboot/patch/kgpe-d16/0084-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
deleted file mode 100644
index 565f248..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0084-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
+++ /dev/null
@@ -1,960 +0,0 @@
-From 02fa90cabc031623e5a5e05888588fb1f22949d2 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 26 Jul 2015 00:55:43 -0500
-Subject: [PATCH 084/139] amd/amdmct/mct_ddr3: Partially fix up registered
- DIMMs on Fam10h
-
-Sufficient support has been added to allow booting with registered
-DIMMs on the KGPE-D16 in certain slots.  ECC support needs additional
-work; the ECC data lanes appear to cause boot failures in some slots.
-
-Change-Id: Ieaf4cbf351908e5a89760be49a6667dc55dbc575
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 196 ++++++++++++++++++++++---
- src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c |  32 ++--
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |  58 +++++---
- src/northbridge/amd/amdmct/mct_ddr3/mctrci.c   | 151 ++++++++++++-------
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |   8 +
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |  26 ++--
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |  72 ++++++---
- 7 files changed, 399 insertions(+), 144 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index b616c2d..8102f2a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -305,6 +305,120 @@ static uint16_t mhz_to_memclk_config(uint16_t freq)
-               return fam10h_mhz_to_memclk_config(freq) + 1;
- }
- 
-+static uint32_t fam10h_address_timing_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
-+{
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-+
-+      uint8_t package_type;
-+      uint32_t calibration_code = 0;
-+
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint16_t MemClkFreq = (Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7) + 1;
-+
-+      /* Obtain number of DIMMs on channel */
-+      uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+
-+      if (package_type == PT_GR) {
-+              /* Socket G34 */
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* RDIMM */
-+                      /* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Tables 60 - 
61 */
-+                      if (MaxDimmsInstallable == 1) {
-+                              if (MemClkFreq == 0x4) {
-+                                      /* DDR3-800 */
-+                                      calibration_code = 0x00000000;
-+                              } else if (MemClkFreq == 0x5) {
-+                                      /* DDR3-1066 */
-+                                      calibration_code = 0x003c3c3c;
-+                              } else if (MemClkFreq == 0x6) {
-+                                      /* DDR3-1333 */
-+                                      calibration_code = 0x003a3a3a;
-+                              }
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-800 */
-+                                              calibration_code = 0x00000000;
-+                                      } else if (MemClkFreq == 0x5) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x003c3c3c;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x003a3a3a;
-+                                      }
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      if (MemClkFreq == 0x4) {
-+                                              /* DDR3-800 */
-+                                              calibration_code = 0x00000000;
-+                                      } else if (MemClkFreq == 0x5) {
-+                                              /* DDR3-1066 */
-+                                              calibration_code = 0x003a3c3a;
-+                                      } else if (MemClkFreq == 0x6) {
-+                                              /* DDR3-1333 */
-+                                              calibration_code = 0x00383a38;
-+                                      }
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-+                      }
-+              } else {
-+                      /* UDIMM */
-+                      /* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Table 56 */
-+                      if (dimm_count == 1) {
-+                              /* 1 DIMM detected */
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
-+
-+                              if (MemClkFreq == 0x4) {
-+                                      /* DDR3-800 */
-+                                      if (rank_count_dimm0 == 1)
-+                                              calibration_code = 0x00000000;
-+                                      else
-+                                              calibration_code = 0x003b0000;
-+                              } else if (MemClkFreq == 0x5) {
-+                                      /* DDR3-1066 */
-+                                      if (rank_count_dimm0 == 1)
-+                                              calibration_code = 0x00000000;
-+                                      else
-+                                              calibration_code = 0x00380000;
-+                              } else if (MemClkFreq == 0x6) {
-+                                      /* DDR3-1333 */
-+                                      if (rank_count_dimm0 == 1)
-+                                              calibration_code = 0x00000000;
-+                                      else
-+                                              calibration_code = 0x00360000;
-+                              }
-+                      } else if (dimm_count == 2) {
-+                              /* 2 DIMMs detected */
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) 
+ dct];
-+                              rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
-+
-+                              if (MemClkFreq == 0x4) {
-+                                      /* DDR3-800 */
-+                                      calibration_code = 0x00390039;
-+                              } else if (MemClkFreq == 0x5) {
-+                                      /* DDR3-1066 */
-+                                      calibration_code = 0x00350037;
-+                              } else if (MemClkFreq == 0x6) {
-+                                      /* DDR3-1333 */
-+                                      calibration_code = 0x00000035;
-+                              }
-+                      }
-+              }
-+      } else {
-+              /* TODO
-+               * Other socket support unimplemented
-+               */
-+      }
-+
-+      return calibration_code;
-+}
-+
- static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t drive_strength)
- {
-       uint8_t lrdimm = 0;
-@@ -999,7 +1113,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
-                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
-                       if (MaxDimmsInstallable == 1) {
-                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
--                                      /* DDR3-667 - DDR3-800*/
-+                                      /* DDR3-667 - DDR3-800 */
-                                       calibration_code = 0x00000000;
-                               } else if (MemClkFreq == 0xa) {
-                                       /* DDR3-1066 */
-@@ -1015,7 +1129,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
-                               if (dimm_count == 1) {
-                                       /* 1 DIMM detected */
-                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
--                                              /* DDR3-667 - DDR3-800*/
-+                                              /* DDR3-667 - DDR3-800 */
-                                               calibration_code = 0x00000000;
-                                       } else if (MemClkFreq == 0xa) {
-                                               /* DDR3-1066 */
-@@ -1030,7 +1144,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
-                               } else if (dimm_count == 2) {
-                                       /* 2 DIMMs detected */
-                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
--                                              /* DDR3-667 - DDR3-800*/
-+                                              /* DDR3-667 - DDR3-800 */
-                                               calibration_code = 0x00000000;
-                                       } else if (MemClkFreq == 0xa) {
-                                               /* DDR3-1066 */
-@@ -1308,6 +1422,26 @@ static void read_spd_bytes(struct MCTStatStruc 
*pMCTstat,
-       }
- }
- 
-+#ifdef DEBUG_DIMM_SPD
-+static void dump_spd_bytes(struct MCTStatStruc *pMCTstat,
-+                      struct DCTStatStruc *pDCTstat, uint8_t dimm)
-+{
-+      uint16_t byte;
-+
-+      printk(BIOS_DEBUG, "SPD dump for DIMM %d\n   ", dimm);
-+      for (byte = 0; byte < 16; byte++) {
-+              printk(BIOS_DEBUG, "%02x ", byte);
-+      }
-+      for (byte = 0; byte < 256; byte++) {
-+              if ((byte & 0xf) == 0x0) {
-+                      printk(BIOS_DEBUG, "\n%02x ", byte >> 4);
-+              }
-+              printk(BIOS_DEBUG, "%02x ", 
pDCTstat->spd_data.spd_bytes[dimm][byte]);
-+      }
-+      printk(BIOS_DEBUG, "\n");
-+}
-+#endif
-+
- #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
- static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat)
-@@ -1508,12 +1642,14 @@ restartinit:
-               pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
- #endif
- 
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
--              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
--                      struct DCTStatStruc *pDCTstat;
--                      pDCTstat = pDCTstatA + Node;
-+              if (is_fam15h()) {
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-+                      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                              struct DCTStatStruc *pDCTstat;
-+                              pDCTstat = pDCTstatA + Node;
- 
--                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
-+                              mct_ForceNBPState0_Dis_Fam15(pMCTstat, 
pDCTstat);
-+                      }
-               }
-       } else {
-               NodesWmem = 0;
-@@ -1675,14 +1811,14 @@ restartinit:
- 
-                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
UMAMemTyping_D\n");
-                       UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for 
UMA sizing */
--              }
- 
--              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
--              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
--                      struct DCTStatStruc *pDCTstat;
--                      pDCTstat = pDCTstatA + Node;
-+                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
-+                      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+                              struct DCTStatStruc *pDCTstat;
-+                              pDCTstat = pDCTstatA + Node;
- 
--                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
-+                              mct_ForceNBPState0_Dis_Fam15(pMCTstat, 
pDCTstat);
-+                      }
-               }
- 
-               if (is_fam15h()) {
-@@ -2717,6 +2853,10 @@ static void DCTFinalInit_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStruc *p
-               dword = 1 << DisDramInterface;
-               Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
- 
-+              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x90);
-+              dword &= ~(1 << ParEn);
-+              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x90, dword);
-+
-               /* To maximize power savings when DisDramInterface=1b,
-                * all of the MemClkDis bits should also be set.
-                */
-@@ -3600,7 +3740,9 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-               dword++;
-       }
- 
--      if (!(Status & (1 << SB_Registered)))
-+      if (Status & (1 << SB_Registered))
-+              DramConfigLo |= 1 << ParEn;             /* Registered DIMMs */
-+      else
-               DramConfigLo |= 1 << UnBuffDimm;        /* Unbuffered DIMMs */
- 
-       if (mctGet_NVbits(NV_ECC_CAP))
-@@ -4089,6 +4231,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                       if (status >= 0) { /* SPD access is ok */
-                               pDCTstat->DIMMPresent |= 1 << i;
-                               read_spd_bytes(pMCTstat, pDCTstat, i);
-+#ifdef DEBUG_DIMM_SPD
-+                              dump_spd_bytes(pMCTstat, pDCTstat, i);
-+#endif
-                               crc_status = crcCheck(pDCTstat, i);
-                               if (!crc_status) {
-                                       /* Try again in case there was a 
transient glitch */
-@@ -4388,6 +4533,10 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
-                               val = 1 << DisDramInterface;
-                               Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
- 
-+                              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
-+                              val &= ~(1 << ParEn);
-+                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
-+
-                               /* To maximize power savings when 
DisDramInterface=1b,
-                                * all of the MemClkDis bits should also be set.
-                                */
-@@ -4540,8 +4689,9 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
-       }
-       for (i=i_start; i<i_end; i++) {
-               index_reg = 0x98;
--              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */
--              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */
-+              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]);      /* Channel A/B Output Driver Compensation 
Control */
-+              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]);     /* Channel A/B Output Driver Compensation 
Control */
-+              printk(BIOS_SPEW, "Programmed DCT %d timing/termination pattern 
%08x %08x\n", dct, pDCTstat->CH_ADDR_TMG[i], pDCTstat->CH_ODC_CTL[i]);
-       }
- 
-       return pDCTstat->ErrCode;
-@@ -4598,11 +4748,19 @@ static u8 mct_SPDCalcWidth(struct MCTStatStruc 
*pMCTstat,
-               val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
-               val |= 1 << DisDramInterface;
-               Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
-+
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
-+              val &= ~(1 << ParEn);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
-       }
-       if (pDCTstat->DIMMValidDCT[1] == 0) {
-               val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
-               val |= 1 << DisDramInterface;
-               Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
-+
-+              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
-+              val &= ~(1 << ParEn);
-+              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
-       }
- 
-       printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
-@@ -6033,6 +6191,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-               dword &= ~(0xf);                                /* 
RdOdtTrnOnDly = read_odt_delay */
-               dword |= (read_odt_delay & 0xf);
-               Set_NB32_DCT(dev, dct, 0x240, dword);
-+
-+              printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x 
%08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
-       } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
-               if (pDCTstat->Speed == 3)
-                       dword = 0x00000800;
-@@ -6168,6 +6328,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, 
odt_pattern_0);
-                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, 
odt_pattern_3);
-                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, 
odt_pattern_2);
-+
-+                      printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x 
%08x %08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
-               }
-       }
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
-index 3df262b..4ae1aec 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
-@@ -21,7 +21,7 @@
- /* AM3/ASB2/C32/G34 DDR3 */
- 
- static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
--                              u32 *AddrTmgCTL, u32 *ODC_CTL,
-+                              u32 *ODC_CTL,
-                               u8 *CMDmode);
- 
- void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
-@@ -34,9 +34,14 @@ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
-       } else {
-               Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
-                                       pDCTstat->MAload[dct],
--                                      &(pDCTstat->CH_ADDR_TMG[dct]), 
&(pDCTstat->CH_ODC_CTL[dct]),
-+                                      &(pDCTstat->CH_ODC_CTL[dct]),
-                                       &pDCTstat->_2Tmode);
- 
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      pDCTstat->_2Tmode = 1;  /* Disable slow access mode */
-+              }
-+              pDCTstat->CH_ADDR_TMG[dct] = 
fam10h_address_timing_compensation_code(pDCTstat, dct);
-+
-               pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;        /* 60ohms */
-       }
- 
-@@ -54,42 +59,25 @@ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
-  *    : ODC_CTL    - Output Driver Compensation Control Register Value
-  *    : CMDmode    - CMD mode
-  */
--static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
--                              u32 *AddrTmgCTL, u32 *ODC_CTL,
-+static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
-+                              u32 *ODC_CTL,
-                               u8 *CMDmode)
- {
--      *AddrTmgCTL = 0;
-       *ODC_CTL = 0;
-       *CMDmode = 1;
- 
--      if(MAAdimms == 1) {
--              if(MAAload >= 16) {
--                      if(Speed == 4)
--                              *AddrTmgCTL = 0x003B0000;
--                      else if (Speed == 5)
--                              *AddrTmgCTL = 0x00380000;
--                      else if (Speed == 6)
--                              *AddrTmgCTL = 0x00360000;
--                      else
--                              *AddrTmgCTL = 0x00340000;
--              } else {
--                      *AddrTmgCTL = 0x00000000;
--              }
-+      if (MAAdimms == 1) {
-               *ODC_CTL = 0x00113222;
-               *CMDmode = 1;
-       } else /* if(MAAdimms == 0) */ {
-               if(Speed == 4) {
-                       *CMDmode = 1;
--                      *AddrTmgCTL = 0x00390039;
-               } else if(Speed == 5) {
-                       *CMDmode = 1;
--                      *AddrTmgCTL = 0x00350037;
-               } else if(Speed == 6) {
-                       *CMDmode = 2;
--                      *AddrTmgCTL = 0x00000035;
-               } else {
-                       *CMDmode = 2;
--                      *AddrTmgCTL = 0x00000033;
-               }
-               *ODC_CTL = 0x00223323;
-       }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index b0ad54b..36e9858 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -241,37 +241,53 @@ static void CalcEccDQSPos_D(struct MCTStatStruc 
*pMCTstat,
-                               struct DCTStatStruc *pDCTstat,
-                               u16 like, u8 scale, u8 ChipSel)
- {
--      u8 DQSDelay0, DQSDelay1;
--      u16 DQSDelay;
-+      uint8_t DQSDelay0, DQSDelay1;
-+      int16_t delay_differential;
-+      uint16_t DQSDelay;
- 
-       if (pDCTstat->Status & (1 << SB_Registered)) {
--              return;
--      }
-+              pDCTstat->ByteLane = 0x2;
-+              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
-+              DQSDelay0 = pDCTstat->DQSDelay;
- 
--      pDCTstat->ByteLane = like & 0xff;
--      GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
--      DQSDelay0 = pDCTstat->DQSDelay;
-+              pDCTstat->ByteLane = 0x3;
-+              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
-+              DQSDelay1 = pDCTstat->DQSDelay;
- 
--      pDCTstat->ByteLane = (like >> 8) & 0xff;
--      GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
--      DQSDelay1 = pDCTstat->DQSDelay;
-+              if (pDCTstat->Direction == DQS_READDIR) {
-+                      DQSDelay = DQSDelay1;
-+              } else {
-+                      delay_differential = (int16_t)DQSDelay1 - 
(int16_t)DQSDelay0;
-+                      delay_differential += (int16_t)DQSDelay1;
- 
--      if (DQSDelay0>DQSDelay1) {
--              DQSDelay = DQSDelay0 - DQSDelay1;
-+                      DQSDelay = delay_differential;
-+              }
-       } else {
--              DQSDelay = DQSDelay1 - DQSDelay0;
--      }
-+              pDCTstat->ByteLane = like & 0xff;
-+              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
-+              DQSDelay0 = pDCTstat->DQSDelay;
- 
--      DQSDelay = DQSDelay * (~scale);
-+              pDCTstat->ByteLane = (like >> 8) & 0xff;
-+              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
-+              DQSDelay1 = pDCTstat->DQSDelay;
- 
--      DQSDelay += 0x80;       /* round it */
-+              if (DQSDelay0>DQSDelay1) {
-+                      DQSDelay = DQSDelay0 - DQSDelay1;
-+              } else {
-+                      DQSDelay = DQSDelay1 - DQSDelay0;
-+              }
- 
--      DQSDelay >>= 8;         /* 256 */
-+              DQSDelay = DQSDelay * (~scale);
- 
--      if (DQSDelay0>DQSDelay1) {
--              DQSDelay = DQSDelay1 - DQSDelay;
--      } else {
--              DQSDelay += DQSDelay1;
-+              DQSDelay += 0x80;       /* round it */
-+
-+              DQSDelay >>= 8;         /* 256 */
-+
-+              if (DQSDelay0>DQSDelay1) {
-+                      DQSDelay = DQSDelay1 - DQSDelay;
-+              } else {
-+                      DQSDelay += DQSDelay1;
-+              }
-       }
- 
-       pDCTstat->DQSDelay = (u8)DQSDelay;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-index 5ea7fa6..9617f84 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-@@ -18,12 +18,39 @@
-  * Foundation, Inc.
-  */
- 
-+static uint16_t memclk_to_freq(uint16_t memclk) {
-+      uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
-+      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
-+
-+      uint16_t mem_freq = 0;
-+
-+      if (is_fam15h()) {
-+              if (memclk < 0x17) {
-+                      mem_freq = fam15h_freq_tab[memclk];
-+              }
-+      } else {
-+              if ((memclk > 0x0) && (memclk < 0x8)) {
-+                      mem_freq = fam10h_freq_tab[memclk - 1];
-+              }
-+      }
-+
-+      return mem_freq;
-+}
-+
-+static uint32_t rc_word_value_to_ctl_bits(uint32_t value) {
-+      return ((value >> 2) & 3) << 16 | ((value & 3) << 3);
-+}
-+
- static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-                       struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 
CtrlWordNum)
- {
--      u8 Dimms, DimmNum, MaxDimm, Speed;
-+      u8 Dimms, DimmNum;
-       u32 val;
-       u32 dct = 0;
-+      uint8_t ddr_voltage_index;
-+      uint16_t mem_freq;
-+      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-       DimmNum = (MrsChipSel >> 20) & 0xFE;
- 
-@@ -32,54 +59,64 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-       /* DimmNum ++; */
-       /* cl +=8; */
- 
--      MaxDimm = mctGet_NVbits(NV_MAX_DIMMS);
--      Speed = pDCTstat->DIMMAutoSpeed;
-+      mem_freq = memclk_to_freq(pDCTstat->DIMMAutoSpeed);
- 
-       if (pDCTstat->CSPresent_DCT[0] > 0) {
-               dct = 0;
--      } else if (pDCTstat->CSPresent_DCT[1] > 0 ){
-+      } else if (pDCTstat->CSPresent_DCT[1] > 0 ) {
-               dct = 1;
--              DimmNum ++;
-+              DimmNum++;
-       }
-       Dimms = pDCTstat->MAdimms[dct];
- 
-+      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
-+
-       val = 0;
-       if (CtrlWordNum == 0)
--              val |= 1 << 1;
-+              val = 0x2;
-       else if (CtrlWordNum == 1) {
-               if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 
<< DimmNum)))
--                      val |= 0xC; /* if single rank, set DBA1 and DBA0 */
-+                      val = 0xC; /* if single rank, set DBA1 and DBA0 */
-       } else if (CtrlWordNum == 2) {
--              if (MaxDimm == 4) {
--                      if (Speed == 4) {
--                              if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) 
&& (Dimms == 1)) || (Dimms == 2))
--                                      if (!(pDCTstat->MirrPresU_NumRegR & (1 
<< DimmNum)))
--                                              val |= 1 << 2;
--                      } else {
--                              if (pDCTstat->MirrPresU_NumRegR & (1 << 
DimmNum))
--                                      val |= 1 << 2;
-+              if (package_type == PT_GR) {
-+                      /* Socket G34 */
-+                      if (MaxDimmsInstallable == 2) {
-+                              if (Dimms > 1)
-+                                      val = 0x4;
-                       }
--              } else {
--                      if (Dimms > 1)
--                              val |= 1 << 2;
-               }
-       } else if (CtrlWordNum == 3) {
--              val |= (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
-+              val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
-       } else if (CtrlWordNum == 4) {
--              val |= (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
-+              val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
-       } else if (CtrlWordNum == 5) {
--              val |= (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
-+              val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
-       } else if (CtrlWordNum == 8) {
--              if (MaxDimm == 4)
--                      if (Speed == 4)
--                              if (pDCTstat->MirrPresU_NumRegR & (1 << 
DimmNum))
--                                      val |= 1 << 2;
-+              if (package_type == PT_GR) {
-+                      /* Socket G34 */
-+                      if (MaxDimmsInstallable == 2) {
-+                              val = 0x0;
-+                      }
-+              }
-       } else if (CtrlWordNum == 9) {
--              val |= 0xD;     /* DBA1, DBA0, DA3 = 0 */
-+              val = 0xD;      /* DBA1, DBA0, DA3 = 0 */
-+      } else if (CtrlWordNum == 10) {
-+              val = 0x0;      /* Lowest operating frequency */
-+      } else if (CtrlWordNum == 11) {
-+              if (ddr_voltage_index & 0x4)
-+                      val = 0x2;      /* 1.25V */
-+              else if (ddr_voltage_index & 0x2)
-+                      val = 0x1;      /* 1.35V */
-+              else
-+                      val = 0x0;      /* 1.5V */
-+      } else if (CtrlWordNum >= 12) {
-+              val = 0x0;      /* Unset */
-       }
--      val &= 0xffffff0f;
-+      val &= 0xf;
-+
-+      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", CtrlWordNum, 
val);
- 
--      val = MrsChipSel | ((val >> 2) & 3) << 16 | ((val & 3) << 3);
-+      val = MrsChipSel | rc_word_value_to_ctl_bits(val);
- 
-       /* transfer Control word number to address [BA2,A2,A1,A0] */
-       if (CtrlWordNum > 7) {
-@@ -129,18 +166,18 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
-                       val &= ~(0xF << 8);
- 
-                       switch (MrsChipSel) {
--                      case 0:
--                      case 1:
--                              val |= 3 << 8;
--                      case 2:
--                      case 3:
--                              val |= (3 << 2) << 8;
--                      case 4:
--                      case 5:
--                              val |= (3 << 4) << 8;
--                      case 6:
--                      case 7:
--                              val |= (3 << 6) << 8;
-+                              case 0:
-+                              case 1:
-+                                      val |= 3 << 8;
-+                              case 2:
-+                              case 3:
-+                                      val |= (3 << 2) << 8;
-+                              case 4:
-+                              case 5:
-+                                      val |= (3 << 4) << 8;
-+                              case 6:
-+                              case 7:
-+                                      val |= (3 << 6) << 8;
-                       }
-                       Set_NB32_DCT(dev, dct, 0xa8, val);
- 
-@@ -164,8 +201,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
-       u32 MrsChipSel;
-       u32 dev = pDCTstat->dev_dct;
-       u32 val;
-+      uint16_t mem_freq;
- 
-       pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
-+      mem_freq = memclk_to_freq(pDCTstat->TargetFreq);
-       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
-                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
-@@ -175,19 +214,31 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
-                       Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 
select */
- 
-                       /* Resend control word 10 */
-+                      uint8_t freq_ctl_val = 0;
-                       mct_Wait(1600);
--                      switch (pDCTstat->TargetFreq) {
--                      case 5:
--                              mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel 
<< 20 | 0x4000A);
--                              break;
--                      case 6:
--                              mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel 
<< 20 | 0x40012);
--                              break;
--                      case 7:
--                              mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel 
<< 20 | 0x4001A);
--                              break;
-+                      switch (mem_freq) {
-+                              case 333:
-+                              case 400:
-+                                      freq_ctl_val = 0x0;
-+                                      break;
-+                              case 533:
-+                                      freq_ctl_val = 0x1;
-+                                      break;
-+                              case 667:
-+                                      freq_ctl_val = 0x2;
-+                                      break;
-+                              case 800:
-+                                      freq_ctl_val = 0x3;
-+                                      break;
-+                              case 933:
-+                                      freq_ctl_val = 0x4;
-+                                      break;
-                       }
- 
-+                      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: 
%02x\n", 10, freq_ctl_val);
-+
-+                      mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 
0x40002 | rc_word_value_to_ctl_bits(freq_ctl_val));
-+
-                       mct_Wait(1600);
- 
-                       /* Resend control word 2 */
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index 6a2c2a7..9ccf77e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -496,6 +496,8 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
-               ret |= ((dword >> 10) & 3) << 9;
-       }
- 
-+      printk(BIOS_SPEW, "Going to send MR2 control word %08x\n", ret);
-+
-       return ret;
- }
- 
-@@ -525,6 +527,8 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
-               ret |= (dword >> 24) & 7;
-       }
- 
-+      printk(BIOS_SPEW, "Going to send MR3 control word %08x\n", ret);
-+
-       return ret;
- }
- 
-@@ -619,6 +623,8 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
-                       ret |= 1 << 12;
-       }
- 
-+      printk(BIOS_SPEW, "Going to send MR1 control word %08x\n", ret);
-+
-       return ret;
- }
- 
-@@ -738,6 +744,8 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
-               ret |= 1 << 8;
-       }
- 
-+      printk(BIOS_SPEW, "Going to send MR0 control word %08x\n", ret);
-+
-       return ret;
- }
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 9313673..981f467 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -1744,6 +1744,7 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
-       u16 EccDQSLike;
-       u8 EccDQSScale;
-       u32 val, val0, val1;
-+      int16_t delay_differential;
- 
-       EccDQSLike = pDCTstat->CH_EccDQSLike[Channel];
-       EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
-@@ -1753,14 +1754,22 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
-                       u16 *p;
-                       p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
- 
--                      /* DQS Delay Value of Data Bytelane
--                       * most like ECC byte lane */
--                      val0 = p[EccDQSLike & 0x07];
--                      /* DQS Delay Value of Data Bytelane
--                       * 2nd most like ECC byte lane */
--                      val1 = p[(EccDQSLike>>8) & 0x07];
-+                      if (pDCTstat->Status & (1 << SB_Registered)) {
-+                              val0 = p[0x2];
-+                              val1 = p[0x3];
-+
-+                              delay_differential = (int16_t)val1 - 
(int16_t)val0;
-+                              delay_differential += (int16_t)val1;
-+
-+                              val = delay_differential;
-+                      } else {
-+                              /* DQS Delay Value of Data Bytelane
-+                               * most like ECC byte lane */
-+                              val0 = p[EccDQSLike & 0x07];
-+                              /* DQS Delay Value of Data Bytelane
-+                               * 2nd most like ECC byte lane */
-+                              val1 = p[(EccDQSLike>>8) & 0x07];
- 
--                      if (!(pDCTstat->Status & (1 << SB_Registered))) {
-                               if(val0 > val1) {
-                                       val = val0 - val1;
-                               } else {
-@@ -1775,9 +1784,6 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
-                               } else {
-                                       val += val0;
-                               }
--                      } else {
--                              val = val1 - val0;
--                              val += val1;
-                       }
- 
-                       pDCTstat->CH_D_BC_RCVRDLY[Channel][ChipSel>>1] = val;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index 47ad152..e5e4031 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -930,7 +930,9 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-               else if ((cs == 4) || (cs == 0))
-                       WrLvOdt1 = (dword & 0xf);
-       } else {
--              if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
-+              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                      WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
-+              } else {
-                       if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
-                               WrLvOdt1 = 0x03;
-                       } else if 
(bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
-@@ -938,14 +940,14 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-                       } else {
-                               WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
-                       }
--              } else {
--                      WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
-               }
-       }
- 
-       set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
- 
-+      printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern 
%08x\n", dct, WrLvOdt1);
-+
- }
- 
- #ifdef UNUSED_CODE
-@@ -980,7 +982,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-       u16 Addl_Data_Offset, Addl_Data_Port;
-       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
--      u16 fam10h_freq_tab[] = {400, 533, 667, 800};
-+      uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
-       uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
- 
-       if (is_fam15h()) {
-@@ -1093,21 +1095,18 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-                               
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-                       }
-               } else {
--                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
--                      {
--                              if(pDCTData->RegMan1Present & 
((1<<(dimm*2+dct))))
--                              {
-+                      if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                              uint8_t AddrCmdPrelaunch = 0;           /* 
TODO: Fetch the correct value from RC2[0] */
-+
-+                              /* The seed values below assume Pass 1 utilizes 
a 400MHz clock frequency (DDR3-800) */
-+                              if (AddrCmdPrelaunch == 0) {
-                                       Seed_Gross = 0x02;
--                                      Seed_Fine = 0x16;
--                              }
--                              else
--                              {
-+                                      Seed_Fine = 0x01;
-+                              } else {
-                                       Seed_Gross = 0x02;
--                                      Seed_Fine = 0x00;
-+                                      Seed_Fine = 0x11;
-                               }
--                      }
--                      else
--                      {
-+                      } else {
-                               if (MemClkFreq == 6) {
-                                       /* DDR-800 */
-                                       Seed_Gross = 0x00;
-@@ -1131,6 +1130,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-                        */
-                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
-                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
-+                      printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", 
ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
-               }
-       } else {
-               /* Pass 2 */
-@@ -1182,21 +1182,30 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
- 
-                               
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-                               
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+
-+                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
-                       }
-               } else {
--                      u32 RegisterDelay, SeedTotal;
-+                      uint32_t RegisterDelay;
-+                      uint32_t SeedTotalPreScaling;
-+                      uint32_t SeedTotal;
-+                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
-                       for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
-                       {
--                              if (pDCTData->Status[DCT_STATUS_REGISTERED])
--                                      RegisterDelay = 0x20; /* TODO: ((RCW2 & 
BIT0) == 0) ? 0x20 : 0x30; */
--                              else
-+                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                      if (AddrCmdPrelaunch == 0)
-+                                              RegisterDelay = 0x20;
-+                                      else
-+                                              RegisterDelay = 0x30;
-+                              } else {
-                                       RegisterDelay = 0;
--                              SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
--                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
-+                              }
-+                              SeedTotalPreScaling = 
((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
-+                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay;
-                               /* SeedTotalPreScaling = (the total delay value 
in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
-                               training) - RegisterDelay. */
--                              SeedTotal = (uint16_t) (RegisterDelay + 
((((uint64_t) SeedTotal - RegisterDelay) *
--                                                                      
fam10h_freq_tab[MemClkFreq-3] * 100) / (fam10h_freq_tab[0] * 100)));
-+                              SeedTotal = (uint16_t) ((((uint64_t) 
SeedTotalPreScaling) *
-+                                                                      
fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 100));
-                               Seed_Gross = SeedTotal / 32;
-                               Seed_Fine = SeedTotal & 0x1f;
-                               if (Seed_Gross == 0)
-@@ -1205,8 +1214,20 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-                                       Seed_Gross = 1;
-                               else
-                                       Seed_Gross = 2;
-+
-+                              /* The BKDG-recommended algorithm causes 
problems with registered DIMMs on some systems
-+                               * due to the long register delays causing 
premature total delay wrap-around.
-+                               * Attempt to work around this...
-+                               */
-+                              SeedTotal = ((Seed_Gross & 0x1f) << 5) | 
(Seed_Fine & 0x1f);
-+                              SeedTotal += RegisterDelay;
-+                              Seed_Gross = SeedTotal / 32;
-+                              Seed_Fine = SeedTotal & 0x1f;
-+
-                               
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
-                               
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+
-+                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
-                       }
-               }
-       }
-@@ -1383,6 +1404,8 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
-       gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
-                               FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
- 
-+      printk(BIOS_SPEW, "\tLane %02x raw readback: %04x\n", ByteLane, ((gross 
& 0x1f) << 5) | (fine & 0x1f));
-+
-       if (!is_fam15h()) {
-               /* Adjust seed gross delay overflow (greater than 3):
-                * - Adjust the trained gross delay to the original seed gross 
delay.
-@@ -1406,4 +1429,5 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
-       }
-       pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
-       pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
-+      printk(BIOS_SPEW, "\tLane %02x final adjusted value: %04x\n", ByteLane, 
((gross & 0x1f) << 5) | (fine & 0x1f));
- }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0084-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
 
b/resources/libreboot/patch/kgpe-d16/0084-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
new file mode 100644
index 0000000..6fd6ad5
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0084-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch
@@ -0,0 +1,304 @@
+From 162cfc9db14b515dd154ff683049bd07b994d346 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 25 Jul 2015 01:23:17 -0500
+Subject: [PATCH 084/143] northbridge/amd/amdmct/mct_ddr3: Fix RDIMM errors
+ due to undefined number of slots
+
+Change-Id: I488511d6262ffa8207c442d133314aed0f75acfb
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct/mct_d.h         |    2 ++
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |   24 ++++--------------------
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |    2 ++
+ src/northbridge/amd/amdmct/mct_ddr3/mctproc.c  |    6 +-----
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |   12 ++----------
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |    6 +-----
+ src/northbridge/amd/amdmct/mct_ddr3/mctwl.c    |    2 --
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |   12 ++----------
+ src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c |   11 ++++++-----
+ src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h   |    4 ----
+ src/northbridge/amd/amdmct/wrappers/mcti_d.c   |    7 +++++++
+ 11 files changed, 27 insertions(+), 61 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h 
b/src/northbridge/amd/amdmct/mct/mct_d.h
+index 7569300..296f3f0 100644
+--- a/src/northbridge/amd/amdmct/mct/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct/mct_d.h
+@@ -691,6 +691,8 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+                                       xx0b = disable
+                                       yy1b = enable with DctSelIntLvAddr set 
to yyb */
+ 
++#define NV_MAX_DIMMS_PER_CH   64      /* Maximum number of DIMMs per channel 
*/
++
+ 
/*===============================================================================
+       CBMEM storage
+ 
===============================================================================*/
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index cfdfd43..9a86c08 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -803,11 +803,7 @@ static uint32_t 
fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *p
+ 
+ static uint32_t fam15h_output_driver_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
+ {
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       uint8_t package_type;
+       uint32_t calibration_code = 0;
+@@ -983,11 +979,7 @@ static uint32_t 
fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCT
+ 
+ static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
+ {
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       uint8_t package_type;
+       uint32_t calibration_code = 0;
+@@ -1165,11 +1157,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+ 
+ static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t 
dct)
+ {
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       uint8_t package_type;
+       uint32_t slow_access = 0;
+@@ -5870,11 +5858,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+ 
+       printk(BIOS_DEBUG, "%s: Start\n", __func__);
+ 
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       if (is_fam15h()) {
+               /* Obtain number of DIMMs on channel */
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 7bc392b..6b5d8c1 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -957,6 +957,8 @@ struct amd_s3_persistent_data {
+                                       xx0b = disable
+                                       yy1b = enable with DctSelIntLvAddr set 
to yyb */
+ 
++#define NV_MAX_DIMMS_PER_CH   64      /* Maximum number of DIMMs per channel 
*/
++
+ 
/*===============================================================================
+         CBMEM storage
+ 
===============================================================================*/
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+index 32b447f..738304e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+@@ -23,11 +23,7 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
+ {
+       u32 val;
+ 
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
+               uint8_t cs_mux_45;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index dfbd2d9..6a2c2a7 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -51,11 +51,7 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
+       else
+               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
+ 
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       if (is_fam15h()) {
+               if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+@@ -184,11 +180,7 @@ static uint8_t fam15_rttnom(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t
+       else
+               frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7;
+ 
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       if (is_fam15h()) {
+               if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 57641a1..9313673 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -105,11 +105,7 @@ static uint16_t 
fam15_receiver_enable_training_seed(struct DCTStatStruc *pDCTsta
+       uint32_t dword;
+       uint16_t seed = 0;
+ 
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       uint8_t channel = dct;
+       if (package_type == PT_GR) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+index 0ff4484..6b63ba0 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+@@ -31,8 +31,6 @@ void PrepareC_MCT(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+ {
+       pDCTstat->C_MCTPtr->AgesaDelay = AgesaDelay;
+-      pDCTstat->C_MCTPtr->PlatMaxTotalDimms = mctGet_NVbits(NV_MAX_DIMMS);
+-      pDCTstat->C_MCTPtr->PlatMaxDimmsDct = 
pDCTstat->C_MCTPtr->PlatMaxTotalDimms >> 1;
+ }
+ 
+ void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 85b8378..47ad152 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -419,11 +419,7 @@ static uint16_t 
unbuffered_dimm_nominal_termination_emrs(uint8_t number_of_dimms
+ {
+       uint16_t term;
+ 
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       if (number_of_dimms == 1) {
+               if (MaxDimmsInstallable < 3) {
+@@ -452,11 +448,7 @@ static uint16_t 
unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms
+ {
+       uint16_t term;
+ 
+-      /* FIXME
+-       * Mainboards need to be able to specify the maximum number of DIMMs 
installable per channel
+-       * For now assume a maximum of 2 DIMMs per channel can be installed
+-       */
+-      uint8_t MaxDimmsInstallable = 2;
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       if (number_of_dimms == 1) {
+               if (MaxDimmsInstallable < 3) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c 
b/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
+index c92143c..bb4c3c0 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -57,7 +58,7 @@ static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, 
sDCTStruct *pDCTData, u8 d
+       u32 tempW1;
+       tempW1 = 0;
+       if (wl) {
+-              switch (pMCTData->PlatMaxDimmsDct) {
++              switch (mctGet_NVbits(NV_MAX_DIMMS_PER_CH)) {
+               case 2:
+                       /* 2 dimms per channel */
+                       if (pDCTData->MaxDimmsInstalled == 1) {
+@@ -111,7 +112,7 @@ static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, 
sDCTStruct *pDCTData, u8 d
+                       ASSERT (FALSE);
+               }
+       } else {
+-              switch (pMCTData->PlatMaxDimmsDct) {
++              switch (mctGet_NVbits(NV_MAX_DIMMS_PER_CH)) {
+               case 2:
+                       /* 2 dimms per channel */
+                       if ((pDCTData->DimmRanks[dimm] == 4) && (rank == 1)) {
+@@ -167,7 +168,7 @@ static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, 
sDCTStruct *pDCTData, u8 d
+  */
+ static u32 RttNomNonTargetRegDimm (sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
+ {
+-      if ((wl) && (pMCTData->PlatMaxDimmsDct == 2) && 
(pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
++      if ((wl) && (mctGet_NVbits(NV_MAX_DIMMS_PER_CH) == 2) && 
(pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
+               return 0x00;    /* for non-target dimm during WL, the second 
rank of a DR dimm need to have Rtt_Nom = OFF */
+       } else {
+               return RttNomTargetRegDimm (pMCTData, pDCTData, dimm, FALSE, 
MemClkFreq, rank); /* otherwise, the same as target dimm in normal mode. */
+@@ -197,7 +198,7 @@ static u32 RttWrRegDimm (sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm, BO
+       if (wl) {
+               tempW1 = 0x00;  /* Rtt_WR = OFF */
+       } else {
+-              switch (pMCTData->PlatMaxDimmsDct) {
++              switch (mctGet_NVbits(NV_MAX_DIMMS_PER_CH)) {
+               case 2:
+                       if (pDCTData->MaxDimmsInstalled == 1) {
+                               if (pDCTData->DimmRanks[dimm] != 4) {
+@@ -262,7 +263,7 @@ static u8 WrLvOdtRegDimm (sMCTStruct *pMCTData, sDCTStruct 
*pDCTData, u8 dimm)
+               }
+               i += 2;
+       }
+-      if (pMCTData->PlatMaxDimmsDct == 2) {
++      if (mctGet_NVbits(NV_MAX_DIMMS_PER_CH) == 2) {
+               if ((pDCTData->DimmRanks[dimm] == 4) && 
(pDCTData->MaxDimmsInstalled != 1)) {
+                       if (dimm >= 2) {
+                               WrLvOdt1 = (u8)bitTestReset (WrLvOdt1, (dimm - 
2));
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
+index 162340e..12e7c4a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
+@@ -109,10 +109,6 @@
+ 
+ typedef struct _sMCTStruct
+ {
+-      u8 PlatMaxTotalDimms;                   /* IBV defined total number of 
DIMMs */
+-                                              /* on a particular node */
+-      u8 PlatMaxDimmsDct;                     /* IBV defined maximum number 
of */
+-                                              /* DIMMs on a DCT */
+       void (*AgesaDelay)(u32 delayval);       /* IBV defined Delay Function */
+ } sMCTStruct;
+ 
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c 
b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+index 116fb92..c8572ef 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
++++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+@@ -74,6 +74,13 @@ static u16 mctGet_NVbits(u8 index)
+               val = MAX_DIMMS_SUPPORTED;
+               //val = 8;
+               break;
++      case NV_MAX_DIMMS_PER_CH:
++              /* FIXME
++               * Mainboards need to be able to specify the maximum number of 
DIMMs installable per channel
++               * For now assume a maximum of 2 DIMMs per channel can be 
installed
++               */
++              val = 2;
++              break;
+       case NV_MAX_MEMCLK:
+               /* Maximum platform supported memclk */
+               val =  MEM_MAX_LOAD_FREQ;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0085-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
 
b/resources/libreboot/patch/kgpe-d16/0085-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
new file mode 100644
index 0000000..719d849
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0085-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch
@@ -0,0 +1,960 @@
+From a65c5d799d59fb722f56aae29f6553def67bbf99 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 26 Jul 2015 00:55:43 -0500
+Subject: [PATCH 085/143] amd/amdmct/mct_ddr3: Partially fix up registered
+ DIMMs on Fam10h
+
+Sufficient support has been added to allow booting with registered
+DIMMs on the KGPE-D16 in certain slots.  ECC support needs additional
+work; the ECC data lanes appear to cause boot failures in some slots.
+
+Change-Id: Ieaf4cbf351908e5a89760be49a6667dc55dbc575
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  196 ++++++++++++++++++++++--
+ src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c |   32 ++--
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   58 ++++---
+ src/northbridge/amd/amdmct/mct_ddr3/mctrci.c   |  151 ++++++++++++------
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |    8 +
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |   26 ++--
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |   72 ++++++---
+ 7 files changed, 399 insertions(+), 144 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 9a86c08..b29ff3c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -305,6 +305,120 @@ static uint16_t mhz_to_memclk_config(uint16_t freq)
+               return fam10h_mhz_to_memclk_config(freq) + 1;
+ }
+ 
++static uint32_t fam10h_address_timing_compensation_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct)
++{
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
++
++      uint8_t package_type;
++      uint32_t calibration_code = 0;
++
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint16_t MemClkFreq = (Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 
0x7) + 1;
++
++      /* Obtain number of DIMMs on channel */
++      uint8_t dimm_count = pDCTstat->MAdimms[dct];
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++
++      if (package_type == PT_GR) {
++              /* Socket G34 */
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* RDIMM */
++                      /* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Tables 60 - 
61 */
++                      if (MaxDimmsInstallable == 1) {
++                              if (MemClkFreq == 0x4) {
++                                      /* DDR3-800 */
++                                      calibration_code = 0x00000000;
++                              } else if (MemClkFreq == 0x5) {
++                                      /* DDR3-1066 */
++                                      calibration_code = 0x003c3c3c;
++                              } else if (MemClkFreq == 0x6) {
++                                      /* DDR3-1333 */
++                                      calibration_code = 0x003a3a3a;
++                              }
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-800 */
++                                              calibration_code = 0x00000000;
++                                      } else if (MemClkFreq == 0x5) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x003c3c3c;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x003a3a3a;
++                                      }
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      if (MemClkFreq == 0x4) {
++                                              /* DDR3-800 */
++                                              calibration_code = 0x00000000;
++                                      } else if (MemClkFreq == 0x5) {
++                                              /* DDR3-1066 */
++                                              calibration_code = 0x003a3c3a;
++                                      } else if (MemClkFreq == 0x6) {
++                                              /* DDR3-1333 */
++                                              calibration_code = 0x00383a38;
++                                      }
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
++                      }
++              } else {
++                      /* UDIMM */
++                      /* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Table 56 */
++                      if (dimm_count == 1) {
++                              /* 1 DIMM detected */
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
++
++                              if (MemClkFreq == 0x4) {
++                                      /* DDR3-800 */
++                                      if (rank_count_dimm0 == 1)
++                                              calibration_code = 0x00000000;
++                                      else
++                                              calibration_code = 0x003b0000;
++                              } else if (MemClkFreq == 0x5) {
++                                      /* DDR3-1066 */
++                                      if (rank_count_dimm0 == 1)
++                                              calibration_code = 0x00000000;
++                                      else
++                                              calibration_code = 0x00380000;
++                              } else if (MemClkFreq == 0x6) {
++                                      /* DDR3-1333 */
++                                      if (rank_count_dimm0 == 1)
++                                              calibration_code = 0x00000000;
++                                      else
++                                              calibration_code = 0x00360000;
++                              }
++                      } else if (dimm_count == 2) {
++                              /* 2 DIMMs detected */
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) 
+ dct];
++                              rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
++
++                              if (MemClkFreq == 0x4) {
++                                      /* DDR3-800 */
++                                      calibration_code = 0x00390039;
++                              } else if (MemClkFreq == 0x5) {
++                                      /* DDR3-1066 */
++                                      calibration_code = 0x00350037;
++                              } else if (MemClkFreq == 0x6) {
++                                      /* DDR3-1333 */
++                                      calibration_code = 0x00000035;
++                              }
++                      }
++              }
++      } else {
++              /* TODO
++               * Other socket support unimplemented
++               */
++      }
++
++      return calibration_code;
++}
++
+ static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc 
*pDCTstat, uint8_t dct, uint8_t drive_strength)
+ {
+       uint8_t lrdimm = 0;
+@@ -999,7 +1113,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+                       /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */
+                       if (MaxDimmsInstallable == 1) {
+                               if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
+-                                      /* DDR3-667 - DDR3-800*/
++                                      /* DDR3-667 - DDR3-800 */
+                                       calibration_code = 0x00000000;
+                               } else if (MemClkFreq == 0xa) {
+                                       /* DDR3-1066 */
+@@ -1015,7 +1129,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+                               if (dimm_count == 1) {
+                                       /* 1 DIMM detected */
+                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
+-                                              /* DDR3-667 - DDR3-800*/
++                                              /* DDR3-667 - DDR3-800 */
+                                               calibration_code = 0x00000000;
+                                       } else if (MemClkFreq == 0xa) {
+                                               /* DDR3-1066 */
+@@ -1030,7 +1144,7 @@ static uint32_t 
fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC
+                               } else if (dimm_count == 2) {
+                                       /* 2 DIMMs detected */
+                                       if ((MemClkFreq == 0x4) || (MemClkFreq 
== 0x6)) {
+-                                              /* DDR3-667 - DDR3-800*/
++                                              /* DDR3-667 - DDR3-800 */
+                                               calibration_code = 0x00000000;
+                                       } else if (MemClkFreq == 0xa) {
+                                               /* DDR3-1066 */
+@@ -1308,6 +1422,26 @@ static void read_spd_bytes(struct MCTStatStruc 
*pMCTstat,
+       }
+ }
+ 
++#ifdef DEBUG_DIMM_SPD
++static void dump_spd_bytes(struct MCTStatStruc *pMCTstat,
++                      struct DCTStatStruc *pDCTstat, uint8_t dimm)
++{
++      uint16_t byte;
++
++      printk(BIOS_DEBUG, "SPD dump for DIMM %d\n   ", dimm);
++      for (byte = 0; byte < 16; byte++) {
++              printk(BIOS_DEBUG, "%02x ", byte);
++      }
++      for (byte = 0; byte < 256; byte++) {
++              if ((byte & 0xf) == 0x0) {
++                      printk(BIOS_DEBUG, "\n%02x ", byte >> 4);
++              }
++              printk(BIOS_DEBUG, "%02x ", 
pDCTstat->spd_data.spd_bytes[dimm][byte]);
++      }
++      printk(BIOS_DEBUG, "\n");
++}
++#endif
++
+ #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+ static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat)
+@@ -1508,12 +1642,14 @@ restartinit:
+               pMCTstat->GStatus |= 1 << GSB_ConfigRestored;
+ #endif
+ 
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+-              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+-                      struct DCTStatStruc *pDCTstat;
+-                      pDCTstat = pDCTstatA + Node;
++              if (is_fam15h()) {
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
++                      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                              struct DCTStatStruc *pDCTstat;
++                              pDCTstat = pDCTstatA + Node;
+ 
+-                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
++                              mct_ForceNBPState0_Dis_Fam15(pMCTstat, 
pDCTstat);
++                      }
+               }
+       } else {
+               NodesWmem = 0;
+@@ -1675,14 +1811,14 @@ restartinit:
+ 
+                       printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
UMAMemTyping_D\n");
+                       UMAMemTyping_D(pMCTstat, pDCTstatA);    /* Fix up for 
UMA sizing */
+-              }
+ 
+-              printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
+-              for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+-                      struct DCTStatStruc *pDCTstat;
+-                      pDCTstat = pDCTstatA + Node;
++                      printk(BIOS_DEBUG, "mctAutoInitMCT_D: 
mct_ForceNBPState0_Dis_Fam15\n");
++                      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++                              struct DCTStatStruc *pDCTstat;
++                              pDCTstat = pDCTstatA + Node;
+ 
+-                      mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
++                              mct_ForceNBPState0_Dis_Fam15(pMCTstat, 
pDCTstat);
++                      }
+               }
+ 
+               if (is_fam15h()) {
+@@ -2719,6 +2855,10 @@ static void DCTFinalInit_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStruc *p
+               dword = 1 << DisDramInterface;
+               Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword);
+ 
++              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x90);
++              dword &= ~(1 << ParEn);
++              Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x90, dword);
++
+               /* To maximize power savings when DisDramInterface=1b,
+                * all of the MemClkDis bits should also be set.
+                */
+@@ -3602,7 +3742,9 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+               dword++;
+       }
+ 
+-      if (!(Status & (1 << SB_Registered)))
++      if (Status & (1 << SB_Registered))
++              DramConfigLo |= 1 << ParEn;             /* Registered DIMMs */
++      else
+               DramConfigLo |= 1 << UnBuffDimm;        /* Unbuffered DIMMs */
+ 
+       if (mctGet_NVbits(NV_ECC_CAP))
+@@ -4091,6 +4233,9 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                       if (status >= 0) { /* SPD access is ok */
+                               pDCTstat->DIMMPresent |= 1 << i;
+                               read_spd_bytes(pMCTstat, pDCTstat, i);
++#ifdef DEBUG_DIMM_SPD
++                              dump_spd_bytes(pMCTstat, pDCTstat, i);
++#endif
+                               crc_status = crcCheck(pDCTstat, i);
+                               if (!crc_status) {
+                                       /* Try again in case there was a 
transient glitch */
+@@ -4390,6 +4535,10 @@ static void mct_initDCT(struct MCTStatStruc *pMCTstat,
+                               val = 1 << DisDramInterface;
+                               Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
+ 
++                              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
++                              val &= ~(1 << ParEn);
++                              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
++
+                               /* To maximize power savings when 
DisDramInterface=1b,
+                                * all of the MemClkDis bits should also be set.
+                                */
+@@ -4542,8 +4691,9 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+       }
+       for (i=i_start; i<i_end; i++) {
+               index_reg = 0x98;
+-              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */
+-              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */
++              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, 
pDCTstat->CH_ODC_CTL[i]);      /* Channel A/B Output Driver Compensation 
Control */
++              Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, 
pDCTstat->CH_ADDR_TMG[i]);     /* Channel A/B Output Driver Compensation 
Control */
++              printk(BIOS_SPEW, "Programmed DCT %d timing/termination pattern 
%08x %08x\n", dct, pDCTstat->CH_ADDR_TMG[i], pDCTstat->CH_ODC_CTL[i]);
+       }
+ 
+       return pDCTstat->ErrCode;
+@@ -4600,11 +4750,19 @@ static u8 mct_SPDCalcWidth(struct MCTStatStruc 
*pMCTstat,
+               val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94);
+               val |= 1 << DisDramInterface;
+               Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val);
++
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90);
++              val &= ~(1 << ParEn);
++              Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val);
+       }
+       if (pDCTstat->DIMMValidDCT[1] == 0) {
+               val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94);
+               val |= 1 << DisDramInterface;
+               Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val);
++
++              val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90);
++              val &= ~(1 << ParEn);
++              Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val);
+       }
+ 
+       printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status);
+@@ -6035,6 +6193,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+               dword &= ~(0xf);                                /* 
RdOdtTrnOnDly = read_odt_delay */
+               dword |= (read_odt_delay & 0xf);
+               Set_NB32_DCT(dev, dct, 0x240, dword);
++
++              printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x 
%08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
+       } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+               if (pDCTstat->Speed == 3)
+                       dword = 0x00000800;
+@@ -6170,6 +6330,8 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, 
odt_pattern_0);
+                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, 
odt_pattern_3);
+                       Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, 
odt_pattern_2);
++
++                      printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x 
%08x %08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
+               }
+       }
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
+index 3df262b..4ae1aec 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
+@@ -21,7 +21,7 @@
+ /* AM3/ASB2/C32/G34 DDR3 */
+ 
+ static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
+-                              u32 *AddrTmgCTL, u32 *ODC_CTL,
++                              u32 *ODC_CTL,
+                               u8 *CMDmode);
+ 
+ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+@@ -34,9 +34,14 @@ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+       } else {
+               Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
+                                       pDCTstat->MAload[dct],
+-                                      &(pDCTstat->CH_ADDR_TMG[dct]), 
&(pDCTstat->CH_ODC_CTL[dct]),
++                                      &(pDCTstat->CH_ODC_CTL[dct]),
+                                       &pDCTstat->_2Tmode);
+ 
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      pDCTstat->_2Tmode = 1;  /* Disable slow access mode */
++              }
++              pDCTstat->CH_ADDR_TMG[dct] = 
fam10h_address_timing_compensation_code(pDCTstat, dct);
++
+               pDCTstat->CH_ODC_CTL[dct] |= 0x20000000;        /* 60ohms */
+       }
+ 
+@@ -54,42 +59,25 @@ void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
+  *    : ODC_CTL    - Output Driver Compensation Control Register Value
+  *    : CMDmode    - CMD mode
+  */
+-static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
+-                              u32 *AddrTmgCTL, u32 *ODC_CTL,
++static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
++                              u32 *ODC_CTL,
+                               u8 *CMDmode)
+ {
+-      *AddrTmgCTL = 0;
+       *ODC_CTL = 0;
+       *CMDmode = 1;
+ 
+-      if(MAAdimms == 1) {
+-              if(MAAload >= 16) {
+-                      if(Speed == 4)
+-                              *AddrTmgCTL = 0x003B0000;
+-                      else if (Speed == 5)
+-                              *AddrTmgCTL = 0x00380000;
+-                      else if (Speed == 6)
+-                              *AddrTmgCTL = 0x00360000;
+-                      else
+-                              *AddrTmgCTL = 0x00340000;
+-              } else {
+-                      *AddrTmgCTL = 0x00000000;
+-              }
++      if (MAAdimms == 1) {
+               *ODC_CTL = 0x00113222;
+               *CMDmode = 1;
+       } else /* if(MAAdimms == 0) */ {
+               if(Speed == 4) {
+                       *CMDmode = 1;
+-                      *AddrTmgCTL = 0x00390039;
+               } else if(Speed == 5) {
+                       *CMDmode = 1;
+-                      *AddrTmgCTL = 0x00350037;
+               } else if(Speed == 6) {
+                       *CMDmode = 2;
+-                      *AddrTmgCTL = 0x00000035;
+               } else {
+                       *CMDmode = 2;
+-                      *AddrTmgCTL = 0x00000033;
+               }
+               *ODC_CTL = 0x00223323;
+       }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index b0ad54b..36e9858 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -241,37 +241,53 @@ static void CalcEccDQSPos_D(struct MCTStatStruc 
*pMCTstat,
+                               struct DCTStatStruc *pDCTstat,
+                               u16 like, u8 scale, u8 ChipSel)
+ {
+-      u8 DQSDelay0, DQSDelay1;
+-      u16 DQSDelay;
++      uint8_t DQSDelay0, DQSDelay1;
++      int16_t delay_differential;
++      uint16_t DQSDelay;
+ 
+       if (pDCTstat->Status & (1 << SB_Registered)) {
+-              return;
+-      }
++              pDCTstat->ByteLane = 0x2;
++              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
++              DQSDelay0 = pDCTstat->DQSDelay;
+ 
+-      pDCTstat->ByteLane = like & 0xff;
+-      GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+-      DQSDelay0 = pDCTstat->DQSDelay;
++              pDCTstat->ByteLane = 0x3;
++              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
++              DQSDelay1 = pDCTstat->DQSDelay;
+ 
+-      pDCTstat->ByteLane = (like >> 8) & 0xff;
+-      GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
+-      DQSDelay1 = pDCTstat->DQSDelay;
++              if (pDCTstat->Direction == DQS_READDIR) {
++                      DQSDelay = DQSDelay1;
++              } else {
++                      delay_differential = (int16_t)DQSDelay1 - 
(int16_t)DQSDelay0;
++                      delay_differential += (int16_t)DQSDelay1;
+ 
+-      if (DQSDelay0>DQSDelay1) {
+-              DQSDelay = DQSDelay0 - DQSDelay1;
++                      DQSDelay = delay_differential;
++              }
+       } else {
+-              DQSDelay = DQSDelay1 - DQSDelay0;
+-      }
++              pDCTstat->ByteLane = like & 0xff;
++              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
++              DQSDelay0 = pDCTstat->DQSDelay;
+ 
+-      DQSDelay = DQSDelay * (~scale);
++              pDCTstat->ByteLane = (like >> 8) & 0xff;
++              GetDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel);
++              DQSDelay1 = pDCTstat->DQSDelay;
+ 
+-      DQSDelay += 0x80;       /* round it */
++              if (DQSDelay0>DQSDelay1) {
++                      DQSDelay = DQSDelay0 - DQSDelay1;
++              } else {
++                      DQSDelay = DQSDelay1 - DQSDelay0;
++              }
+ 
+-      DQSDelay >>= 8;         /* 256 */
++              DQSDelay = DQSDelay * (~scale);
+ 
+-      if (DQSDelay0>DQSDelay1) {
+-              DQSDelay = DQSDelay1 - DQSDelay;
+-      } else {
+-              DQSDelay += DQSDelay1;
++              DQSDelay += 0x80;       /* round it */
++
++              DQSDelay >>= 8;         /* 256 */
++
++              if (DQSDelay0>DQSDelay1) {
++                      DQSDelay = DQSDelay1 - DQSDelay;
++              } else {
++                      DQSDelay += DQSDelay1;
++              }
+       }
+ 
+       pDCTstat->DQSDelay = (u8)DQSDelay;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+index 5ea7fa6..9617f84 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+@@ -18,12 +18,39 @@
+  * Foundation, Inc.
+  */
+ 
++static uint16_t memclk_to_freq(uint16_t memclk) {
++      uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
++      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
++
++      uint16_t mem_freq = 0;
++
++      if (is_fam15h()) {
++              if (memclk < 0x17) {
++                      mem_freq = fam15h_freq_tab[memclk];
++              }
++      } else {
++              if ((memclk > 0x0) && (memclk < 0x8)) {
++                      mem_freq = fam10h_freq_tab[memclk - 1];
++              }
++      }
++
++      return mem_freq;
++}
++
++static uint32_t rc_word_value_to_ctl_bits(uint32_t value) {
++      return ((value >> 2) & 3) << 16 | ((value & 3) << 3);
++}
++
+ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+                       struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 
CtrlWordNum)
+ {
+-      u8 Dimms, DimmNum, MaxDimm, Speed;
++      u8 Dimms, DimmNum;
+       u32 val;
+       u32 dct = 0;
++      uint8_t ddr_voltage_index;
++      uint16_t mem_freq;
++      uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+       DimmNum = (MrsChipSel >> 20) & 0xFE;
+ 
+@@ -32,54 +59,64 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+       /* DimmNum ++; */
+       /* cl +=8; */
+ 
+-      MaxDimm = mctGet_NVbits(NV_MAX_DIMMS);
+-      Speed = pDCTstat->DIMMAutoSpeed;
++      mem_freq = memclk_to_freq(pDCTstat->DIMMAutoSpeed);
+ 
+       if (pDCTstat->CSPresent_DCT[0] > 0) {
+               dct = 0;
+-      } else if (pDCTstat->CSPresent_DCT[1] > 0 ){
++      } else if (pDCTstat->CSPresent_DCT[1] > 0 ) {
+               dct = 1;
+-              DimmNum ++;
++              DimmNum++;
+       }
+       Dimms = pDCTstat->MAdimms[dct];
+ 
++      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
++
+       val = 0;
+       if (CtrlWordNum == 0)
+-              val |= 1 << 1;
++              val = 0x2;
+       else if (CtrlWordNum == 1) {
+               if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 
<< DimmNum)))
+-                      val |= 0xC; /* if single rank, set DBA1 and DBA0 */
++                      val = 0xC; /* if single rank, set DBA1 and DBA0 */
+       } else if (CtrlWordNum == 2) {
+-              if (MaxDimm == 4) {
+-                      if (Speed == 4) {
+-                              if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) 
&& (Dimms == 1)) || (Dimms == 2))
+-                                      if (!(pDCTstat->MirrPresU_NumRegR & (1 
<< DimmNum)))
+-                                              val |= 1 << 2;
+-                      } else {
+-                              if (pDCTstat->MirrPresU_NumRegR & (1 << 
DimmNum))
+-                                      val |= 1 << 2;
++              if (package_type == PT_GR) {
++                      /* Socket G34 */
++                      if (MaxDimmsInstallable == 2) {
++                              if (Dimms > 1)
++                                      val = 0x4;
+                       }
+-              } else {
+-                      if (Dimms > 1)
+-                              val |= 1 << 2;
+               }
+       } else if (CtrlWordNum == 3) {
+-              val |= (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
++              val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
+       } else if (CtrlWordNum == 4) {
+-              val |= (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
++              val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
+       } else if (CtrlWordNum == 5) {
+-              val |= (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
++              val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
+       } else if (CtrlWordNum == 8) {
+-              if (MaxDimm == 4)
+-                      if (Speed == 4)
+-                              if (pDCTstat->MirrPresU_NumRegR & (1 << 
DimmNum))
+-                                      val |= 1 << 2;
++              if (package_type == PT_GR) {
++                      /* Socket G34 */
++                      if (MaxDimmsInstallable == 2) {
++                              val = 0x0;
++                      }
++              }
+       } else if (CtrlWordNum == 9) {
+-              val |= 0xD;     /* DBA1, DBA0, DA3 = 0 */
++              val = 0xD;      /* DBA1, DBA0, DA3 = 0 */
++      } else if (CtrlWordNum == 10) {
++              val = 0x0;      /* Lowest operating frequency */
++      } else if (CtrlWordNum == 11) {
++              if (ddr_voltage_index & 0x4)
++                      val = 0x2;      /* 1.25V */
++              else if (ddr_voltage_index & 0x2)
++                      val = 0x1;      /* 1.35V */
++              else
++                      val = 0x0;      /* 1.5V */
++      } else if (CtrlWordNum >= 12) {
++              val = 0x0;      /* Unset */
+       }
+-      val &= 0xffffff0f;
++      val &= 0xf;
++
++      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", CtrlWordNum, 
val);
+ 
+-      val = MrsChipSel | ((val >> 2) & 3) << 16 | ((val & 3) << 3);
++      val = MrsChipSel | rc_word_value_to_ctl_bits(val);
+ 
+       /* transfer Control word number to address [BA2,A2,A1,A0] */
+       if (CtrlWordNum > 7) {
+@@ -129,18 +166,18 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+                       val &= ~(0xF << 8);
+ 
+                       switch (MrsChipSel) {
+-                      case 0:
+-                      case 1:
+-                              val |= 3 << 8;
+-                      case 2:
+-                      case 3:
+-                              val |= (3 << 2) << 8;
+-                      case 4:
+-                      case 5:
+-                              val |= (3 << 4) << 8;
+-                      case 6:
+-                      case 7:
+-                              val |= (3 << 6) << 8;
++                              case 0:
++                              case 1:
++                                      val |= 3 << 8;
++                              case 2:
++                              case 3:
++                                      val |= (3 << 2) << 8;
++                              case 4:
++                              case 5:
++                                      val |= (3 << 4) << 8;
++                              case 6:
++                              case 7:
++                                      val |= (3 << 6) << 8;
+                       }
+                       Set_NB32_DCT(dev, dct, 0xa8, val);
+ 
+@@ -164,8 +201,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+       u32 MrsChipSel;
+       u32 dev = pDCTstat->dev_dct;
+       u32 val;
++      uint16_t mem_freq;
+ 
+       pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
++      mem_freq = memclk_to_freq(pDCTstat->TargetFreq);
+       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
+@@ -175,19 +214,31 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+                       Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 
select */
+ 
+                       /* Resend control word 10 */
++                      uint8_t freq_ctl_val = 0;
+                       mct_Wait(1600);
+-                      switch (pDCTstat->TargetFreq) {
+-                      case 5:
+-                              mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel 
<< 20 | 0x4000A);
+-                              break;
+-                      case 6:
+-                              mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel 
<< 20 | 0x40012);
+-                              break;
+-                      case 7:
+-                              mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel 
<< 20 | 0x4001A);
+-                              break;
++                      switch (mem_freq) {
++                              case 333:
++                              case 400:
++                                      freq_ctl_val = 0x0;
++                                      break;
++                              case 533:
++                                      freq_ctl_val = 0x1;
++                                      break;
++                              case 667:
++                                      freq_ctl_val = 0x2;
++                                      break;
++                              case 800:
++                                      freq_ctl_val = 0x3;
++                                      break;
++                              case 933:
++                                      freq_ctl_val = 0x4;
++                                      break;
+                       }
+ 
++                      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: 
%02x\n", 10, freq_ctl_val);
++
++                      mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 
0x40002 | rc_word_value_to_ctl_bits(freq_ctl_val));
++
+                       mct_Wait(1600);
+ 
+                       /* Resend control word 2 */
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 6a2c2a7..9ccf77e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -496,6 +496,8 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+               ret |= ((dword >> 10) & 3) << 9;
+       }
+ 
++      printk(BIOS_SPEW, "Going to send MR2 control word %08x\n", ret);
++
+       return ret;
+ }
+ 
+@@ -525,6 +527,8 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
+               ret |= (dword >> 24) & 7;
+       }
+ 
++      printk(BIOS_SPEW, "Going to send MR3 control word %08x\n", ret);
++
+       return ret;
+ }
+ 
+@@ -619,6 +623,8 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+                       ret |= 1 << 12;
+       }
+ 
++      printk(BIOS_SPEW, "Going to send MR1 control word %08x\n", ret);
++
+       return ret;
+ }
+ 
+@@ -738,6 +744,8 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
+               ret |= 1 << 8;
+       }
+ 
++      printk(BIOS_SPEW, "Going to send MR0 control word %08x\n", ret);
++
+       return ret;
+ }
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 9313673..981f467 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -1744,6 +1744,7 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+       u16 EccDQSLike;
+       u8 EccDQSScale;
+       u32 val, val0, val1;
++      int16_t delay_differential;
+ 
+       EccDQSLike = pDCTstat->CH_EccDQSLike[Channel];
+       EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
+@@ -1753,14 +1754,22 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+                       u16 *p;
+                       p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
+ 
+-                      /* DQS Delay Value of Data Bytelane
+-                       * most like ECC byte lane */
+-                      val0 = p[EccDQSLike & 0x07];
+-                      /* DQS Delay Value of Data Bytelane
+-                       * 2nd most like ECC byte lane */
+-                      val1 = p[(EccDQSLike>>8) & 0x07];
++                      if (pDCTstat->Status & (1 << SB_Registered)) {
++                              val0 = p[0x2];
++                              val1 = p[0x3];
++
++                              delay_differential = (int16_t)val1 - 
(int16_t)val0;
++                              delay_differential += (int16_t)val1;
++
++                              val = delay_differential;
++                      } else {
++                              /* DQS Delay Value of Data Bytelane
++                               * most like ECC byte lane */
++                              val0 = p[EccDQSLike & 0x07];
++                              /* DQS Delay Value of Data Bytelane
++                               * 2nd most like ECC byte lane */
++                              val1 = p[(EccDQSLike>>8) & 0x07];
+ 
+-                      if (!(pDCTstat->Status & (1 << SB_Registered))) {
+                               if(val0 > val1) {
+                                       val = val0 - val1;
+                               } else {
+@@ -1775,9 +1784,6 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+                               } else {
+                                       val += val0;
+                               }
+-                      } else {
+-                              val = val1 - val0;
+-                              val += val1;
+                       }
+ 
+                       pDCTstat->CH_D_BC_RCVRDLY[Channel][ChipSel>>1] = val;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 47ad152..e5e4031 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -930,7 +930,9 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+               else if ((cs == 4) || (cs == 0))
+                       WrLvOdt1 = (dword & 0xf);
+       } else {
+-              if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
++              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                      WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
++              } else {
+                       if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
+                               WrLvOdt1 = 0x03;
+                       } else if 
(bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
+@@ -938,14 +940,14 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+                       } else {
+                               WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
+                       }
+-              } else {
+-                      WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
+               }
+       }
+ 
+       set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
+ 
++      printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern 
%08x\n", dct, WrLvOdt1);
++
+ }
+ 
+ #ifdef UNUSED_CODE
+@@ -980,7 +982,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+       u16 Addl_Data_Offset, Addl_Data_Port;
+       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+-      u16 fam10h_freq_tab[] = {400, 533, 667, 800};
++      uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
+       uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+ 
+       if (is_fam15h()) {
+@@ -1093,21 +1095,18 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+                               
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
+                       }
+               } else {
+-                      if (pDCTData->Status[DCT_STATUS_REGISTERED])
+-                      {
+-                              if(pDCTData->RegMan1Present & 
((1<<(dimm*2+dct))))
+-                              {
++                      if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                              uint8_t AddrCmdPrelaunch = 0;           /* 
TODO: Fetch the correct value from RC2[0] */
++
++                              /* The seed values below assume Pass 1 utilizes 
a 400MHz clock frequency (DDR3-800) */
++                              if (AddrCmdPrelaunch == 0) {
+                                       Seed_Gross = 0x02;
+-                                      Seed_Fine = 0x16;
+-                              }
+-                              else
+-                              {
++                                      Seed_Fine = 0x01;
++                              } else {
+                                       Seed_Gross = 0x02;
+-                                      Seed_Fine = 0x00;
++                                      Seed_Fine = 0x11;
+                               }
+-                      }
+-                      else
+-                      {
++                      } else {
+                               if (MemClkFreq == 6) {
+                                       /* DDR-800 */
+                                       Seed_Gross = 0x00;
+@@ -1131,6 +1130,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+                        */
+                       pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Gross;
+                       pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
Seed_Fine;
++                      printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", 
ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
+               }
+       } else {
+               /* Pass 2 */
+@@ -1182,21 +1182,30 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+ 
+                               
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
+                               
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++
++                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
+                       }
+               } else {
+-                      u32 RegisterDelay, SeedTotal;
++                      uint32_t RegisterDelay;
++                      uint32_t SeedTotalPreScaling;
++                      uint32_t SeedTotal;
++                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
+                       for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
+                       {
+-                              if (pDCTData->Status[DCT_STATUS_REGISTERED])
+-                                      RegisterDelay = 0x20; /* TODO: ((RCW2 & 
BIT0) == 0) ? 0x20 : 0x30; */
+-                              else
++                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                      if (AddrCmdPrelaunch == 0)
++                                              RegisterDelay = 0x20;
++                                      else
++                                              RegisterDelay = 0x30;
++                              } else {
+                                       RegisterDelay = 0;
+-                              SeedTotal = 
(pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
+-                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5);
++                              }
++                              SeedTotalPreScaling = 
((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
++                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay;
+                               /* SeedTotalPreScaling = (the total delay value 
in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
+                               training) - RegisterDelay. */
+-                              SeedTotal = (uint16_t) (RegisterDelay + 
((((uint64_t) SeedTotal - RegisterDelay) *
+-                                                                      
fam10h_freq_tab[MemClkFreq-3] * 100) / (fam10h_freq_tab[0] * 100)));
++                              SeedTotal = (uint16_t) ((((uint64_t) 
SeedTotalPreScaling) *
++                                                                      
fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 100));
+                               Seed_Gross = SeedTotal / 32;
+                               Seed_Fine = SeedTotal & 0x1f;
+                               if (Seed_Gross == 0)
+@@ -1205,8 +1214,20 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+                                       Seed_Gross = 1;
+                               else
+                                       Seed_Gross = 2;
++
++                              /* The BKDG-recommended algorithm causes 
problems with registered DIMMs on some systems
++                               * due to the long register delays causing 
premature total delay wrap-around.
++                               * Attempt to work around this...
++                               */
++                              SeedTotal = ((Seed_Gross & 0x1f) << 5) | 
(Seed_Fine & 0x1f);
++                              SeedTotal += RegisterDelay;
++                              Seed_Gross = SeedTotal / 32;
++                              Seed_Fine = SeedTotal & 0x1f;
++
+                               
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
+                               
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++
++                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
+                       }
+               }
+       }
+@@ -1383,6 +1404,8 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
+       gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
+                               FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
+ 
++      printk(BIOS_SPEW, "\tLane %02x raw readback: %04x\n", ByteLane, ((gross 
& 0x1f) << 5) | (fine & 0x1f));
++
+       if (!is_fam15h()) {
+               /* Adjust seed gross delay overflow (greater than 3):
+                * - Adjust the trained gross delay to the original seed gross 
delay.
+@@ -1406,4 +1429,5 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
+       }
+       pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
+       pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
++      printk(BIOS_SPEW, "\tLane %02x final adjusted value: %04x\n", ByteLane, 
((gross & 0x1f) << 5) | (fine & 0x1f));
+ }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0085-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0085-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
deleted file mode 100644
index f9d5afb..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0085-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From 5ab09d94caec3d1b2cbc156fdf0b32bd7c2e518c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 28 Jul 2015 13:45:29 -0500
-Subject: [PATCH 085/139] northbridge/amd/amdmct: Fix Family 15h detection
-
-Change-Id: I3623f8945bd62b7050ec609934f96543552c792b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct/mct.h        | 3 ++-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h | 2 +-
- 2 files changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct/mct.h 
b/src/northbridge/amd/amdmct/mct/mct.h
-index d399eea..1af11b1 100644
---- a/src/northbridge/amd/amdmct/mct/mct.h
-+++ b/src/northbridge/amd/amdmct/mct/mct.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -501,7 +502,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
- u32 NodePresent(u32 Node);
- u32 Get_NB32n(struct DCTStatStruc *pDCTstat, u32 addrx);
- u32 Get_NB32(u32 addr); /* NOTE: extend addr to 32 bit for bus > 0 */
--u32 mctGetLogicalCPUID(u32 Node);
-+uint64_t mctGetLogicalCPUID(u32 Node);
- 
- void K8FInterleaveBanks(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 6b5d8c1..e327d38 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -985,7 +985,7 @@ u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
- u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, 
u16 RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
- void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
--u32 mctGetLogicalCPUID(u32 Node);
-+uint64_t mctGetLogicalCPUID(u32 Node);
- u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
- void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA, u8 Pass);
- void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
new file mode 100644
index 0000000..569e6e7
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-Fix-Family-15h-detection.patch
@@ -0,0 +1,49 @@
+From bcab168a4fe68defa0683d49d2b7b1b73721bc8b Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 28 Jul 2015 13:45:29 -0500
+Subject: [PATCH 086/143] northbridge/amd/amdmct: Fix Family 15h detection
+
+Change-Id: I3623f8945bd62b7050ec609934f96543552c792b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct/mct.h        |    3 ++-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h |    2 +-
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct/mct.h 
b/src/northbridge/amd/amdmct/mct/mct.h
+index d399eea..1af11b1 100644
+--- a/src/northbridge/amd/amdmct/mct/mct.h
++++ b/src/northbridge/amd/amdmct/mct/mct.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -501,7 +502,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+ u32 NodePresent(u32 Node);
+ u32 Get_NB32n(struct DCTStatStruc *pDCTstat, u32 addrx);
+ u32 Get_NB32(u32 addr); /* NOTE: extend addr to 32 bit for bus > 0 */
+-u32 mctGetLogicalCPUID(u32 Node);
++uint64_t mctGetLogicalCPUID(u32 Node);
+ 
+ void K8FInterleaveBanks(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat);
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 6b5d8c1..e327d38 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -985,7 +985,7 @@ u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
+ u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, 
u16 RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
+ void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+-u32 mctGetLogicalCPUID(u32 Node);
++uint64_t mctGetLogicalCPUID(u32 Node);
+ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA, u8 Pass);
+ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
 
b/resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
deleted file mode 100644
index 37cda08..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0086-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
+++ /dev/null
@@ -1,1887 +0,0 @@
-From 95e15fd07cd76057737c0b52a4ece6f73501ea1e Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 28 Jul 2015 15:16:46 -0500
-Subject: [PATCH 086/139] northbridge/amd/amdmct/mct_ddr3: Add registered and
- x4 DIMM support to Fam15h
-
-Change-Id: I9ee0bb7346aa35f564fe535cdd337ec7f6148f2b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 186 +++++++-----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |   2 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   4 +
- src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c   |  17 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctrci.c   | 191 ++++++++----
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |  42 ++-
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   | 253 +++++++++-------
- src/northbridge/amd/amdmct/mct_ddr3/mctwl.c    |  16 +-
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  | 400 +++++++++++++++----------
- src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h   |  13 +-
- 10 files changed, 698 insertions(+), 426 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 8102f2a..5a57dc0 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -166,7 +166,7 @@ static void mct_EnDllShutdownSR(struct MCTStatStruc 
*pMCTstat,
- static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat);
- void SetTargetFreq(struct MCTStatStruc *pMCTstat,
--                                        struct DCTStatStruc *pDCTstat);
-+                                        struct DCTStatStruc *pDCTstatA, 
uint8_t Node);
- 
- static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u32 MrsChipSel);
-@@ -1404,6 +1404,10 @@ static void precise_memclk_delay_fam15(struct 
MCTStatStruc *pMCTstat, struct DCT
- 
-       memclk_freq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
- 
-+      if (fam15h_freq_tab[memclk_freq] == 0) {
-+              printk(BIOS_DEBUG, "ERROR: precise_memclk_delay_fam15 for DCT 
%d (delay %d clocks) failed to obtain valid memory frequency!"
-+                      " (pDCTstat: %p pDCTstat->dev_dct: %08x memclk_freq: 
%02x)\n", dct, clocks, pDCTstat, pDCTstat->dev_dct, memclk_freq);
-+      }
-       delay_ns = (((uint64_t)clocks * 1000) / fam15h_freq_tab[memclk_freq]);
-       precise_ndelay_fam15(pMCTstat, delay_ns);
- }
-@@ -2320,7 +2324,7 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-       nv_DQSTrainCTL = !allow_config_restore;
- 
-       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
--      phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
-+      phyAssistedMemFnceTraining(pMCTstat, pDCTstatA, -1);
- 
-       if (is_fam15h()) {
-               uint8_t Node;
-@@ -3357,7 +3361,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
- }
- 
- static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat, u8 dct)
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct)
- {
-       /* Initialize  DCT Timing registers as per DIMM SPD.
-        * For primary timing (T, CL) use best case T value.
-@@ -3461,7 +3465,7 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
- }
- 
- static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat, u8 dct)
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct)
- {
-       /* Find the best T and CL primary timing parameter pair, per Mfg.,
-        * for the given set of DIMMs, and store into DCTStatStruc
-@@ -3740,10 +3744,15 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-               dword++;
-       }
- 
--      if (Status & (1 << SB_Registered))
--              DramConfigLo |= 1 << ParEn;             /* Registered DIMMs */
--      else
--              DramConfigLo |= 1 << UnBuffDimm;        /* Unbuffered DIMMs */
-+      if (Status & (1 << SB_Registered)) {
-+              /* Registered DIMMs */
-+              if (!is_fam15h()) {
-+                      DramConfigLo |= 1 << ParEn;
-+              }
-+      } else {
-+              /* Unbuffered DIMMs */
-+              DramConfigLo |= 1 << UnBuffDimm;
-+      }
- 
-       if (mctGet_NVbits(NV_ECC_CAP))
-               if (Status & (1 << SB_ECCDIMMs))
-@@ -3761,10 +3770,11 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-       DramConfigHi |= dword - offset; /* get MemClk encoding */
-       DramConfigHi |= 1 << MemClkFreqVal;
- 
--      if (Status & (1 << SB_Registered))
--              if ((pDCTstat->Dimmx4Present != 0) && (pDCTstat->Dimmx8Present 
!= 0))
--                      /* set only if x8 Registered DIMMs in System*/
--                      DramConfigHi |= 1 << RDqsEn;
-+      if (!is_fam15h())
-+              if (Status & (1 << SB_Registered))
-+                      if ((pDCTstat->Dimmx4Present != 0) && 
(pDCTstat->Dimmx8Present != 0))
-+                              /* set only if x8 Registered DIMMs in System*/
-+                              DramConfigHi |= 1 << RDqsEn;
- 
-       if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
-               DramConfigLo |= 1 << 25;        /* PendRefPaybackS3En = 1 */
-@@ -3776,14 +3786,16 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-                       DramConfigHi |= 1 << 16;
-       }
- 
--      /* Control Bank Swizzle */
--      if (0) /* call back not needed mctBankSwizzleControl_D()) */
--              DramConfigHi &= ~(1 << BankSwizzleMode);
--      else
--              DramConfigHi |= 1 << BankSwizzleMode; /* recommended setting 
(default) */
-+      if (!is_fam15h()) {
-+              /* Control Bank Swizzle */
-+              if (0) /* call back not needed mctBankSwizzleControl_D()) */
-+                      DramConfigHi &= ~(1 << BankSwizzleMode);
-+              else
-+                      DramConfigHi |= 1 << BankSwizzleMode; /* recommended 
setting (default) */
-+      }
- 
-       /* Check for Quadrank DIMM presence */
--      if ( pDCTstat->DimmQRPresent != 0) {
-+      if (pDCTstat->DimmQRPresent != 0) {
-               byte = mctGet_NVbits(NV_4RANKType);
-               if (byte == 2)
-                       DramConfigHi |= 1 << 17;        /* S4 (4-Rank SO-DIMMs) 
*/
-@@ -4588,8 +4600,9 @@ static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
-                       Set_NB32(pDCTstat->dev_dct, reg, val);
-               }
-               if (byte)       /* NV_Unganged */
--                      pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); /* 
Clear so that there is no DIMM missmatch error */
-+                      pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); /* 
Clear so that there is no DIMM mismatch error */
-       }
-+
-       return pDCTstat->ErrCode;
- }
- 
-@@ -4650,6 +4663,8 @@ void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 
index, u32 data)
- static u8 mct_BeforePlatformSpec(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       /* mct_checkForCxDxSupport_D */
-       if (pDCTstat->LogicalCPUID & AMD_DR_GT_Bx) {
-               /* Family 10h Errata 322: Address and Command Fine Delay Values 
May Be Incorrect */
-@@ -4664,6 +4679,9 @@ static u8 mct_BeforePlatformSpec(struct MCTStatStruc 
*pMCTstat,
-               else
-                       Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D02E001, 0x90);
-       }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
-+
-       return pDCTstat->ErrCode;
- }
- 
-@@ -4674,6 +4692,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
-        * and program them into DCT.
-        */
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       u32 dev = pDCTstat->dev_dct;
-       u32 index_reg;
-       u8 i, i_start, i_end;
-@@ -4694,6 +4714,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
-               printk(BIOS_SPEW, "Programmed DCT %d timing/termination pattern 
%08x %08x\n", dct, pDCTstat->CH_ADDR_TMG[i], pDCTstat->CH_ODC_CTL[i]);
-       }
- 
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
-+
-       return pDCTstat->ErrCode;
- }
- 
-@@ -4705,7 +4727,8 @@ static void mct_SyncDCTsReady(struct DCTStatStruc 
*pDCTstat)
-       if (pDCTstat->NodePresent) {
-               dev = pDCTstat->dev_dct;
- 
--              if ((pDCTstat->DIMMValidDCT[0] ) || 
(pDCTstat->DIMMValidDCT[1])) {              /* This Node has dram */
-+              if ((pDCTstat->DIMMValidDCT[0]) || (pDCTstat->DIMMValidDCT[1])) 
{
-+                      /* This Node has DRAM */
-                       do {
-                               val = Get_NB32(dev, 0x110);
-                       } while (!(val & (1 << DramEnabled)));
-@@ -5653,57 +5676,56 @@ static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
-       /* Fam15h BKDG v3.14 section 2.10.5.3
-        * The remainder of the Phy Initialization algorithm picks up in 
phyAssistedMemFnceTraining
-        */
--      for (dct = 0; dct < 2; dct++) {
--              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 
0x80000000);
--              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 
0x00000118);
--
--              /* Program desired VDDIO level */
--              if (ddr_voltage_index & 0x4) {
--                      /* 1.25V */
--                      amd_voltage_level_index = 0x2;
--              } else if (ddr_voltage_index & 0x2) {
--                      /* 1.35V */
--                      amd_voltage_level_index = 0x1;
--              } else if (ddr_voltage_index & 0x1) {
--                      /* 1.50V */
--                      amd_voltage_level_index = 0x0;
--              }
--
--              /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */
--              for (index = 0; index < 0x9; index++) {
--                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f001f | (index << 8));
--                      dword &= ~(0x3 << 3);
--                      dword |= (amd_voltage_level_index << 3);
--                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f 
| (index << 8), dword);
--              }
--
--              /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */
--              for (index = 0; index < 0x3; index++) {
--                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f201f | (index << 8));
--                      dword &= ~(0x3 << 3);
--                      dword |= (amd_voltage_level_index << 3);
--                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f 
| (index << 8), dword);
--              }
--              for (index = 0; index < 0x2; index++) {
--                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f801f | (index << 8));
--                      dword &= ~(0x3 << 3);
--                      dword |= (amd_voltage_level_index << 3);
--                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f 
| (index << 8), dword);
--              }
--              for (index = 0; index < 0x1; index++) {
--                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc01f | (index << 8));
--                      dword &= ~(0x3 << 3);
--                      dword |= (amd_voltage_level_index << 3);
--                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f 
| (index << 8), dword);
--              }
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 0x80000000);
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 0x00000118);
- 
--              /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */
--              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f4009);
--              dword &= ~(0x0000c00c);
--              dword |= (amd_voltage_level_index << 14);
--              dword |= (amd_voltage_level_index << 2);
--              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f4009, dword);
--      }
-+      /* Program desired VDDIO level */
-+      if (ddr_voltage_index & 0x4) {
-+              /* 1.25V */
-+              amd_voltage_level_index = 0x2;
-+      } else if (ddr_voltage_index & 0x2) {
-+              /* 1.35V */
-+              amd_voltage_level_index = 0x1;
-+      } else if (ddr_voltage_index & 0x1) {
-+              /* 1.50V */
-+              amd_voltage_level_index = 0x0;
-+      }
-+
-+      /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */
-+      for (index = 0; index < 0x9; index++) {
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f 
| (index << 8));
-+              dword &= ~(0x3 << 3);
-+              dword |= (amd_voltage_level_index << 3);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f | 
(index << 8), dword);
-+      }
-+
-+      /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */
-+      for (index = 0; index < 0x3; index++) {
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f 
| (index << 8));
-+              dword &= ~(0x3 << 3);
-+              dword |= (amd_voltage_level_index << 3);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f | 
(index << 8), dword);
-+      }
-+      for (index = 0; index < 0x2; index++) {
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f 
| (index << 8));
-+              dword &= ~(0x3 << 3);
-+              dword |= (amd_voltage_level_index << 3);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f | 
(index << 8), dword);
-+      }
-+      for (index = 0; index < 0x1; index++) {
-+              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f 
| (index << 8));
-+              dword &= ~(0x3 << 3);
-+              dword |= (amd_voltage_level_index << 3);
-+              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f | 
(index << 8), dword);
-+      }
-+
-+      /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */
-+      /* NOTE: CmpVioLvl and ComparatorAdjust only take effect when set on 
DCT 0 */
-+      dword = Get_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0f4009);
-+      dword &= ~(0x0000c00c);
-+      dword |= (amd_voltage_level_index << 14);
-+      dword |= (amd_voltage_level_index << 2);
-+      Set_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0f4009, dword);
- 
-       printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
-@@ -5719,18 +5741,24 @@ static void InitPhyCompensation(struct MCTStatStruc 
*pMCTstat,
-       uint32_t dword;
-       const u8 *p;
- 
--      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+      printk(BIOS_DEBUG, "%s: DCT %d: Start\n", __func__, dct);
- 
-       if (is_fam15h()) {
-               /* Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 
2.10.5.3.4 */
-               uint32_t tx_pre;
-               uint32_t drive_strength;
- 
--              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
-+              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp] */
-               dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
--              dword |= (0x3 << 13);
-+              dword |= (0x1 << 14);
-               Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
- 
-+              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisablePredriverCal] */
-+              /* NOTE: DisablePredriverCal only takes effect when set on DCT 
0 */
-+              dword = Get_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0fe003);
-+              dword |= (0x1 << 13);
-+              Set_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0fe003, dword);
-+
-               /* Determine TxPreP/TxPreN for data lanes (Stage 1) */
-               dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
-               drive_strength = (dword >> 20) & 0x7;   /* DqsDrvStren */
-@@ -5876,12 +5904,14 @@ static void InitPhyCompensation(struct MCTStatStruc 
*pMCTstat,
-               Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0a, dword);
-       }
- 
--      printk(BIOS_DEBUG, "%s: Done\n", __func__);
-+      printk(BIOS_DEBUG, "%s: DCT %d: Done\n", __func__, dct);
- }
- 
- static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct)
- {
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       if (!is_fam15h()) {
-               u32 reg;
-               u32 val;
-@@ -5903,6 +5933,8 @@ static void mct_EarlyArbEn_D(struct MCTStatStruc 
*pMCTstat,
- 
-               Set_NB32_DCT(dev, dct, reg, val);
-       }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
-@@ -6546,6 +6578,8 @@ void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
- 
-       uint32_t dword;
- 
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       if (is_fam15h()) {
-               /* Initial setup for frequency change
-                * 9C_x0000_0004 must be configured before MemClkFreqVal is set
-@@ -6578,6 +6612,8 @@ void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
-               mct_Wait(100);
-       }
- 
-+      printk(BIOS_DEBUG, "mct_SetDramConfigHi_D: DramConfigHi:    %08x\n", 
DramConfigHi);
-+
-       /* Program the DRAM Configuration High register */
-       Set_NB32_DCT(dev, dct, 0x94, DramConfigHi);
- 
-@@ -6593,6 +6629,8 @@ void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
-               dword |= 0x0000000f;
-               Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 
0x0d0fe006, dword);
-       }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index e327d38..486b16c 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -1014,7 +1014,7 @@ void InterleaveNodes_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTs
- void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
- 
--void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA);
-+void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA, int16_t Node);
- u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass);
- u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct);
- void mct_Wait(u32 cycles);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index 36e9858..c70fa6d 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -1588,6 +1588,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
- 
-       for (dct = 0; dct < 2; dct++) {
-               /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
-+              /* NOTE: DisablePredriverCal only takes effect when set on DCT 
0 */
-               dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
-               dword &= ~(0x3 << 13);
-               dword |= (0x1 << 13);
-@@ -1627,6 +1628,9 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                               rx_en_offset = (initial_phy_phase_delay[lane] + 
0x10) % 0x40;
- 
-                               /* 2.10.5.8.3 (4) */
-+#if DQS_TRAIN_DEBUG > 0
-+                              printk(BIOS_DEBUG, 
"TrainDQSReceiverEnCyc_D_Fam15 Receiver %d lane %d initial phy delay %04x: 
iterating from %04x to %04x\n", Receiver, lane, initial_phy_phase_delay[lane], 
rx_en_offset, 0x3ff);
-+#endif
-                               for (current_phy_phase_delay[lane] = 
rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; 
current_phy_phase_delay[lane] += ren_step) {
-                                       /* 2.10.5.8.3 (4 A) */
-                                       
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-index 539cb0d..1b81d15 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
-@@ -21,7 +21,7 @@
- static uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
- static uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
-+                                      struct DCTStatStruc *pDCTstat, uint8_t 
dct, uint8_t dimm, uint8_t pass);
- static uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
- static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
-@@ -133,7 +133,7 @@ static uint8_t PhyWLPass1(struct MCTStatStruc *pMCTstat,
- }
- 
- static uint8_t PhyWLPass2(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, u8 dct)
-+                                      struct DCTStatStruc *pDCTstat, uint8_t 
dct, uint8_t final)
- {
-       u8 dimm;
-       u16 DIMMValid;
-@@ -187,12 +187,15 @@ static uint16_t fam15h_next_highest_memclk_freq(uint16_t 
memclk_freq)
-  * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
-  */
- static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat, uint8_t 
Pass)
-+                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Node, uint8_t Pass)
- {
-       uint8_t status;
-       uint8_t timeout;
-       uint16_t final_target_freq;
- 
-+      struct DCTStatStruc *pDCTstat;
-+      pDCTstat = pDCTstatA + Node;
-+
-       pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
-       pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
-       pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
-@@ -240,13 +243,13 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
-                                       pDCTstat->TargetFreq = 
fam15h_next_highest_memclk_freq(pDCTstat->Speed);
-                               else
-                                       pDCTstat->TargetFreq = 
final_target_freq;
--                              SetTargetFreq(pMCTstat, pDCTstat);
-+                              SetTargetFreq(pMCTstat, pDCTstatA, Node);
-                               timeout = 0;
-                               do {
-                                       status = 0;
-                                       timeout++;
--                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 0);
--                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 1);
-+                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 0, (pDCTstat->TargetFreq == final_target_freq));
-+                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 1, (pDCTstat->TargetFreq == final_target_freq));
-                                       if (status)
-                                               printk(BIOS_INFO,
-                                                       "%s: Retrying write 
levelling due to invalid value(s) detected in last phase\n",
-@@ -290,7 +293,7 @@ void mct_WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
-               if (pDCTstat->NodePresent) {
-                       mctSMBhub_Init(Node);
-                       Clear_OnDimmMirror(pMCTstat, pDCTstat);
--                      WriteLevelization_HW(pMCTstat, pDCTstat, Pass);
-+                      WriteLevelization_HW(pMCTstat, pDCTstatA, Node, Pass);
-                       Restore_OnDimmMirror(pMCTstat, pDCTstat);
-               }
-       }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-index 9617f84..624a543 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-@@ -18,6 +18,78 @@
-  * Foundation, Inc.
-  */
- 
-+static uint8_t fam15h_rdimm_rc2_control_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
-+{
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-+
-+      uint8_t package_type;
-+      uint8_t control_code = 0;
-+
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
-+
-+      /* Obtain number of DIMMs on channel */
-+      uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+
-+      /* FIXME
-+       * Assume there is only one register on the RDIMM for now
-+       */
-+      uint8_t num_registers = 1;
-+
-+      if (package_type == PT_GR) {
-+              /* Socket G34 */
-+              /* Fam15h BKDG Rev. 3.14 section 2.10.5.7.1.2.1 Table 85 */
-+              if (MaxDimmsInstallable == 1) {
-+                      if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
-+                              /* DDR3-667 - DDR3-800 */
-+                              control_code = 0x1;
-+                      } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
-+                              /* DDR3-1066 - DDR3-1333 */
-+                              if (num_registers == 1) {
-+                                      control_code = 0x0;
-+                              } else {
-+                                      control_code = 0x1;
-+                              }
-+                      } else if ((MemClkFreq == 0x12) || (MemClkFreq == 
0x16)) {
-+                              /* DDR3-1600 - DDR3-1866 */
-+                              control_code = 0x0;
-+                      }
-+              } else if (MaxDimmsInstallable == 2) {
-+                      if (dimm_count == 1) {
-+                              /* 1 DIMM detected */
-+                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
-+                                      /* DDR3-667 - DDR3-800 */
-+                                      control_code = 0x1;
-+                              } else if ((MemClkFreq >= 0xa) && (MemClkFreq 
<= 0x12)) {
-+                                      /* DDR3-1066 - DDR3-1600 */
-+                                      if (num_registers == 1) {
-+                                              control_code = 0x0;
-+                                      } else {
-+                                              control_code = 0x1;
-+                                      }
-+                              }
-+                      } else if (dimm_count == 2) {
-+                              /* 2 DIMMs detected */
-+                              if (num_registers == 1) {
-+                                      control_code = 0x1;
-+                              } else {
-+                                      control_code = 0x8;
-+                              }
-+                      }
-+              } else if (MaxDimmsInstallable == 3) {
-+                      /* TODO
-+                       * 3 DIMM/channel support unimplemented
-+                       */
-+              }
-+      } else {
-+              /* TODO
-+               * Other socket support unimplemented
-+               */
-+      }
-+
-+      return control_code;
-+}
-+
- static uint16_t memclk_to_freq(uint16_t memclk) {
-       uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
-       uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
-@@ -37,36 +109,46 @@ static uint16_t memclk_to_freq(uint16_t memclk) {
-       return mem_freq;
- }
- 
-+static uint8_t rc_word_chip_select_lower_bit(void) {
-+      if (is_fam15h()) {
-+              return 21;
-+      } else {
-+              return 20;
-+      }
-+}
-+
-+static uint32_t rc_word_address_to_ctl_bits(uint32_t address) {
-+      if (is_fam15h()) {
-+              return (((address >> 3) & 0x1) << 2) << 18 | (address & 0x7);
-+      } else {
-+              return (((address >> 3) & 0x1) << 2) << 16 | (address & 0x7);
-+      }
-+}
-+
- static uint32_t rc_word_value_to_ctl_bits(uint32_t value) {
--      return ((value >> 2) & 3) << 16 | ((value & 3) << 3);
-+      if (is_fam15h()) {
-+              return ((value >> 2) & 0x3) << 18 | ((value & 0x3) << 3);
-+      } else {
-+              return ((value >> 2) & 0x3) << 16 | ((value & 0x3) << 3);
-+      }
- }
- 
- static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
--                      struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 
CtrlWordNum)
-+                      struct DCTStatStruc *pDCTstat, uint8_t dct, u32 
MrsChipSel, u32 CtrlWordNum)
- {
-       u8 Dimms, DimmNum;
-       u32 val;
--      u32 dct = 0;
-       uint8_t ddr_voltage_index;
-       uint16_t mem_freq;
-       uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-       uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
--      DimmNum = (MrsChipSel >> 20) & 0xFE;
-+      DimmNum = (MrsChipSel >> rc_word_chip_select_lower_bit()) & 0xfe;
- 
--      /* assume dct=0; */
--      /* if (dct == 1) */
--      /* DimmNum ++; */
--      /* cl +=8; */
-+      if (dct == 1)
-+              DimmNum++;
- 
-       mem_freq = memclk_to_freq(pDCTstat->DIMMAutoSpeed);
--
--      if (pDCTstat->CSPresent_DCT[0] > 0) {
--              dct = 0;
--      } else if (pDCTstat->CSPresent_DCT[1] > 0 ) {
--              dct = 1;
--              DimmNum++;
--      }
-       Dimms = pDCTstat->MAdimms[dct];
- 
-       ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
-@@ -76,21 +158,25 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-               val = 0x2;
-       else if (CtrlWordNum == 1) {
-               if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 
<< DimmNum)))
--                      val = 0xC; /* if single rank, set DBA1 and DBA0 */
-+                      val = 0xc; /* if single rank, set DBA1 and DBA0 */
-       } else if (CtrlWordNum == 2) {
--              if (package_type == PT_GR) {
--                      /* Socket G34 */
--                      if (MaxDimmsInstallable == 2) {
--                              if (Dimms > 1)
--                                      val = 0x4;
-+              if (is_fam15h()) {
-+                      val = fam15h_rdimm_rc2_control_code(pDCTstat, dct);
-+              } else {
-+                      if (package_type == PT_GR) {
-+                              /* Socket G34 */
-+                              if (MaxDimmsInstallable == 2) {
-+                                      if (Dimms > 1)
-+                                              val = 0x4;
-+                              }
-                       }
-               }
-       } else if (CtrlWordNum == 3) {
--              val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
-+              val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xff;
-       } else if (CtrlWordNum == 4) {
--              val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
-+              val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xff;
-       } else if (CtrlWordNum == 5) {
--              val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
-+              val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xff;
-       } else if (CtrlWordNum == 8) {
-               if (package_type == PT_GR) {
-                       /* Socket G34 */
-@@ -99,7 +185,7 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-                       }
-               }
-       } else if (CtrlWordNum == 9) {
--              val = 0xD;      /* DBA1, DBA0, DA3 = 0 */
-+              val = 0xd;      /* DBA1, DBA0, DA3 = 0 */
-       } else if (CtrlWordNum == 10) {
-               val = 0x0;      /* Lowest operating frequency */
-       } else if (CtrlWordNum == 11) {
-@@ -114,43 +200,30 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-       }
-       val &= 0xf;
- 
--      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", CtrlWordNum, 
val);
-+      printk(BIOS_SPEW, "Preparing to send DCT %d DIMM RC%d: %02x\n", dct, 
CtrlWordNum, val);
- 
-       val = MrsChipSel | rc_word_value_to_ctl_bits(val);
--
--      /* transfer Control word number to address [BA2,A2,A1,A0] */
--      if (CtrlWordNum > 7) {
--              val |= 1 << 18;
--              CtrlWordNum &= 7;
--      }
--      val |= CtrlWordNum;
-+      val |= rc_word_address_to_ctl_bits(CtrlWordNum);
- 
-       return val;
- }
- 
- static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
--                      struct DCTStatStruc *pDCTstat, u32 val)
-+                      struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
val)
- {
--      uint8_t dct = 0;
-       u32 dev = pDCTstat->dev_dct;
- 
--      if (pDCTstat->CSPresent_DCT[0] > 0) {
--              dct = 0;
--      } else if (pDCTstat->CSPresent_DCT[1] > 0 ){
--              dct = 1;
--      }
--
--      val |= Get_NB32_DCT(dev, dct, 0x7C) & ~0xFFFFFF;
-+      val |= Get_NB32_DCT(dev, dct, 0x7c) & ~0xffffff;
-       val |= 1 << SendControlWord;
--      Set_NB32_DCT(dev, dct, 0x7C, val);
-+      Set_NB32_DCT(dev, dct, 0x7c, val);
- 
-       do {
--              val = Get_NB32_DCT(dev, dct, 0x7C);
-+              val = Get_NB32_DCT(dev, dct, 0x7c);
-       } while (val & (1 << SendControlWord));
- }
- 
- void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat, u8 dct)
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct)
- {
-       u8 MrsChipSel;
-       u32 dev = pDCTstat->dev_dct;
-@@ -163,7 +236,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
-       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
-                       val = Get_NB32_DCT(dev, dct, 0xa8);
--                      val &= ~(0xF << 8);
-+                      val &= ~(0xf << 8);
- 
-                       switch (MrsChipSel) {
-                               case 0:
-@@ -184,8 +257,8 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
-                       for (cw=0; cw <=15; cw ++) {
-                               mct_Wait(1600);
-                               if (!(cw==6 || cw==7)) {
--                                      val = mct_ControlRC(pMCTstat, pDCTstat, 
MrsChipSel << 20, cw);
--                                      mct_SendCtrlWrd(pMCTstat, pDCTstat, 
val);
-+                                      val = mct_ControlRC(pMCTstat, pDCTstat, 
dct, MrsChipSel << rc_word_chip_select_lower_bit(), cw);
-+                                      mct_SendCtrlWrd(pMCTstat, pDCTstat, 
dct, val);
-                               }
-                       }
-               }
-@@ -195,7 +268,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
- }
- 
- void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
--                      struct DCTStatStruc *pDCTstat)
-+                      struct DCTStatStruc *pDCTstat, uint8_t dct)
- {
-       u32 SaveSpeed = pDCTstat->DIMMAutoSpeed;
-       u32 MrsChipSel;
-@@ -208,10 +281,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
-       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
-                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
--                      val = Get_NB32_DCT(dev, 0, 0xA8); /* TODO: dct 0 / 1 
select */
--                      val &= ~(0xFF << 8);
--                      val |= (0x3 << (MrsChipSel & 0xFE)) << 8;
--                      Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 
select */
-+                      val = Get_NB32_DCT(dev, dct, 0xa8);
-+                      val &= ~(0xff << 8);
-+                      val |= (0x3 << (MrsChipSel & 0xfe)) << 8;
-+                      Set_NB32_DCT(dev, dct, 0xa8, val);
- 
-                       /* Resend control word 10 */
-                       uint8_t freq_ctl_val = 0;
-@@ -235,21 +308,21 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
-                                       break;
-                       }
- 
--                      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: 
%02x\n", 10, freq_ctl_val);
-+                      printk(BIOS_SPEW, "Preparing to send DCT %d DIMM RC%d: 
%02x\n", dct, 10, freq_ctl_val);
- 
--                      mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 
0x40002 | rc_word_value_to_ctl_bits(freq_ctl_val));
-+                      mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, MrsChipSel << 
rc_word_chip_select_lower_bit() | rc_word_address_to_ctl_bits(10) | 
rc_word_value_to_ctl_bits(freq_ctl_val));
- 
-                       mct_Wait(1600);
- 
-                       /* Resend control word 2 */
--                      val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 
20, 2);
--                      mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
-+                      val = mct_ControlRC(pMCTstat, pDCTstat, dct, MrsChipSel 
<< rc_word_chip_select_lower_bit(), 2);
-+                      mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, val);
- 
-                       mct_Wait(1600);
- 
-                       /* Resend control word 8 */
--                      val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 
20, 8);
--                      mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
-+                      val = mct_ControlRC(pMCTstat, pDCTstat, dct, MrsChipSel 
<< rc_word_chip_select_lower_bit(), 8);
-+                      mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, val);
- 
-                       mct_Wait(1600);
-               }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index 9ccf77e..09a5f68 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -445,13 +445,13 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret;
- 
-+      /* The formula for chip select number is: CS = dimm*2+rank */
-+      uint8_t dimm = MrsChipSel / 2;
-+      uint8_t rank = MrsChipSel % 2;
-+
-       if (is_fam15h()) {
-               uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
- 
--              /* The formula for chip select number is: CS = dimm*2+rank */
--              uint8_t dimm = MrsChipSel / 2;
--              uint8_t rank = MrsChipSel % 2;
--
-               /* FIXME: These parameters should be configurable
-                * For now, err on the side of caution and enable automatic 2x 
refresh
-                * when the DDR temperature rises above the internal limits
-@@ -496,7 +496,7 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
-               ret |= ((dword >> 10) & 3) << 9;
-       }
- 
--      printk(BIOS_SPEW, "Going to send MR2 control word %08x\n", ret);
-+      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR2 control 
word %08x\n", dct, dimm, rank, ret);
- 
-       return ret;
- }
-@@ -507,6 +507,10 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret;
- 
-+      /* The formula for chip select number is: CS = dimm*2+rank */
-+      uint8_t dimm = MrsChipSel / 2;
-+      uint8_t rank = MrsChipSel % 2;
-+
-       if (is_fam15h()) {
-               ret = 0xc0000;
-               ret |= (MrsChipSel << 21);
-@@ -527,7 +531,7 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
-               ret |= (dword >> 24) & 7;
-       }
- 
--      printk(BIOS_SPEW, "Going to send MR3 control word %08x\n", ret);
-+      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR3 control 
word %08x\n", dct, dimm, rank, ret);
- 
-       return ret;
- }
-@@ -538,6 +542,10 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret;
- 
-+      /* The formula for chip select number is: CS = dimm*2+rank */
-+      uint8_t dimm = MrsChipSel / 2;
-+      uint8_t rank = MrsChipSel % 2;
-+
-       if (is_fam15h()) {
-               uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
- 
-@@ -553,10 +561,6 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
-               ret = 0x40000;
-               ret |= (MrsChipSel << 21);
- 
--              /* The formula for chip select number is: CS = dimm*2+rank */
--              uint8_t dimm = MrsChipSel / 2;
--              uint8_t rank = MrsChipSel % 2;
--
-               /* Determine if TQDS should be set */
-               if ((pDCTstat->Dimmx8Present & (1 << dimm))
-                       && (((dimm & 
0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0)
-@@ -623,7 +627,7 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
-                       ret |= 1 << 12;
-       }
- 
--      printk(BIOS_SPEW, "Going to send MR1 control word %08x\n", ret);
-+      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR1 control 
word %08x\n", dct, dimm, rank, ret);
- 
-       return ret;
- }
-@@ -634,6 +638,10 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
-       u32 dev = pDCTstat->dev_dct;
-       u32 dword, ret, dword2;
- 
-+      /* The formula for chip select number is: CS = dimm*2+rank */
-+      uint8_t dimm = MrsChipSel / 2;
-+      uint8_t rank = MrsChipSel % 2;
-+
-       if (is_fam15h()) {
-               ret = 0x00000;
-               ret |= (MrsChipSel << 21);
-@@ -744,7 +752,7 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
-               ret |= 1 << 8;
-       }
- 
--      printk(BIOS_SPEW, "Going to send MR0 control word %08x\n", ret);
-+      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR0 control 
word %08x\n", dct, dimm, rank, ret);
- 
-       return ret;
- }
-@@ -811,6 +819,16 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-               /* 8.wait 360ns */
-               mct_Wait(80);
- 
-+              /* Set up address parity */
-+              if ((pDCTstat->Status & (1 << SB_Registered))
-+                      || (pDCTstat->Status & (1 << SB_LoadReduced))) {
-+                      if (is_fam15h()) {
-+                              dword = Get_NB32_DCT(dev, dct, 0x90);
-+                              dword |= 1 << ParEn;
-+                              Set_NB32_DCT(dev, dct, 0x90, dword);
-+                      }
-+              }
-+
-               /* The following steps are performed with registered DIMMs only 
and
-                * must be done for each chip select pair */
-               if (pDCTstat->Status & (1 << SB_Registered))
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 981f467..707e6a9 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -1146,8 +1146,10 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
-       uint8_t dimm;
-       uint8_t rank;
-       uint8_t lane;
-+      uint8_t nibble;
-       uint8_t mem_clk;
-       uint16_t initial_seed;
-+      uint8_t train_both_nibbles;
-       uint16_t current_total_delay[MAX_BYTE_LANES];
-       uint16_t dqs_ret_pass1_total_delay[MAX_BYTE_LANES];
-       uint16_t rank0_current_total_delay[MAX_BYTE_LANES];
-@@ -1163,6 +1165,11 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
-       print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
-       print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
- 
-+      train_both_nibbles = 0;
-+      if (pDCTstat->Dimmx4Present)
-+              if (is_fam15h())
-+                      train_both_nibbles = 1;
-+
-       dev = pDCTstat->dev_dct;
-       index_reg = 0x98;
-       ch_start = 0;
-@@ -1245,132 +1252,148 @@ static void dqsTrainRcvrEn_SW_Fam15(struct 
MCTStatStruc *pMCTstat,
-                       else
-                               _2Ranks = 0;
-                       for (rank = 0; rank < (_2Ranks + 1); rank++) {
--                              /* 2.10.5.8.2 (1)
--                               * Specify the target DIMM to be trained
--                               * Set TrNibbleSel = 0
--                               *
--                               * TODO: Add support for x4 DIMMs
--                               */
--                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
--                              dword &= ~(0x3 << 4);           /* TrDimmSel */
--                              dword |= ((dimm & 0x3) << 4);
--                              dword &= ~(0x1 << 2);           /* TrNibbleSel 
*/
--                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
--
--                              /* 2.10.5.8.2 (2)
--                               * Retrieve gross and fine timing fields from 
write DQS registers
--                               */
--                              
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-+                              for (nibble = 0; nibble < (train_both_nibbles + 
1); nibble++) {
-+                                      /* 2.10.5.8.2 (1)
-+                                       * Specify the target DIMM and nibble 
to be trained
-+                                       */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
Channel, index_reg, 0x00000008);
-+                                      dword &= ~(0x3 << 4);           /* 
TrDimmSel = dimm */
-+                                      dword |= ((dimm & 0x3) << 4);
-+                                      dword &= ~(0x1 << 2);           /* 
TrNibbleSel = nibble */
-+                                      dword |= ((nibble & 0x1) << 2);
-+                                      Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
-+
-+                                      /* 2.10.5.8.2 (2)
-+                                       * Retrieve gross and fine timing 
fields from write DQS registers
-+                                       */
-+                                      
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
- 
--                              /* 2.10.5.8.2.1
--                               * Generate the DQS Receiver Enable Training 
Seed Values
--                               */
--                              if (Pass == FirstPass) {
--                                      initial_seed = 
fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, 
package_type);
-+                                      /* 2.10.5.8.2.1
-+                                       * Generate the DQS Receiver Enable 
Training Seed Values
-+                                       */
-+                                      if (Pass == FirstPass) {
-+                                              initial_seed = 
fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, 
package_type);
- 
--                                      /* Adjust seed for the minimum platform 
supported frequency */
--                                      initial_seed = (uint16_t) 
(((((uint64_t) initial_seed) *
--                                              fam15h_freq_tab[mem_clk] * 100) 
/ (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
-+                                              /* Adjust seed for the minimum 
platform supported frequency */
-+                                              initial_seed = (uint16_t) 
(((((uint64_t) initial_seed) *
-+                                                      
fam15h_freq_tab[mem_clk] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
- 
--                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
--                                              uint16_t wl_pass1_delay;
--                                              wl_pass1_delay = 
current_total_delay[lane];
-+                                              for (lane = 0; lane < 
MAX_BYTE_LANES; lane++) {
-+                                                      uint16_t wl_pass1_delay;
-+                                                      wl_pass1_delay = 
current_total_delay[lane];
- 
--                                              seed[lane] = initial_seed + 
wl_pass1_delay;
--                                      }
--                              } else {
--                                      uint8_t addr_prelaunch = 0;             
/* TODO: Fetch the correct value from RC2[0] */
--                                      uint16_t register_delay;
--                                      int16_t seed_prescaling;
--
--                                      memcpy(current_total_delay, 
dqs_ret_pass1_total_delay, sizeof(current_total_delay));
--                                      if ((pDCTstat->Status & (1 << 
SB_Registered))) {
--                                              if (addr_prelaunch)
--                                                      register_delay = 0x30;
--                                              else
--                                                      register_delay = 0x20;
--                                      } else if ((pDCTstat->Status & (1 << 
SB_LoadReduced))) {
--                                              /* TODO
--                                              * Load reduced DIMM support 
unimplemented
--                                              */
--                                              register_delay = 0x0;
-+                                                      seed[lane] = 
initial_seed + wl_pass1_delay;
-+                                              }
-                                       } else {
--                                              register_delay = 0x0;
-+                                              uint8_t addr_prelaunch = 0;     
        /* TODO: Fetch the correct value from RC2[0] */
-+                                              uint16_t register_delay;
-+                                              int16_t seed_prescaling;
-+
-+                                              memcpy(current_total_delay, 
dqs_ret_pass1_total_delay, sizeof(current_total_delay));
-+                                              if ((pDCTstat->Status & (1 << 
SB_Registered))) {
-+                                                      if (addr_prelaunch)
-+                                                              register_delay 
= 0x30;
-+                                                      else
-+                                                              register_delay 
= 0x20;
-+                                              } else if ((pDCTstat->Status & 
(1 << SB_LoadReduced))) {
-+                                                      /* TODO
-+                                                       * Load reduced DIMM 
support unimplemented
-+                                                       */
-+                                                      register_delay = 0x0;
-+                                              } else {
-+                                                      register_delay = 0x0;
-+                                              }
-+
-+                                              for (lane = 0; lane < 
MAX_BYTE_LANES; lane++) {
-+                                                      seed_prescaling = 
current_total_delay[lane] - register_delay - 0x20;
-+                                                      seed[lane] = (uint16_t) 
(register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 
100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
-+                                              }
-                                       }
- 
-                                       for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
--                                              seed_prescaling = 
current_total_delay[lane] - register_delay - 0x20;
--                                              seed[lane] = (uint16_t) 
(register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 
100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
--                                      }
--                              }
-+                                              seed_gross[lane] = (seed[lane] 
>> 5) & 0x1f;
-+                                              seed_fine[lane] = seed[lane] & 
0x1f;
- 
--                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
--                                      seed_gross[lane] = (seed[lane] >> 5) & 
0x1f;
--                                      seed_fine[lane] = seed[lane] & 0x1f;
-+                                              /*if (seed_gross[lane] == 0)
-+                                                      seed_pre_gross[lane] = 
0;
-+                                              else */if (seed_gross[lane] & 
0x1)
-+                                                      seed_pre_gross[lane] = 
1;
-+                                              else
-+                                                      seed_pre_gross[lane] = 
2;
- 
--                                      /*if (seed_gross[lane] == 0)
--                                              seed_pre_gross[lane] = 0;
--                                      else */if (seed_gross[lane] & 0x1)
--                                              seed_pre_gross[lane] = 1;
--                                      else
--                                              seed_pre_gross[lane] = 2;
-+                                              /* Calculate phase recovery 
delays */
-+                                              phase_recovery_delays[lane] = 
((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
- 
--                                      /* Calculate phase recovery delays */
--                                      phase_recovery_delays[lane] = 
((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
-+                                              /* Set the gross delay.
-+                                              * NOTE: While the BKDG states 
to only program DqsRcvEnGrossDelay, this appears
-+                                              * to have been a misprint as 
DqsRcvEnFineDelay should be set to zero as well.
-+                                              */
-+                                              current_total_delay[lane] = 
((seed_gross[lane] & 0x1f) << 5);
-+                                      }
- 
--                                      /* Set the gross delay.
--                                       * NOTE: While the BKDG states to only 
program DqsRcvEnGrossDelay, this appears
--                                       * to have been a misprint as 
DqsRcvEnFineDelay should be set to zero as well.
-+                                      /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
-+                                       * Program PhRecFineDly and 
PhRecGrossDly
-                                        */
--                                      current_total_delay[lane] = 
((seed_gross[lane] & 0x1f) << 5);
--                              }
-+                                      
write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, 
Channel, dimm, index_reg);
- 
--                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
--                               * Program PhRecFineDly and PhRecGrossDly
--                               */
--                              
write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, 
Channel, dimm, index_reg);
-+                                      /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
-+                                       * Program the DQS Receiver Enable 
delay values for each lane
-+                                       */
-+                                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
- 
--                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
--                               * Program the DQS Receiver Enable delay values 
for each lane
--                               */
--                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-+                                      /* 2.10.5.8.2 (3)
-+                                       * Program DqsRcvTrEn = 1
-+                                       */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
Channel, index_reg, 0x00000008);
-+                                      dword |= (0x1 << 13);
-+                                      Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
- 
--                              /* 2.10.5.8.2 (3)
--                               * Program DqsRcvTrEn = 1
--                               */
--                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
--                              dword |= (0x1 << 13);
--                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
-+                                      /* 2.10.5.8.2 (4)
-+                                       * Issue 192 read requests to the 
target rank
-+                                       */
-+                                      
generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, Receiver + (rank & 0x1));
- 
--                              /* 2.10.5.8.2 (4)
--                               * Issue 192 read requests to the target rank
--                               */
--                              
generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, Receiver + (rank & 0x1));
-+                                      /* 2.10.5.8.2 (5)
-+                                       * Program DqsRcvTrEn = 0
-+                                       */
-+                                      dword = Get_NB32_index_wait_DCT(dev, 
Channel, index_reg, 0x00000008);
-+                                      dword &= ~(0x1 << 13);
-+                                      Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
- 
--                              /* 2.10.5.8.2 (5)
--                               * Program DqsRcvTrEn = 0
--                               */
--                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
--                              dword &= ~(0x1 << 13);
--                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
-+                                      /* 2.10.5.8.2 (6)
-+                                       * Read PhRecGrossDly, PhRecFineDly
-+                                       */
-+                                      
read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, 
dimm, index_reg);
- 
--                              /* 2.10.5.8.2 (6)
--                               * Read PhRecGrossDly, PhRecFineDly
--                               */
--                              
read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, 
dimm, index_reg);
-+                                      /* 2.10.5.8.2 (7)
-+                                       * Calculate and program the DQS 
Receiver Enable delay values
-+                                       */
-+                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
-+                                              current_total_delay[lane] = 
(phase_recovery_delays[lane] & 0x1f);
-+                                              current_total_delay[lane] |= 
((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - 
seed_pre_gross[lane] + 1) << 5);
-+                                              if (nibble == 0) {
-+                                                      if (lane == 8)
-+                                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
-+                                                      else
-+                                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
-+                                              } else {
-+                                                      /* 2.10.5.8.2 (1)
-+                                                       * Average the trained 
values of both nibbles on x4 DIMMs
-+                                                       */
-+                                                      if (lane == 8)
-+                                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = 
(pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] + current_total_delay[lane]) / 2;
-+                                                      else
-+                                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = 
(pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] + current_total_delay[lane]) / 2;
-+                                              }
-+                                      }
- 
--                              /* 2.10.5.8.2 (7)
--                               * Calculate and program the DQS Receiver 
Enable delay values
--                               */
--                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
--                                      current_total_delay[lane] = 
(phase_recovery_delays[lane] & 0x1f);
--                                      current_total_delay[lane] |= 
((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - 
seed_pre_gross[lane] + 1) << 5);
--                                      if (lane == 8)
--                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
--                                      else
--                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
-+#if DQS_TRAIN_DEBUG > 1
-+                                      for (lane = 0; lane < 8; lane++)
-+                                              printk(BIOS_DEBUG, 
"\t\tTrainRcvEn55: Channel: %d dimm: %d nibble: %d lane %d current_total_delay: 
%04x CH_D_B_RCVRDLY: %04x\n",
-+                                                      Channel, dimm, nibble, 
lane, current_total_delay[lane], pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane]);
-+#endif
-+                                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-                               }
--                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
- 
-                               if (rank == 0) {
-                                       /* Back up the Rank 0 delays for later 
use */
-@@ -1395,7 +1418,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
- 
- #if DQS_TRAIN_DEBUG > 0
-                       for (lane = 0; lane < 8; lane++)
--                              print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
-+                              print_debug_dqs_pair("\t\tTrainRcvEn56: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
- #endif
-               }
-       }
-@@ -1815,15 +1838,23 @@ void mctSetEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
- }
- 
- void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat,
--                      struct DCTStatStruc *pDCTstatA)
-+                      struct DCTStatStruc *pDCTstatA, int16_t 
single_node_number)
- {
-       u8 Node = 0;
-       struct DCTStatStruc *pDCTstat;
- 
-       printk(BIOS_DEBUG, "%s: Start\n", __func__);
- 
-+      uint8_t start_node = 0;
-+      uint8_t end_node = MAX_NODES_SUPPORTED;
-+
-+      if (single_node_number >= 0) {
-+              start_node = single_node_number;
-+              end_node = single_node_number;
-+      }
-+
-       /* FIXME: skip for Ax */
--      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-+      for (Node = start_node; Node < end_node; Node++) {
-               pDCTstat = pDCTstatA + Node;
-               if (!pDCTstat->NodePresent)
-                       continue;
-@@ -1847,6 +1878,8 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
-                                       if (!pDCTstat->DIMMValidDCT[dct])
-                                               continue;
- 
-+                                      printk(BIOS_SPEW, "%s: training node %d 
DCT %d\n", __func__, Node, dct);
-+
-                                       /* Back up D18F2x9C_x0000_0004_dct[1:0] 
*/
-                                       datc_backup = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004);
- 
-@@ -1985,6 +2018,8 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
- 
-                                       /* Restore D18F2x9C_x0000_0004_dct[1:0] 
*/
-                                       Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000004, datc_backup);
-+
-+                                      printk(BIOS_SPEW, "%s: done training 
node %d DCT %d\n", __func__, Node, dct);
-                               }
-                       } else {
-                               fenceDynTraining_D(pMCTstat, pDCTstat, 0);
-@@ -1997,7 +2032,7 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
- }
- 
- static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
--                      struct DCTStatStruc *pDCTstat, u8 dct)
-+                      struct DCTStatStruc *pDCTstat, uint8_t dct)
- {
-       u16 avRecValue;
-       u32 val;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-index 6b63ba0..3153e46 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-@@ -19,7 +19,7 @@
-  */
- 
- static void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
--                      struct DCTStatStruc *pDCTstat);
-+                      struct DCTStatStruc *pDCTstat, uint8_t dct);
- 
- 
- static void AgesaDelay(u32 msec)
-@@ -353,11 +353,14 @@ static void ExitSelfRefresh(struct MCTStatStruc 
*pMCTstat,
- }
- 
- void SetTargetFreq(struct MCTStatStruc *pMCTstat,
--                                      struct DCTStatStruc *pDCTstat)
-+                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Node)
- {
-       uint32_t dword;
-       uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
- 
-+      struct DCTStatStruc *pDCTstat;
-+      pDCTstat = pDCTstatA + Node;
-+
-       if (is_fam15h()) {
-               /* Program F2x[1, 0]90[DisDllShutDownSR]=1. */
-               if (pDCTstat->DIMMValidDCT[0]) {
-@@ -391,7 +394,7 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
-               uint8_t dct;
-               for (dct = 0; dct < 2; dct++) {
-                       if (pDCTstat->DIMMValidDCT[dct]) {
--                              phyAssistedMemFnceTraining(pMCTstat, pDCTstat);
-+                              phyAssistedMemFnceTraining(pMCTstat, pDCTstatA, 
Node);
-                               InitPhyCompensation(pMCTstat, pDCTstat, dct);
-                       }
-               }
-@@ -438,7 +441,12 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
-               else
-                       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[1];
- 
--              FreqChgCtrlWrd(pMCTstat, pDCTstat);
-+              if (pDCTstat->DIMMValidDCT[0]) {
-+                      FreqChgCtrlWrd(pMCTstat, pDCTstat, 0);
-+              }
-+              if (pDCTstat->DIMMValidDCT[1]) {
-+                      FreqChgCtrlWrd(pMCTstat, pDCTstat, 1);
-+              }
-       }
- }
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index e5e4031..73b231e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -35,9 +35,9 @@ u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint32_t MRSValue);
- void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
-       u8 dct, u8 dimm, BOOL wl);
- void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm);
--void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass);
-+void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble);
- void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, u8 targetAddr, uint8_t pass);
--void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass);
-+void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass, uint8_t nibble);
- 
- static int32_t abs(int32_t val) {
-       if (val < 0)
-@@ -76,6 +76,8 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
- {
-       u8 ByteLane;
-       u32 Value, Addr;
-+      uint8_t nibble = 0;
-+      uint8_t train_both_nibbles;
-       u16 Addl_Data_Offset, Addl_Data_Port;
-       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-@@ -88,98 +90,108 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
-                       DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
-                       TrDimmSelEnd, (u32)dimm);
- 
--      if (is_fam15h()) {
--              /* Set TrNibbleSel = 0
--               *
--               * TODO: Add support for x4 DIMMs
--               */
--              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
--                              DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
--                              2, (u32)0);
--      }
-+      train_both_nibbles = 0;
-+      if (pDCTstat->Dimmx4Present)
-+              if (is_fam15h())
-+                      train_both_nibbles = 1;
- 
--      /* 2. Prepare the DIMMs for write levelization using DDR3-defined
--       * MR commands. */
--      prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
-+      for (nibble = 0; nibble < (train_both_nibbles + 1); nibble++) {
-+              printk(BIOS_SPEW, "AgesaHwWlPhase1: training nibble %d\n", 
nibble);
- 
--      /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
--       *    satisfy DDR3-defined internal DRAM timing.
--       */
--      if (is_fam15h())
--              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
--      else
--              pMCTData->AgesaDelay(40);
-+              if (is_fam15h()) {
-+                      /* Program F2x[1, 0]9C_x08[WrtLvTrEn]=0 */
-+                      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, 
FUN_DCT,
-+                                      DRAM_ADD_DCT_PHY_CONTROL_REG, 
WrtLvTrEn, WrtLvTrEn, 0);
-+
-+                      /* Set TrNibbleSel */
-+                      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, 
FUN_DCT,
-+                                      DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
-+                                      2, (uint32_t)nibble);
-+              }
- 
--      /* 4. Configure the processor's DDR phy for write levelization 
training: */
--      procConfig(pMCTstat, pDCTstat, dct, dimm, pass);
-+              /* 2. Prepare the DIMMs for write levelization using 
DDR3-defined
-+               * MR commands. */
-+              prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
- 
--      /* 5. Begin write levelization training:
--       *  Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
--      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL))
--      {
--              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
--                              DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, 
WrtLvTrEn, 1);
--      }
--      else
--      {
--              /* Broadcast write to all D3Dbyte chipset register offset 0xc
--               * Set bit 0 (wrTrain)
--               * Program bit 4 to nibble being trained (only matters for 
x4dimms)
--               * retain value of 3:2 (Trdimmsel)
--               * reset bit 5 (FrzPR)
-+              /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
-+               *    satisfy DDR3-defined internal DRAM timing.
-                */
--              if (dct)
-+              if (is_fam15h())
-+                      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
-+              else
-+                      pMCTData->AgesaDelay(40);
-+
-+              /* 4. Configure the processor's DDR phy for write levelization 
training: */
-+              procConfig(pMCTstat, pDCTstat, dct, dimm, pass, nibble);
-+
-+              /* 5. Begin write levelization training:
-+               *  Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
-+              if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | 
AMD_FAM15_ALL))
-               {
--                      Addl_Data_Offset=0x198;
--                      Addl_Data_Port=0x19C;
-+                      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, 
FUN_DCT,
-+                                      DRAM_ADD_DCT_PHY_CONTROL_REG, 
WrtLvTrEn, WrtLvTrEn, 1);
-               }
-               else
-               {
--                      Addl_Data_Offset=0x98;
--                      Addl_Data_Port=0x9C;
-+                      /* Broadcast write to all D3Dbyte chipset register 
offset 0xc
-+                       * Set bit 0 (wrTrain)
-+                       * Program bit 4 to nibble being trained (only matters 
for x4dimms)
-+                       * retain value of 3:2 (Trdimmsel)
-+                       * reset bit 5 (FrzPR)
-+                       */
-+                      if (dct)
-+                      {
-+                              Addl_Data_Offset=0x198;
-+                              Addl_Data_Port=0x19C;
-+                      }
-+                      else
-+                      {
-+                              Addl_Data_Offset=0x98;
-+                              Addl_Data_Port=0x9C;
-+                      }
-+                      Addr=0x0D00000C;
-+                      
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
-+                      while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, 
FUN_DCT, Addl_Data_Offset,
-+                                      DctAccessDone, DctAccessDone)) == 0);
-+                      
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 
31, 0, &Value);
-+                      Value = bitTestSet(Value, 0);   /* enable WL training */
-+                      Value = bitTestReset(Value, 4); /* for x8 only */
-+                      Value = bitTestReset(Value, 5); /* for hardware WL 
training */
-+                      
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port),
 31, 0, &Value);
-+                      Addr=0x4D030F0C;
-+                      
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
-+                      while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, 
FUN_DCT, Addl_Data_Offset,
-+                                      DctAccessDone, DctAccessDone)) == 0);
-               }
--              Addr=0x0D00000C;
--              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
--              while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, 
Addl_Data_Offset,
--                              DctAccessDone, DctAccessDone)) == 0);
--              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 
31, 0, &Value);
--              Value = bitTestSet(Value, 0);   /* enable WL training */
--              Value = bitTestReset(Value, 4); /* for x8 only */
--              Value = bitTestReset(Value, 5); /* for hardware WL training */
--              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port),
 31, 0, &Value);
--              Addr=0x4D030F0C;
--              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
--              while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, 
Addl_Data_Offset,
--                              DctAccessDone, DctAccessDone)) == 0);
--      }
- 
--      if (is_fam15h())
--              proc_MFENCE();
-+              if (is_fam15h())
-+                      proc_MFENCE();
- 
--      /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
--      if (is_fam15h())
--              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 200);
--      else
--              pMCTData->AgesaDelay(140);
-+              /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
-+              if (is_fam15h())
-+                      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 
200);
-+              else
-+                      pMCTData->AgesaDelay(140);
- 
--      /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
--      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
--                      DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
-+              /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
-+              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-+                              DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, 
WrtLvTrEn, 0);
- 
--      /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
--       * to get the gross and fine delay settings
--       * for the target DIMM and save these values. */
--      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
--              getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass);
--      }
-+              /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
-+               * to get the gross and fine delay settings
-+               * for the target DIMM and save these values. */
-+              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-+                      getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, 
nibble);
-+              }
- 
--      pDCTData->WLCriticalGrossDelayPrevPass = 0x1f;
-+              pDCTData->WLCriticalGrossDelayPrevPass = 0x0;
-+      }
- 
-       return 0;
- }
- 
- uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
--              u8 dct, u8 dimm, u8 pass)
-+              uint8_t dct, uint8_t dimm, uint8_t pass)
- {
-       u8 ByteLane;
-       uint8_t status = 0;
-@@ -190,6 +202,12 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
-               int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
-               uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
- 
-+              printk(BIOS_SPEW, "\toriginal critical gross delay: %d\n", cgd);
-+
-+              /* FIXME
-+               * For now, disable CGD adjustment as it seems to interfere 
with registered DIMM training
-+               */
-+
-               /* Calculate the Critical Gross Delay */
-               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
-                       /* Calculate the gross delay differential for this lane 
*/
-@@ -205,6 +223,8 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
-                               cgd = gross_diff[ByteLane];
-               }
- 
-+              printk(BIOS_SPEW, "\tnew critical gross delay: %d\n", cgd);
-+
-               pDCTData->WLCriticalGrossDelayPrevPass = cgd;
- 
-               if (pDCTstat->Speed != pDCTstat->TargetFreq) {
-@@ -281,7 +301,7 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
-                               gross_diff[ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane] + 
pDCTData->WLGrossDelay[index+ByteLane];
-                               gross_diff[ByteLane] -= 
pDCTData->WLSeedPreGrossDelay[index+ByteLane];
- 
--                              /* Prevent underflow in the presence of noise / 
instability*/
-+                              /* Prevent underflow in the presence of noise / 
instability */
-                               if (gross_diff[ByteLane] < cgd)
-                                       gross_diff[ByteLane] = cgd;
- 
-@@ -289,7 +309,8 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
-                       }
-               } else {
-                       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
--                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= 0 */
-+                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= pDCTData->WrDqsGrossDlyBaseOffset */
-+                      dword |= ((pDCTData->WrDqsGrossDlyBaseOffset & 0x3) << 
24);
-                       Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
-               }
-       }
-@@ -959,7 +980,7 @@ static uint16_t fam15h_next_lowest_memclk_freq(uint16_t 
memclk_freq)
- #endif
- 
- 
/*-----------------------------------------------------------------------------
-- * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
-+ * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass, 
u8 Nibble)
-  *
-  *  Description:
-  *       This function programs the ODT values for the NB
-@@ -972,13 +993,14 @@ static uint16_t fam15h_next_lowest_memclk_freq(uint16_t 
memclk_freq)
-  *       OUT
-  * 
----------------------------------------------------------------------------
-  */
--void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass)
-+void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble)
- {
-       u8 ByteLane, MemClkFreq;
-       int32_t Seed_Gross;
-       int32_t Seed_Fine;
-       uint8_t Seed_PreGross;
-       u32 Value, Addr;
-+      uint32_t dword;
-       u16 Addl_Data_Offset, Addl_Data_Port;
-       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-@@ -1048,10 +1070,17 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-                       uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
-                       uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
-                       uint16_t Seed_Total = 0;
-+                      pDCTData->WrDqsGrossDlyBaseOffset = 0x0;
-                       if (package_type == PT_GR) {
-                               /* Socket G34: Fam15h BKDG v3.14 Table 96 */
-                               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                      /* TODO
-+                                       * Implement mainboard-specific seed and
-+                                       * WrDqsGrossDly base overrides.
-+                                       * 0x41 and 0x0 are the "stock" values
-+                                       */
-                                       Seed_Total = 0x41;
-+                                      pDCTData->WrDqsGrossDlyBaseOffset = 0x2;
-                               } else if 
(pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
-                                       Seed_Total = 0x0;
-                               } else {
-@@ -1133,15 +1162,16 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-                       printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", 
ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
-               }
-       } else {
--              /* Pass 2 */
--              /* From BKDG, Write Leveling Seed Value. */
--              if (is_fam15h()) {
--                      uint32_t RegisterDelay;
--                      int32_t SeedTotal;
--                      int32_t SeedTotalPreScaling;
--                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
-+              if (nibble == 0) {
-+                      /* Pass 2 */
-+                      /* From BKDG, Write Leveling Seed Value. */
-+                      if (is_fam15h()) {
-+                              uint32_t RegisterDelay;
-+                              int32_t SeedTotal[MAX_BYTE_LANES];
-+                              int32_t SeedTotalPreScaling[MAX_BYTE_LANES];
-+                              uint32_t WrDqDqsEarly;
-+                              uint8_t AddrCmdPrelaunch = 0;           /* 
TODO: Fetch the correct value from RC2[0] */
- 
--                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-                               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
-                                       if (AddrCmdPrelaunch)
-                                               RegisterDelay = 0x30;
-@@ -1150,84 +1180,133 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-                               } else {
-                                       RegisterDelay = 0;
-                               }
-+
-                               /* Retrieve WrDqDqsEarly */
--                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId), FUN_DCT, 0xa8), 25, 24, 
&Value);
-+                              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
0xa8);
-+                              WrDqDqsEarly = (dword >> 24) & 0x3;
- 
--                              /* Calculate adjusted seed values */
--                              SeedTotal = 
(pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
--                                      
((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5);
--                              SeedTotalPreScaling = (SeedTotal - 
RegisterDelay - (0x20 * Value));
--                              SeedTotal = (int32_t) (RegisterDelay + 
((((int64_t) SeedTotalPreScaling) *
--                                      fam15h_freq_tab[MemClkFreq] * 100) / 
(fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
-+                              /* FIXME
-+                               * Ignore WrDqDqsEarly for now to work around 
training issues
-+                               */
-+                              WrDqDqsEarly = 0;
- 
--                              if (SeedTotal >= 0) {
--                                      Seed_Gross = SeedTotal / 32;
--                                      Seed_Fine = SeedTotal % 32;
--                              } else {
--                                      Seed_Gross = (SeedTotal / 32) - 1;
--                                      Seed_Fine = (SeedTotal % 32) + 32;
-+                              /* Generate new seed values */
-+                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                                      /* Calculate adjusted seed values */
-+                                      SeedTotal[ByteLane] = 
(pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
-+                                              
((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5);
-+                                      SeedTotalPreScaling[ByteLane] = 
(SeedTotal[ByteLane] - RegisterDelay - (0x20 * WrDqDqsEarly));
-+                                      SeedTotal[ByteLane] = (int32_t) 
(RegisterDelay + ((((int64_t) SeedTotalPreScaling[ByteLane]) *
-+                                              fam15h_freq_tab[MemClkFreq] * 
100) / (fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
-                               }
- 
--                              if (Seed_Gross == 0)
--                                      Seed_PreGross = 0;
--                              else if (Seed_Gross & 0x1)
--                                      Seed_PreGross = 1;
--                              else
--                                      Seed_PreGross = 2;
-+                              /* Generate register values from seeds */
-+                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                                      printk(BIOS_SPEW, "\tLane %02x scaled 
delay: %04x\n", ByteLane, SeedTotal[ByteLane]);
- 
--                              /* Save seed values for later use */
--                              
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
--                              
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
--                              
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-+                                      if (SeedTotal[ByteLane] >= 0) {
-+                                              Seed_Gross = 
SeedTotal[ByteLane] / 32;
-+                                              Seed_Fine = SeedTotal[ByteLane] 
% 32;
-+                                      } else {
-+                                              Seed_Gross = 
(SeedTotal[ByteLane] / 32) - 1;
-+                                              Seed_Fine = 
(SeedTotal[ByteLane] % 32) + 32;
-+                                      }
- 
--                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
--                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+                                      if (Seed_Gross == 0)
-+                                              Seed_PreGross = 0;
-+                                      else if (Seed_Gross & 0x1)
-+                                              Seed_PreGross = 1;
-+                                      else
-+                                              Seed_PreGross = 2;
- 
--                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
--                      }
--              } else {
--                      uint32_t RegisterDelay;
--                      uint32_t SeedTotalPreScaling;
--                      uint32_t SeedTotal;
--                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
--                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
--                      {
--                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
--                                      if (AddrCmdPrelaunch == 0)
--                                              RegisterDelay = 0x20;
-+                                      /* The BKDG-recommended algorithm 
causes problems with registered DIMMs on some systems
-+                                       * due to the long register delays 
causing premature total delay wrap-around.
-+                                       * Attempt to work around this...
-+                                       */
-+                                      Seed_PreGross = Seed_Gross;
-+
-+                                      /* Save seed values for later use */
-+                                      
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
-+                                      
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+                                      
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-+
-+                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
-+                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+
-+                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
-+                              }
-+                      } else {
-+                              uint32_t RegisterDelay;
-+                              uint32_t SeedTotalPreScaling;
-+                              uint32_t SeedTotal;
-+                              uint8_t AddrCmdPrelaunch = 0;           /* 
TODO: Fetch the correct value from RC2[0] */
-+                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
-+                              {
-+                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED]) {
-+                                              if (AddrCmdPrelaunch == 0)
-+                                                      RegisterDelay = 0x20;
-+                                              else
-+                                                      RegisterDelay = 0x30;
-+                                      } else {
-+                                              RegisterDelay = 0;
-+                                      }
-+                                      SeedTotalPreScaling = 
((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
-+                                              
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay;
-+                                      /* SeedTotalPreScaling = (the total 
delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
-+                                      training) - RegisterDelay. */
-+                                      SeedTotal = (uint16_t) ((((uint64_t) 
SeedTotalPreScaling) *
-+                                                                              
fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 100));
-+                                      Seed_Gross = SeedTotal / 32;
-+                                      Seed_Fine = SeedTotal & 0x1f;
-+                                      if (Seed_Gross == 0)
-+                                              Seed_Gross = 0;
-+                                      else if (Seed_Gross & 0x1)
-+                                              Seed_Gross = 1;
-                                       else
--                                              RegisterDelay = 0x30;
--                              } else {
--                                      RegisterDelay = 0;
-+                                              Seed_Gross = 2;
-+
-+                                      /* The BKDG-recommended algorithm 
causes problems with registered DIMMs on some systems
-+                                      * due to the long register delays 
causing premature total delay wrap-around.
-+                                      * Attempt to work around this...
-+                                      */
-+                                      SeedTotal = ((Seed_Gross & 0x1f) << 5) 
| (Seed_Fine & 0x1f);
-+                                      SeedTotal += RegisterDelay;
-+                                      Seed_Gross = SeedTotal / 32;
-+                                      Seed_Fine = SeedTotal & 0x1f;
-+
-+                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
-+                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+
-+                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
-                               }
--                              SeedTotalPreScaling = 
((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
--                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay;
--                              /* SeedTotalPreScaling = (the total delay value 
in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
--                              training) - RegisterDelay. */
--                              SeedTotal = (uint16_t) ((((uint64_t) 
SeedTotalPreScaling) *
--                                                                      
fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 100));
--                              Seed_Gross = SeedTotal / 32;
--                              Seed_Fine = SeedTotal & 0x1f;
--                              if (Seed_Gross == 0)
--                                      Seed_Gross = 0;
--                              else if (Seed_Gross & 0x1)
--                                      Seed_Gross = 1;
--                              else
--                                      Seed_Gross = 2;
-+                      }
- 
--                              /* The BKDG-recommended algorithm causes 
problems with registered DIMMs on some systems
--                               * due to the long register delays causing 
premature total delay wrap-around.
--                               * Attempt to work around this...
--                               */
--                              SeedTotal = ((Seed_Gross & 0x1f) << 5) | 
(Seed_Fine & 0x1f);
--                              SeedTotal += RegisterDelay;
--                              Seed_Gross = SeedTotal / 32;
--                              Seed_Fine = SeedTotal & 0x1f;
-+                      /* Save initial seeds for upper nibble pass */
-+                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                              
pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane];
-+                              
pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane];
-+                              
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane];
-+                      }
-+              } else {
-+                      /* Restore seed values from lower nibble pass */
-+                      if (is_fam15h()) {
-+                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                                      
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
-+                                      
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
-+                                      
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
- 
--                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
--                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
-+                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
-+                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
- 
--                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
-+                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
-+                              }
-+                      } else {
-+                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
-+                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
-+                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
-+
-+                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
-+                              }
-                       }
-               }
-       }
-@@ -1358,7 +1437,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
- }
- 
- 
/*-----------------------------------------------------------------------------
-- *  void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm)
-+ *  void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm, u8 Nibble)
-  *
-  *  Description:
-  *       This function reads the write levelization byte delay from the Phase
-@@ -1376,7 +1455,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
-  *
-  
*-----------------------------------------------------------------------------
-  */
--void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass)
-+void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass, uint8_t nibble)
- {
-       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, 
index;
-@@ -1427,7 +1506,16 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
-                       fine = 0;
-               }
-       }
--      pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
--      pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
--      printk(BIOS_SPEW, "\tLane %02x final adjusted value: %04x\n", ByteLane, 
((gross & 0x1f) << 5) | (fine & 0x1f));
-+      if (nibble == 0) {
-+              pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)fine;
-+              pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)gross;
-+      } else {
-+              uint32_t WLTotalDelay = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
-+              WLTotalDelay += ((gross & 0x1f) << 5) | (fine & 0x1f);
-+              WLTotalDelay /= 2;
-+              pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)(WLTotalDelay 
& 0x1f);
-+              pDCTData->WLGrossDelay[index+ByteLane] = 
(uint8_t)((WLTotalDelay >> 5) & 0x1f);
-+      }
-+
-+      printk(BIOS_SPEW, "\tLane %02x adjusted value: %04x\n", ByteLane, 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f));
- }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-index 12e7c4a..3337c14 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
-@@ -119,16 +119,21 @@ typedef struct _sDCTStruct
-       u8 DctTrain;                    /* Current DCT being trained */
-       u8 CurrDct;                     /* Current DCT number (0 or 1) */
-       u8 DctCSPresent;                /* Current DCT CS mapping */
-+      uint8_t WrDqsGrossDlyBaseOffset;
-       int32_t WLSeedGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];    /* Write 
Levelization Seed Gross Delay */
-                                                               /* per byte 
Lane Per Logical DIMM*/
-       int32_t WLSeedFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write 
Levelization Seed Fine Delay */
-                                                               /* per byte 
Lane Per Logical DIMM*/
-       int32_t WLSeedPreGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write 
Levelization Seed Pre-Gross Delay */
-                                                               /* per byte 
Lane Per Logical DIMM*/
--      u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write Levelization 
Gross Delay */
--                                                      /* per byte Lane Per 
Logical DIMM*/
--      u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];      /* Write Levelization 
Fine Delay */
--                                                      /* per byte Lane Per 
Logical DIMM*/
-+      uint8_t WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*MAX_LDIMMS];
-+      uint8_t WLSeedGrossPrevNibble[MAX_BYTE_LANES*MAX_LDIMMS];
-+      uint8_t WLSeedFinePrevNibble[MAX_BYTE_LANES*MAX_LDIMMS];
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];             /* Write 
Levelization Gross Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-+      u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];              /* Write 
Levelization Fine Delay */
-+                                                              /* per byte 
Lane Per Logical DIMM*/
-       u8 WLGrossDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];    /* First-Pass 
Write Levelization Gross Delay */
-                                                               /* per byte 
Lane Per Logical DIMM*/
-       u8 WLFineDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* First-Pass 
Write Levelization Fine Delay */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0087-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
 
b/resources/libreboot/patch/kgpe-d16/0087-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
deleted file mode 100644
index 2037f44..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0087-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
+++ /dev/null
@@ -1,1931 +0,0 @@
-From 0489e5c40921fd2ec7c7b5adb7ae69d180af8f9c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 30 Jul 2015 14:07:15 -0500
-Subject: [PATCH 087/139] cpu/amd/family_10h-family_15h: Fix Family 15h
- multiple package support
-
-TEST: Booted ASUS KGPE-D16 with two Opteron 6328 processors
-and several different RDIMM configurations.
-
-Change-Id: I171197c90f72d3496a385465937b7666cbf7e308
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/car/cache_as_ram.inc                   |  17 ++-
- src/cpu/amd/family_10h-family_15h/defaults.h       | 101 +++++++++++++--
- src/cpu/amd/family_10h-family_15h/fidvid.c         |  81 ++++++------
- src/cpu/amd/family_10h-family_15h/init_cpus.c      |  66 +++++++++-
- src/cpu/amd/quadcore/quadcore.c                    |  19 +--
- src/cpu/amd/quadcore/quadcore_id.c                 |   1 -
- src/mainboard/advansus/a785e-i/romstage.c          |   2 +-
- src/mainboard/amd/bimini_fam10/romstage.c          |   2 +-
- src/mainboard/amd/dbm690t/romstage.c               |   2 +-
- src/mainboard/amd/mahogany/romstage.c              |   2 +-
- src/mainboard/amd/mahogany_fam10/romstage.c        |   2 +-
- src/mainboard/amd/pistachio/romstage.c             |   2 +-
- src/mainboard/amd/serengeti_cheetah/romstage.c     |   2 +-
- .../amd/serengeti_cheetah_fam10/romstage.c         |   2 +-
- src/mainboard/amd/tilapia_fam10/romstage.c         |   2 +-
- src/mainboard/arima/hdama/romstage.c               |   2 +-
- src/mainboard/asrock/939a785gmh/romstage.c         |   2 +-
- src/mainboard/asus/a8n_e/romstage.c                |   2 +-
- src/mainboard/asus/a8v-e_deluxe/romstage.c         |   2 +-
- src/mainboard/asus/a8v-e_se/romstage.c             |   2 +-
- src/mainboard/asus/k8v-x/romstage.c                |   2 +-
- src/mainboard/asus/kfsn4-dre/romstage.c            |   2 +-
- src/mainboard/asus/kgpe-d16/romstage.c             |  46 +++++--
- src/mainboard/asus/m2n-e/romstage.c                |   2 +-
- src/mainboard/asus/m2v-mx_se/romstage.c            |   2 +-
- src/mainboard/asus/m2v/romstage.c                  |   2 +-
- src/mainboard/asus/m4a78-em/romstage.c             |   2 +-
- src/mainboard/asus/m4a785-m/romstage.c             |   2 +-
- src/mainboard/asus/m5a88-v/romstage.c              |   2 +-
- src/mainboard/avalue/eax-785e/romstage.c           |   2 +-
- src/mainboard/broadcom/blast/romstage.c            |   2 +-
- src/mainboard/gigabyte/ga_2761gxdk/romstage.c      |   2 +-
- src/mainboard/gigabyte/m57sli/romstage.c           |   2 +-
- src/mainboard/gigabyte/ma785gm/romstage.c          |   2 +-
- src/mainboard/gigabyte/ma785gmt/romstage.c         |   2 +-
- src/mainboard/gigabyte/ma78gm/romstage.c           |   2 +-
- src/mainboard/hp/dl145_g1/romstage.c               |   2 +-
- src/mainboard/hp/dl145_g3/romstage.c               |   2 +-
- src/mainboard/hp/dl165_g6_fam10/romstage.c         |   2 +-
- src/mainboard/ibm/e325/romstage.c                  |   2 +-
- src/mainboard/ibm/e326/romstage.c                  |   2 +-
- src/mainboard/iei/kino-780am2-fam10/romstage.c     |   2 +-
- src/mainboard/iwill/dk8_htx/romstage.c             |   2 +-
- src/mainboard/iwill/dk8s2/romstage.c               |   2 +-
- src/mainboard/iwill/dk8x/romstage.c                |   2 +-
- src/mainboard/jetway/pa78vm5/romstage.c            |   2 +-
- src/mainboard/kontron/kt690/romstage.c             |   2 +-
- src/mainboard/msi/ms7135/romstage.c                |   2 +-
- src/mainboard/msi/ms7260/romstage.c                |   2 +-
- src/mainboard/msi/ms9185/romstage.c                |   2 +-
- src/mainboard/msi/ms9282/romstage.c                |   2 +-
- src/mainboard/msi/ms9652_fam10/romstage.c          |   2 +-
- src/mainboard/newisys/khepri/romstage.c            |   2 +-
- src/mainboard/nvidia/l1_2pvv/romstage.c            |   2 +-
- src/mainboard/siemens/sitemp_g1p1/romstage.c       |   2 +-
- src/mainboard/sunw/ultra40/romstage.c              |   2 +-
- src/mainboard/supermicro/h8dme/romstage.c          |   2 +-
- src/mainboard/supermicro/h8dmr/romstage.c          |   2 +-
- src/mainboard/supermicro/h8dmr_fam10/romstage.c    |   2 +-
- src/mainboard/supermicro/h8qme_fam10/romstage.c    |   2 +-
- src/mainboard/supermicro/h8scm_fam10/romstage.c    |   2 +-
- src/mainboard/technexion/tim5690/romstage.c        |   2 +-
- src/mainboard/technexion/tim8690/romstage.c        |   2 +-
- src/mainboard/tyan/s2850/romstage.c                |   2 +-
- src/mainboard/tyan/s2875/romstage.c                |   2 +-
- src/mainboard/tyan/s2880/romstage.c                |   2 +-
- src/mainboard/tyan/s2881/romstage.c                |   2 +-
- src/mainboard/tyan/s2882/romstage.c                |   2 +-
- src/mainboard/tyan/s2885/romstage.c                |   2 +-
- src/mainboard/tyan/s2891/romstage.c                |   2 +-
- src/mainboard/tyan/s2892/romstage.c                |   2 +-
- src/mainboard/tyan/s2895/romstage.c                |   2 +-
- src/mainboard/tyan/s2912/romstage.c                |   2 +-
- src/mainboard/tyan/s2912_fam10/romstage.c          |   2 +-
- src/mainboard/tyan/s4880/romstage.c                |   2 +-
- src/mainboard/tyan/s4882/romstage.c                |   2 +-
- src/mainboard/winent/mb6047/romstage.c             |   2 +-
- src/northbridge/amd/amdht/h3finit.c                |  57 ++++++++-
- src/northbridge/amd/amdht/h3ncmn.c                 |  30 ++++-
- src/northbridge/amd/amdht/ht_wrapper.c             | 141 +++++++++++++++++++--
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c        |   1 +
- 81 files changed, 528 insertions(+), 172 deletions(-)
-
-diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
-index 5db9224..6bfb0e6 100644
---- a/src/cpu/amd/car/cache_as_ram.inc
-+++ b/src/cpu/amd/car/cache_as_ram.inc
-@@ -525,8 +525,23 @@ CAR_FAM10_ap:
-       /* Fam10h NB config bit 54 was not set */
-       rolb    %cl, %bl
- roll_cfg:
-+      jmp_if_not_fam15h(ap_apicid_ready)
-+      cmp     $0x5, %ecx
-+      jne     ap_apicid_ready
- 
--      /* Calculate stack pointer. */
-+      /* This is a multi-node CPU
-+       * Adjust the maximum APIC ID to a more reasonable value
-+       * given that no 32-core Family 15h processors exist
-+       */
-+      movl    %ebx, %ecx
-+      and     $0x0f, %ecx             /* Get lower 4 bits of CPU number */
-+      and     $0x60, %ebx             /* Get node ID */
-+      shrl    $0x1, %ebx              /* Shift node ID part of APIC ID down 
by 1 */
-+      or      %ecx, %ebx              /* Recombine node ID and CPU number */
-+
-+ap_apicid_ready:
-+
-+      /* Calculate stack pointer using adjusted APIC ID stored in ebx */
-       movl    $CacheSizeAPStack, %eax
-       mull    %ebx
-       movl    $(CacheBase + (CacheSize - (CacheSizeBSPStack + 
CacheSizeBSPSlush))), %esp
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index 24f87ba..513d169 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -244,18 +244,50 @@ static const struct {
-       { 0, 0x68, (AMD_DR_B0 | AMD_DR_B1),
-         AMD_PTYPE_SVR, 0x00200000, 0x00600000 },      /* [22:21] DsNpReqLmt0 
= 01b */
- 
--      { 0, 0x84, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+      { 0, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
--      { 0, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+      { 0, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
--      { 0, 0xC4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+      { 0, 0xC4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
--      { 0, 0xE4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-+      { 0, 0xE4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
- 
-+      /* FIXME
-+       * Non-C32 packages only
-+       */
-+      { 0, 0x84, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+
-+      { 0, 0xA4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+
-+      { 0, 0xC4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+
-+      { 0, 0xE4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+
-+      /* FIXME
-+       * C32 package only
-+       */
-+#if 0
-+      { 0, 0x84, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+
-+      { 0, 0xA4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+
-+      { 0, 0xC4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+
-+      { 0, 0xE4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
-+#endif
-+
-       /* Link Global Retry Control Register */
-       { 0, 0x150, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00073900, 0x00073F00 },
-@@ -614,38 +646,79 @@ static const struct {
-       { 0x530A, AMD_DR_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
-         0x00004400, 0x00006400 },     /* HT_PHY_DLL_REG */
- 
--      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-+      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+        0x00000000, 0x000000FF },     /* Provide clear setting for logical
-+                                         completeness */
-+
-+      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+        0x00000000, 0x000000FF },     /* Provide clear setting for logical
-+                                         completeness */
-+
-+      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-+        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
-+
-+      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
-+        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
-+
-+      /* Link Phy Receiver Loop Filter Registers */
-+      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+        0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
-+                                         [21:14] LfcMin = 10h */
-+
-+      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+        0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
-+                                         [21:14] LfcMin = 10h */
-+
-+      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-+        0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
-+                                         [21:14] LfcMin = 08h */
-+
-+      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-+        0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
-+                                         [21:14] LfcMin = 08h */
-+
-+      { 0xC0, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
-+        0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
-+                                        [20:16] RttIndex = 04h */
-+
-+/* FIXME
-+ * Causes lockups for some reason when more than one package is installed
-+ * Debug and reactivate!
-+ */
-+// #if 0
-+      { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-         0x00000000, 0x000000FF },     /* Provide clear setting for logical
-                                          completeness */
- 
--      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-+      { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-         0x00000000, 0x000000FF },     /* Provide clear setting for logical
-                                          completeness */
- 
--      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
-+      { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
- 
--      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,  
HTPHY_LINKTYPE_HT1,
-+      { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
-         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
- 
-       /* Link Phy Receiver Loop Filter Registers */
--      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-+      { 0xD1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
-                                          [21:14] LfcMin = 10h */
- 
--      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
-+      { 0xC1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
-                                          [21:14] LfcMin = 10h */
- 
--      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
-+      { 0xD1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
-                                          [21:14] LfcMin = 08h */
- 
--      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
-+      { 0xC1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
-         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
-                                          [21:14] LfcMin = 08h */
- 
--      { 0xC0, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_ALL,
-+      { 0xC0, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
-         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
--                                                                 [20:16] 
RttIndex = 04h */
-+                                        [20:16] RttIndex = 04h */
-+// #endif
- };
-diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
-index 0e870e3..471456a 100644
---- a/src/cpu/amd/family_10h-family_15h/fidvid.c
-+++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
-@@ -633,44 +633,45 @@ static void prep_fid_change(void)
- }
- 
- static void waitCurrentPstate(u32 target_pstate) {
--  msr_t initial_msr = rdmsr(TSC_MSR);
--  msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
--  msr_t tsc_msr;
--  u8 timedout ;
--
--  /* paranoia ? I fear when we run fixPsNbVidBeforeWR we can enter a
--   * P1 that is a copy of P0, therefore has the same NB DID but the
--   * TSC will count twice per tick, so we have to wait for twice the
--   * count to achieve the desired timeout. But I'm likely to
--   * misunderstand this...
--   */
--  u32 corrected_timeout = (    (pstate_msr.lo==1)
--                          && (!(rdmsr(0xC0010065).lo & NB_DID_M_ON)) ) ?
--                          WAIT_PSTATE_TIMEOUT*2 : WAIT_PSTATE_TIMEOUT  ;
--  msr_t timeout;
--
--  timeout.lo = initial_msr.lo + corrected_timeout ;
--  timeout.hi = initial_msr.hi;
--  if ( (((u32)0xffffffff) - initial_msr.lo) < corrected_timeout ) {
--     timeout.hi++;
--  }
--
--  // assuming TSC ticks at 1.25 ns per tick (800 MHz)
--  do {
--      pstate_msr = rdmsr(CUR_PSTATE_MSR);
--      tsc_msr = rdmsr(TSC_MSR);
--      timedout = (tsc_msr.hi > timeout.hi)
--              || ((tsc_msr.hi == timeout.hi) && (tsc_msr.lo > timeout.lo ));
--  } while ( (pstate_msr.lo != target_pstate) && (! timedout) ) ;
--
--  if (pstate_msr.lo != target_pstate) {
--    msr_t limit_msr = rdmsr(0xc0010061);
--    printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state 
%01x P-state current limit MSRC001_0061=%08x %08x\n", target_pstate, 
pstate_msr.lo, limit_msr.hi, limit_msr.lo);
--
--    do { // should we just go on instead ?
--      pstate_msr = rdmsr(CUR_PSTATE_MSR);
--    } while ( pstate_msr.lo != target_pstate  ) ;
--  }
-+      msr_t initial_msr = rdmsr(TSC_MSR);
-+      msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
-+      msr_t tsc_msr;
-+      u8 timedout ;
-+
-+      /* paranoia ? I fear when we run fixPsNbVidBeforeWR we can enter a
-+      * P1 that is a copy of P0, therefore has the same NB DID but the
-+      * TSC will count twice per tick, so we have to wait for twice the
-+      * count to achieve the desired timeout. But I'm likely to
-+      * misunderstand this...
-+      */
-+      u32 corrected_timeout = ((pstate_msr.lo==1)
-+                              && (!(rdmsr(0xC0010065).lo & NB_DID_M_ON)) ) ?
-+                              WAIT_PSTATE_TIMEOUT*2 : WAIT_PSTATE_TIMEOUT;
-+      msr_t timeout;
-+
-+      timeout.lo = initial_msr.lo + corrected_timeout ;
-+      timeout.hi = initial_msr.hi;
-+      if ( (((u32)0xffffffff) - initial_msr.lo) < corrected_timeout ) {
-+              timeout.hi++;
-+      }
-+
-+      // assuming TSC ticks at 1.25 ns per tick (800 MHz)
-+      do {
-+              pstate_msr = rdmsr(CUR_PSTATE_MSR);
-+              tsc_msr = rdmsr(TSC_MSR);
-+              timedout = (tsc_msr.hi > timeout.hi)
-+                      || ((tsc_msr.hi == timeout.hi) && (tsc_msr.lo > 
timeout.lo ));
-+      } while ( (pstate_msr.lo != target_pstate) && (! timedout) ) ;
-+
-+      if (pstate_msr.lo != target_pstate) {
-+              msr_t limit_msr = rdmsr(0xc0010061);
-+              printk(BIOS_ERR, "*** APIC ID %02x: timed out waiting for 
P-state %01x. Current P-state %01x P-state current limit MSRC001_0061=%08x 
%08x\n",
-+                      cpuid_ebx(0x00000001) >> 24, target_pstate, 
pstate_msr.lo, limit_msr.hi, limit_msr.lo);
-+
-+              do { // should we just go on instead ?
-+                      pstate_msr = rdmsr(CUR_PSTATE_MSR);
-+              } while ( pstate_msr.lo != target_pstate  ) ;
-+      }
- }
- 
- static void set_pstate(u32 nonBoostedPState) {
-@@ -1063,13 +1064,13 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes)
-          APs and BSP */
-       ap_apicidx.num = 0;
- 
--      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE_RANGE, store_ap_apicid, 
&ap_apicidx);
-+      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE_RANGE, -1, 
store_ap_apicid, &ap_apicidx);
- 
-       for (i = 0; i < ap_apicidx.num; i++) {
-               init_fidvid_bsp_stage1(ap_apicidx.apicid[i], &fv);
-       }
- #else
--      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE0_ONLY, 
init_fidvid_bsp_stage1, &fv);
-+      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE0_ONLY, -1, 
init_fidvid_bsp_stage1, &fv);
- #endif
- 
-       print_debug_fv("common_fid = ", fv.common_fid);
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 0044dc6..986c024 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -59,6 +59,8 @@ static void set_EnableCf8ExtCfg(void)
- static void set_EnableCf8ExtCfg(void) { }
- #endif
- 
-+// #define DEBUG_HT_SETUP 1
-+// #define FAM10_AP_NODE_SEQUENTIAL_START 1
- 
- typedef void (*process_ap_t) (u32 apicid, void *gp);
- 
-@@ -143,8 +145,8 @@ uint32_t get_boot_apic_id(uint8_t node, uint32_t core) {
- //core range = 1 : core 0 only
- //core range = 2 : cores other than core0
- 
--static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t 
process_ap,
--                      void *gp)
-+static void for_each_ap(uint32_t bsp_apicid, uint32_t core_range, int8_t node,
-+                      process_ap_t process_ap, void *gp)
- {
-       // here assume the OS don't change our apicid
-       u32 ap_apicid;
-@@ -165,6 +167,9 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
-       }
- 
-       for (i = 0; i < nodes; i++) {
-+              if ((node >= 0) && (i != node))
-+                      continue;
-+
-               cores_found = get_core_num_in_bsp(i);
- 
-               u32 jstart, jend;
-@@ -280,7 +285,7 @@ void wait_all_other_cores_started(u32 bsp_apicid)
- {
-       // all aps other than core0
-       printk(BIOS_DEBUG, "started ap apicid: ");
--      for_each_ap(bsp_apicid, 2, wait_ap_started, (void *)0);
-+      for_each_ap(bsp_apicid, 2, -1, wait_ap_started, (void *)0);
-       printk(BIOS_DEBUG, "\n");
- }
- 
-@@ -373,8 +378,10 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
-       /* NB_CFG MSR is shared between cores, so we need make sure
-          core0 is done at first --- use wait_all_core0_started  */
-       if (id.coreid == 0) {
--              set_apicid_cpuid_lo();  /* only set it on core0 */
--              set_EnableCf8ExtCfg();  /* only set it on core0 */
-+              /* Set InitApicIdCpuIdLo / EnableCf8ExtCfg on core0 only */
-+              if (!is_fam15h())
-+                      set_apicid_cpuid_lo();
-+              set_EnableCf8ExtCfg();
- #if CONFIG_ENABLE_APIC_EXT_ID
-               enable_apic_ext_id(id.nodeid);
- #endif
-@@ -427,6 +434,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
-       }
-       // Mark the core as started.
-       lapic_write(LAPIC_MSG_REG, (apicid << 24) | F10_APSTATE_STARTED);
-+      printk(BIOS_DEBUG, "CPU APICID %02x start flag set\n", apicid);
- 
-       if (apicid != bsp_apicid) {
-               /* Setup each AP's cores MSRs.
-@@ -588,6 +596,34 @@ static void setup_remote_node(u8 node)
- }
- #endif                                /* CONFIG_MAX_PHYSICAL_CPUS > 1 */
- 
-+//it is running on core0 of node0
-+static void start_other_cores(uint32_t bsp_apicid)
-+{
-+      u32 nodes;
-+      u32 nodeid;
-+
-+      // disable multi_core
-+      if (read_option(multi_core, 0) != 0)  {
-+              printk(BIOS_DEBUG, "Skip additional core init\n");
-+              return;
-+      }
-+
-+      nodes = get_nodes();
-+
-+      for (nodeid = 0; nodeid < nodes; nodeid++) {
-+              u32 cores = get_core_num_in_bsp(nodeid);
-+              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1\n", 
nodeid, cores);
-+              if (cores > 0) {
-+                      real_start_other_core(nodeid, cores);
-+#ifdef FAM10_AP_NODE_SEQUENTIAL_START
-+                      printk(BIOS_DEBUG, "waiting for core start on node 
%d...\n", nodeid);
-+                      for_each_ap(bsp_apicid, 2, nodeid, wait_ap_started, 
(void *)0);
-+                      printk(BIOS_DEBUG, "...started\n");
-+#endif
-+              }
-+      }
-+}
-+
- static void AMD_Errata281(u8 node, uint64_t revision, u32 platform)
- {
-       /* Workaround for Transaction Scheduling Conflict in
-@@ -847,6 +883,10 @@ static void AMD_SetHtPhyRegister(u8 node, u8 link, u8 
entry)
- 
-       phyBase = ((u32) link << 3) | 0x180;
- 
-+      /* Determine if link is connected and abort if not */
-+      if (!(pci_read_config32(NODE_PCI(node, 0), 0x98 + (link * 0x20)) & 0x1))
-+              return;
-+
-       /* Get the portal control register's initial value
-        * and update it to access the desired phy register
-        */
-@@ -1008,10 +1048,11 @@ static void cpuSetAMDPCI(u8 node)
-        * Hypertransport initialization has taken place.  Also note
-        * that it is run for the first core on each node
-        */
--      u8 i, j;
-+      uint8_t i;
-+      uint8_t j;
-       u32 platform;
-       u32 val;
--      u8 offset;
-+      uint8_t offset;
-       uint32_t dword;
-       uint64_t revision;
- 
-@@ -1038,6 +1079,17 @@ static void cpuSetAMDPCI(u8 node)
-               }
-       }
- 
-+#ifdef DEBUG_HT_SETUP
-+      /* Dump link settings */
-+      for (i = 0; i < 4; i++) {
-+              for (j = 0; j < 4; j++) {
-+                      printk(BIOS_DEBUG, "Node %d link %d: type register: 
%08x control register: %08x extended control sublink 0: %08x 1: %08x\n", i, j,
-+                              pci_read_config32(NODE_PCI(i, 0), 0x98 + (j * 
0x20)), pci_read_config32(NODE_PCI(i, 0), 0x84 + (j * 0x20)),
-+                              pci_read_config32(NODE_PCI(i, 0), 0x170 + (j * 
0x4)), pci_read_config32(NODE_PCI(i, 0), 0x180 + (j * 0x4)));
-+              }
-+      }
-+#endif
-+
-       for (i = 0; i < ARRAY_SIZE(fam10_htphy_default); i++) {
-               if ((fam10_htphy_default[i].revision & revision) &&
-                   (fam10_htphy_default[i].platform & platform)) {
-diff --git a/src/cpu/amd/quadcore/quadcore.c b/src/cpu/amd/quadcore/quadcore.c
-index 8a9b5ed..9c31eac 100644
---- a/src/cpu/amd/quadcore/quadcore.c
-+++ b/src/cpu/amd/quadcore/quadcore.c
-@@ -31,21 +31,6 @@
- uint32_t get_boot_apic_id(uint8_t node, uint32_t core);
- uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2);
- 
--static inline uint8_t is_fam15h(void)
--{
--      uint8_t fam15h = 0;
--      uint32_t family;
--
--      family = cpuid_eax(0x80000001);
--      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
--
--      if (family >= 0x6f)
--              /* Family 15h or later */
--              fam15h = 1;
--
--      return fam15h;
--}
--
- static u32 get_core_num_in_bsp(u32 nodeid)
- {
-       u32 dword;
-@@ -141,6 +126,7 @@ static void real_start_other_core(uint32_t nodeid, 
uint32_t cores)
-       }
- }
- 
-+#if (!IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
- //it is running on core0 of node0
- static void start_other_cores(void)
- {
-@@ -157,9 +143,10 @@ static void start_other_cores(void)
- 
-       for (nodeid = 0; nodeid < nodes; nodeid++) {
-               u32 cores = get_core_num_in_bsp(nodeid);
--              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1 \n", 
nodeid, cores);
-+              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1\n", 
nodeid, cores);
-               if (cores > 0) {
-                       real_start_other_core(nodeid, cores);
-               }
-       }
- }
-+#endif
-diff --git a/src/cpu/amd/quadcore/quadcore_id.c 
b/src/cpu/amd/quadcore/quadcore_id.c
-index c0537b3..1f5cbd8 100644
---- a/src/cpu/amd/quadcore/quadcore_id.c
-+++ b/src/cpu/amd/quadcore/quadcore_id.c
-@@ -108,7 +108,6 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
-                       id.nodeid = apicid & 0x7;
-               }
-       }
--
-       if (fam15h && dual_node) {
-               /* Coreboot expects each separate processor die to be on a 
different nodeid.
-                * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
-diff --git a/src/mainboard/advansus/a785e-i/romstage.c 
b/src/mainboard/advansus/a785e-i/romstage.c
-index ab717fd..591faab 100644
---- a/src/mainboard/advansus/a785e-i/romstage.c
-+++ b/src/mainboard/advansus/a785e-i/romstage.c
-@@ -155,7 +155,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/amd/bimini_fam10/romstage.c 
b/src/mainboard/amd/bimini_fam10/romstage.c
-index 5e2cf82..95384ac 100644
---- a/src/mainboard/amd/bimini_fam10/romstage.c
-+++ b/src/mainboard/amd/bimini_fam10/romstage.c
-@@ -147,7 +147,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/amd/dbm690t/romstage.c 
b/src/mainboard/amd/dbm690t/romstage.c
-index 1f77afa..29edf30 100644
---- a/src/mainboard/amd/dbm690t/romstage.c
-+++ b/src/mainboard/amd/dbm690t/romstage.c
-@@ -98,7 +98,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/amd/mahogany/romstage.c 
b/src/mainboard/amd/mahogany/romstage.c
-index 542ee60..a52a69f 100644
---- a/src/mainboard/amd/mahogany/romstage.c
-+++ b/src/mainboard/amd/mahogany/romstage.c
-@@ -99,7 +99,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/amd/mahogany_fam10/romstage.c 
b/src/mainboard/amd/mahogany_fam10/romstage.c
-index 025a8bb..aac6b4e 100644
---- a/src/mainboard/amd/mahogany_fam10/romstage.c
-+++ b/src/mainboard/amd/mahogany_fam10/romstage.c
-@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-  #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
-  #endif
-diff --git a/src/mainboard/amd/pistachio/romstage.c 
b/src/mainboard/amd/pistachio/romstage.c
-index ca2edae..3ba011e 100644
---- a/src/mainboard/amd/pistachio/romstage.c
-+++ b/src/mainboard/amd/pistachio/romstage.c
-@@ -97,7 +97,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/amd/serengeti_cheetah/romstage.c 
b/src/mainboard/amd/serengeti_cheetah/romstage.c
-index 7da7925..20a34bf 100644
---- a/src/mainboard/amd/serengeti_cheetah/romstage.c
-+++ b/src/mainboard/amd/serengeti_cheetah/romstage.c
-@@ -126,7 +126,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-        */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c 
b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
-index 5063439..6d36575 100644
---- a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
-+++ b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
-@@ -255,7 +255,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-  #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
-  #endif
-diff --git a/src/mainboard/amd/tilapia_fam10/romstage.c 
b/src/mainboard/amd/tilapia_fam10/romstage.c
-index e37bc08..c9a9928 100644
---- a/src/mainboard/amd/tilapia_fam10/romstage.c
-+++ b/src/mainboard/amd/tilapia_fam10/romstage.c
-@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/arima/hdama/romstage.c 
b/src/mainboard/arima/hdama/romstage.c
-index d1e1c5f..0b6a833 100644
---- a/src/mainboard/arima/hdama/romstage.c
-+++ b/src/mainboard/arima/hdama/romstage.c
-@@ -91,7 +91,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-       /* This is needed to be able to call udelay().  It could be moved to
-diff --git a/src/mainboard/asrock/939a785gmh/romstage.c 
b/src/mainboard/asrock/939a785gmh/romstage.c
-index 09c5b18..48862fd 100644
---- a/src/mainboard/asrock/939a785gmh/romstage.c
-+++ b/src/mainboard/asrock/939a785gmh/romstage.c
-@@ -164,7 +164,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/asus/a8n_e/romstage.c 
b/src/mainboard/asus/a8n_e/romstage.c
-index d1485bf..5c89a83 100644
---- a/src/mainboard/asus/a8n_e/romstage.c
-+++ b/src/mainboard/asus/a8n_e/romstage.c
-@@ -121,7 +121,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched. */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/asus/a8v-e_deluxe/romstage.c 
b/src/mainboard/asus/a8v-e_deluxe/romstage.c
-index dc1d6ff..cf713ee 100644
---- a/src/mainboard/asus/a8v-e_deluxe/romstage.c
-+++ b/src/mainboard/asus/a8v-e_deluxe/romstage.c
-@@ -181,7 +181,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched. */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-       init_timer();
-diff --git a/src/mainboard/asus/a8v-e_se/romstage.c 
b/src/mainboard/asus/a8v-e_se/romstage.c
-index 0531cd3..eba2acf 100644
---- a/src/mainboard/asus/a8v-e_se/romstage.c
-+++ b/src/mainboard/asus/a8v-e_se/romstage.c
-@@ -181,7 +181,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched. */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-       init_timer();
-diff --git a/src/mainboard/asus/k8v-x/romstage.c 
b/src/mainboard/asus/k8v-x/romstage.c
-index 45103fd..f1100dd 100644
---- a/src/mainboard/asus/k8v-x/romstage.c
-+++ b/src/mainboard/asus/k8v-x/romstage.c
-@@ -136,7 +136,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched. */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-       init_timer();
-diff --git a/src/mainboard/asus/kfsn4-dre/romstage.c 
b/src/mainboard/asus/kfsn4-dre/romstage.c
-index dd5c7dc..1307e57 100644
---- a/src/mainboard/asus/kfsn4-dre/romstage.c
-+++ b/src/mainboard/asus/kfsn4-dre/romstage.c
-@@ -288,7 +288,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
-               /* Core0 on each node is configured. Now setup any additional 
cores. */
-               printk(BIOS_DEBUG, "start_other_cores()\n");
--              start_other_cores();
-+              start_other_cores(bsp_apicid);
-               post_code(0x37);
-               wait_all_other_cores_started(bsp_apicid);
-       }
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index 9ea7cec..3504126 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -97,7 +97,18 @@ static void switch_spd_mux(uint8_t channel)
-       pci_write_config8(PCI_DEV(0, 0x14, 0), 0x54, byte);
- }
- 
--static const uint8_t spd_addr[] = {
-+static const uint8_t spd_addr_fam15[] = {
-+      // Socket 0 Node 0 ("Node 0")
-+      RC00, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
-+      // Socket 0 Node 1 ("Node 1")
-+      RC00, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
-+      // Socket 1 Node 0 ("Node 2")
-+      RC01, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
-+      // Socket 1 Node 1 ("Node 3")
-+      RC01, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
-+};
-+
-+static const uint8_t spd_addr_fam10[] = {
-       // Socket 0 Node 0 ("Node 0")
-       RC00, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
-       // Socket 0 Node 1 ("Node 1")
-@@ -117,10 +128,10 @@ static void activate_spd_rom(const struct mem_controller 
*ctrl) {
-               switch_spd_mux(0x2);
-       } else if (ctrl->node_id == 1) {
-               printk(BIOS_DEBUG, "enable_spd_node1()\n");
--              switch_spd_mux((sysinfo->nodes <= 2)?0x2:0x3);
-+              switch_spd_mux((is_fam15h() || (sysinfo->nodes <= 2))?0x2:0x3);
-       } else if (ctrl->node_id == 2) {
-               printk(BIOS_DEBUG, "enable_spd_node2()\n");
--              switch_spd_mux((sysinfo->nodes <= 2)?0x3:0x2);
-+              switch_spd_mux((is_fam15h() || (sysinfo->nodes <= 2))?0x3:0x2);
-       } else if (ctrl->node_id == 3) {
-               printk(BIOS_DEBUG, "enable_spd_node3()\n");
-               switch_spd_mux(0x3);
-@@ -306,18 +317,25 @@ void initialize_romstage_console_lock(void)
- 
- void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
- {
-+      uint32_t esp;
-+      __asm__ volatile (
-+              "movl %%esp, %0"
-+              : "=r" (esp)
-+              );
-+
-       struct sys_info *sysinfo = &sysinfo_car;
- 
-       uint32_t bsp_apicid = 0, val;
-       uint8_t byte;
-       msr_t msr;
- 
--      timestamp_init(timestamp_get());
--      timestamp_add_now(TS_START_ROMSTAGE);
--
-       int s3resume = acpi_is_wakeup_s3();
- 
-       if (!cpu_init_detectedx && boot_cpu()) {
-+              /* Initial timestamp */
-+              timestamp_init(timestamp_get());
-+              timestamp_add_now(TS_START_ROMSTAGE);
-+
-               /* Initialize the printk spinlock */
-               initialize_romstage_console_lock();
- 
-@@ -344,6 +362,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               pci_write_config8(PCI_DEV(0, 0x14, 3), 0x78, byte);
-       }
- 
-+      printk(BIOS_SPEW, "Initial stack pointer: %08x\n", esp);
-+
-       post_code(0x30);
- 
-       if (bist == 0)
-@@ -397,7 +417,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
-               /* Core0 on each node is configured. Now setup any additional 
cores. */
-               printk(BIOS_DEBUG, "start_other_cores()\n");
--              start_other_cores();
-+              start_other_cores(bsp_apicid);
-               post_code(0x37);
-               wait_all_other_cores_started(bsp_apicid);
-       }
-@@ -455,7 +475,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       /* It's the time to set ctrl in sysinfo now; */
-       printk(BIOS_DEBUG, "fill_mem_ctrl() detected %d nodes\n", 
sysinfo->nodes);
--      fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr);
-+      if (is_fam15h())
-+              fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr_fam15);
-+      else
-+              fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr_fam10);
-       post_code(0x3D);
- 
- #if 0
-@@ -527,5 +550,12 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-  */
- BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 **List)
- {
-+      /* Force BUID to 0 */
-+      static const u8 swaplist[] = {0, 0, 0xFF, 0, 0xFF};
-+      if ((node == 0) && (link == 1)) {       /* BSP SB link */
-+              *List = swaplist;
-+              return 1;
-+      }
-+
-       return 0;
- }
-\ No newline at end of file
-diff --git a/src/mainboard/asus/m2n-e/romstage.c 
b/src/mainboard/asus/m2n-e/romstage.c
-index 306c124..351a411 100644
---- a/src/mainboard/asus/m2n-e/romstage.c
-+++ b/src/mainboard/asus/m2n-e/romstage.c
-@@ -129,7 +129,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * started, esp for two way system (there may be APIC ID conflicts in
-        * that case).
-        */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/asus/m2v-mx_se/romstage.c 
b/src/mainboard/asus/m2v-mx_se/romstage.c
-index 89e24a4..4364c6c 100644
---- a/src/mainboard/asus/m2v-mx_se/romstage.c
-+++ b/src/mainboard/asus/m2v-mx_se/romstage.c
-@@ -147,7 +147,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched. */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-       init_timer();
-diff --git a/src/mainboard/asus/m2v/romstage.c 
b/src/mainboard/asus/m2v/romstage.c
-index 8c99080..60cb1d4 100644
---- a/src/mainboard/asus/m2v/romstage.c
-+++ b/src/mainboard/asus/m2v/romstage.c
-@@ -247,7 +247,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched. */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-       init_timer();
-diff --git a/src/mainboard/asus/m4a78-em/romstage.c 
b/src/mainboard/asus/m4a78-em/romstage.c
-index 82b96bf..75894d8 100644
---- a/src/mainboard/asus/m4a78-em/romstage.c
-+++ b/src/mainboard/asus/m4a78-em/romstage.c
-@@ -151,7 +151,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-  #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
-  #endif
-diff --git a/src/mainboard/asus/m4a785-m/romstage.c 
b/src/mainboard/asus/m4a785-m/romstage.c
-index 30975fa..f81cb95 100644
---- a/src/mainboard/asus/m4a785-m/romstage.c
-+++ b/src/mainboard/asus/m4a785-m/romstage.c
-@@ -151,7 +151,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-  #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
-  #endif
-diff --git a/src/mainboard/asus/m5a88-v/romstage.c 
b/src/mainboard/asus/m5a88-v/romstage.c
-index 4edaba2..9914025 100644
---- a/src/mainboard/asus/m5a88-v/romstage.c
-+++ b/src/mainboard/asus/m5a88-v/romstage.c
-@@ -152,7 +152,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/avalue/eax-785e/romstage.c 
b/src/mainboard/avalue/eax-785e/romstage.c
-index 447012b..c57454d 100644
---- a/src/mainboard/avalue/eax-785e/romstage.c
-+++ b/src/mainboard/avalue/eax-785e/romstage.c
-@@ -156,7 +156,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/broadcom/blast/romstage.c 
b/src/mainboard/broadcom/blast/romstage.c
-index d7ba383..a7c0a84 100644
---- a/src/mainboard/broadcom/blast/romstage.c
-+++ b/src/mainboard/broadcom/blast/romstage.c
-@@ -93,7 +93,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
-         wait_all_core0_started();
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-         wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/gigabyte/ga_2761gxdk/romstage.c 
b/src/mainboard/gigabyte/ga_2761gxdk/romstage.c
-index 008a23f..8045164 100644
---- a/src/mainboard/gigabyte/ga_2761gxdk/romstage.c
-+++ b/src/mainboard/gigabyte/ga_2761gxdk/romstage.c
-@@ -150,7 +150,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-          * So here need to make sure last core0 is started, esp for two way 
system,
-          * (there may be apic id conflicts in that case)
-          */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/gigabyte/m57sli/romstage.c 
b/src/mainboard/gigabyte/m57sli/romstage.c
-index fe97e68..e1c2fe3 100644
---- a/src/mainboard/gigabyte/m57sli/romstage.c
-+++ b/src/mainboard/gigabyte/m57sli/romstage.c
-@@ -157,7 +157,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-          * So here need to make sure last core0 is started, esp for two way 
system,
-          * (there may be apic id conflicts in that case)
-          */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/gigabyte/ma785gm/romstage.c 
b/src/mainboard/gigabyte/ma785gm/romstage.c
-index 444e59d..ae661e8 100644
---- a/src/mainboard/gigabyte/ma785gm/romstage.c
-+++ b/src/mainboard/gigabyte/ma785gm/romstage.c
-@@ -146,7 +146,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/gigabyte/ma785gmt/romstage.c 
b/src/mainboard/gigabyte/ma785gmt/romstage.c
-index 705d7c5..968aa8f 100644
---- a/src/mainboard/gigabyte/ma785gmt/romstage.c
-+++ b/src/mainboard/gigabyte/ma785gmt/romstage.c
-@@ -146,7 +146,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/gigabyte/ma78gm/romstage.c 
b/src/mainboard/gigabyte/ma78gm/romstage.c
-index 5d21801..7e18724 100644
---- a/src/mainboard/gigabyte/ma78gm/romstage.c
-+++ b/src/mainboard/gigabyte/ma78gm/romstage.c
-@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/hp/dl145_g1/romstage.c 
b/src/mainboard/hp/dl145_g1/romstage.c
-index 8b5b428..e2b215b 100644
---- a/src/mainboard/hp/dl145_g1/romstage.c
-+++ b/src/mainboard/hp/dl145_g1/romstage.c
-@@ -129,7 +129,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/hp/dl145_g3/romstage.c 
b/src/mainboard/hp/dl145_g3/romstage.c
-index d8e8a16..d6e72d2 100644
---- a/src/mainboard/hp/dl145_g3/romstage.c
-+++ b/src/mainboard/hp/dl145_g3/romstage.c
-@@ -163,7 +163,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-       */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/hp/dl165_g6_fam10/romstage.c 
b/src/mainboard/hp/dl165_g6_fam10/romstage.c
-index 26c0bb9..e70d274 100644
---- a/src/mainboard/hp/dl165_g6_fam10/romstage.c
-+++ b/src/mainboard/hp/dl165_g6_fam10/romstage.c
-@@ -160,7 +160,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/ibm/e325/romstage.c 
b/src/mainboard/ibm/e325/romstage.c
-index 48e7de8..960b46b 100644
---- a/src/mainboard/ibm/e325/romstage.c
-+++ b/src/mainboard/ibm/e325/romstage.c
-@@ -100,7 +100,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-         // automatically set that for you, but you might meet tight space
-         needs_reset |= ht_setup_chains_x();
-diff --git a/src/mainboard/ibm/e326/romstage.c 
b/src/mainboard/ibm/e326/romstage.c
-index a27a218..1b88035 100644
---- a/src/mainboard/ibm/e326/romstage.c
-+++ b/src/mainboard/ibm/e326/romstage.c
-@@ -100,7 +100,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-         // automatically set that for you, but you might meet tight space
-         needs_reset |= ht_setup_chains_x();
-diff --git a/src/mainboard/iei/kino-780am2-fam10/romstage.c 
b/src/mainboard/iei/kino-780am2-fam10/romstage.c
-index 321eea6..89cfe83 100644
---- a/src/mainboard/iei/kino-780am2-fam10/romstage.c
-+++ b/src/mainboard/iei/kino-780am2-fam10/romstage.c
-@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-  #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
-  #endif
-diff --git a/src/mainboard/iwill/dk8_htx/romstage.c 
b/src/mainboard/iwill/dk8_htx/romstage.c
-index 9b5b38d..a1e45f0 100644
---- a/src/mainboard/iwill/dk8_htx/romstage.c
-+++ b/src/mainboard/iwill/dk8_htx/romstage.c
-@@ -104,7 +104,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-        */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/iwill/dk8s2/romstage.c 
b/src/mainboard/iwill/dk8s2/romstage.c
-index 601c649..d140baf 100644
---- a/src/mainboard/iwill/dk8s2/romstage.c
-+++ b/src/mainboard/iwill/dk8s2/romstage.c
-@@ -105,7 +105,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-        */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/iwill/dk8x/romstage.c 
b/src/mainboard/iwill/dk8x/romstage.c
-index 273e9f1..bdac810 100644
---- a/src/mainboard/iwill/dk8x/romstage.c
-+++ b/src/mainboard/iwill/dk8x/romstage.c
-@@ -105,7 +105,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-        */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/jetway/pa78vm5/romstage.c 
b/src/mainboard/jetway/pa78vm5/romstage.c
-index 93dd2ce..6106b66 100644
---- a/src/mainboard/jetway/pa78vm5/romstage.c
-+++ b/src/mainboard/jetway/pa78vm5/romstage.c
-@@ -154,7 +154,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-  #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
-  #endif
-diff --git a/src/mainboard/kontron/kt690/romstage.c 
b/src/mainboard/kontron/kt690/romstage.c
-index d8db6aa..7210dae 100644
---- a/src/mainboard/kontron/kt690/romstage.c
-+++ b/src/mainboard/kontron/kt690/romstage.c
-@@ -100,7 +100,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/msi/ms7135/romstage.c 
b/src/mainboard/msi/ms7135/romstage.c
-index 68cddad..34dbb8a 100644
---- a/src/mainboard/msi/ms7135/romstage.c
-+++ b/src/mainboard/msi/ms7135/romstage.c
-@@ -139,7 +139,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/msi/ms7260/romstage.c 
b/src/mainboard/msi/ms7260/romstage.c
-index 15f389a..be82fd0 100644
---- a/src/mainboard/msi/ms7260/romstage.c
-+++ b/src/mainboard/msi/ms7260/romstage.c
-@@ -146,7 +146,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * started, esp for two way system (there may be APIC ID conflicts in
-        * that case).
-        */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/msi/ms9185/romstage.c 
b/src/mainboard/msi/ms9185/romstage.c
-index 795a890..fc5cfd6 100644
---- a/src/mainboard/msi/ms9185/romstage.c
-+++ b/src/mainboard/msi/ms9185/romstage.c
-@@ -134,7 +134,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-         * So here need to make sure last core0 is started, esp for two way 
system,
-         * (there may be apic id conflicts in that case)
-         */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- //bx_a010-     wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/msi/ms9282/romstage.c 
b/src/mainboard/msi/ms9282/romstage.c
-index f5b75cc..05d8aee 100644
---- a/src/mainboard/msi/ms9282/romstage.c
-+++ b/src/mainboard/msi/ms9282/romstage.c
-@@ -144,7 +144,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       //wait_all_other_cores_started(bsp_apicid);
- #endif
-       ht_setup_chains_x(sysinfo); // it will init sblnk and sbbusn, nodes, 
sbdn
-diff --git a/src/mainboard/msi/ms9652_fam10/romstage.c 
b/src/mainboard/msi/ms9652_fam10/romstage.c
-index 5da971f..f552db5 100644
---- a/src/mainboard/msi/ms9652_fam10/romstage.c
-+++ b/src/mainboard/msi/ms9652_fam10/romstage.c
-@@ -177,7 +177,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       printk(BIOS_DEBUG, "wait_all_other_cores_started()\n");
-       wait_all_other_cores_started(bsp_apicid);
-diff --git a/src/mainboard/newisys/khepri/romstage.c 
b/src/mainboard/newisys/khepri/romstage.c
-index bf8a0a2..5174f32 100644
---- a/src/mainboard/newisys/khepri/romstage.c
-+++ b/src/mainboard/newisys/khepri/romstage.c
-@@ -102,7 +102,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-         wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/nvidia/l1_2pvv/romstage.c 
b/src/mainboard/nvidia/l1_2pvv/romstage.c
-index b5731c8..3725c04 100644
---- a/src/mainboard/nvidia/l1_2pvv/romstage.c
-+++ b/src/mainboard/nvidia/l1_2pvv/romstage.c
-@@ -143,7 +143,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-        */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/siemens/sitemp_g1p1/romstage.c 
b/src/mainboard/siemens/sitemp_g1p1/romstage.c
-index 1b2501f..96cec72 100644
---- a/src/mainboard/siemens/sitemp_g1p1/romstage.c
-+++ b/src/mainboard/siemens/sitemp_g1p1/romstage.c
-@@ -127,7 +127,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/sunw/ultra40/romstage.c 
b/src/mainboard/sunw/ultra40/romstage.c
-index ecb7fe7..13aa272 100644
---- a/src/mainboard/sunw/ultra40/romstage.c
-+++ b/src/mainboard/sunw/ultra40/romstage.c
-@@ -127,7 +127,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-         wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/supermicro/h8dme/romstage.c 
b/src/mainboard/supermicro/h8dme/romstage.c
-index c10aba4..b9082a3 100644
---- a/src/mainboard/supermicro/h8dme/romstage.c
-+++ b/src/mainboard/supermicro/h8dme/romstage.c
-@@ -161,7 +161,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-        */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/supermicro/h8dmr/romstage.c 
b/src/mainboard/supermicro/h8dmr/romstage.c
-index 1e5582c..f31f586 100644
---- a/src/mainboard/supermicro/h8dmr/romstage.c
-+++ b/src/mainboard/supermicro/h8dmr/romstage.c
-@@ -138,7 +138,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-          * So here need to make sure last core0 is started, esp for two way 
system,
-          * (there may be apic id conflicts in that case)
-          */
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/supermicro/h8dmr_fam10/romstage.c 
b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
-index 1425546..333a213 100644
---- a/src/mainboard/supermicro/h8dmr_fam10/romstage.c
-+++ b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
-@@ -171,7 +171,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/supermicro/h8qme_fam10/romstage.c 
b/src/mainboard/supermicro/h8qme_fam10/romstage.c
-index 4721eba..8caf615 100644
---- a/src/mainboard/supermicro/h8qme_fam10/romstage.c
-+++ b/src/mainboard/supermicro/h8qme_fam10/romstage.c
-@@ -238,7 +238,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/supermicro/h8scm_fam10/romstage.c 
b/src/mainboard/supermicro/h8scm_fam10/romstage.c
-index 858aca0..0e5adcd 100644
---- a/src/mainboard/supermicro/h8scm_fam10/romstage.c
-+++ b/src/mainboard/supermicro/h8scm_fam10/romstage.c
-@@ -162,7 +162,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/technexion/tim5690/romstage.c 
b/src/mainboard/technexion/tim5690/romstage.c
-index 27c0024..f3f3117 100644
---- a/src/mainboard/technexion/tim5690/romstage.c
-+++ b/src/mainboard/technexion/tim5690/romstage.c
-@@ -105,7 +105,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/technexion/tim8690/romstage.c 
b/src/mainboard/technexion/tim8690/romstage.c
-index 4830bf9..368eb0e 100644
---- a/src/mainboard/technexion/tim8690/romstage.c
-+++ b/src/mainboard/technexion/tim8690/romstage.c
-@@ -100,7 +100,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* It is said that we should start core1 after all core0 launched */
-       wait_all_core0_started();
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
- #endif
-       wait_all_aps_started(bsp_apicid);
- 
-diff --git a/src/mainboard/tyan/s2850/romstage.c 
b/src/mainboard/tyan/s2850/romstage.c
-index bb91a2a..9b5aff6 100644
---- a/src/mainboard/tyan/s2850/romstage.c
-+++ b/src/mainboard/tyan/s2850/romstage.c
-@@ -88,7 +88,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-         needs_reset |= ht_setup_chains_x();
- 
-diff --git a/src/mainboard/tyan/s2875/romstage.c 
b/src/mainboard/tyan/s2875/romstage.c
-index e63734e..41ae094 100644
---- a/src/mainboard/tyan/s2875/romstage.c
-+++ b/src/mainboard/tyan/s2875/romstage.c
-@@ -97,7 +97,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-         needs_reset |= ht_setup_chains_x();
- 
-diff --git a/src/mainboard/tyan/s2880/romstage.c 
b/src/mainboard/tyan/s2880/romstage.c
-index dba58f2..c632b62 100644
---- a/src/mainboard/tyan/s2880/romstage.c
-+++ b/src/mainboard/tyan/s2880/romstage.c
-@@ -97,7 +97,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-         // automatically set that for you, but you might meet tight space
-         needs_reset |= ht_setup_chains_x();
-diff --git a/src/mainboard/tyan/s2881/romstage.c 
b/src/mainboard/tyan/s2881/romstage.c
-index b97ba18..c134f2d 100644
---- a/src/mainboard/tyan/s2881/romstage.c
-+++ b/src/mainboard/tyan/s2881/romstage.c
-@@ -91,7 +91,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-         wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/tyan/s2882/romstage.c 
b/src/mainboard/tyan/s2882/romstage.c
-index dba58f2..c632b62 100644
---- a/src/mainboard/tyan/s2882/romstage.c
-+++ b/src/mainboard/tyan/s2882/romstage.c
-@@ -97,7 +97,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-         // automatically set that for you, but you might meet tight space
-         needs_reset |= ht_setup_chains_x();
-diff --git a/src/mainboard/tyan/s2885/romstage.c 
b/src/mainboard/tyan/s2885/romstage.c
-index fdf9606..81e3817 100644
---- a/src/mainboard/tyan/s2885/romstage.c
-+++ b/src/mainboard/tyan/s2885/romstage.c
-@@ -91,7 +91,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-         wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/tyan/s2891/romstage.c 
b/src/mainboard/tyan/s2891/romstage.c
-index 93189f1..7d170b5 100644
---- a/src/mainboard/tyan/s2891/romstage.c
-+++ b/src/mainboard/tyan/s2891/romstage.c
-@@ -112,7 +112,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/tyan/s2892/romstage.c 
b/src/mainboard/tyan/s2892/romstage.c
-index 881972d..460c909 100644
---- a/src/mainboard/tyan/s2892/romstage.c
-+++ b/src/mainboard/tyan/s2892/romstage.c
-@@ -103,7 +103,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/tyan/s2895/romstage.c 
b/src/mainboard/tyan/s2895/romstage.c
-index 086df63..5f3169a 100644
---- a/src/mainboard/tyan/s2895/romstage.c
-+++ b/src/mainboard/tyan/s2895/romstage.c
-@@ -130,7 +130,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-       wait_all_core0_started();
- 
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- 
-       needs_reset |= ht_setup_chains_x();
-diff --git a/src/mainboard/tyan/s2912/romstage.c 
b/src/mainboard/tyan/s2912/romstage.c
-index c608bb9..bbe2e43 100644
---- a/src/mainboard/tyan/s2912/romstage.c
-+++ b/src/mainboard/tyan/s2912/romstage.c
-@@ -141,7 +141,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-        * So here need to make sure last core0 is started, esp for two way 
system,
-        * (there may be apic id conflicts in that case)
-        */
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/tyan/s2912_fam10/romstage.c 
b/src/mainboard/tyan/s2912_fam10/romstage.c
-index cdf51b1..0fe004e 100644
---- a/src/mainboard/tyan/s2912_fam10/romstage.c
-+++ b/src/mainboard/tyan/s2912_fam10/romstage.c
-@@ -173,7 +173,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- #if CONFIG_LOGICAL_CPUS
-       /* Core0 on each node is configured. Now setup any additional cores. */
-       printk(BIOS_DEBUG, "start_other_cores()\n");
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       post_code(0x37);
-       wait_all_other_cores_started(bsp_apicid);
- #endif
-diff --git a/src/mainboard/tyan/s4880/romstage.c 
b/src/mainboard/tyan/s4880/romstage.c
-index 5c0b128..fcf9568 100644
---- a/src/mainboard/tyan/s4880/romstage.c
-+++ b/src/mainboard/tyan/s4880/romstage.c
-@@ -132,7 +132,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
- #endif
-       // automatically set that for you, but you might meet tight space
-         needs_reset |= ht_setup_chains_x();
-diff --git a/src/mainboard/tyan/s4882/romstage.c 
b/src/mainboard/tyan/s4882/romstage.c
-index ed84ab6..f2ea852 100644
---- a/src/mainboard/tyan/s4882/romstage.c
-+++ b/src/mainboard/tyan/s4882/romstage.c
-@@ -108,7 +108,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-         wait_all_core0_started();
- #if CONFIG_LOGICAL_CPUS
-         // It is said that we should start core1 after all core0 launched
--        start_other_cores();
-+        start_other_cores(bsp_apicid);
-         wait_all_other_cores_started(bsp_apicid);
- #endif
- 
-diff --git a/src/mainboard/winent/mb6047/romstage.c 
b/src/mainboard/winent/mb6047/romstage.c
-index 20eb92e..76e6393 100644
---- a/src/mainboard/winent/mb6047/romstage.c
-+++ b/src/mainboard/winent/mb6047/romstage.c
-@@ -99,7 +99,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       wait_all_core0_started();
-       // It is said that we should start core1 after all core0 launched
--      start_other_cores();
-+      start_other_cores(bsp_apicid);
-       wait_all_other_cores_started(bsp_apicid);
- 
- #if CONFIG_SET_FIDVID
-diff --git a/src/northbridge/amd/amdht/h3finit.c 
b/src/northbridge/amd/amdht/h3finit.c
-index 849f4a8..82bf885 100644
---- a/src/northbridge/amd/amdht/h3finit.c
-+++ b/src/northbridge/amd/amdht/h3finit.c
-@@ -389,13 +389,49 @@ static u8 convertNodeToLink(u8 srcNode, u8 targetNode, 
sMainData *pDat)
-  */
- static void htDiscoveryFloodFill(sMainData *pDat)
- {
--      u8 currentNode = 0;
--      u8 currentLink;
-+      uint8_t currentNode = 0;
-+      uint8_t currentLink;
-+      uint8_t currentLinkID;
-+
-+      /* NOTE
-+       * Each node inside a dual node (socket G34) processor must share
-+       * an adjacent node ID.  Alter the link scan order such that the
-+       * other internal node is always scanned first...
-+       */
-+      uint8_t currentLinkScanOrder_Default[8] = {0, 1, 2, 3, 4, 5, 6, 7};
-+      uint8_t currentLinkScanOrder_G34_Fam10[8] = {1, 0, 2, 3, 4, 5, 6, 7};
-+      uint8_t currentLinkScanOrder_G34_Fam15[8] = {2, 0, 1, 3, 4, 5, 6, 7};
-+
-+      uint8_t fam15h = 0;
-+      uint8_t rev_gte_d = 0;
-+      uint8_t dual_node = 0;
-+      uint32_t f3xe8;
-+      uint32_t family;
-+      uint32_t model;
-+
-+      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
-+
-+      family = model = cpuid_eax(0x80000001);
-+      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f) {
-+              /* Family 15h or later */
-+              fam15h = 1;
-+      }
-+
-+      if ((model >= 0x8) || fam15h)
-+              /* Revision D or later */
-+              rev_gte_d = 1;
-+
-+      if (rev_gte_d)
-+               /* Check for dual node capability */
-+              if (f3xe8 & 0x20000000)
-+                      dual_node = 1;
- 
-       /* Entries are always added in pairs, the even indices are the 'source'
-        * side closest to the BSP, the odd indices are the 'destination' side
-        */
--
-       while (currentNode <= pDat->NodesDiscovered)
-       {
-               u32 temp;
-@@ -423,11 +459,24 @@ static void htDiscoveryFloodFill(sMainData *pDat)
-               /* Enable routing tables on currentNode*/
-               pDat->nb->enableRoutingTables(currentNode, pDat->nb);
- 
--              for (currentLink = 0; currentLink < pDat->nb->maxLinks; 
currentLink++)
-+              for (currentLinkID = 0; currentLinkID < pDat->nb->maxLinks; 
currentLinkID++)
-               {
-                       BOOL linkfound;
-                       u8 token;
- 
-+                      if (currentLinkID < 8) {
-+                              if (dual_node) {
-+                                      if (fam15h)
-+                                              currentLink = 
currentLinkScanOrder_G34_Fam15[currentLinkID];
-+                                      else
-+                                              currentLink = 
currentLinkScanOrder_G34_Fam10[currentLinkID];
-+                              } else {
-+                                      currentLink = 
currentLinkScanOrder_Default[currentLinkID];
-+                              }
-+                      } else {
-+                              currentLink = currentLinkID;
-+                      }
-+
-                       if (pDat->HtBlock->AMD_CB_IgnoreLink && 
pDat->HtBlock->AMD_CB_IgnoreLink(currentNode, currentLink))
-                               continue;
- 
-diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
-index 8f9177f..1026d0e 100644
---- a/src/northbridge/amd/amdht/h3ncmn.c
-+++ b/src/northbridge/amd/amdht/h3ncmn.c
-@@ -51,8 +51,9 @@
- #define REG_NODE_ID_0X60              0x60
- #define REG_UNIT_ID_0X64              0x64
- #define REG_LINK_TRANS_CONTROL_0X68   0x68
--#define REG_LINK_INIT_CONTROL_0X6C    0x6C
-+#define REG_LINK_INIT_CONTROL_0X6C    0x6c
- #define REG_HT_CAP_BASE_0X80          0x80
-+#define REG_NORTHBRIDGE_CFG_3X8C      0x8c
- #define REG_HT_LINK_RETRY0_0X130      0x130
- #define REG_HT_TRAFFIC_DIST_0X164     0x164
- #define REG_HT_LINK_EXT_CONTROL0_0X170        0x170
-@@ -91,6 +92,21 @@
-  ***                  FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS           ***
-  ***************************************************************************/
- 
-+static inline uint8_t is_fam15h(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint32_t family;
-+
-+      family = cpuid_eax(0x80000001);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      return fam15h;
-+}
-+
- 
/***************************************************************************//**
-  *
-  * SBDFO
-@@ -219,8 +235,18 @@ static void writeRoutingTable(u8 node, u8 target, u8 
link, cNorthBridge *nb)
- 
- static void writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
- {
--      u32 temp = nodeID;
-+      u32 temp;
-       ASSERT((node < nb->maxNodes) && (nodeID < nb->maxNodes));
-+      if (is_fam15h()) {
-+              temp = 1;
-+              AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
-+                                      makePCIBusFromNode(node),
-+                                      makePCIDeviceFromNode(node),
-+                                      CPU_NB_FUNC_03,
-+                                      REG_NORTHBRIDGE_CFG_3X8C),
-+                                      22, 22, &temp);
-+      }
-+      temp = nodeID;
-       AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
-                               makePCIBusFromNode(node),
-                               makePCIDeviceFromNode(node),
-diff --git a/src/northbridge/amd/amdht/ht_wrapper.c 
b/src/northbridge/amd/amdht/ht_wrapper.c
-index c0ccc69..a4aaa12 100644
---- a/src/northbridge/amd/amdht/ht_wrapper.c
-+++ b/src/northbridge/amd/amdht/ht_wrapper.c
-@@ -92,16 +92,132 @@ static  u32 get_nodes(void)
-  */
- static void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0)
- {
--      u8 i;
-+      uint8_t i;
-+      uint8_t log_level;
-+      uint8_t dump_event_detail;
- 
--      printk(BIOS_DEBUG, "AMD_CB_EventNotify()\n");
--      printk(BIOS_DEBUG, " event class: %02x\n event: %04x\n data: ", 
evtClass, event);
-+      printk(BIOS_DEBUG, "AMD_CB_EventNotify(): ");
- 
--      for (i = 0; i < *pEventData0; i++) {
--              printk(BIOS_DEBUG, " %02x ", *(pEventData0 + i));
-+      /* Decode event */
-+      dump_event_detail = 1;
-+      switch (evtClass) {
-+              case HT_EVENT_CLASS_CRITICAL:
-+                      log_level = BIOS_DEBUG;
-+                      printk(log_level, "CRITICAL");
-+                      break;
-+              case HT_EVENT_CLASS_ERROR:
-+                      log_level = BIOS_DEBUG;
-+                      printk(log_level, "ERROR");
-+                      break;
-+              case HT_EVENT_CLASS_HW_FAULT:
-+                      log_level = BIOS_DEBUG;
-+                      printk(log_level, "HARDWARE FAULT");
-+                      break;
-+              case HT_EVENT_CLASS_WARNING:
-+                      log_level = BIOS_DEBUG;
-+                      printk(log_level, "WARNING");
-+                      break;
-+              case HT_EVENT_CLASS_INFO:
-+                      log_level = BIOS_DEBUG;
-+                      printk(log_level, "INFO");
-+                      break;
-+              default:
-+                      log_level = BIOS_DEBUG;
-+                      printk(log_level, "UNKNOWN");
-+                      break;
-       }
--      printk(BIOS_DEBUG, "\n");
-+      printk(log_level, ": ");
- 
-+      switch(event) {
-+              case HT_EVENT_COH_EVENTS:
-+                      printk(log_level, "HT_EVENT_COH_EVENTS");
-+                      break;
-+              case HT_EVENT_COH_NO_TOPOLOGY:
-+                      printk(log_level, "HT_EVENT_COH_NO_TOPOLOGY");
-+                      break;
-+              case HT_EVENT_COH_LINK_EXCEED:
-+                      printk(log_level, "HT_EVENT_COH_LINK_EXCEED");
-+                      break;
-+              case HT_EVENT_COH_FAMILY_FEUD:
-+                      printk(log_level, "HT_EVENT_COH_FAMILY_FEUD");
-+                      break;
-+              case HT_EVENT_COH_NODE_DISCOVERED:
-+                      {
-+                              printk(log_level, 
"HT_EVENT_COH_NODE_DISCOVERED");
-+                              sHtEventCohNodeDiscovered *evt = 
(sHtEventCohNodeDiscovered*)pEventData0;
-+                              printk(log_level, ": node %d link %d new node: 
%d",
-+                                      evt->node, evt->link, evt->newNode);
-+                              dump_event_detail = 0;
-+                              break;
-+                      }
-+              case HT_EVENT_COH_MPCAP_MISMATCH:
-+                      printk(log_level, "HT_EVENT_COH_MPCAP_MISMATCH");
-+                      break;
-+              case HT_EVENT_NCOH_EVENTS:
-+                      printk(log_level, "HT_EVENT_NCOH_EVENTS");
-+                      break;
-+              case HT_EVENT_NCOH_BUID_EXCEED:
-+                      printk(log_level, "HT_EVENT_NCOH_BUID_EXCEED");
-+                      break;
-+              case HT_EVENT_NCOH_LINK_EXCEED:
-+                      printk(log_level, "HT_EVENT_NCOH_LINK_EXCEED");
-+                      break;
-+              case HT_EVENT_NCOH_BUS_MAX_EXCEED:
-+                      printk(log_level, "HT_EVENT_NCOH_BUS_MAX_EXCEED");
-+                      break;
-+              case HT_EVENT_NCOH_CFG_MAP_EXCEED:
-+                      printk(log_level, "HT_EVENT_NCOH_CFG_MAP_EXCEED");
-+                      break;
-+              case HT_EVENT_NCOH_DEVICE_FAILED:
-+                      {
-+                              printk(log_level, 
"HT_EVENT_NCOH_DEVICE_FAILED");
-+                              sHtEventNcohDeviceFailed *evt = 
(sHtEventNcohDeviceFailed*)pEventData0;
-+                              printk(log_level, ": node %d link %d depth: %d 
attemptedBUID: %d",
-+                                      evt->node, evt->link, evt->depth, 
evt->attemptedBUID);
-+                              dump_event_detail = 0;
-+                              break;
-+                      }
-+              case HT_EVENT_NCOH_AUTO_DEPTH:
-+                      {
-+                              printk(log_level, "HT_EVENT_NCOH_AUTO_DEPTH");
-+                              sHtEventNcohAutoDepth *evt = 
(sHtEventNcohAutoDepth*)pEventData0;
-+                              printk(log_level, ": node %d link %d depth: %d",
-+                                      evt->node, evt->link, evt->depth);
-+                              dump_event_detail = 0;
-+                              break;
-+                      }
-+              case HT_EVENT_OPT_EVENTS:
-+                      printk(log_level, "HT_EVENT_OPT_EVENTS");
-+                      break;
-+              case HT_EVENT_OPT_REQUIRED_CAP_RETRY:
-+                      printk(log_level, "HT_EVENT_OPT_REQUIRED_CAP_RETRY");
-+                      break;
-+              case HT_EVENT_OPT_REQUIRED_CAP_GEN3:
-+                      printk(log_level, "HT_EVENT_OPT_REQUIRED_CAP_GEN3");
-+                      break;
-+              case HT_EVENT_HW_EVENTS:
-+                      printk(log_level, "HT_EVENT_HW_EVENTS");
-+                      break;
-+              case HT_EVENT_HW_SYNCHFLOOD:
-+                      printk(log_level, "HT_EVENT_HW_SYNCHFLOOD");
-+                      break;
-+              case HT_EVENT_HW_HTCRC:
-+                      printk(log_level, "HT_EVENT_HW_HTCRC");
-+                      break;
-+              default:
-+                      printk(log_level, "HT_EVENT_UNKNOWN");
-+                      break;
-+      }
-+      printk(log_level, "\n");
-+
-+      if (dump_event_detail) {
-+              printk(BIOS_DEBUG, " event class: %02x\n event: %04x\n data: ", 
evtClass, event);
-+
-+              for (i = 0; i < *pEventData0; i++) {
-+                      printk(BIOS_DEBUG, " %02x ", *(pEventData0 + i));
-+              }
-+              printk(BIOS_DEBUG, "\n");
-+      }
- }
- 
- /**
-@@ -210,9 +326,10 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
-                               for (node = 0; node < node_count; node++) {
-                                       f3xe8 = 
pci_read_config32(NODE_PCI(node, 3), 0xe8);
-                                       uint8_t internal_node_number = ((f3xe8 
& 0xc0000000) >> 30);
--                                      printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link\n", node, 
internal_node_number);
-+                                      printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link", node, 
internal_node_number);
-                                       if (internal_node_number == 0) {
-                                               uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0x98:0xd8) & 0x1;
-+                                              printk(BIOS_DEBUG, " (L3 
connected: %d)\n", package_link_3_connected);
-                                               if (package_link_3_connected) {
-                                                       /* Set WidthIn and 
WidthOut to 0 */
-                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4);
-@@ -234,15 +351,21 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
-                                               }
-                                       } else if (internal_node_number == 1) {
-                                               uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0xf8:0xb8) & 0x1;
-+                                              printk(BIOS_DEBUG, " (L3 
connected: %d)\n", package_link_3_connected);
-                                               if (package_link_3_connected) {
-                                                       /* Set WidthIn and 
WidthOut to 0 */
-                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4);
-                                                       dword &= ~0x77000000;
-                                                       
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4, dword);
-                                                       /* Set Ganged to 1 */
--                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174);
-+                                                      /* WARNING
-+                                                       * The Family 15h BKDG 
states that 0x18c should be set,
-+                                                       * however this is in 
error.  0x17c is the correct control
-+                                                       * register (sublink 0) 
for these processors...
-+                                                       */
-+                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x17c:0x174);
-                                                       dword |= 0x00000001;
--                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174, dword);
-+                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x17c:0x174, dword);
-                                               } else {
-                                                       /* Set ConnDly to 1 */
-                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 5a57dc0..0b61106 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -5441,6 +5441,7 @@ static void mct_InitialMCT_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStruc
-               cpu_divisor = (0x1 << cpu_did);
-               pMCTstat->TSCFreq = (100 * (cpu_fid + 0x10)) / cpu_divisor;
- 
-+              printk(BIOS_DEBUG, "mct_InitialMCT_D: 
mct_ForceNBPState0_En_Fam15\n");
-               mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
-       } else {
-               /* K10 BKDG v3.62 section 2.8.9.2 */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0087-northbridge-amd-amdmct-Reduce-maximum-number-of-DDR3.patch
 
b/resources/libreboot/patch/kgpe-d16/0087-northbridge-amd-amdmct-Reduce-maximum-number-of-DDR3.patch
new file mode 100644
index 0000000..08333f6
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0087-northbridge-amd-amdmct-Reduce-maximum-number-of-DDR3.patch
@@ -0,0 +1,41 @@
+From e262fc3ee190bafb58adfab926cc24ff9cbd239c Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 20 Oct 2015 21:32:09 -0500
+Subject: [PATCH 087/143] northbridge/amd/amdmct: Reduce maximum number of
+ DDR3 DIMMs
+
+CAR space on certain platforms is nearly full.  This prevents the
+addition of necessary RAM initialization features such as x4 DIMM
+support.  As the DIMM SPD cache uses a sizeable amount of CAR RAM,
+reducing it would free up a significant amount of CAR RAM.
+
+DDR3-based AMD platforms only support up to 3 physical DIMMs on
+each channel (6 per node).  Reduce the maximum number of DIMMs
+on a node from 8 to 6 accordingly.
+
+Change-Id: I38def86da76fc622785318c825670209b2ac9017
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/wrappers/mcti.h |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/src/northbridge/amd/amdmct/wrappers/mcti.h 
b/src/northbridge/amd/amdmct/wrappers/mcti.h
+index 2aba377..ef6e3dc 100644
+--- a/src/northbridge/amd/amdmct/wrappers/mcti.h
++++ b/src/northbridge/amd/amdmct/wrappers/mcti.h
+@@ -51,7 +51,11 @@ UPDATE AS NEEDED
+ #endif
+ 
+ #ifndef MAX_DIMMS_SUPPORTED
+-#define MAX_DIMMS_SUPPORTED           8
++#if IS_ENABLED(CONFIG_DIMM_DDR3)
++ #define MAX_DIMMS_SUPPORTED          6
++#else
++ #define MAX_DIMMS_SUPPORTED          8
++#endif
+ #endif
+ 
+ #ifndef MAX_CS_SUPPORTED
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdfam10-Add-probe-filter-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdfam10-Add-probe-filter-support.patch
deleted file mode 100644
index 09531d0..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdfam10-Add-probe-filter-support.patch
+++ /dev/null
@@ -1,214 +0,0 @@
-From c2436d732bdb97abdc4b4784598bc6c5d467a61f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 2 Aug 2015 21:06:39 -0500
-Subject: [PATCH 088/139] northbridge/amd/amdfam10: Add probe filter support
-
-Change-Id: I00a27a828260be8685ae622cfa5a4995add95a8e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/init_cpus.c |  13 +++
- src/northbridge/amd/amdfam10/northbridge.c    | 144 +++++++++++++++++++++++++-
- 2 files changed, 156 insertions(+), 1 deletion(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 986c024..2bc54dc 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -445,6 +445,19 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
- 
-               cpuSetAMDMSR(id.nodeid);
- 
-+              /* Set up probe filter support */
-+              if (is_gt_rev_d()) {
-+                      uint8_t node_count;
-+                      node_count = (pci_read_config32(NODE_PCI(id.nodeid, 0), 
0x60) >> 4) & 0x7;
-+                      node_count++;
-+
-+                      if (node_count > 1) {
-+                              msr_t msr = rdmsr(BU_CFG2_MSR);
-+                              msr.hi |= 1 << (42 - 32);
-+                              wrmsr(BU_CFG2_MSR, msr);
-+                      }
-+              }
-+
- #if CONFIG_SET_FIDVID
- #if CONFIG_LOGICAL_CPUS && CONFIG_SET_FIDVID_CORE0_ONLY
-               // Run on all AP for proper FID/VID setup.
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 95e902d..cdb8afa 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -30,10 +30,13 @@
- #include <lib.h>
- #include <smbios.h>
- #include <cpu/cpu.h>
-+#include <delay.h>
- 
- #include <cpu/x86/lapic.h>
-+#include <cpu/x86/cache.h>
- #include <cpu/amd/mtrr.h>
- #include <cpu/amd/amdfam10_sysconf.h>
-+#include <cpu/amd/model_10xxx_msr.h>
- #include <cpu/amd/family_10h-family_15h/ram_calc.h>
- 
- #if CONFIG_LOGICAL_CPUS
-@@ -1527,7 +1530,7 @@ static void cpu_bus_scan(device_t dev)
-               if(i>=32) {
-                       busn--;
-                       devn-=32;
--                      pbus = pci_domain->link_list->next);
-+                      pbus = pci_domain->link_list->next;
-               }
- #endif
- 
-@@ -1647,8 +1650,147 @@ static void cpu_bus_scan(device_t dev)
-       }
- }
- 
-+static void detect_and_enable_probe_filter(device_t dev)
-+{
-+      uint32_t dword;
-+
-+      uint8_t fam15h = 0;
-+      uint8_t rev_gte_d = 0;
-+      uint8_t dual_node = 0;
-+      unsigned nb_cfg_54;
-+      uint32_t f3xe8;
-+      uint32_t family;
-+      uint32_t model;
-+
-+      family = model = cpuid_eax(0x80000001);
-+      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+
-+      if (is_fam15h()) {
-+              /* Family 15h or later */
-+              fam15h = 1;
-+              nb_cfg_54 = 1;
-+      }
-+
-+      if ((model >= 0x8) || fam15h)
-+              /* Revision D or later */
-+              rev_gte_d = 1;
-+
-+      if (rev_gte_d)
-+              /* Check for dual node capability */
-+              if (f3xe8 & 0x20000000)
-+                      dual_node = 1;
-+
-+      if (rev_gte_d && (sysconf.nodes > 1)) {
-+              /* Enable the probe filter */
-+              uint8_t i;
-+              uint8_t pfmode = 0x0;
-+
-+              uint32_t f3x58[MAX_NODES_SUPPORTED];
-+              uint32_t f3x5c[MAX_NODES_SUPPORTED];
-+
-+              printk(BIOS_DEBUG, "Enabling probe filter\n");
-+
-+              /* Disable L3 and DRAM scrubbers and configure system for probe 
filter support */
-+              for (i = 0; i < sysconf.nodes; i++) {
-+                      device_t f2x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
2));
-+                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
-+
-+                      f3x58[i] = pci_read_config32(f3x_dev, 0x58);
-+                      f3x5c[i] = pci_read_config32(f3x_dev, 0x5c);
-+                      pci_write_config32(f3x_dev, 0x58, f3x58[i] & ~((0x1f << 
24) | 0x1f));
-+                      pci_write_config32(f3x_dev, 0x5c, f3x5c[i] & ~0x1);
-+
-+                      dword = pci_read_config32(f2x_dev, 0x1b0);
-+                      dword &= ~(0x7 << 8);   /* CohPrefPrbLmt = 0x0 */
-+                      pci_write_config32(f2x_dev, 0x1b0, dword);
-+
-+                      msr_t msr = rdmsr_amd(BU_CFG2_MSR);
-+                      msr.hi |= 1 << (42 - 32);
-+                      wrmsr_amd(BU_CFG2_MSR, msr);
-+
-+                      if (is_fam15h()) {
-+                              uint8_t subcache_size = 0x0;
-+                              uint8_t pref_so_repl = 0x0;
-+                              uint32_t f3x1c4 = pci_read_config32(f3x_dev, 
0x1c4);
-+                              if ((f3x1c4 & 0xffff) == 0xcccc) {
-+                                      subcache_size = 0x1;
-+                                      pref_so_repl = 0x2;
-+                                      pfmode = 0x3;
-+                              } else {
-+                                      pfmode = 0x2;
-+                              }
-+
-+                              dword = pci_read_config32(f3x_dev, 0x1d4);
-+                              dword |= 0x1 << 29;     /* PFLoIndexHashEn = 
0x1 */
-+                              dword &= ~(0x3 << 20);  /* PFPreferredSORepl = 
pref_so_repl */
-+                              dword |= (pref_so_repl & 0x3) << 20;
-+                              dword |= 0x1 << 17;     /* PFWayHashEn = 0x1 */
-+                              dword |= 0xf << 12;     /* PFSubCacheEn = 0xf */
-+                              dword &= ~(0x3 << 10);  /* PFSubCacheSize3 = 
subcache_size */
-+                              dword |= (subcache_size & 0x3) << 10;
-+                              dword &= ~(0x3 << 8);   /* PFSubCacheSize2 = 
subcache_size */
-+                              dword |= (subcache_size & 0x3) << 8;
-+                              dword &= ~(0x3 << 6);   /* PFSubCacheSize1 = 
subcache_size */
-+                              dword |= (subcache_size & 0x3) << 6;
-+                              dword &= ~(0x3 << 4);   /* PFSubCacheSize0 = 
subcache_size */
-+                              dword |= (subcache_size & 0x3) << 4;
-+                              dword &= ~(0x3 << 2);   /* PFWayNum = 0x2 */
-+                              dword |= 0x2 << 2;
-+                              pci_write_config32(f3x_dev, 0x1d4, dword);
-+                      } else {
-+                              pfmode = 0x2;
-+
-+                              dword = pci_read_config32(f3x_dev, 0x1d4);
-+                              dword |= 0x1 << 29;     /* PFLoIndexHashEn = 
0x1 */
-+                              dword &= ~(0x3 << 20);  /* PFPreferredSORepl = 
0x2 */
-+                              dword |= 0x2 << 20;
-+                              dword |= 0xf << 12;     /* PFSubCacheEn = 0xf */
-+                              dword &= ~(0x3 << 10);  /* PFSubCacheSize3 = 
0x0 */
-+                              dword &= ~(0x3 << 8);   /* PFSubCacheSize2 = 
0x0 */
-+                              dword &= ~(0x3 << 6);   /* PFSubCacheSize1 = 
0x0 */
-+                              dword &= ~(0x3 << 4);   /* PFSubCacheSize0 = 
0x0 */
-+                              dword &= ~(0x3 << 2);   /* PFWayNum = 0x2 */
-+                              dword |= 0x2 << 2;
-+                              pci_write_config32(f3x_dev, 0x1d4, dword);
-+                      }
-+              }
-+
-+              udelay(40);
-+
-+              disable_cache();
-+              asm("wbinvd");
-+              for (i = 0; i < sysconf.nodes; i++) {
-+                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
-+
-+                      dword = pci_read_config32(f3x_dev, 0x1c4);
-+                      dword |= (0x1 << 31);   /* L3TagInit = 1 */
-+                      pci_write_config32(f3x_dev, 0x1c4, dword);
-+                      do {
-+                      } while (pci_read_config32(f3x_dev, 0x1c4) & (0x1 << 
31));
-+
-+                      dword = pci_read_config32(f3x_dev, 0x1d4);
-+                      dword &= ~0x3;          /* PFMode = pfmode */
-+                      dword |= pfmode & 0x3;
-+                      pci_write_config32(f3x_dev, 0x1d4, dword);
-+                      do {
-+                      } while (!(pci_read_config32(f3x_dev, 0x1d4) & (0x1 << 
19)));
-+              }
-+              enable_cache();
-+
-+              /* Reenable L3 and DRAM scrubbers */
-+              for (i = 0; i < sysconf.nodes; i++) {
-+                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
-+
-+                      pci_write_config32(f3x_dev, 0x58, f3x58[i]);
-+                      pci_write_config32(f3x_dev, 0x5c, f3x5c[i]);
-+              }
-+
-+      }
-+}
-+
- static void cpu_bus_init(device_t dev)
- {
-+      detect_and_enable_probe_filter(dev);
-       initialize_cpus(dev->link_list);
- #if CONFIG_AMD_SB_CIMX
-       sb_After_Pci_Init();
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
 
b/resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
new file mode 100644
index 0000000..3e708f5
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch
@@ -0,0 +1,1887 @@
+From f30d6c75652c95152eb0dbe6bf9da2198a780a84 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 28 Jul 2015 15:16:46 -0500
+Subject: [PATCH 088/143] northbridge/amd/amdmct/mct_ddr3: Add registered and
+ x4 DIMM support to Fam15h
+
+Change-Id: I9ee0bb7346aa35f564fe535cdd337ec7f6148f2b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  186 ++++++-----
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |    2 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |    4 +
+ src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c   |   17 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctrci.c   |  191 +++++++----
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |   42 ++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |  253 ++++++++-------
+ src/northbridge/amd/amdmct/mct_ddr3/mctwl.c    |   16 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |  400 +++++++++++++++---------
+ src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h   |   13 +-
+ 10 files changed, 698 insertions(+), 426 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index b29ff3c..1c9c568 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -166,7 +166,7 @@ static void mct_EnDllShutdownSR(struct MCTStatStruc 
*pMCTstat,
+ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat);
+ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+-                                        struct DCTStatStruc *pDCTstat);
++                                        struct DCTStatStruc *pDCTstatA, 
uint8_t Node);
+ 
+ static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u32 MrsChipSel);
+@@ -1404,6 +1404,10 @@ static void precise_memclk_delay_fam15(struct 
MCTStatStruc *pMCTstat, struct DCT
+ 
+       memclk_freq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
+ 
++      if (fam15h_freq_tab[memclk_freq] == 0) {
++              printk(BIOS_DEBUG, "ERROR: precise_memclk_delay_fam15 for DCT 
%d (delay %d clocks) failed to obtain valid memory frequency!"
++                      " (pDCTstat: %p pDCTstat->dev_dct: %08x memclk_freq: 
%02x)\n", dct, clocks, pDCTstat, pDCTstat->dev_dct, memclk_freq);
++      }
+       delay_ns = (((uint64_t)clocks * 1000) / fam15h_freq_tab[memclk_freq]);
+       precise_ndelay_fam15(pMCTstat, delay_ns);
+ }
+@@ -2320,7 +2324,7 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+       nv_DQSTrainCTL = !allow_config_restore;
+ 
+       mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
+-      phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
++      phyAssistedMemFnceTraining(pMCTstat, pDCTstatA, -1);
+ 
+       if (is_fam15h()) {
+               uint8_t Node;
+@@ -3359,7 +3363,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ }
+ 
+ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat, u8 dct)
++                              struct DCTStatStruc *pDCTstat, uint8_t dct)
+ {
+       /* Initialize  DCT Timing registers as per DIMM SPD.
+        * For primary timing (T, CL) use best case T value.
+@@ -3463,7 +3467,7 @@ static void GetPresetmaxF_D(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat, u8 dct)
++                              struct DCTStatStruc *pDCTstat, uint8_t dct)
+ {
+       /* Find the best T and CL primary timing parameter pair, per Mfg.,
+        * for the given set of DIMMs, and store into DCTStatStruc
+@@ -3742,10 +3746,15 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+               dword++;
+       }
+ 
+-      if (Status & (1 << SB_Registered))
+-              DramConfigLo |= 1 << ParEn;             /* Registered DIMMs */
+-      else
+-              DramConfigLo |= 1 << UnBuffDimm;        /* Unbuffered DIMMs */
++      if (Status & (1 << SB_Registered)) {
++              /* Registered DIMMs */
++              if (!is_fam15h()) {
++                      DramConfigLo |= 1 << ParEn;
++              }
++      } else {
++              /* Unbuffered DIMMs */
++              DramConfigLo |= 1 << UnBuffDimm;
++      }
+ 
+       if (mctGet_NVbits(NV_ECC_CAP))
+               if (Status & (1 << SB_ECCDIMMs))
+@@ -3763,10 +3772,11 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+       DramConfigHi |= dword - offset; /* get MemClk encoding */
+       DramConfigHi |= 1 << MemClkFreqVal;
+ 
+-      if (Status & (1 << SB_Registered))
+-              if ((pDCTstat->Dimmx4Present != 0) && (pDCTstat->Dimmx8Present 
!= 0))
+-                      /* set only if x8 Registered DIMMs in System*/
+-                      DramConfigHi |= 1 << RDqsEn;
++      if (!is_fam15h())
++              if (Status & (1 << SB_Registered))
++                      if ((pDCTstat->Dimmx4Present != 0) && 
(pDCTstat->Dimmx8Present != 0))
++                              /* set only if x8 Registered DIMMs in System*/
++                              DramConfigHi |= 1 << RDqsEn;
+ 
+       if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
+               DramConfigLo |= 1 << 25;        /* PendRefPaybackS3En = 1 */
+@@ -3778,14 +3788,16 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+                       DramConfigHi |= 1 << 16;
+       }
+ 
+-      /* Control Bank Swizzle */
+-      if (0) /* call back not needed mctBankSwizzleControl_D()) */
+-              DramConfigHi &= ~(1 << BankSwizzleMode);
+-      else
+-              DramConfigHi |= 1 << BankSwizzleMode; /* recommended setting 
(default) */
++      if (!is_fam15h()) {
++              /* Control Bank Swizzle */
++              if (0) /* call back not needed mctBankSwizzleControl_D()) */
++                      DramConfigHi &= ~(1 << BankSwizzleMode);
++              else
++                      DramConfigHi |= 1 << BankSwizzleMode; /* recommended 
setting (default) */
++      }
+ 
+       /* Check for Quadrank DIMM presence */
+-      if ( pDCTstat->DimmQRPresent != 0) {
++      if (pDCTstat->DimmQRPresent != 0) {
+               byte = mctGet_NVbits(NV_4RANKType);
+               if (byte == 2)
+                       DramConfigHi |= 1 << 17;        /* S4 (4-Rank SO-DIMMs) 
*/
+@@ -4590,8 +4602,9 @@ static u8 mct_setMode(struct MCTStatStruc *pMCTstat,
+                       Set_NB32(pDCTstat->dev_dct, reg, val);
+               }
+               if (byte)       /* NV_Unganged */
+-                      pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); /* 
Clear so that there is no DIMM missmatch error */
++                      pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); /* 
Clear so that there is no DIMM mismatch error */
+       }
++
+       return pDCTstat->ErrCode;
+ }
+ 
+@@ -4652,6 +4665,8 @@ void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 
index, u32 data)
+ static u8 mct_BeforePlatformSpec(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       /* mct_checkForCxDxSupport_D */
+       if (pDCTstat->LogicalCPUID & AMD_DR_GT_Bx) {
+               /* Family 10h Errata 322: Address and Command Fine Delay Values 
May Be Incorrect */
+@@ -4666,6 +4681,9 @@ static u8 mct_BeforePlatformSpec(struct MCTStatStruc 
*pMCTstat,
+               else
+                       Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 
0x0D02E001, 0x90);
+       }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
++
+       return pDCTstat->ErrCode;
+ }
+ 
+@@ -4676,6 +4694,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+        * and program them into DCT.
+        */
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       u32 dev = pDCTstat->dev_dct;
+       u32 index_reg;
+       u8 i, i_start, i_end;
+@@ -4696,6 +4716,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
+               printk(BIOS_SPEW, "Programmed DCT %d timing/termination pattern 
%08x %08x\n", dct, pDCTstat->CH_ADDR_TMG[i], pDCTstat->CH_ODC_CTL[i]);
+       }
+ 
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
++
+       return pDCTstat->ErrCode;
+ }
+ 
+@@ -4707,7 +4729,8 @@ static void mct_SyncDCTsReady(struct DCTStatStruc 
*pDCTstat)
+       if (pDCTstat->NodePresent) {
+               dev = pDCTstat->dev_dct;
+ 
+-              if ((pDCTstat->DIMMValidDCT[0] ) || 
(pDCTstat->DIMMValidDCT[1])) {              /* This Node has dram */
++              if ((pDCTstat->DIMMValidDCT[0]) || (pDCTstat->DIMMValidDCT[1])) 
{
++                      /* This Node has DRAM */
+                       do {
+                               val = Get_NB32(dev, 0x110);
+                       } while (!(val & (1 << DramEnabled)));
+@@ -5655,57 +5678,56 @@ static void InitDDRPhy(struct MCTStatStruc *pMCTstat,
+       /* Fam15h BKDG v3.14 section 2.10.5.3
+        * The remainder of the Phy Initialization algorithm picks up in 
phyAssistedMemFnceTraining
+        */
+-      for (dct = 0; dct < 2; dct++) {
+-              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 
0x80000000);
+-              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 
0x00000118);
+-
+-              /* Program desired VDDIO level */
+-              if (ddr_voltage_index & 0x4) {
+-                      /* 1.25V */
+-                      amd_voltage_level_index = 0x2;
+-              } else if (ddr_voltage_index & 0x2) {
+-                      /* 1.35V */
+-                      amd_voltage_level_index = 0x1;
+-              } else if (ddr_voltage_index & 0x1) {
+-                      /* 1.50V */
+-                      amd_voltage_level_index = 0x0;
+-              }
+-
+-              /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */
+-              for (index = 0; index < 0x9; index++) {
+-                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f001f | (index << 8));
+-                      dword &= ~(0x3 << 3);
+-                      dword |= (amd_voltage_level_index << 3);
+-                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f 
| (index << 8), dword);
+-              }
+-
+-              /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */
+-              for (index = 0; index < 0x3; index++) {
+-                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f201f | (index << 8));
+-                      dword &= ~(0x3 << 3);
+-                      dword |= (amd_voltage_level_index << 3);
+-                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f 
| (index << 8), dword);
+-              }
+-              for (index = 0; index < 0x2; index++) {
+-                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f801f | (index << 8));
+-                      dword &= ~(0x3 << 3);
+-                      dword |= (amd_voltage_level_index << 3);
+-                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f 
| (index << 8), dword);
+-              }
+-              for (index = 0; index < 0x1; index++) {
+-                      dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fc01f | (index << 8));
+-                      dword &= ~(0x3 << 3);
+-                      dword |= (amd_voltage_level_index << 3);
+-                      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f 
| (index << 8), dword);
+-              }
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 0x80000000);
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 0x00000118);
+ 
+-              /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */
+-              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f4009);
+-              dword &= ~(0x0000c00c);
+-              dword |= (amd_voltage_level_index << 14);
+-              dword |= (amd_voltage_level_index << 2);
+-              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f4009, dword);
+-      }
++      /* Program desired VDDIO level */
++      if (ddr_voltage_index & 0x4) {
++              /* 1.25V */
++              amd_voltage_level_index = 0x2;
++      } else if (ddr_voltage_index & 0x2) {
++              /* 1.35V */
++              amd_voltage_level_index = 0x1;
++      } else if (ddr_voltage_index & 0x1) {
++              /* 1.50V */
++              amd_voltage_level_index = 0x0;
++      }
++
++      /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */
++      for (index = 0; index < 0x9; index++) {
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f 
| (index << 8));
++              dword &= ~(0x3 << 3);
++              dword |= (amd_voltage_level_index << 3);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f | 
(index << 8), dword);
++      }
++
++      /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */
++      for (index = 0; index < 0x3; index++) {
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f 
| (index << 8));
++              dword &= ~(0x3 << 3);
++              dword |= (amd_voltage_level_index << 3);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f | 
(index << 8), dword);
++      }
++      for (index = 0; index < 0x2; index++) {
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f 
| (index << 8));
++              dword &= ~(0x3 << 3);
++              dword |= (amd_voltage_level_index << 3);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f | 
(index << 8), dword);
++      }
++      for (index = 0; index < 0x1; index++) {
++              dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f 
| (index << 8));
++              dword &= ~(0x3 << 3);
++              dword |= (amd_voltage_level_index << 3);
++              Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f | 
(index << 8), dword);
++      }
++
++      /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */
++      /* NOTE: CmpVioLvl and ComparatorAdjust only take effect when set on 
DCT 0 */
++      dword = Get_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0f4009);
++      dword &= ~(0x0000c00c);
++      dword |= (amd_voltage_level_index << 14);
++      dword |= (amd_voltage_level_index << 2);
++      Set_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0f4009, dword);
+ 
+       printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+@@ -5721,18 +5743,24 @@ static void InitPhyCompensation(struct MCTStatStruc 
*pMCTstat,
+       uint32_t dword;
+       const u8 *p;
+ 
+-      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++      printk(BIOS_DEBUG, "%s: DCT %d: Start\n", __func__, dct);
+ 
+       if (is_fam15h()) {
+               /* Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 
2.10.5.3.4 */
+               uint32_t tx_pre;
+               uint32_t drive_strength;
+ 
+-              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
++              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp] */
+               dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
+-              dword |= (0x3 << 13);
++              dword |= (0x1 << 14);
+               Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword);
+ 
++              /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisablePredriverCal] */
++              /* NOTE: DisablePredriverCal only takes effect when set on DCT 
0 */
++              dword = Get_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0fe003);
++              dword |= (0x1 << 13);
++              Set_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0fe003, dword);
++
+               /* Determine TxPreP/TxPreN for data lanes (Stage 1) */
+               dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x00000000);
+               drive_strength = (dword >> 20) & 0x7;   /* DqsDrvStren */
+@@ -5878,12 +5906,14 @@ static void InitPhyCompensation(struct MCTStatStruc 
*pMCTstat,
+               Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0a, dword);
+       }
+ 
+-      printk(BIOS_DEBUG, "%s: Done\n", __func__);
++      printk(BIOS_DEBUG, "%s: DCT %d: Done\n", __func__, dct);
+ }
+ 
+ static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct)
+ {
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       if (!is_fam15h()) {
+               u32 reg;
+               u32 val;
+@@ -5905,6 +5935,8 @@ static void mct_EarlyArbEn_D(struct MCTStatStruc 
*pMCTstat,
+ 
+               Set_NB32_DCT(dev, dct, reg, val);
+       }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat,
+@@ -6548,6 +6580,8 @@ void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
+ 
+       uint32_t dword;
+ 
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       if (is_fam15h()) {
+               /* Initial setup for frequency change
+                * 9C_x0000_0004 must be configured before MemClkFreqVal is set
+@@ -6580,6 +6614,8 @@ void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
+               mct_Wait(100);
+       }
+ 
++      printk(BIOS_DEBUG, "mct_SetDramConfigHi_D: DramConfigHi:    %08x\n", 
DramConfigHi);
++
+       /* Program the DRAM Configuration High register */
+       Set_NB32_DCT(dev, dct, 0x94, DramConfigHi);
+ 
+@@ -6595,6 +6631,8 @@ void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat,
+               dword |= 0x0000000f;
+               Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 
0x0d0fe006, dword);
+       }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat,
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index e327d38..486b16c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -1014,7 +1014,7 @@ void InterleaveNodes_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTs
+ void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+ 
+-void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA);
++void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA, int16_t Node);
+ u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass);
+ u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct);
+ void mct_Wait(u32 cycles);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index 36e9858..c70fa6d 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -1588,6 +1588,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+ 
+       for (dct = 0; dct < 2; dct++) {
+               /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp, 
DisablePredriverCal] */
++              /* NOTE: DisablePredriverCal only takes effect when set on DCT 
0 */
+               dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0fe003);
+               dword &= ~(0x3 << 13);
+               dword |= (0x1 << 13);
+@@ -1627,6 +1628,9 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                               rx_en_offset = (initial_phy_phase_delay[lane] + 
0x10) % 0x40;
+ 
+                               /* 2.10.5.8.3 (4) */
++#if DQS_TRAIN_DEBUG > 0
++                              printk(BIOS_DEBUG, 
"TrainDQSReceiverEnCyc_D_Fam15 Receiver %d lane %d initial phy delay %04x: 
iterating from %04x to %04x\n", Receiver, lane, initial_phy_phase_delay[lane], 
rx_en_offset, 0x3ff);
++#endif
+                               for (current_phy_phase_delay[lane] = 
rx_en_offset; current_phy_phase_delay[lane] < 0x3ff; 
current_phy_phase_delay[lane] += ren_step) {
+                                       /* 2.10.5.8.3 (4 A) */
+                                       
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+index 539cb0d..1b81d15 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
+@@ -21,7 +21,7 @@
+ static uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
+ static uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
++                                      struct DCTStatStruc *pDCTstat, uint8_t 
dct, uint8_t dimm, uint8_t pass);
+ static uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u8 dimm, u8 pass);
+ static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat);
+@@ -133,7 +133,7 @@ static uint8_t PhyWLPass1(struct MCTStatStruc *pMCTstat,
+ }
+ 
+ static uint8_t PhyWLPass2(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, u8 dct)
++                                      struct DCTStatStruc *pDCTstat, uint8_t 
dct, uint8_t final)
+ {
+       u8 dimm;
+       u16 DIMMValid;
+@@ -187,12 +187,15 @@ static uint16_t fam15h_next_highest_memclk_freq(uint16_t 
memclk_freq)
+  * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1
+  */
+ static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat, uint8_t 
Pass)
++                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Node, uint8_t Pass)
+ {
+       uint8_t status;
+       uint8_t timeout;
+       uint16_t final_target_freq;
+ 
++      struct DCTStatStruc *pDCTstat;
++      pDCTstat = pDCTstatA + Node;
++
+       pDCTstat->C_MCTPtr  = &(pDCTstat->s_C_MCTPtr);
+       pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
+       pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
+@@ -240,13 +243,13 @@ static void WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+                                       pDCTstat->TargetFreq = 
fam15h_next_highest_memclk_freq(pDCTstat->Speed);
+                               else
+                                       pDCTstat->TargetFreq = 
final_target_freq;
+-                              SetTargetFreq(pMCTstat, pDCTstat);
++                              SetTargetFreq(pMCTstat, pDCTstatA, Node);
+                               timeout = 0;
+                               do {
+                                       status = 0;
+                                       timeout++;
+-                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 0);
+-                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 1);
++                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 0, (pDCTstat->TargetFreq == final_target_freq));
++                                      status |= PhyWLPass2(pMCTstat, 
pDCTstat, 1, (pDCTstat->TargetFreq == final_target_freq));
+                                       if (status)
+                                               printk(BIOS_INFO,
+                                                       "%s: Retrying write 
levelling due to invalid value(s) detected in last phase\n",
+@@ -290,7 +293,7 @@ void mct_WriteLevelization_HW(struct MCTStatStruc 
*pMCTstat,
+               if (pDCTstat->NodePresent) {
+                       mctSMBhub_Init(Node);
+                       Clear_OnDimmMirror(pMCTstat, pDCTstat);
+-                      WriteLevelization_HW(pMCTstat, pDCTstat, Pass);
++                      WriteLevelization_HW(pMCTstat, pDCTstatA, Node, Pass);
+                       Restore_OnDimmMirror(pMCTstat, pDCTstat);
+               }
+       }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+index 9617f84..624a543 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+@@ -18,6 +18,78 @@
+  * Foundation, Inc.
+  */
+ 
++static uint8_t fam15h_rdimm_rc2_control_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
++{
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
++
++      uint8_t package_type;
++      uint8_t control_code = 0;
++
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++      uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f;
++
++      /* Obtain number of DIMMs on channel */
++      uint8_t dimm_count = pDCTstat->MAdimms[dct];
++
++      /* FIXME
++       * Assume there is only one register on the RDIMM for now
++       */
++      uint8_t num_registers = 1;
++
++      if (package_type == PT_GR) {
++              /* Socket G34 */
++              /* Fam15h BKDG Rev. 3.14 section 2.10.5.7.1.2.1 Table 85 */
++              if (MaxDimmsInstallable == 1) {
++                      if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) {
++                              /* DDR3-667 - DDR3-800 */
++                              control_code = 0x1;
++                      } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) {
++                              /* DDR3-1066 - DDR3-1333 */
++                              if (num_registers == 1) {
++                                      control_code = 0x0;
++                              } else {
++                                      control_code = 0x1;
++                              }
++                      } else if ((MemClkFreq == 0x12) || (MemClkFreq == 
0x16)) {
++                              /* DDR3-1600 - DDR3-1866 */
++                              control_code = 0x0;
++                      }
++              } else if (MaxDimmsInstallable == 2) {
++                      if (dimm_count == 1) {
++                              /* 1 DIMM detected */
++                              if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) 
{
++                                      /* DDR3-667 - DDR3-800 */
++                                      control_code = 0x1;
++                              } else if ((MemClkFreq >= 0xa) && (MemClkFreq 
<= 0x12)) {
++                                      /* DDR3-1066 - DDR3-1600 */
++                                      if (num_registers == 1) {
++                                              control_code = 0x0;
++                                      } else {
++                                              control_code = 0x1;
++                                      }
++                              }
++                      } else if (dimm_count == 2) {
++                              /* 2 DIMMs detected */
++                              if (num_registers == 1) {
++                                      control_code = 0x1;
++                              } else {
++                                      control_code = 0x8;
++                              }
++                      }
++              } else if (MaxDimmsInstallable == 3) {
++                      /* TODO
++                       * 3 DIMM/channel support unimplemented
++                       */
++              }
++      } else {
++              /* TODO
++               * Other socket support unimplemented
++               */
++      }
++
++      return control_code;
++}
++
+ static uint16_t memclk_to_freq(uint16_t memclk) {
+       uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
+       uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
+@@ -37,36 +109,46 @@ static uint16_t memclk_to_freq(uint16_t memclk) {
+       return mem_freq;
+ }
+ 
++static uint8_t rc_word_chip_select_lower_bit(void) {
++      if (is_fam15h()) {
++              return 21;
++      } else {
++              return 20;
++      }
++}
++
++static uint32_t rc_word_address_to_ctl_bits(uint32_t address) {
++      if (is_fam15h()) {
++              return (((address >> 3) & 0x1) << 2) << 18 | (address & 0x7);
++      } else {
++              return (((address >> 3) & 0x1) << 2) << 16 | (address & 0x7);
++      }
++}
++
+ static uint32_t rc_word_value_to_ctl_bits(uint32_t value) {
+-      return ((value >> 2) & 3) << 16 | ((value & 3) << 3);
++      if (is_fam15h()) {
++              return ((value >> 2) & 0x3) << 18 | ((value & 0x3) << 3);
++      } else {
++              return ((value >> 2) & 0x3) << 16 | ((value & 0x3) << 3);
++      }
+ }
+ 
+ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+-                      struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 
CtrlWordNum)
++                      struct DCTStatStruc *pDCTstat, uint8_t dct, u32 
MrsChipSel, u32 CtrlWordNum)
+ {
+       u8 Dimms, DimmNum;
+       u32 val;
+-      u32 dct = 0;
+       uint8_t ddr_voltage_index;
+       uint16_t mem_freq;
+       uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+       uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+-      DimmNum = (MrsChipSel >> 20) & 0xFE;
++      DimmNum = (MrsChipSel >> rc_word_chip_select_lower_bit()) & 0xfe;
+ 
+-      /* assume dct=0; */
+-      /* if (dct == 1) */
+-      /* DimmNum ++; */
+-      /* cl +=8; */
++      if (dct == 1)
++              DimmNum++;
+ 
+       mem_freq = memclk_to_freq(pDCTstat->DIMMAutoSpeed);
+-
+-      if (pDCTstat->CSPresent_DCT[0] > 0) {
+-              dct = 0;
+-      } else if (pDCTstat->CSPresent_DCT[1] > 0 ) {
+-              dct = 1;
+-              DimmNum++;
+-      }
+       Dimms = pDCTstat->MAdimms[dct];
+ 
+       ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
+@@ -76,21 +158,25 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+               val = 0x2;
+       else if (CtrlWordNum == 1) {
+               if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 
<< DimmNum)))
+-                      val = 0xC; /* if single rank, set DBA1 and DBA0 */
++                      val = 0xc; /* if single rank, set DBA1 and DBA0 */
+       } else if (CtrlWordNum == 2) {
+-              if (package_type == PT_GR) {
+-                      /* Socket G34 */
+-                      if (MaxDimmsInstallable == 2) {
+-                              if (Dimms > 1)
+-                                      val = 0x4;
++              if (is_fam15h()) {
++                      val = fam15h_rdimm_rc2_control_code(pDCTstat, dct);
++              } else {
++                      if (package_type == PT_GR) {
++                              /* Socket G34 */
++                              if (MaxDimmsInstallable == 2) {
++                                      if (Dimms > 1)
++                                              val = 0x4;
++                              }
+                       }
+               }
+       } else if (CtrlWordNum == 3) {
+-              val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xFF;
++              val = (pDCTstat->CtrlWrd3 >> (DimmNum << 2)) & 0xff;
+       } else if (CtrlWordNum == 4) {
+-              val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xFF;
++              val = (pDCTstat->CtrlWrd4 >> (DimmNum << 2)) & 0xff;
+       } else if (CtrlWordNum == 5) {
+-              val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xFF;
++              val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xff;
+       } else if (CtrlWordNum == 8) {
+               if (package_type == PT_GR) {
+                       /* Socket G34 */
+@@ -99,7 +185,7 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+                       }
+               }
+       } else if (CtrlWordNum == 9) {
+-              val = 0xD;      /* DBA1, DBA0, DA3 = 0 */
++              val = 0xd;      /* DBA1, DBA0, DA3 = 0 */
+       } else if (CtrlWordNum == 10) {
+               val = 0x0;      /* Lowest operating frequency */
+       } else if (CtrlWordNum == 11) {
+@@ -114,43 +200,30 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+       }
+       val &= 0xf;
+ 
+-      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: %02x\n", CtrlWordNum, 
val);
++      printk(BIOS_SPEW, "Preparing to send DCT %d DIMM RC%d: %02x\n", dct, 
CtrlWordNum, val);
+ 
+       val = MrsChipSel | rc_word_value_to_ctl_bits(val);
+-
+-      /* transfer Control word number to address [BA2,A2,A1,A0] */
+-      if (CtrlWordNum > 7) {
+-              val |= 1 << 18;
+-              CtrlWordNum &= 7;
+-      }
+-      val |= CtrlWordNum;
++      val |= rc_word_address_to_ctl_bits(CtrlWordNum);
+ 
+       return val;
+ }
+ 
+ static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
+-                      struct DCTStatStruc *pDCTstat, u32 val)
++                      struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t 
val)
+ {
+-      uint8_t dct = 0;
+       u32 dev = pDCTstat->dev_dct;
+ 
+-      if (pDCTstat->CSPresent_DCT[0] > 0) {
+-              dct = 0;
+-      } else if (pDCTstat->CSPresent_DCT[1] > 0 ){
+-              dct = 1;
+-      }
+-
+-      val |= Get_NB32_DCT(dev, dct, 0x7C) & ~0xFFFFFF;
++      val |= Get_NB32_DCT(dev, dct, 0x7c) & ~0xffffff;
+       val |= 1 << SendControlWord;
+-      Set_NB32_DCT(dev, dct, 0x7C, val);
++      Set_NB32_DCT(dev, dct, 0x7c, val);
+ 
+       do {
+-              val = Get_NB32_DCT(dev, dct, 0x7C);
++              val = Get_NB32_DCT(dev, dct, 0x7c);
+       } while (val & (1 << SendControlWord));
+ }
+ 
+ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat, u8 dct)
++                              struct DCTStatStruc *pDCTstat, uint8_t dct)
+ {
+       u8 MrsChipSel;
+       u32 dev = pDCTstat->dev_dct;
+@@ -163,7 +236,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       val = Get_NB32_DCT(dev, dct, 0xa8);
+-                      val &= ~(0xF << 8);
++                      val &= ~(0xf << 8);
+ 
+                       switch (MrsChipSel) {
+                               case 0:
+@@ -184,8 +257,8 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+                       for (cw=0; cw <=15; cw ++) {
+                               mct_Wait(1600);
+                               if (!(cw==6 || cw==7)) {
+-                                      val = mct_ControlRC(pMCTstat, pDCTstat, 
MrsChipSel << 20, cw);
+-                                      mct_SendCtrlWrd(pMCTstat, pDCTstat, 
val);
++                                      val = mct_ControlRC(pMCTstat, pDCTstat, 
dct, MrsChipSel << rc_word_chip_select_lower_bit(), cw);
++                                      mct_SendCtrlWrd(pMCTstat, pDCTstat, 
dct, val);
+                               }
+                       }
+               }
+@@ -195,7 +268,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+-                      struct DCTStatStruc *pDCTstat)
++                      struct DCTStatStruc *pDCTstat, uint8_t dct)
+ {
+       u32 SaveSpeed = pDCTstat->DIMMAutoSpeed;
+       u32 MrsChipSel;
+@@ -208,10 +281,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
+-                      val = Get_NB32_DCT(dev, 0, 0xA8); /* TODO: dct 0 / 1 
select */
+-                      val &= ~(0xFF << 8);
+-                      val |= (0x3 << (MrsChipSel & 0xFE)) << 8;
+-                      Set_NB32_DCT(dev, 0, 0xA8, val); /* TODO: dct 0 / 1 
select */
++                      val = Get_NB32_DCT(dev, dct, 0xa8);
++                      val &= ~(0xff << 8);
++                      val |= (0x3 << (MrsChipSel & 0xfe)) << 8;
++                      Set_NB32_DCT(dev, dct, 0xa8, val);
+ 
+                       /* Resend control word 10 */
+                       uint8_t freq_ctl_val = 0;
+@@ -235,21 +308,21 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+                                       break;
+                       }
+ 
+-                      printk(BIOS_SPEW, "Preparing to send DIMM RC%d: 
%02x\n", 10, freq_ctl_val);
++                      printk(BIOS_SPEW, "Preparing to send DCT %d DIMM RC%d: 
%02x\n", dct, 10, freq_ctl_val);
+ 
+-                      mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 
0x40002 | rc_word_value_to_ctl_bits(freq_ctl_val));
++                      mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, MrsChipSel << 
rc_word_chip_select_lower_bit() | rc_word_address_to_ctl_bits(10) | 
rc_word_value_to_ctl_bits(freq_ctl_val));
+ 
+                       mct_Wait(1600);
+ 
+                       /* Resend control word 2 */
+-                      val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 
20, 2);
+-                      mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
++                      val = mct_ControlRC(pMCTstat, pDCTstat, dct, MrsChipSel 
<< rc_word_chip_select_lower_bit(), 2);
++                      mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, val);
+ 
+                       mct_Wait(1600);
+ 
+                       /* Resend control word 8 */
+-                      val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 
20, 8);
+-                      mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
++                      val = mct_ControlRC(pMCTstat, pDCTstat, dct, MrsChipSel 
<< rc_word_chip_select_lower_bit(), 8);
++                      mct_SendCtrlWrd(pMCTstat, pDCTstat, dct, val);
+ 
+                       mct_Wait(1600);
+               }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 9ccf77e..09a5f68 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -445,13 +445,13 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+ 
++      /* The formula for chip select number is: CS = dimm*2+rank */
++      uint8_t dimm = MrsChipSel / 2;
++      uint8_t rank = MrsChipSel % 2;
++
+       if (is_fam15h()) {
+               uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+ 
+-              /* The formula for chip select number is: CS = dimm*2+rank */
+-              uint8_t dimm = MrsChipSel / 2;
+-              uint8_t rank = MrsChipSel % 2;
+-
+               /* FIXME: These parameters should be configurable
+                * For now, err on the side of caution and enable automatic 2x 
refresh
+                * when the DDR temperature rises above the internal limits
+@@ -496,7 +496,7 @@ static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+               ret |= ((dword >> 10) & 3) << 9;
+       }
+ 
+-      printk(BIOS_SPEW, "Going to send MR2 control word %08x\n", ret);
++      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR2 control 
word %08x\n", dct, dimm, rank, ret);
+ 
+       return ret;
+ }
+@@ -507,6 +507,10 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+ 
++      /* The formula for chip select number is: CS = dimm*2+rank */
++      uint8_t dimm = MrsChipSel / 2;
++      uint8_t rank = MrsChipSel % 2;
++
+       if (is_fam15h()) {
+               ret = 0xc0000;
+               ret |= (MrsChipSel << 21);
+@@ -527,7 +531,7 @@ static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
+               ret |= (dword >> 24) & 7;
+       }
+ 
+-      printk(BIOS_SPEW, "Going to send MR3 control word %08x\n", ret);
++      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR3 control 
word %08x\n", dct, dimm, rank, ret);
+ 
+       return ret;
+ }
+@@ -538,6 +542,10 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret;
+ 
++      /* The formula for chip select number is: CS = dimm*2+rank */
++      uint8_t dimm = MrsChipSel / 2;
++      uint8_t rank = MrsChipSel % 2;
++
+       if (is_fam15h()) {
+               uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+ 
+@@ -553,10 +561,6 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+               ret = 0x40000;
+               ret |= (MrsChipSel << 21);
+ 
+-              /* The formula for chip select number is: CS = dimm*2+rank */
+-              uint8_t dimm = MrsChipSel / 2;
+-              uint8_t rank = MrsChipSel % 2;
+-
+               /* Determine if TQDS should be set */
+               if ((pDCTstat->Dimmx8Present & (1 << dimm))
+                       && (((dimm & 
0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0)
+@@ -623,7 +627,7 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+                       ret |= 1 << 12;
+       }
+ 
+-      printk(BIOS_SPEW, "Going to send MR1 control word %08x\n", ret);
++      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR1 control 
word %08x\n", dct, dimm, rank, ret);
+ 
+       return ret;
+ }
+@@ -634,6 +638,10 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
+       u32 dev = pDCTstat->dev_dct;
+       u32 dword, ret, dword2;
+ 
++      /* The formula for chip select number is: CS = dimm*2+rank */
++      uint8_t dimm = MrsChipSel / 2;
++      uint8_t rank = MrsChipSel % 2;
++
+       if (is_fam15h()) {
+               ret = 0x00000;
+               ret |= (MrsChipSel << 21);
+@@ -744,7 +752,7 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
+               ret |= 1 << 8;
+       }
+ 
+-      printk(BIOS_SPEW, "Going to send MR0 control word %08x\n", ret);
++      printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR0 control 
word %08x\n", dct, dimm, rank, ret);
+ 
+       return ret;
+ }
+@@ -811,6 +819,16 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+               /* 8.wait 360ns */
+               mct_Wait(80);
+ 
++              /* Set up address parity */
++              if ((pDCTstat->Status & (1 << SB_Registered))
++                      || (pDCTstat->Status & (1 << SB_LoadReduced))) {
++                      if (is_fam15h()) {
++                              dword = Get_NB32_DCT(dev, dct, 0x90);
++                              dword |= 1 << ParEn;
++                              Set_NB32_DCT(dev, dct, 0x90, dword);
++                      }
++              }
++
+               /* The following steps are performed with registered DIMMs only 
and
+                * must be done for each chip select pair */
+               if (pDCTstat->Status & (1 << SB_Registered))
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 981f467..707e6a9 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -1146,8 +1146,10 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
+       uint8_t dimm;
+       uint8_t rank;
+       uint8_t lane;
++      uint8_t nibble;
+       uint8_t mem_clk;
+       uint16_t initial_seed;
++      uint8_t train_both_nibbles;
+       uint16_t current_total_delay[MAX_BYTE_LANES];
+       uint16_t dqs_ret_pass1_total_delay[MAX_BYTE_LANES];
+       uint16_t rank0_current_total_delay[MAX_BYTE_LANES];
+@@ -1163,6 +1165,11 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
+       print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
+       print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
+ 
++      train_both_nibbles = 0;
++      if (pDCTstat->Dimmx4Present)
++              if (is_fam15h())
++                      train_both_nibbles = 1;
++
+       dev = pDCTstat->dev_dct;
+       index_reg = 0x98;
+       ch_start = 0;
+@@ -1245,132 +1252,148 @@ static void dqsTrainRcvrEn_SW_Fam15(struct 
MCTStatStruc *pMCTstat,
+                       else
+                               _2Ranks = 0;
+                       for (rank = 0; rank < (_2Ranks + 1); rank++) {
+-                              /* 2.10.5.8.2 (1)
+-                               * Specify the target DIMM to be trained
+-                               * Set TrNibbleSel = 0
+-                               *
+-                               * TODO: Add support for x4 DIMMs
+-                               */
+-                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
+-                              dword &= ~(0x3 << 4);           /* TrDimmSel */
+-                              dword |= ((dimm & 0x3) << 4);
+-                              dword &= ~(0x1 << 2);           /* TrNibbleSel 
*/
+-                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
+-
+-                              /* 2.10.5.8.2 (2)
+-                               * Retrieve gross and fine timing fields from 
write DQS registers
+-                               */
+-                              
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
++                              for (nibble = 0; nibble < (train_both_nibbles + 
1); nibble++) {
++                                      /* 2.10.5.8.2 (1)
++                                       * Specify the target DIMM and nibble 
to be trained
++                                       */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
Channel, index_reg, 0x00000008);
++                                      dword &= ~(0x3 << 4);           /* 
TrDimmSel = dimm */
++                                      dword |= ((dimm & 0x3) << 4);
++                                      dword &= ~(0x1 << 2);           /* 
TrNibbleSel = nibble */
++                                      dword |= ((nibble & 0x1) << 2);
++                                      Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
++
++                                      /* 2.10.5.8.2 (2)
++                                       * Retrieve gross and fine timing 
fields from write DQS registers
++                                       */
++                                      
read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+ 
+-                              /* 2.10.5.8.2.1
+-                               * Generate the DQS Receiver Enable Training 
Seed Values
+-                               */
+-                              if (Pass == FirstPass) {
+-                                      initial_seed = 
fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, 
package_type);
++                                      /* 2.10.5.8.2.1
++                                       * Generate the DQS Receiver Enable 
Training Seed Values
++                                       */
++                                      if (Pass == FirstPass) {
++                                              initial_seed = 
fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, 
package_type);
+ 
+-                                      /* Adjust seed for the minimum platform 
supported frequency */
+-                                      initial_seed = (uint16_t) 
(((((uint64_t) initial_seed) *
+-                                              fam15h_freq_tab[mem_clk] * 100) 
/ (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
++                                              /* Adjust seed for the minimum 
platform supported frequency */
++                                              initial_seed = (uint16_t) 
(((((uint64_t) initial_seed) *
++                                                      
fam15h_freq_tab[mem_clk] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
+ 
+-                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
+-                                              uint16_t wl_pass1_delay;
+-                                              wl_pass1_delay = 
current_total_delay[lane];
++                                              for (lane = 0; lane < 
MAX_BYTE_LANES; lane++) {
++                                                      uint16_t wl_pass1_delay;
++                                                      wl_pass1_delay = 
current_total_delay[lane];
+ 
+-                                              seed[lane] = initial_seed + 
wl_pass1_delay;
+-                                      }
+-                              } else {
+-                                      uint8_t addr_prelaunch = 0;             
/* TODO: Fetch the correct value from RC2[0] */
+-                                      uint16_t register_delay;
+-                                      int16_t seed_prescaling;
+-
+-                                      memcpy(current_total_delay, 
dqs_ret_pass1_total_delay, sizeof(current_total_delay));
+-                                      if ((pDCTstat->Status & (1 << 
SB_Registered))) {
+-                                              if (addr_prelaunch)
+-                                                      register_delay = 0x30;
+-                                              else
+-                                                      register_delay = 0x20;
+-                                      } else if ((pDCTstat->Status & (1 << 
SB_LoadReduced))) {
+-                                              /* TODO
+-                                              * Load reduced DIMM support 
unimplemented
+-                                              */
+-                                              register_delay = 0x0;
++                                                      seed[lane] = 
initial_seed + wl_pass1_delay;
++                                              }
+                                       } else {
+-                                              register_delay = 0x0;
++                                              uint8_t addr_prelaunch = 0;     
        /* TODO: Fetch the correct value from RC2[0] */
++                                              uint16_t register_delay;
++                                              int16_t seed_prescaling;
++
++                                              memcpy(current_total_delay, 
dqs_ret_pass1_total_delay, sizeof(current_total_delay));
++                                              if ((pDCTstat->Status & (1 << 
SB_Registered))) {
++                                                      if (addr_prelaunch)
++                                                              register_delay 
= 0x30;
++                                                      else
++                                                              register_delay 
= 0x20;
++                                              } else if ((pDCTstat->Status & 
(1 << SB_LoadReduced))) {
++                                                      /* TODO
++                                                       * Load reduced DIMM 
support unimplemented
++                                                       */
++                                                      register_delay = 0x0;
++                                              } else {
++                                                      register_delay = 0x0;
++                                              }
++
++                                              for (lane = 0; lane < 
MAX_BYTE_LANES; lane++) {
++                                                      seed_prescaling = 
current_total_delay[lane] - register_delay - 0x20;
++                                                      seed[lane] = (uint16_t) 
(register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 
100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
++                                              }
+                                       }
+ 
+                                       for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
+-                                              seed_prescaling = 
current_total_delay[lane] - register_delay - 0x20;
+-                                              seed[lane] = (uint16_t) 
(register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 
100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
+-                                      }
+-                              }
++                                              seed_gross[lane] = (seed[lane] 
>> 5) & 0x1f;
++                                              seed_fine[lane] = seed[lane] & 
0x1f;
+ 
+-                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+-                                      seed_gross[lane] = (seed[lane] >> 5) & 
0x1f;
+-                                      seed_fine[lane] = seed[lane] & 0x1f;
++                                              /*if (seed_gross[lane] == 0)
++                                                      seed_pre_gross[lane] = 
0;
++                                              else */if (seed_gross[lane] & 
0x1)
++                                                      seed_pre_gross[lane] = 
1;
++                                              else
++                                                      seed_pre_gross[lane] = 
2;
+ 
+-                                      /*if (seed_gross[lane] == 0)
+-                                              seed_pre_gross[lane] = 0;
+-                                      else */if (seed_gross[lane] & 0x1)
+-                                              seed_pre_gross[lane] = 1;
+-                                      else
+-                                              seed_pre_gross[lane] = 2;
++                                              /* Calculate phase recovery 
delays */
++                                              phase_recovery_delays[lane] = 
((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
+ 
+-                                      /* Calculate phase recovery delays */
+-                                      phase_recovery_delays[lane] = 
((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
++                                              /* Set the gross delay.
++                                              * NOTE: While the BKDG states 
to only program DqsRcvEnGrossDelay, this appears
++                                              * to have been a misprint as 
DqsRcvEnFineDelay should be set to zero as well.
++                                              */
++                                              current_total_delay[lane] = 
((seed_gross[lane] & 0x1f) << 5);
++                                      }
+ 
+-                                      /* Set the gross delay.
+-                                       * NOTE: While the BKDG states to only 
program DqsRcvEnGrossDelay, this appears
+-                                       * to have been a misprint as 
DqsRcvEnFineDelay should be set to zero as well.
++                                      /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
++                                       * Program PhRecFineDly and 
PhRecGrossDly
+                                        */
+-                                      current_total_delay[lane] = 
((seed_gross[lane] & 0x1f) << 5);
+-                              }
++                                      
write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, 
Channel, dimm, index_reg);
+ 
+-                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
+-                               * Program PhRecFineDly and PhRecGrossDly
+-                               */
+-                              
write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, 
Channel, dimm, index_reg);
++                                      /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
++                                       * Program the DQS Receiver Enable 
delay values for each lane
++                                       */
++                                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+ 
+-                              /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
+-                               * Program the DQS Receiver Enable delay values 
for each lane
+-                               */
+-                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
++                                      /* 2.10.5.8.2 (3)
++                                       * Program DqsRcvTrEn = 1
++                                       */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
Channel, index_reg, 0x00000008);
++                                      dword |= (0x1 << 13);
++                                      Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
+ 
+-                              /* 2.10.5.8.2 (3)
+-                               * Program DqsRcvTrEn = 1
+-                               */
+-                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
+-                              dword |= (0x1 << 13);
+-                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
++                                      /* 2.10.5.8.2 (4)
++                                       * Issue 192 read requests to the 
target rank
++                                       */
++                                      
generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, Receiver + (rank & 0x1));
+ 
+-                              /* 2.10.5.8.2 (4)
+-                               * Issue 192 read requests to the target rank
+-                               */
+-                              
generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, Receiver + (rank & 0x1));
++                                      /* 2.10.5.8.2 (5)
++                                       * Program DqsRcvTrEn = 0
++                                       */
++                                      dword = Get_NB32_index_wait_DCT(dev, 
Channel, index_reg, 0x00000008);
++                                      dword &= ~(0x1 << 13);
++                                      Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
+ 
+-                              /* 2.10.5.8.2 (5)
+-                               * Program DqsRcvTrEn = 0
+-                               */
+-                              dword = Get_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008);
+-                              dword &= ~(0x1 << 13);
+-                              Set_NB32_index_wait_DCT(dev, Channel, 
index_reg, 0x00000008, dword);
++                                      /* 2.10.5.8.2 (6)
++                                       * Read PhRecGrossDly, PhRecFineDly
++                                       */
++                                      
read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, 
dimm, index_reg);
+ 
+-                              /* 2.10.5.8.2 (6)
+-                               * Read PhRecGrossDly, PhRecFineDly
+-                               */
+-                              
read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, 
dimm, index_reg);
++                                      /* 2.10.5.8.2 (7)
++                                       * Calculate and program the DQS 
Receiver Enable delay values
++                                       */
++                                      for (lane = 0; lane < MAX_BYTE_LANES; 
lane++) {
++                                              current_total_delay[lane] = 
(phase_recovery_delays[lane] & 0x1f);
++                                              current_total_delay[lane] |= 
((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - 
seed_pre_gross[lane] + 1) << 5);
++                                              if (nibble == 0) {
++                                                      if (lane == 8)
++                                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
++                                                      else
++                                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
++                                              } else {
++                                                      /* 2.10.5.8.2 (1)
++                                                       * Average the trained 
values of both nibbles on x4 DIMMs
++                                                       */
++                                                      if (lane == 8)
++                                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = 
(pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] + current_total_delay[lane]) / 2;
++                                                      else
++                                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = 
(pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] + current_total_delay[lane]) / 2;
++                                              }
++                                      }
+ 
+-                              /* 2.10.5.8.2 (7)
+-                               * Calculate and program the DQS Receiver 
Enable delay values
+-                               */
+-                              for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
+-                                      current_total_delay[lane] = 
(phase_recovery_delays[lane] & 0x1f);
+-                                      current_total_delay[lane] |= 
((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - 
seed_pre_gross[lane] + 1) << 5);
+-                                      if (lane == 8)
+-                                              
pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
+-                                      else
+-                                              
pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
++#if DQS_TRAIN_DEBUG > 1
++                                      for (lane = 0; lane < 8; lane++)
++                                              printk(BIOS_DEBUG, 
"\t\tTrainRcvEn55: Channel: %d dimm: %d nibble: %d lane %d current_total_delay: 
%04x CH_D_B_RCVRDLY: %04x\n",
++                                                      Channel, dimm, nibble, 
lane, current_total_delay[lane], pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane]);
++#endif
++                                      
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+                               }
+-                              
write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
+ 
+                               if (rank == 0) {
+                                       /* Back up the Rank 0 delays for later 
use */
+@@ -1395,7 +1418,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
+ 
+ #if DQS_TRAIN_DEBUG > 0
+                       for (lane = 0; lane < 8; lane++)
+-                              print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
++                              print_debug_dqs_pair("\t\tTrainRcvEn56: Lane ", 
lane, " current_total_delay ", current_total_delay[lane], 2);
+ #endif
+               }
+       }
+@@ -1815,15 +1838,23 @@ void mctSetEccDQSRcvrEn_D(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat,
+-                      struct DCTStatStruc *pDCTstatA)
++                      struct DCTStatStruc *pDCTstatA, int16_t 
single_node_number)
+ {
+       u8 Node = 0;
+       struct DCTStatStruc *pDCTstat;
+ 
+       printk(BIOS_DEBUG, "%s: Start\n", __func__);
+ 
++      uint8_t start_node = 0;
++      uint8_t end_node = MAX_NODES_SUPPORTED;
++
++      if (single_node_number >= 0) {
++              start_node = single_node_number;
++              end_node = single_node_number;
++      }
++
+       /* FIXME: skip for Ax */
+-      for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
++      for (Node = start_node; Node < end_node; Node++) {
+               pDCTstat = pDCTstatA + Node;
+               if (!pDCTstat->NodePresent)
+                       continue;
+@@ -1847,6 +1878,8 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
+                                       if (!pDCTstat->DIMMValidDCT[dct])
+                                               continue;
+ 
++                                      printk(BIOS_SPEW, "%s: training node %d 
DCT %d\n", __func__, Node, dct);
++
+                                       /* Back up D18F2x9C_x0000_0004_dct[1:0] 
*/
+                                       datc_backup = 
Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004);
+ 
+@@ -1985,6 +2018,8 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
+ 
+                                       /* Restore D18F2x9C_x0000_0004_dct[1:0] 
*/
+                                       Set_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x00000004, datc_backup);
++
++                                      printk(BIOS_SPEW, "%s: done training 
node %d DCT %d\n", __func__, Node, dct);
+                               }
+                       } else {
+                               fenceDynTraining_D(pMCTstat, pDCTstat, 0);
+@@ -1997,7 +2032,7 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ static uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
+-                      struct DCTStatStruc *pDCTstat, u8 dct)
++                      struct DCTStatStruc *pDCTstat, uint8_t dct)
+ {
+       u16 avRecValue;
+       u32 val;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+index 6b63ba0..3153e46 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+@@ -19,7 +19,7 @@
+  */
+ 
+ static void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+-                      struct DCTStatStruc *pDCTstat);
++                      struct DCTStatStruc *pDCTstat, uint8_t dct);
+ 
+ 
+ static void AgesaDelay(u32 msec)
+@@ -353,11 +353,14 @@ static void ExitSelfRefresh(struct MCTStatStruc 
*pMCTstat,
+ }
+ 
+ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+-                                      struct DCTStatStruc *pDCTstat)
++                                      struct DCTStatStruc *pDCTstatA, uint8_t 
Node)
+ {
+       uint32_t dword;
+       uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+ 
++      struct DCTStatStruc *pDCTstat;
++      pDCTstat = pDCTstatA + Node;
++
+       if (is_fam15h()) {
+               /* Program F2x[1, 0]90[DisDllShutDownSR]=1. */
+               if (pDCTstat->DIMMValidDCT[0]) {
+@@ -391,7 +394,7 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+               uint8_t dct;
+               for (dct = 0; dct < 2; dct++) {
+                       if (pDCTstat->DIMMValidDCT[dct]) {
+-                              phyAssistedMemFnceTraining(pMCTstat, pDCTstat);
++                              phyAssistedMemFnceTraining(pMCTstat, pDCTstatA, 
Node);
+                               InitPhyCompensation(pMCTstat, pDCTstat, dct);
+                       }
+               }
+@@ -438,7 +441,12 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat,
+               else
+                       pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[1];
+ 
+-              FreqChgCtrlWrd(pMCTstat, pDCTstat);
++              if (pDCTstat->DIMMValidDCT[0]) {
++                      FreqChgCtrlWrd(pMCTstat, pDCTstat, 0);
++              }
++              if (pDCTstat->DIMMValidDCT[1]) {
++                      FreqChgCtrlWrd(pMCTstat, pDCTstat, 1);
++              }
+       }
+ }
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index e5e4031..73b231e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -35,9 +35,9 @@ u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint32_t MRSValue);
+ void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
+       u8 dct, u8 dimm, BOOL wl);
+ void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm);
+-void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass);
++void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble);
+ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, u8 targetAddr, uint8_t pass);
+-void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass);
++void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass, uint8_t nibble);
+ 
+ static int32_t abs(int32_t val) {
+       if (val < 0)
+@@ -76,6 +76,8 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
+ {
+       u8 ByteLane;
+       u32 Value, Addr;
++      uint8_t nibble = 0;
++      uint8_t train_both_nibbles;
+       u16 Addl_Data_Offset, Addl_Data_Port;
+       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+@@ -88,98 +90,108 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
+                       TrDimmSelEnd, (u32)dimm);
+ 
+-      if (is_fam15h()) {
+-              /* Set TrNibbleSel = 0
+-               *
+-               * TODO: Add support for x4 DIMMs
+-               */
+-              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+-                              DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
+-                              2, (u32)0);
+-      }
++      train_both_nibbles = 0;
++      if (pDCTstat->Dimmx4Present)
++              if (is_fam15h())
++                      train_both_nibbles = 1;
+ 
+-      /* 2. Prepare the DIMMs for write levelization using DDR3-defined
+-       * MR commands. */
+-      prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
++      for (nibble = 0; nibble < (train_both_nibbles + 1); nibble++) {
++              printk(BIOS_SPEW, "AgesaHwWlPhase1: training nibble %d\n", 
nibble);
+ 
+-      /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
+-       *    satisfy DDR3-defined internal DRAM timing.
+-       */
+-      if (is_fam15h())
+-              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
+-      else
+-              pMCTData->AgesaDelay(40);
++              if (is_fam15h()) {
++                      /* Program F2x[1, 0]9C_x08[WrtLvTrEn]=0 */
++                      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, 
FUN_DCT,
++                                      DRAM_ADD_DCT_PHY_CONTROL_REG, 
WrtLvTrEn, WrtLvTrEn, 0);
++
++                      /* Set TrNibbleSel */
++                      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, 
FUN_DCT,
++                                      DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
++                                      2, (uint32_t)nibble);
++              }
+ 
+-      /* 4. Configure the processor's DDR phy for write levelization 
training: */
+-      procConfig(pMCTstat, pDCTstat, dct, dimm, pass);
++              /* 2. Prepare the DIMMs for write levelization using 
DDR3-defined
++               * MR commands. */
++              prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
+ 
+-      /* 5. Begin write levelization training:
+-       *  Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
+-      if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL))
+-      {
+-              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+-                              DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, 
WrtLvTrEn, 1);
+-      }
+-      else
+-      {
+-              /* Broadcast write to all D3Dbyte chipset register offset 0xc
+-               * Set bit 0 (wrTrain)
+-               * Program bit 4 to nibble being trained (only matters for 
x4dimms)
+-               * retain value of 3:2 (Trdimmsel)
+-               * reset bit 5 (FrzPR)
++              /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
++               *    satisfy DDR3-defined internal DRAM timing.
+                */
+-              if (dct)
++              if (is_fam15h())
++                      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
++              else
++                      pMCTData->AgesaDelay(40);
++
++              /* 4. Configure the processor's DDR phy for write levelization 
training: */
++              procConfig(pMCTstat, pDCTstat, dct, dimm, pass, nibble);
++
++              /* 5. Begin write levelization training:
++               *  Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
++              if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | 
AMD_FAM15_ALL))
+               {
+-                      Addl_Data_Offset=0x198;
+-                      Addl_Data_Port=0x19C;
++                      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, 
FUN_DCT,
++                                      DRAM_ADD_DCT_PHY_CONTROL_REG, 
WrtLvTrEn, WrtLvTrEn, 1);
+               }
+               else
+               {
+-                      Addl_Data_Offset=0x98;
+-                      Addl_Data_Port=0x9C;
++                      /* Broadcast write to all D3Dbyte chipset register 
offset 0xc
++                       * Set bit 0 (wrTrain)
++                       * Program bit 4 to nibble being trained (only matters 
for x4dimms)
++                       * retain value of 3:2 (Trdimmsel)
++                       * reset bit 5 (FrzPR)
++                       */
++                      if (dct)
++                      {
++                              Addl_Data_Offset=0x198;
++                              Addl_Data_Port=0x19C;
++                      }
++                      else
++                      {
++                              Addl_Data_Offset=0x98;
++                              Addl_Data_Port=0x9C;
++                      }
++                      Addr=0x0D00000C;
++                      
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
++                      while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, 
FUN_DCT, Addl_Data_Offset,
++                                      DctAccessDone, DctAccessDone)) == 0);
++                      
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 
31, 0, &Value);
++                      Value = bitTestSet(Value, 0);   /* enable WL training */
++                      Value = bitTestReset(Value, 4); /* for x8 only */
++                      Value = bitTestReset(Value, 5); /* for hardware WL 
training */
++                      
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port),
 31, 0, &Value);
++                      Addr=0x4D030F0C;
++                      
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
++                      while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, 
FUN_DCT, Addl_Data_Offset,
++                                      DctAccessDone, DctAccessDone)) == 0);
+               }
+-              Addr=0x0D00000C;
+-              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
+-              while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, 
Addl_Data_Offset,
+-                              DctAccessDone, DctAccessDone)) == 0);
+-              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 
31, 0, &Value);
+-              Value = bitTestSet(Value, 0);   /* enable WL training */
+-              Value = bitTestReset(Value, 4); /* for x8 only */
+-              Value = bitTestReset(Value, 5); /* for hardware WL training */
+-              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port),
 31, 0, &Value);
+-              Addr=0x4D030F0C;
+-              
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset),
 31, 0, &Addr);
+-              while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, 
Addl_Data_Offset,
+-                              DctAccessDone, DctAccessDone)) == 0);
+-      }
+ 
+-      if (is_fam15h())
+-              proc_MFENCE();
++              if (is_fam15h())
++                      proc_MFENCE();
+ 
+-      /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
+-      if (is_fam15h())
+-              precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 200);
+-      else
+-              pMCTData->AgesaDelay(140);
++              /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
++              if (is_fam15h())
++                      precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 
200);
++              else
++                      pMCTData->AgesaDelay(140);
+ 
+-      /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
+-      set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+-                      DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
++              /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
++              set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
++                              DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, 
WrtLvTrEn, 0);
+ 
+-      /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
+-       * to get the gross and fine delay settings
+-       * for the target DIMM and save these values. */
+-      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+-              getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass);
+-      }
++              /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
++               * to get the gross and fine delay settings
++               * for the target DIMM and save these values. */
++              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
++                      getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, 
nibble);
++              }
+ 
+-      pDCTData->WLCriticalGrossDelayPrevPass = 0x1f;
++              pDCTData->WLCriticalGrossDelayPrevPass = 0x0;
++      }
+ 
+       return 0;
+ }
+ 
+ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat,
+-              u8 dct, u8 dimm, u8 pass)
++              uint8_t dct, uint8_t dimm, uint8_t pass)
+ {
+       u8 ByteLane;
+       uint8_t status = 0;
+@@ -190,6 +202,12 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
+               int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
+               uint8_t index = (uint8_t)(MAX_BYTE_LANES * dimm);
+ 
++              printk(BIOS_SPEW, "\toriginal critical gross delay: %d\n", cgd);
++
++              /* FIXME
++               * For now, disable CGD adjustment as it seems to interfere 
with registered DIMM training
++               */
++
+               /* Calculate the Critical Gross Delay */
+               for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) {
+                       /* Calculate the gross delay differential for this lane 
*/
+@@ -205,6 +223,8 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
+                               cgd = gross_diff[ByteLane];
+               }
+ 
++              printk(BIOS_SPEW, "\tnew critical gross delay: %d\n", cgd);
++
+               pDCTData->WLCriticalGrossDelayPrevPass = cgd;
+ 
+               if (pDCTstat->Speed != pDCTstat->TargetFreq) {
+@@ -281,7 +301,7 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
+                               gross_diff[ByteLane] = 
pDCTData->WLSeedGrossDelay[index+ByteLane] + 
pDCTData->WLGrossDelay[index+ByteLane];
+                               gross_diff[ByteLane] -= 
pDCTData->WLSeedPreGrossDelay[index+ByteLane];
+ 
+-                              /* Prevent underflow in the presence of noise / 
instability*/
++                              /* Prevent underflow in the presence of noise / 
instability */
+                               if (gross_diff[ByteLane] < cgd)
+                                       gross_diff[ByteLane] = cgd;
+ 
+@@ -289,7 +309,8 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCT
+                       }
+               } else {
+                       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
+-                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= 0 */
++                      dword &= ~(0x3 << 24);                  /* WrDqDqsEarly 
= pDCTData->WrDqsGrossDlyBaseOffset */
++                      dword |= ((pDCTData->WrDqsGrossDlyBaseOffset & 0x3) << 
24);
+                       Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
+               }
+       }
+@@ -959,7 +980,7 @@ static uint16_t fam15h_next_lowest_memclk_freq(uint16_t 
memclk_freq)
+ #endif
+ 
+ 
/*-----------------------------------------------------------------------------
+- * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
++ * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass, 
u8 Nibble)
+  *
+  *  Description:
+  *       This function programs the ODT values for the NB
+@@ -972,13 +993,14 @@ static uint16_t fam15h_next_lowest_memclk_freq(uint16_t 
memclk_freq)
+  *       OUT
+  * 
----------------------------------------------------------------------------
+  */
+-void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm, u8 pass)
++void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble)
+ {
+       u8 ByteLane, MemClkFreq;
+       int32_t Seed_Gross;
+       int32_t Seed_Fine;
+       uint8_t Seed_PreGross;
+       u32 Value, Addr;
++      uint32_t dword;
+       u16 Addl_Data_Offset, Addl_Data_Port;
+       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+@@ -1048,10 +1070,17 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+                       uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
+                       uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
+                       uint16_t Seed_Total = 0;
++                      pDCTData->WrDqsGrossDlyBaseOffset = 0x0;
+                       if (package_type == PT_GR) {
+                               /* Socket G34: Fam15h BKDG v3.14 Table 96 */
+                               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                      /* TODO
++                                       * Implement mainboard-specific seed and
++                                       * WrDqsGrossDly base overrides.
++                                       * 0x41 and 0x0 are the "stock" values
++                                       */
+                                       Seed_Total = 0x41;
++                                      pDCTData->WrDqsGrossDlyBaseOffset = 0x2;
+                               } else if 
(pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
+                                       Seed_Total = 0x0;
+                               } else {
+@@ -1133,15 +1162,16 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+                       printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", 
ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
+               }
+       } else {
+-              /* Pass 2 */
+-              /* From BKDG, Write Leveling Seed Value. */
+-              if (is_fam15h()) {
+-                      uint32_t RegisterDelay;
+-                      int32_t SeedTotal;
+-                      int32_t SeedTotalPreScaling;
+-                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
++              if (nibble == 0) {
++                      /* Pass 2 */
++                      /* From BKDG, Write Leveling Seed Value. */
++                      if (is_fam15h()) {
++                              uint32_t RegisterDelay;
++                              int32_t SeedTotal[MAX_BYTE_LANES];
++                              int32_t SeedTotalPreScaling[MAX_BYTE_LANES];
++                              uint32_t WrDqDqsEarly;
++                              uint8_t AddrCmdPrelaunch = 0;           /* 
TODO: Fetch the correct value from RC2[0] */
+ 
+-                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
+                               if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+                                       if (AddrCmdPrelaunch)
+                                               RegisterDelay = 0x30;
+@@ -1150,84 +1180,133 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+                               } else {
+                                       RegisterDelay = 0;
+                               }
++
+                               /* Retrieve WrDqDqsEarly */
+-                              
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId), FUN_DCT, 0xa8), 25, 24, 
&Value);
++                              dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
0xa8);
++                              WrDqDqsEarly = (dword >> 24) & 0x3;
+ 
+-                              /* Calculate adjusted seed values */
+-                              SeedTotal = 
(pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
+-                                      
((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5);
+-                              SeedTotalPreScaling = (SeedTotal - 
RegisterDelay - (0x20 * Value));
+-                              SeedTotal = (int32_t) (RegisterDelay + 
((((int64_t) SeedTotalPreScaling) *
+-                                      fam15h_freq_tab[MemClkFreq] * 100) / 
(fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
++                              /* FIXME
++                               * Ignore WrDqDqsEarly for now to work around 
training issues
++                               */
++                              WrDqDqsEarly = 0;
+ 
+-                              if (SeedTotal >= 0) {
+-                                      Seed_Gross = SeedTotal / 32;
+-                                      Seed_Fine = SeedTotal % 32;
+-                              } else {
+-                                      Seed_Gross = (SeedTotal / 32) - 1;
+-                                      Seed_Fine = (SeedTotal % 32) + 32;
++                              /* Generate new seed values */
++                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                                      /* Calculate adjusted seed values */
++                                      SeedTotal[ByteLane] = 
(pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
++                                              
((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5);
++                                      SeedTotalPreScaling[ByteLane] = 
(SeedTotal[ByteLane] - RegisterDelay - (0x20 * WrDqDqsEarly));
++                                      SeedTotal[ByteLane] = (int32_t) 
(RegisterDelay + ((((int64_t) SeedTotalPreScaling[ByteLane]) *
++                                              fam15h_freq_tab[MemClkFreq] * 
100) / (fam15h_freq_tab[pDCTData->WLPrevMemclkFreq] * 100)));
+                               }
+ 
+-                              if (Seed_Gross == 0)
+-                                      Seed_PreGross = 0;
+-                              else if (Seed_Gross & 0x1)
+-                                      Seed_PreGross = 1;
+-                              else
+-                                      Seed_PreGross = 2;
++                              /* Generate register values from seeds */
++                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                                      printk(BIOS_SPEW, "\tLane %02x scaled 
delay: %04x\n", ByteLane, SeedTotal[ByteLane]);
+ 
+-                              /* Save seed values for later use */
+-                              
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
+-                              
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
+-                              
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
++                                      if (SeedTotal[ByteLane] >= 0) {
++                                              Seed_Gross = 
SeedTotal[ByteLane] / 32;
++                                              Seed_Fine = SeedTotal[ByteLane] 
% 32;
++                                      } else {
++                                              Seed_Gross = 
(SeedTotal[ByteLane] / 32) - 1;
++                                              Seed_Fine = 
(SeedTotal[ByteLane] % 32) + 32;
++                                      }
+ 
+-                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
+-                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++                                      if (Seed_Gross == 0)
++                                              Seed_PreGross = 0;
++                                      else if (Seed_Gross & 0x1)
++                                              Seed_PreGross = 1;
++                                      else
++                                              Seed_PreGross = 2;
+ 
+-                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
+-                      }
+-              } else {
+-                      uint32_t RegisterDelay;
+-                      uint32_t SeedTotalPreScaling;
+-                      uint32_t SeedTotal;
+-                      uint8_t AddrCmdPrelaunch = 0;           /* TODO: Fetch 
the correct value from RC2[0] */
+-                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
+-                      {
+-                              if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
+-                                      if (AddrCmdPrelaunch == 0)
+-                                              RegisterDelay = 0x20;
++                                      /* The BKDG-recommended algorithm 
causes problems with registered DIMMs on some systems
++                                       * due to the long register delays 
causing premature total delay wrap-around.
++                                       * Attempt to work around this...
++                                       */
++                                      Seed_PreGross = Seed_Gross;
++
++                                      /* Save seed values for later use */
++                                      
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
++                                      
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++                                      
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
++
++                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_PreGross;
++                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++
++                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
++                              }
++                      } else {
++                              uint32_t RegisterDelay;
++                              uint32_t SeedTotalPreScaling;
++                              uint32_t SeedTotal;
++                              uint8_t AddrCmdPrelaunch = 0;           /* 
TODO: Fetch the correct value from RC2[0] */
++                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++)
++                              {
++                                      if 
(pDCTData->Status[DCT_STATUS_REGISTERED]) {
++                                              if (AddrCmdPrelaunch == 0)
++                                                      RegisterDelay = 0x20;
++                                              else
++                                                      RegisterDelay = 0x30;
++                                      } else {
++                                              RegisterDelay = 0;
++                                      }
++                                      SeedTotalPreScaling = 
((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
++                                              
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay;
++                                      /* SeedTotalPreScaling = (the total 
delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
++                                      training) - RegisterDelay. */
++                                      SeedTotal = (uint16_t) ((((uint64_t) 
SeedTotalPreScaling) *
++                                                                              
fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 100));
++                                      Seed_Gross = SeedTotal / 32;
++                                      Seed_Fine = SeedTotal & 0x1f;
++                                      if (Seed_Gross == 0)
++                                              Seed_Gross = 0;
++                                      else if (Seed_Gross & 0x1)
++                                              Seed_Gross = 1;
+                                       else
+-                                              RegisterDelay = 0x30;
+-                              } else {
+-                                      RegisterDelay = 0;
++                                              Seed_Gross = 2;
++
++                                      /* The BKDG-recommended algorithm 
causes problems with registered DIMMs on some systems
++                                      * due to the long register delays 
causing premature total delay wrap-around.
++                                      * Attempt to work around this...
++                                      */
++                                      SeedTotal = ((Seed_Gross & 0x1f) << 5) 
| (Seed_Fine & 0x1f);
++                                      SeedTotal += RegisterDelay;
++                                      Seed_Gross = SeedTotal / 32;
++                                      Seed_Fine = SeedTotal & 0x1f;
++
++                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
++                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++
++                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
+                               }
+-                              SeedTotalPreScaling = 
((pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) |
+-                                      
(pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5)) - RegisterDelay;
+-                              /* SeedTotalPreScaling = (the total delay value 
in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
+-                              training) - RegisterDelay. */
+-                              SeedTotal = (uint16_t) ((((uint64_t) 
SeedTotalPreScaling) *
+-                                                                      
fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 100));
+-                              Seed_Gross = SeedTotal / 32;
+-                              Seed_Fine = SeedTotal & 0x1f;
+-                              if (Seed_Gross == 0)
+-                                      Seed_Gross = 0;
+-                              else if (Seed_Gross & 0x1)
+-                                      Seed_Gross = 1;
+-                              else
+-                                      Seed_Gross = 2;
++                      }
+ 
+-                              /* The BKDG-recommended algorithm causes 
problems with registered DIMMs on some systems
+-                               * due to the long register delays causing 
premature total delay wrap-around.
+-                               * Attempt to work around this...
+-                               */
+-                              SeedTotal = ((Seed_Gross & 0x1f) << 5) | 
(Seed_Fine & 0x1f);
+-                              SeedTotal += RegisterDelay;
+-                              Seed_Gross = SeedTotal / 32;
+-                              Seed_Fine = SeedTotal & 0x1f;
++                      /* Save initial seeds for upper nibble pass */
++                      for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                              
pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane];
++                              
pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane];
++                              
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane];
++                      }
++              } else {
++                      /* Restore seed values from lower nibble pass */
++                      if (is_fam15h()) {
++                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                                      
pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
++                                      
pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
++                                      
pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
+ 
+-                              
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
+-                              
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
++                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
++                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
+ 
+-                              printk(BIOS_SPEW, "\tLane %02x new seed: 
%04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
++                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
++                              }
++                      } else {
++                              for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; 
ByteLane++) {
++                                      
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
++                                      
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = 
pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
++
++                                      printk(BIOS_SPEW, "\tLane %02x new 
seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] 
& 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f));
++                              }
+                       }
+               }
+       }
+@@ -1358,7 +1437,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
+ }
+ 
+ 
/*-----------------------------------------------------------------------------
+- *  void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm)
++ *  void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 
ByteLane, u8 Dimm, u8 Nibble)
+  *
+  *  Description:
+  *       This function reads the write levelization byte delay from the Phase
+@@ -1376,7 +1455,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
+  *
+  
*-----------------------------------------------------------------------------
+  */
+-void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass)
++void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, 
u8 dimm, uint8_t pass, uint8_t nibble)
+ {
+       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+       u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, 
index;
+@@ -1427,7 +1506,16 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 ByteLane, u8
+                       fine = 0;
+               }
+       }
+-      pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
+-      pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
+-      printk(BIOS_SPEW, "\tLane %02x final adjusted value: %04x\n", ByteLane, 
((gross & 0x1f) << 5) | (fine & 0x1f));
++      if (nibble == 0) {
++              pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)fine;
++              pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)gross;
++      } else {
++              uint32_t WLTotalDelay = 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
++              WLTotalDelay += ((gross & 0x1f) << 5) | (fine & 0x1f);
++              WLTotalDelay /= 2;
++              pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)(WLTotalDelay 
& 0x1f);
++              pDCTData->WLGrossDelay[index+ByteLane] = 
(uint8_t)((WLTotalDelay >> 5) & 0x1f);
++      }
++
++      printk(BIOS_SPEW, "\tLane %02x adjusted value: %04x\n", ByteLane, 
((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | 
(pDCTData->WLFineDelay[index+ByteLane] & 0x1f));
+ }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
+index 12e7c4a..3337c14 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
+@@ -119,16 +119,21 @@ typedef struct _sDCTStruct
+       u8 DctTrain;                    /* Current DCT being trained */
+       u8 CurrDct;                     /* Current DCT number (0 or 1) */
+       u8 DctCSPresent;                /* Current DCT CS mapping */
++      uint8_t WrDqsGrossDlyBaseOffset;
+       int32_t WLSeedGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];    /* Write 
Levelization Seed Gross Delay */
+                                                               /* per byte 
Lane Per Logical DIMM*/
+       int32_t WLSeedFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write 
Levelization Seed Fine Delay */
+                                                               /* per byte 
Lane Per Logical DIMM*/
+       int32_t WLSeedPreGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write 
Levelization Seed Pre-Gross Delay */
+                                                               /* per byte 
Lane Per Logical DIMM*/
+-      u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];     /* Write Levelization 
Gross Delay */
+-                                                      /* per byte Lane Per 
Logical DIMM*/
+-      u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];      /* Write Levelization 
Fine Delay */
+-                                                      /* per byte Lane Per 
Logical DIMM*/
++      uint8_t WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*MAX_LDIMMS];
++      uint8_t WLSeedGrossPrevNibble[MAX_BYTE_LANES*MAX_LDIMMS];
++      uint8_t WLSeedFinePrevNibble[MAX_BYTE_LANES*MAX_LDIMMS];
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS];             /* Write 
Levelization Gross Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
++      u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS];              /* Write 
Levelization Fine Delay */
++                                                              /* per byte 
Lane Per Logical DIMM*/
+       u8 WLGrossDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];    /* First-Pass 
Write Levelization Gross Delay */
+                                                               /* per byte 
Lane Per Logical DIMM*/
+       u8 WLFineDelayFirstPass[MAX_BYTE_LANES*MAX_LDIMMS];     /* First-Pass 
Write Levelization Fine Delay */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
 
b/resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
deleted file mode 100644
index 4b5845b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
+++ /dev/null
@@ -1,248 +0,0 @@
-From 5fb316c1ccf4427fbd86458e85c3bda2076f6fa0 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 2 Aug 2015 21:18:29 -0500
-Subject: [PATCH 089/139] cpu/amd/family_10h-family_15h: Bring initial HT
- register configuration in line with BKDG
-
-Change-Id: I009b6f478340e2dbfcda2b4534473d4397f9ecef
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h | 168 +++++++++++++++++++++------
- 1 file changed, 133 insertions(+), 35 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index 513d169..1080cfc 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -388,44 +388,140 @@ static const struct {
-                                          [2] SyncOnUcEccEn = 1 */
- 
-       /* XBAR buffer settings */
--      { 3, 0x6c, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        0x00018052, 0x700780f7 },
-+      { 3, 0x6c, AMD_FAM10_ALL & ~(AMD_DR_Dx), AMD_PTYPE_ALL,
-+        0x00018052, 0x700780f7 },     /* IsocRspDBC = 0x0,
-+                                         UpRspDBC = 0x1,
-+                                         DatBuf24 = 0x1,
-+                                         DnRspDBC = 0x1,
-+                                         DnReqDBC = 0x1,
-+                                         UpReqDBC = 0x2 */
-+
-+      /* XBAR buffer settings */
-+      { 3, 0x6c, AMD_DR_Dx, AMD_PTYPE_ALL,
-+        0x00028052, 0x700780f7 },     /* IsocRspDBC = 0x0,
-+                                         UpRspDBC = 0x2,
-+                                         DatBuf24 = 0x1,
-+                                         DnRspDBC = 0x1,
-+                                         DnReqDBC = 0x1,
-+                                         UpReqDBC = 0x2 */
- 
-       /* XBAR buffer settings */
-       { 3, 0x6c, AMD_FAM15_ALL, AMD_PTYPE_ALL,
--        0x10010052, 0x700700f7 },
-+        0x10010052, 0x700700f7 },     /* IsocRspDBC = 0x1,
-+                                         UpRspDBC = 0x1,
-+                                         DnRspDBC = 0x1,
-+                                         DnReqDBC = 0x1,
-+                                         UpReqDBC = 0x2 */
- 
-       /* Errata 281 Workaround */
--      { 3, 0x6C, ( AMD_DR_B0 | AMD_DR_B1),
-+      { 3, 0x6c, (AMD_DR_B0 | AMD_DR_B1),
-         AMD_PTYPE_SVR, 0x00010094, 0x700780F7 },
- 
--      { 3, 0x6C, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-+      { 3, 0x6c, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x60018051, 0x700780F7 },
- 
--      { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        0x00041153, 0x777777F7 },
-+      { 3, 0x70, AMD_FAM10_ALL & ~(AMD_DR_Dx), AMD_PTYPE_ALL,
-+        0x00041153, 0x777777f7 },     /* IsocRspCBC = 0x0,
-+                                         IsocPreqCBC = 0x0,
-+                                         IsocReqCBC = 0x0,
-+                                         UpRspCBC = 0x4,
-+                                         DnPreqCBC = 0x1,
-+                                         UpPreqCBC = 0x1,
-+                                         DnRspCBC = 0x1,
-+                                         DnReqCBC = 0x1,
-+                                         UpReqCBC = 0x3 */
-+
-+      { 3, 0x70, AMD_DR_Dx, AMD_PTYPE_ALL,
-+        0x00051153, 0x777777f7 },     /* IsocRspCBC = 0x0,
-+                                         IsocPreqCBC = 0x0,
-+                                         IsocReqCBC = 0x0,
-+                                         UpRspCBC = 0x5,
-+                                         DnPreqCBC = 0x1,
-+                                         UpPreqCBC = 0x1,
-+                                         DnRspCBC = 0x1,
-+                                         DnReqCBC = 0x1,
-+                                         UpReqCBC = 0x3 */
- 
-       { 3, 0x70, AMD_FAM15_ALL, AMD_PTYPE_ALL,
--        0x10171155, 0x777777f7 },
-+        0x10171155, 0x777777f7 },     /* IsocRspCBC = 0x1,
-+                                         IsocPreqCBC = 0x0,
-+                                         IsocReqCBC = 0x1,
-+                                         UpRspCBC = 0x7,
-+                                         DnPreqCBC = 0x1,
-+                                         UpPreqCBC = 0x1,
-+                                         DnRspCBC = 0x1,
-+                                         DnReqCBC = 0x1,
-+                                         UpReqCBC = 0x5 */
- 
-       { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_UMA,
--        0x61221151, 0x777777F7 },
-+        0x61221151, 0x777777f7 },     /* IsocRspCBC = 0x6,
-+                                         IsocPreqCBC = 0x1,
-+                                         IsocReqCBC = 0x2,
-+                                         UpRspCBC = 0x2,
-+                                         DnPreqCBC = 0x1,
-+                                         UpPreqCBC = 0x1,
-+                                         DnRspCBC = 0x1,
-+                                         DnReqCBC = 0x1,
-+                                         UpReqCBC = 0x1 */
-+
-+      { 3, 0x74, AMD_FAM10_ALL, ~AMD_PTYPE_UMA,
-+        0x00081111, 0xf7ff7777 },     /* DRReqCBC = 0x0,
-+                                         IsocPreqCBC = 0x0,
-+                                         IsocReqCBC = 0x0,
-+                                         ProbeCBC = 0x8,
-+                                         DnPreqCBC = 0x1,
-+                                         UpPreqCBC = 0x1,
-+                                         DnReqCBC = 0x1,
-+                                         UpReqCBC = 0x1 */
- 
-       { 3, 0x74, AMD_FAM10_ALL, AMD_PTYPE_UMA,
--        0x00080101, 0x000F7777 },
-+        0x00480101, 0xf7ff7777 },     /* DRReqCBC = 0x0,
-+                                         IsocPreqCBC = 0x0,
-+                                         IsocReqCBC = 0x4,
-+                                         ProbeCBC = 0x8,
-+                                         DnPreqCBC = 0x0,
-+                                         UpPreqCBC = 0x1,
-+                                         DnReqCBC = 0x0,
-+                                         UpReqCBC = 0x1 */
- 
-       { 3, 0x74, AMD_FAM15_ALL, AMD_PTYPE_ALL,
--        0x00172111, 0x77ff7777 },
--
--      { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
--        0x00090914, 0x707FFF1F },
-+        0x00172111, 0xf7ff7777 },     /* DRReqCBC = 0x0,
-+                                         IsocPreqCBC = 0x0,
-+                                         IsocReqCBC = 0x1,
-+                                         ProbeCBC = 0x7,
-+                                         DnPreqCBC = 0x2,
-+                                         UpPreqCBC = 0x1,
-+                                         DnReqCBC = 0x1,
-+                                         UpReqCBC = 0x1 */
-+
-+      { 3, 0x7c, AMD_FAM10_ALL & ~(AMD_DR_Dx), AMD_PTYPE_ALL,
-+       0x00090914, 0x707fff1f },      /* XBar2SriFreeListCBInc = 0x0,
-+                                         Sri2XbarFreeRspDBC = 0x0,
-+                                         Sri2XbarFreeXreqDBC = 0x9,
-+                                         Sri2XbarFreeRspCBC = 0x0,
-+                                         Sri2XbarFreeXreqCBC = 0x9,
-+                                         Xbar2SriFreeListCBC = 0x14 */
-+
-+      { 3, 0x7c, AMD_DR_Dx, AMD_PTYPE_ALL,
-+       0x00090a18, 0x707fff1f },      /* XBar2SriFreeListCBInc = 0x0,
-+                                         Sri2XbarFreeRspDBC = 0x0,
-+                                         Sri2XbarFreeXreqDBC = 0x9,
-+                                         Sri2XbarFreeRspCBC = 0x0,
-+                                         Sri2XbarFreeXreqCBC = 0x9,
-+                                         Xbar2SriFreeListCBC = 0x14 */
- 
-       /* Errata 281 Workaround */
-       { 3, 0x7C, ( AMD_DR_B0 | AMD_DR_B1),
-        AMD_PTYPE_SVR, 0x00144514, 0x707FFF1F },
- 
--      { 3, 0x7C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
--        0x040d0f16, 0x07ffff1f },
-+      { 3, 0x7c, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x040d0f16, 0x77ffff1f },     /* XBar2SriFreeListCBInc = 0x0,
-+                                         SrqExtFreeListBC = 0x8,
-+                                         Sri2XbarFreeRspDBC = 0x0,
-+                                         Sri2XbarFreeXreqDBC = 0xd,
-+                                         Sri2XbarFreeRspCBC = 0x0,
-+                                         Sri2XbarFreeXreqCBC = 0xf,
-+                                         Xbar2SriFreeListCBC = 0x16 */
- 
-       { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x00070814, 0x007FFF1F },
-@@ -647,18 +743,16 @@ static const struct {
-         0x00004400, 0x00006400 },     /* HT_PHY_DLL_REG */
- 
-       { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
--        0x00000000, 0x000000FF },     /* Provide clear setting for logical
--                                         completeness */
-+        0x0000005a, 0x000000ff },     /* Use common "safe" setting for K10 */
- 
-       { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
--        0x00000000, 0x000000FF },     /* Provide clear setting for logical
--                                         completeness */
-+        0x0000005a, 0x000000ff },     /* Use common "safe" setting for K10 */
- 
-       { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
--        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
-+        0x0000006d, 0x000000ff },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
- 
-       { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
--        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
-+        0x0000006d, 0x000000ff },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
- 
-       /* Link Phy Receiver Loop Filter Registers */
-       { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-@@ -681,24 +775,29 @@ static const struct {
-         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
-                                         [20:16] RttIndex = 04h */
- 
--/* FIXME
-- * Causes lockups for some reason when more than one package is installed
-- * Debug and reactivate!
-- */
--// #if 0
-       { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
--        0x00000000, 0x000000FF },     /* Provide clear setting for logical
--                                         completeness */
-+        0x00000a2a, 0x000000ff },     /* P0RcvRdPtr = 0xa,
-+                                         P0XmtRdPtr = 0x2
-+                                         P1RcvRdPtr = 0xa
-+                                         P1XmtRdPtr = 0x0 */
- 
-       { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
--        0x00000000, 0x000000FF },     /* Provide clear setting for logical
--                                         completeness */
-+        0x00000a2a, 0x000000ff },     /* P0RcvRdPtr = 0xa,
-+                                         P0XmtRdPtr = 0x2
-+                                         P1RcvRdPtr = 0xa
-+                                         P1XmtRdPtr = 0x0 */
- 
-       { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
--        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
-+        0x00000d4d, 0x000000ff },     /* P0RcvRdPtr = 0xd,
-+                                         P0XmtRdPtr = 0x4
-+                                         P1RcvRdPtr = 0xd
-+                                         P1XmtRdPtr = 0x0 */
- 
-       { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
--        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
-+        0x00000d4d, 0x000000ff },     /* P0RcvRdPtr = 0xd,
-+                                         P0XmtRdPtr = 0x4
-+                                         P1RcvRdPtr = 0xd
-+                                         P1XmtRdPtr = 0x0 */
- 
-       /* Link Phy Receiver Loop Filter Registers */
-       { 0xD1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-@@ -719,6 +818,5 @@ static const struct {
- 
-       { 0xC0, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
-         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
--                                        [20:16] RttIndex = 04h */
--// #endif
-+                                         [20:16] RttIndex = 04h */
- };
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
 
b/resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
new file mode 100644
index 0000000..4cda10f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0089-cpu-amd-family_10h-family_15h-Fix-Family-15h-multipl.patch
@@ -0,0 +1,1244 @@
+From 14d498ea0d069418099c6c4a374d0de62e37dca0 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 30 Jul 2015 14:07:15 -0500
+Subject: [PATCH 089/143] cpu/amd/family_10h-family_15h: Fix Family 15h
+ multiple package support
+
+TEST: Booted ASUS KGPE-D16 with two Opteron 6328 processors
+and several different RDIMM configurations.
+
+Change-Id: I171197c90f72d3496a385465937b7666cbf7e308
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/car/cache_as_ram.inc                   |   17 ++-
+ src/cpu/amd/family_10h-family_15h/defaults.h       |  101 ++++++++++++--
+ src/cpu/amd/family_10h-family_15h/fidvid.c         |   81 +++++------
+ src/cpu/amd/family_10h-family_15h/init_cpus.c      |   66 ++++++++-
+ src/cpu/amd/quadcore/quadcore.c                    |   19 +--
+ src/cpu/amd/quadcore/quadcore_id.c                 |    1 -
+ src/mainboard/advansus/a785e-i/romstage.c          |    2 +-
+ src/mainboard/amd/bimini_fam10/romstage.c          |    2 +-
+ src/mainboard/amd/mahogany_fam10/romstage.c        |    2 +-
+ .../amd/serengeti_cheetah_fam10/romstage.c         |    2 +-
+ src/mainboard/amd/tilapia_fam10/romstage.c         |    2 +-
+ src/mainboard/asus/kfsn4-dre/romstage.c            |    2 +-
+ src/mainboard/asus/kgpe-d16/romstage.c             |   46 +++++--
+ src/mainboard/asus/m4a78-em/romstage.c             |    2 +-
+ src/mainboard/asus/m4a785-m/romstage.c             |    2 +-
+ src/mainboard/asus/m5a88-v/romstage.c              |    2 +-
+ src/mainboard/avalue/eax-785e/romstage.c           |    2 +-
+ src/mainboard/gigabyte/ma785gm/romstage.c          |    2 +-
+ src/mainboard/gigabyte/ma785gmt/romstage.c         |    2 +-
+ src/mainboard/gigabyte/ma78gm/romstage.c           |    2 +-
+ src/mainboard/hp/dl165_g6_fam10/romstage.c         |    2 +-
+ src/mainboard/iei/kino-780am2-fam10/romstage.c     |    2 +-
+ src/mainboard/jetway/pa78vm5/romstage.c            |    2 +-
+ src/mainboard/msi/ms9652_fam10/romstage.c          |    2 +-
+ src/mainboard/supermicro/h8dmr_fam10/romstage.c    |    2 +-
+ src/mainboard/supermicro/h8qme_fam10/romstage.c    |    2 +-
+ src/mainboard/supermicro/h8scm_fam10/romstage.c    |    2 +-
+ src/mainboard/tyan/s2912_fam10/romstage.c          |    2 +-
+ src/northbridge/amd/amdht/h3finit.c                |   57 +++++++-
+ src/northbridge/amd/amdht/h3ncmn.c                 |   30 ++++-
+ src/northbridge/amd/amdht/ht_wrapper.c             |  141 ++++++++++++++++++--
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c        |    1 +
+ 32 files changed, 479 insertions(+), 123 deletions(-)
+
+diff --git a/src/cpu/amd/car/cache_as_ram.inc 
b/src/cpu/amd/car/cache_as_ram.inc
+index 5db9224..6bfb0e6 100644
+--- a/src/cpu/amd/car/cache_as_ram.inc
++++ b/src/cpu/amd/car/cache_as_ram.inc
+@@ -525,8 +525,23 @@ CAR_FAM10_ap:
+       /* Fam10h NB config bit 54 was not set */
+       rolb    %cl, %bl
+ roll_cfg:
++      jmp_if_not_fam15h(ap_apicid_ready)
++      cmp     $0x5, %ecx
++      jne     ap_apicid_ready
+ 
+-      /* Calculate stack pointer. */
++      /* This is a multi-node CPU
++       * Adjust the maximum APIC ID to a more reasonable value
++       * given that no 32-core Family 15h processors exist
++       */
++      movl    %ebx, %ecx
++      and     $0x0f, %ecx             /* Get lower 4 bits of CPU number */
++      and     $0x60, %ebx             /* Get node ID */
++      shrl    $0x1, %ebx              /* Shift node ID part of APIC ID down 
by 1 */
++      or      %ecx, %ebx              /* Recombine node ID and CPU number */
++
++ap_apicid_ready:
++
++      /* Calculate stack pointer using adjusted APIC ID stored in ebx */
+       movl    $CacheSizeAPStack, %eax
+       mull    %ebx
+       movl    $(CacheBase + (CacheSize - (CacheSizeBSPStack + 
CacheSizeBSPSlush))), %esp
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index 24f87ba..513d169 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -244,18 +244,50 @@ static const struct {
+       { 0, 0x68, (AMD_DR_B0 | AMD_DR_B1),
+         AMD_PTYPE_SVR, 0x00200000, 0x00600000 },      /* [22:21] DsNpReqLmt0 
= 01b */
+ 
+-      { 0, 0x84, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++      { 0, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
+-      { 0, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++      { 0, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
+-      { 0, 0xC4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++      { 0, 0xC4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
+-      { 0, 0xE4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
++      { 0, 0xE4, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
+ 
++      /* FIXME
++       * Non-C32 packages only
++       */
++      { 0, 0x84, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++
++      { 0, 0xA4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++
++      { 0, 0xC4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++
++      { 0, 0xE4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++
++      /* FIXME
++       * C32 package only
++       */
++#if 0
++      { 0, 0x84, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++
++      { 0, 0xA4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++
++      { 0, 0xC4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++
++      { 0, 0xE4, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00002000, 0x00002000 },     /* [13] LdtStopTriEn = 1 */
++#endif
++
+       /* Link Global Retry Control Register */
+       { 0, 0x150, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00073900, 0x00073F00 },
+@@ -614,38 +646,79 @@ static const struct {
+       { 0x530A, AMD_DR_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
+         0x00004400, 0x00006400 },     /* HT_PHY_DLL_REG */
+ 
+-      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
++      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++        0x00000000, 0x000000FF },     /* Provide clear setting for logical
++                                         completeness */
++
++      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++        0x00000000, 0x000000FF },     /* Provide clear setting for logical
++                                         completeness */
++
++      { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
++        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
++
++      { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
++        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
++
++      /* Link Phy Receiver Loop Filter Registers */
++      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++        0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
++                                         [21:14] LfcMin = 10h */
++
++      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++        0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
++                                         [21:14] LfcMin = 10h */
++
++      { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
++        0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
++                                         [21:14] LfcMin = 08h */
++
++      { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
++        0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
++                                         [21:14] LfcMin = 08h */
++
++      { 0xC0, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
++        0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
++                                        [20:16] RttIndex = 04h */
++
++/* FIXME
++ * Causes lockups for some reason when more than one package is installed
++ * Debug and reactivate!
++ */
++// #if 0
++      { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+         0x00000000, 0x000000FF },     /* Provide clear setting for logical
+                                          completeness */
+ 
+-      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
++      { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+         0x00000000, 0x000000FF },     /* Provide clear setting for logical
+                                          completeness */
+ 
+-      { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
++      { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
+         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
+ 
+-      { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,  
HTPHY_LINKTYPE_HT1,
++      { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
+         0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
+ 
+       /* Link Phy Receiver Loop Filter Registers */
+-      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
++      { 0xD1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
+                                          [21:14] LfcMin = 10h */
+ 
+-      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT3,
++      { 0xC1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+         0x08040000, 0x3FFFC000 },     /* [29:22] LfcMax = 20h,
+                                          [21:14] LfcMin = 10h */
+ 
+-      { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
++      { 0xD1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
+         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
+                                          [21:14] LfcMin = 08h */
+ 
+-      { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_HT1,
++      { 0xC1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
+         0x04020000, 0x3FFFC000 },     /* [29:22] LfcMax = 10h,
+                                          [21:14] LfcMin = 08h */
+ 
+-      { 0xC0, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 
HTPHY_LINKTYPE_ALL,
++      { 0xC0, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
+         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
+-                                                                 [20:16] 
RttIndex = 04h */
++                                        [20:16] RttIndex = 04h */
++// #endif
+ };
+diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
+index 0e7d299..d99c37f 100644
+--- a/src/cpu/amd/family_10h-family_15h/fidvid.c
++++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
+@@ -633,44 +633,45 @@ static void prep_fid_change(void)
+ }
+ 
+ static void waitCurrentPstate(u32 target_pstate) {
+-  msr_t initial_msr = rdmsr(TSC_MSR);
+-  msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
+-  msr_t tsc_msr;
+-  u8 timedout ;
+-
+-  /* paranoia ? I fear when we run fixPsNbVidBeforeWR we can enter a
+-   * P1 that is a copy of P0, therefore has the same NB DID but the
+-   * TSC will count twice per tick, so we have to wait for twice the
+-   * count to achieve the desired timeout. But I'm likely to
+-   * misunderstand this...
+-   */
+-  u32 corrected_timeout = (    (pstate_msr.lo==1)
+-                          && (!(rdmsr(0xC0010065).lo & NB_DID_M_ON)) ) ?
+-                          WAIT_PSTATE_TIMEOUT*2 : WAIT_PSTATE_TIMEOUT  ;
+-  msr_t timeout;
+-
+-  timeout.lo = initial_msr.lo + corrected_timeout ;
+-  timeout.hi = initial_msr.hi;
+-  if ( (((u32)0xffffffff) - initial_msr.lo) < corrected_timeout ) {
+-     timeout.hi++;
+-  }
+-
+-  // assuming TSC ticks at 1.25 ns per tick (800 MHz)
+-  do {
+-      pstate_msr = rdmsr(CUR_PSTATE_MSR);
+-      tsc_msr = rdmsr(TSC_MSR);
+-      timedout = (tsc_msr.hi > timeout.hi)
+-              || ((tsc_msr.hi == timeout.hi) && (tsc_msr.lo > timeout.lo ));
+-  } while ( (pstate_msr.lo != target_pstate) && (! timedout) ) ;
+-
+-  if (pstate_msr.lo != target_pstate) {
+-    msr_t limit_msr = rdmsr(0xc0010061);
+-    printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state 
%01x P-state current limit MSRC001_0061=%08x %08x\n", target_pstate, 
pstate_msr.lo, limit_msr.hi, limit_msr.lo);
+-
+-    do { // should we just go on instead ?
+-      pstate_msr = rdmsr(CUR_PSTATE_MSR);
+-    } while ( pstate_msr.lo != target_pstate  ) ;
+-  }
++      msr_t initial_msr = rdmsr(TSC_MSR);
++      msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR);
++      msr_t tsc_msr;
++      u8 timedout ;
++
++      /* paranoia ? I fear when we run fixPsNbVidBeforeWR we can enter a
++      * P1 that is a copy of P0, therefore has the same NB DID but the
++      * TSC will count twice per tick, so we have to wait for twice the
++      * count to achieve the desired timeout. But I'm likely to
++      * misunderstand this...
++      */
++      u32 corrected_timeout = ((pstate_msr.lo==1)
++                              && (!(rdmsr(0xC0010065).lo & NB_DID_M_ON)) ) ?
++                              WAIT_PSTATE_TIMEOUT*2 : WAIT_PSTATE_TIMEOUT;
++      msr_t timeout;
++
++      timeout.lo = initial_msr.lo + corrected_timeout ;
++      timeout.hi = initial_msr.hi;
++      if ( (((u32)0xffffffff) - initial_msr.lo) < corrected_timeout ) {
++              timeout.hi++;
++      }
++
++      // assuming TSC ticks at 1.25 ns per tick (800 MHz)
++      do {
++              pstate_msr = rdmsr(CUR_PSTATE_MSR);
++              tsc_msr = rdmsr(TSC_MSR);
++              timedout = (tsc_msr.hi > timeout.hi)
++                      || ((tsc_msr.hi == timeout.hi) && (tsc_msr.lo > 
timeout.lo ));
++      } while ( (pstate_msr.lo != target_pstate) && (! timedout) ) ;
++
++      if (pstate_msr.lo != target_pstate) {
++              msr_t limit_msr = rdmsr(0xc0010061);
++              printk(BIOS_ERR, "*** APIC ID %02x: timed out waiting for 
P-state %01x. Current P-state %01x P-state current limit MSRC001_0061=%08x 
%08x\n",
++                      cpuid_ebx(0x00000001) >> 24, target_pstate, 
pstate_msr.lo, limit_msr.hi, limit_msr.lo);
++
++              do { // should we just go on instead ?
++                      pstate_msr = rdmsr(CUR_PSTATE_MSR);
++              } while ( pstate_msr.lo != target_pstate  ) ;
++      }
+ }
+ 
+ static void set_pstate(u32 nonBoostedPState) {
+@@ -1064,13 +1065,13 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes)
+          APs and BSP */
+       ap_apicidx.num = 0;
+ 
+-      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE_RANGE, store_ap_apicid, 
&ap_apicidx);
++      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE_RANGE, -1, 
store_ap_apicid, &ap_apicidx);
+ 
+       for (i = 0; i < ap_apicidx.num; i++) {
+               init_fidvid_bsp_stage1(ap_apicidx.apicid[i], &fv);
+       }
+ #else
+-      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE0_ONLY, 
init_fidvid_bsp_stage1, &fv);
++      for_each_ap(bsp_apicid, CONFIG_SET_FIDVID_CORE0_ONLY, -1, 
init_fidvid_bsp_stage1, &fv);
+ #endif
+ 
+       print_debug_fv("common_fid = ", fv.common_fid);
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index d45671c..4e5098e 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -59,6 +59,8 @@ static void set_EnableCf8ExtCfg(void)
+ static void set_EnableCf8ExtCfg(void) { }
+ #endif
+ 
++// #define DEBUG_HT_SETUP 1
++// #define FAM10_AP_NODE_SEQUENTIAL_START 1
+ 
+ typedef void (*process_ap_t) (u32 apicid, void *gp);
+ 
+@@ -143,8 +145,8 @@ uint32_t get_boot_apic_id(uint8_t node, uint32_t core) {
+ //core range = 1 : core 0 only
+ //core range = 2 : cores other than core0
+ 
+-static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t 
process_ap,
+-                      void *gp)
++static void for_each_ap(uint32_t bsp_apicid, uint32_t core_range, int8_t node,
++                      process_ap_t process_ap, void *gp)
+ {
+       // here assume the OS don't change our apicid
+       u32 ap_apicid;
+@@ -165,6 +167,9 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, 
process_ap_t process_ap,
+       }
+ 
+       for (i = 0; i < nodes; i++) {
++              if ((node >= 0) && (i != node))
++                      continue;
++
+               cores_found = get_core_num_in_bsp(i);
+ 
+               u32 jstart, jend;
+@@ -280,7 +285,7 @@ void wait_all_other_cores_started(u32 bsp_apicid)
+ {
+       // all aps other than core0
+       printk(BIOS_DEBUG, "started ap apicid: ");
+-      for_each_ap(bsp_apicid, 2, wait_ap_started, (void *)0);
++      for_each_ap(bsp_apicid, 2, -1, wait_ap_started, (void *)0);
+       printk(BIOS_DEBUG, "\n");
+ }
+ 
+@@ -373,8 +378,10 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
+       /* NB_CFG MSR is shared between cores, so we need make sure
+          core0 is done at first --- use wait_all_core0_started  */
+       if (id.coreid == 0) {
+-              set_apicid_cpuid_lo();  /* only set it on core0 */
+-              set_EnableCf8ExtCfg();  /* only set it on core0 */
++              /* Set InitApicIdCpuIdLo / EnableCf8ExtCfg on core0 only */
++              if (!is_fam15h())
++                      set_apicid_cpuid_lo();
++              set_EnableCf8ExtCfg();
+ #if CONFIG_ENABLE_APIC_EXT_ID
+               enable_apic_ext_id(id.nodeid);
+ #endif
+@@ -427,6 +434,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
+       }
+       // Mark the core as started.
+       lapic_write(LAPIC_MSG_REG, (apicid << 24) | F10_APSTATE_STARTED);
++      printk(BIOS_DEBUG, "CPU APICID %02x start flag set\n", apicid);
+ 
+       if (apicid != bsp_apicid) {
+               /* Setup each AP's cores MSRs.
+@@ -588,6 +596,34 @@ static void setup_remote_node(u8 node)
+ }
+ #endif                                /* CONFIG_MAX_PHYSICAL_CPUS > 1 */
+ 
++//it is running on core0 of node0
++static void start_other_cores(uint32_t bsp_apicid)
++{
++      u32 nodes;
++      u32 nodeid;
++
++      // disable multi_core
++      if (read_option(multi_core, 0) != 0)  {
++              printk(BIOS_DEBUG, "Skip additional core init\n");
++              return;
++      }
++
++      nodes = get_nodes();
++
++      for (nodeid = 0; nodeid < nodes; nodeid++) {
++              u32 cores = get_core_num_in_bsp(nodeid);
++              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1\n", 
nodeid, cores);
++              if (cores > 0) {
++                      real_start_other_core(nodeid, cores);
++#ifdef FAM10_AP_NODE_SEQUENTIAL_START
++                      printk(BIOS_DEBUG, "waiting for core start on node 
%d...\n", nodeid);
++                      for_each_ap(bsp_apicid, 2, nodeid, wait_ap_started, 
(void *)0);
++                      printk(BIOS_DEBUG, "...started\n");
++#endif
++              }
++      }
++}
++
+ static void AMD_Errata281(u8 node, uint64_t revision, u32 platform)
+ {
+       /* Workaround for Transaction Scheduling Conflict in
+@@ -847,6 +883,10 @@ static void AMD_SetHtPhyRegister(u8 node, u8 link, u8 
entry)
+ 
+       phyBase = ((u32) link << 3) | 0x180;
+ 
++      /* Determine if link is connected and abort if not */
++      if (!(pci_read_config32(NODE_PCI(node, 0), 0x98 + (link * 0x20)) & 0x1))
++              return;
++
+       /* Get the portal control register's initial value
+        * and update it to access the desired phy register
+        */
+@@ -1009,10 +1049,11 @@ static void cpuSetAMDPCI(u8 node)
+        * Hypertransport initialization has taken place.  Also note
+        * that it is run for the first core on each node
+        */
+-      u8 i, j;
++      uint8_t i;
++      uint8_t j;
+       u32 platform;
+       u32 val;
+-      u8 offset;
++      uint8_t offset;
+       uint32_t dword;
+       uint64_t revision;
+ 
+@@ -1039,6 +1080,17 @@ static void cpuSetAMDPCI(u8 node)
+               }
+       }
+ 
++#ifdef DEBUG_HT_SETUP
++      /* Dump link settings */
++      for (i = 0; i < 4; i++) {
++              for (j = 0; j < 4; j++) {
++                      printk(BIOS_DEBUG, "Node %d link %d: type register: 
%08x control register: %08x extended control sublink 0: %08x 1: %08x\n", i, j,
++                              pci_read_config32(NODE_PCI(i, 0), 0x98 + (j * 
0x20)), pci_read_config32(NODE_PCI(i, 0), 0x84 + (j * 0x20)),
++                              pci_read_config32(NODE_PCI(i, 0), 0x170 + (j * 
0x4)), pci_read_config32(NODE_PCI(i, 0), 0x180 + (j * 0x4)));
++              }
++      }
++#endif
++
+       for (i = 0; i < ARRAY_SIZE(fam10_htphy_default); i++) {
+               if ((fam10_htphy_default[i].revision & revision) &&
+                   (fam10_htphy_default[i].platform & platform)) {
+diff --git a/src/cpu/amd/quadcore/quadcore.c b/src/cpu/amd/quadcore/quadcore.c
+index 8a9b5ed..9c31eac 100644
+--- a/src/cpu/amd/quadcore/quadcore.c
++++ b/src/cpu/amd/quadcore/quadcore.c
+@@ -31,21 +31,6 @@
+ uint32_t get_boot_apic_id(uint8_t node, uint32_t core);
+ uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2);
+ 
+-static inline uint8_t is_fam15h(void)
+-{
+-      uint8_t fam15h = 0;
+-      uint32_t family;
+-
+-      family = cpuid_eax(0x80000001);
+-      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+-
+-      if (family >= 0x6f)
+-              /* Family 15h or later */
+-              fam15h = 1;
+-
+-      return fam15h;
+-}
+-
+ static u32 get_core_num_in_bsp(u32 nodeid)
+ {
+       u32 dword;
+@@ -141,6 +126,7 @@ static void real_start_other_core(uint32_t nodeid, 
uint32_t cores)
+       }
+ }
+ 
++#if (!IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX))
+ //it is running on core0 of node0
+ static void start_other_cores(void)
+ {
+@@ -157,9 +143,10 @@ static void start_other_cores(void)
+ 
+       for (nodeid = 0; nodeid < nodes; nodeid++) {
+               u32 cores = get_core_num_in_bsp(nodeid);
+-              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1 \n", 
nodeid, cores);
++              printk(BIOS_DEBUG, "init node: %02x  cores: %02x pass 1\n", 
nodeid, cores);
+               if (cores > 0) {
+                       real_start_other_core(nodeid, cores);
+               }
+       }
+ }
++#endif
+diff --git a/src/cpu/amd/quadcore/quadcore_id.c 
b/src/cpu/amd/quadcore/quadcore_id.c
+index c0537b3..1f5cbd8 100644
+--- a/src/cpu/amd/quadcore/quadcore_id.c
++++ b/src/cpu/amd/quadcore/quadcore_id.c
+@@ -108,7 +108,6 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
+                       id.nodeid = apicid & 0x7;
+               }
+       }
+-
+       if (fam15h && dual_node) {
+               /* Coreboot expects each separate processor die to be on a 
different nodeid.
+                * Since the code above returns nodeid 0 even on internal node 
1 some fixup is needed...
+diff --git a/src/mainboard/advansus/a785e-i/romstage.c 
b/src/mainboard/advansus/a785e-i/romstage.c
+index ab717fd..591faab 100644
+--- a/src/mainboard/advansus/a785e-i/romstage.c
++++ b/src/mainboard/advansus/a785e-i/romstage.c
+@@ -155,7 +155,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/amd/bimini_fam10/romstage.c 
b/src/mainboard/amd/bimini_fam10/romstage.c
+index 5e2cf82..95384ac 100644
+--- a/src/mainboard/amd/bimini_fam10/romstage.c
++++ b/src/mainboard/amd/bimini_fam10/romstage.c
+@@ -147,7 +147,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/amd/mahogany_fam10/romstage.c 
b/src/mainboard/amd/mahogany_fam10/romstage.c
+index 025a8bb..aac6b4e 100644
+--- a/src/mainboard/amd/mahogany_fam10/romstage.c
++++ b/src/mainboard/amd/mahogany_fam10/romstage.c
+@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+  #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+  #endif
+diff --git a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c 
b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
+index 5063439..6d36575 100644
+--- a/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
++++ b/src/mainboard/amd/serengeti_cheetah_fam10/romstage.c
+@@ -255,7 +255,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+  #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+  #endif
+diff --git a/src/mainboard/amd/tilapia_fam10/romstage.c 
b/src/mainboard/amd/tilapia_fam10/romstage.c
+index e37bc08..c9a9928 100644
+--- a/src/mainboard/amd/tilapia_fam10/romstage.c
++++ b/src/mainboard/amd/tilapia_fam10/romstage.c
+@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/asus/kfsn4-dre/romstage.c 
b/src/mainboard/asus/kfsn4-dre/romstage.c
+index dd5c7dc..1307e57 100644
+--- a/src/mainboard/asus/kfsn4-dre/romstage.c
++++ b/src/mainboard/asus/kfsn4-dre/romstage.c
+@@ -288,7 +288,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+       if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
+               /* Core0 on each node is configured. Now setup any additional 
cores. */
+               printk(BIOS_DEBUG, "start_other_cores()\n");
+-              start_other_cores();
++              start_other_cores(bsp_apicid);
+               post_code(0x37);
+               wait_all_other_cores_started(bsp_apicid);
+       }
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index 4b4e305..f80fb8c 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -97,7 +97,18 @@ static void switch_spd_mux(uint8_t channel)
+       pci_write_config8(PCI_DEV(0, 0x14, 0), 0x54, byte);
+ }
+ 
+-static const uint8_t spd_addr[] = {
++static const uint8_t spd_addr_fam15[] = {
++      // Socket 0 Node 0 ("Node 0")
++      RC00, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
++      // Socket 0 Node 1 ("Node 1")
++      RC00, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
++      // Socket 1 Node 0 ("Node 2")
++      RC01, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
++      // Socket 1 Node 1 ("Node 3")
++      RC01, DIMM4, DIMM5, 0, 0, DIMM6, DIMM7, 0, 0,
++};
++
++static const uint8_t spd_addr_fam10[] = {
+       // Socket 0 Node 0 ("Node 0")
+       RC00, DIMM0, DIMM1, 0, 0, DIMM2, DIMM3, 0, 0,
+       // Socket 0 Node 1 ("Node 1")
+@@ -117,10 +128,10 @@ static void activate_spd_rom(const struct mem_controller 
*ctrl) {
+               switch_spd_mux(0x2);
+       } else if (ctrl->node_id == 1) {
+               printk(BIOS_DEBUG, "enable_spd_node1()\n");
+-              switch_spd_mux((sysinfo->nodes <= 2)?0x2:0x3);
++              switch_spd_mux((is_fam15h() || (sysinfo->nodes <= 2))?0x2:0x3);
+       } else if (ctrl->node_id == 2) {
+               printk(BIOS_DEBUG, "enable_spd_node2()\n");
+-              switch_spd_mux((sysinfo->nodes <= 2)?0x3:0x2);
++              switch_spd_mux((is_fam15h() || (sysinfo->nodes <= 2))?0x3:0x2);
+       } else if (ctrl->node_id == 3) {
+               printk(BIOS_DEBUG, "enable_spd_node3()\n");
+               switch_spd_mux(0x3);
+@@ -306,18 +317,25 @@ void initialize_romstage_console_lock(void)
+ 
+ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
+ {
++      uint32_t esp;
++      __asm__ volatile (
++              "movl %%esp, %0"
++              : "=r" (esp)
++              );
++
+       struct sys_info *sysinfo = &sysinfo_car;
+ 
+       uint32_t bsp_apicid = 0, val;
+       uint8_t byte;
+       msr_t msr;
+ 
+-      timestamp_init(timestamp_get());
+-      timestamp_add_now(TS_START_ROMSTAGE);
+-
+       int s3resume = acpi_is_wakeup_s3();
+ 
+       if (!cpu_init_detectedx && boot_cpu()) {
++              /* Initial timestamp */
++              timestamp_init(timestamp_get());
++              timestamp_add_now(TS_START_ROMSTAGE);
++
+               /* Initialize the printk spinlock */
+               initialize_romstage_console_lock();
+ 
+@@ -344,6 +362,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               pci_write_config8(PCI_DEV(0, 0x14, 3), 0x78, byte);
+       }
+ 
++      printk(BIOS_SPEW, "Initial stack pointer: %08x\n", esp);
++
+       post_code(0x30);
+ 
+       if (bist == 0)
+@@ -397,7 +417,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+       if (IS_ENABLED(CONFIG_LOGICAL_CPUS)) {
+               /* Core0 on each node is configured. Now setup any additional 
cores. */
+               printk(BIOS_DEBUG, "start_other_cores()\n");
+-              start_other_cores();
++              start_other_cores(bsp_apicid);
+               post_code(0x37);
+               wait_all_other_cores_started(bsp_apicid);
+       }
+@@ -455,7 +475,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       /* It's the time to set ctrl in sysinfo now; */
+       printk(BIOS_DEBUG, "fill_mem_ctrl() detected %d nodes\n", 
sysinfo->nodes);
+-      fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr);
++      if (is_fam15h())
++              fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr_fam15);
++      else
++              fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr_fam10);
+       post_code(0x3D);
+ 
+ #if 0
+@@ -527,5 +550,12 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+  */
+ BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 **List)
+ {
++      /* Force BUID to 0 */
++      static const u8 swaplist[] = {0, 0, 0xFF, 0, 0xFF};
++      if ((node == 0) && (link == 1)) {       /* BSP SB link */
++              *List = swaplist;
++              return 1;
++      }
++
+       return 0;
+ }
+diff --git a/src/mainboard/asus/m4a78-em/romstage.c 
b/src/mainboard/asus/m4a78-em/romstage.c
+index 82b96bf..75894d8 100644
+--- a/src/mainboard/asus/m4a78-em/romstage.c
++++ b/src/mainboard/asus/m4a78-em/romstage.c
+@@ -151,7 +151,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+  #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+  #endif
+diff --git a/src/mainboard/asus/m4a785-m/romstage.c 
b/src/mainboard/asus/m4a785-m/romstage.c
+index 30975fa..f81cb95 100644
+--- a/src/mainboard/asus/m4a785-m/romstage.c
++++ b/src/mainboard/asus/m4a785-m/romstage.c
+@@ -151,7 +151,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+  #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+  #endif
+diff --git a/src/mainboard/asus/m5a88-v/romstage.c 
b/src/mainboard/asus/m5a88-v/romstage.c
+index 4edaba2..9914025 100644
+--- a/src/mainboard/asus/m5a88-v/romstage.c
++++ b/src/mainboard/asus/m5a88-v/romstage.c
+@@ -152,7 +152,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/avalue/eax-785e/romstage.c 
b/src/mainboard/avalue/eax-785e/romstage.c
+index 447012b..c57454d 100644
+--- a/src/mainboard/avalue/eax-785e/romstage.c
++++ b/src/mainboard/avalue/eax-785e/romstage.c
+@@ -156,7 +156,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/gigabyte/ma785gm/romstage.c 
b/src/mainboard/gigabyte/ma785gm/romstage.c
+index 444e59d..ae661e8 100644
+--- a/src/mainboard/gigabyte/ma785gm/romstage.c
++++ b/src/mainboard/gigabyte/ma785gm/romstage.c
+@@ -146,7 +146,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/gigabyte/ma785gmt/romstage.c 
b/src/mainboard/gigabyte/ma785gmt/romstage.c
+index 705d7c5..968aa8f 100644
+--- a/src/mainboard/gigabyte/ma785gmt/romstage.c
++++ b/src/mainboard/gigabyte/ma785gmt/romstage.c
+@@ -146,7 +146,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/gigabyte/ma78gm/romstage.c 
b/src/mainboard/gigabyte/ma78gm/romstage.c
+index 5d21801..7e18724 100644
+--- a/src/mainboard/gigabyte/ma78gm/romstage.c
++++ b/src/mainboard/gigabyte/ma78gm/romstage.c
+@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/hp/dl165_g6_fam10/romstage.c 
b/src/mainboard/hp/dl165_g6_fam10/romstage.c
+index 26c0bb9..e70d274 100644
+--- a/src/mainboard/hp/dl165_g6_fam10/romstage.c
++++ b/src/mainboard/hp/dl165_g6_fam10/romstage.c
+@@ -160,7 +160,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/iei/kino-780am2-fam10/romstage.c 
b/src/mainboard/iei/kino-780am2-fam10/romstage.c
+index 321eea6..89cfe83 100644
+--- a/src/mainboard/iei/kino-780am2-fam10/romstage.c
++++ b/src/mainboard/iei/kino-780am2-fam10/romstage.c
+@@ -149,7 +149,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+  #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+  #endif
+diff --git a/src/mainboard/jetway/pa78vm5/romstage.c 
b/src/mainboard/jetway/pa78vm5/romstage.c
+index 93dd2ce..6106b66 100644
+--- a/src/mainboard/jetway/pa78vm5/romstage.c
++++ b/src/mainboard/jetway/pa78vm5/romstage.c
+@@ -154,7 +154,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+  #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+  #endif
+diff --git a/src/mainboard/msi/ms9652_fam10/romstage.c 
b/src/mainboard/msi/ms9652_fam10/romstage.c
+index 5da971f..f552db5 100644
+--- a/src/mainboard/msi/ms9652_fam10/romstage.c
++++ b/src/mainboard/msi/ms9652_fam10/romstage.c
+@@ -177,7 +177,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       printk(BIOS_DEBUG, "wait_all_other_cores_started()\n");
+       wait_all_other_cores_started(bsp_apicid);
+diff --git a/src/mainboard/supermicro/h8dmr_fam10/romstage.c 
b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
+index 1425546..333a213 100644
+--- a/src/mainboard/supermicro/h8dmr_fam10/romstage.c
++++ b/src/mainboard/supermicro/h8dmr_fam10/romstage.c
+@@ -171,7 +171,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/supermicro/h8qme_fam10/romstage.c 
b/src/mainboard/supermicro/h8qme_fam10/romstage.c
+index 4721eba..8caf615 100644
+--- a/src/mainboard/supermicro/h8qme_fam10/romstage.c
++++ b/src/mainboard/supermicro/h8qme_fam10/romstage.c
+@@ -238,7 +238,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/supermicro/h8scm_fam10/romstage.c 
b/src/mainboard/supermicro/h8scm_fam10/romstage.c
+index 858aca0..0e5adcd 100644
+--- a/src/mainboard/supermicro/h8scm_fam10/romstage.c
++++ b/src/mainboard/supermicro/h8scm_fam10/romstage.c
+@@ -162,7 +162,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/mainboard/tyan/s2912_fam10/romstage.c 
b/src/mainboard/tyan/s2912_fam10/romstage.c
+index cdf51b1..0fe004e 100644
+--- a/src/mainboard/tyan/s2912_fam10/romstage.c
++++ b/src/mainboard/tyan/s2912_fam10/romstage.c
+@@ -173,7 +173,7 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ #if CONFIG_LOGICAL_CPUS
+       /* Core0 on each node is configured. Now setup any additional cores. */
+       printk(BIOS_DEBUG, "start_other_cores()\n");
+-      start_other_cores();
++      start_other_cores(bsp_apicid);
+       post_code(0x37);
+       wait_all_other_cores_started(bsp_apicid);
+ #endif
+diff --git a/src/northbridge/amd/amdht/h3finit.c 
b/src/northbridge/amd/amdht/h3finit.c
+index 849f4a8..82bf885 100644
+--- a/src/northbridge/amd/amdht/h3finit.c
++++ b/src/northbridge/amd/amdht/h3finit.c
+@@ -389,13 +389,49 @@ static u8 convertNodeToLink(u8 srcNode, u8 targetNode, 
sMainData *pDat)
+  */
+ static void htDiscoveryFloodFill(sMainData *pDat)
+ {
+-      u8 currentNode = 0;
+-      u8 currentLink;
++      uint8_t currentNode = 0;
++      uint8_t currentLink;
++      uint8_t currentLinkID;
++
++      /* NOTE
++       * Each node inside a dual node (socket G34) processor must share
++       * an adjacent node ID.  Alter the link scan order such that the
++       * other internal node is always scanned first...
++       */
++      uint8_t currentLinkScanOrder_Default[8] = {0, 1, 2, 3, 4, 5, 6, 7};
++      uint8_t currentLinkScanOrder_G34_Fam10[8] = {1, 0, 2, 3, 4, 5, 6, 7};
++      uint8_t currentLinkScanOrder_G34_Fam15[8] = {2, 0, 1, 3, 4, 5, 6, 7};
++
++      uint8_t fam15h = 0;
++      uint8_t rev_gte_d = 0;
++      uint8_t dual_node = 0;
++      uint32_t f3xe8;
++      uint32_t family;
++      uint32_t model;
++
++      f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
++
++      family = model = cpuid_eax(0x80000001);
++      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f) {
++              /* Family 15h or later */
++              fam15h = 1;
++      }
++
++      if ((model >= 0x8) || fam15h)
++              /* Revision D or later */
++              rev_gte_d = 1;
++
++      if (rev_gte_d)
++               /* Check for dual node capability */
++              if (f3xe8 & 0x20000000)
++                      dual_node = 1;
+ 
+       /* Entries are always added in pairs, the even indices are the 'source'
+        * side closest to the BSP, the odd indices are the 'destination' side
+        */
+-
+       while (currentNode <= pDat->NodesDiscovered)
+       {
+               u32 temp;
+@@ -423,11 +459,24 @@ static void htDiscoveryFloodFill(sMainData *pDat)
+               /* Enable routing tables on currentNode*/
+               pDat->nb->enableRoutingTables(currentNode, pDat->nb);
+ 
+-              for (currentLink = 0; currentLink < pDat->nb->maxLinks; 
currentLink++)
++              for (currentLinkID = 0; currentLinkID < pDat->nb->maxLinks; 
currentLinkID++)
+               {
+                       BOOL linkfound;
+                       u8 token;
+ 
++                      if (currentLinkID < 8) {
++                              if (dual_node) {
++                                      if (fam15h)
++                                              currentLink = 
currentLinkScanOrder_G34_Fam15[currentLinkID];
++                                      else
++                                              currentLink = 
currentLinkScanOrder_G34_Fam10[currentLinkID];
++                              } else {
++                                      currentLink = 
currentLinkScanOrder_Default[currentLinkID];
++                              }
++                      } else {
++                              currentLink = currentLinkID;
++                      }
++
+                       if (pDat->HtBlock->AMD_CB_IgnoreLink && 
pDat->HtBlock->AMD_CB_IgnoreLink(currentNode, currentLink))
+                               continue;
+ 
+diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
+index 8f9177f..1026d0e 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.c
++++ b/src/northbridge/amd/amdht/h3ncmn.c
+@@ -51,8 +51,9 @@
+ #define REG_NODE_ID_0X60              0x60
+ #define REG_UNIT_ID_0X64              0x64
+ #define REG_LINK_TRANS_CONTROL_0X68   0x68
+-#define REG_LINK_INIT_CONTROL_0X6C    0x6C
++#define REG_LINK_INIT_CONTROL_0X6C    0x6c
+ #define REG_HT_CAP_BASE_0X80          0x80
++#define REG_NORTHBRIDGE_CFG_3X8C      0x8c
+ #define REG_HT_LINK_RETRY0_0X130      0x130
+ #define REG_HT_TRAFFIC_DIST_0X164     0x164
+ #define REG_HT_LINK_EXT_CONTROL0_0X170        0x170
+@@ -91,6 +92,21 @@
+  ***                  FAMILY/NORTHBRIDGE SPECIFIC FUNCTIONS           ***
+  ***************************************************************************/
+ 
++static inline uint8_t is_fam15h(void)
++{
++      uint8_t fam15h = 0;
++      uint32_t family;
++
++      family = cpuid_eax(0x80000001);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      return fam15h;
++}
++
+ 
/***************************************************************************//**
+  *
+  * SBDFO
+@@ -219,8 +235,18 @@ static void writeRoutingTable(u8 node, u8 target, u8 
link, cNorthBridge *nb)
+ 
+ static void writeNodeID(u8 node, u8 nodeID, cNorthBridge *nb)
+ {
+-      u32 temp = nodeID;
++      u32 temp;
+       ASSERT((node < nb->maxNodes) && (nodeID < nb->maxNodes));
++      if (is_fam15h()) {
++              temp = 1;
++              AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
++                                      makePCIBusFromNode(node),
++                                      makePCIDeviceFromNode(node),
++                                      CPU_NB_FUNC_03,
++                                      REG_NORTHBRIDGE_CFG_3X8C),
++                                      22, 22, &temp);
++      }
++      temp = nodeID;
+       AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(node),
+                               makePCIBusFromNode(node),
+                               makePCIDeviceFromNode(node),
+diff --git a/src/northbridge/amd/amdht/ht_wrapper.c 
b/src/northbridge/amd/amdht/ht_wrapper.c
+index c0ccc69..a4aaa12 100644
+--- a/src/northbridge/amd/amdht/ht_wrapper.c
++++ b/src/northbridge/amd/amdht/ht_wrapper.c
+@@ -92,16 +92,132 @@ static  u32 get_nodes(void)
+  */
+ static void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0)
+ {
+-      u8 i;
++      uint8_t i;
++      uint8_t log_level;
++      uint8_t dump_event_detail;
+ 
+-      printk(BIOS_DEBUG, "AMD_CB_EventNotify()\n");
+-      printk(BIOS_DEBUG, " event class: %02x\n event: %04x\n data: ", 
evtClass, event);
++      printk(BIOS_DEBUG, "AMD_CB_EventNotify(): ");
+ 
+-      for (i = 0; i < *pEventData0; i++) {
+-              printk(BIOS_DEBUG, " %02x ", *(pEventData0 + i));
++      /* Decode event */
++      dump_event_detail = 1;
++      switch (evtClass) {
++              case HT_EVENT_CLASS_CRITICAL:
++                      log_level = BIOS_DEBUG;
++                      printk(log_level, "CRITICAL");
++                      break;
++              case HT_EVENT_CLASS_ERROR:
++                      log_level = BIOS_DEBUG;
++                      printk(log_level, "ERROR");
++                      break;
++              case HT_EVENT_CLASS_HW_FAULT:
++                      log_level = BIOS_DEBUG;
++                      printk(log_level, "HARDWARE FAULT");
++                      break;
++              case HT_EVENT_CLASS_WARNING:
++                      log_level = BIOS_DEBUG;
++                      printk(log_level, "WARNING");
++                      break;
++              case HT_EVENT_CLASS_INFO:
++                      log_level = BIOS_DEBUG;
++                      printk(log_level, "INFO");
++                      break;
++              default:
++                      log_level = BIOS_DEBUG;
++                      printk(log_level, "UNKNOWN");
++                      break;
+       }
+-      printk(BIOS_DEBUG, "\n");
++      printk(log_level, ": ");
+ 
++      switch(event) {
++              case HT_EVENT_COH_EVENTS:
++                      printk(log_level, "HT_EVENT_COH_EVENTS");
++                      break;
++              case HT_EVENT_COH_NO_TOPOLOGY:
++                      printk(log_level, "HT_EVENT_COH_NO_TOPOLOGY");
++                      break;
++              case HT_EVENT_COH_LINK_EXCEED:
++                      printk(log_level, "HT_EVENT_COH_LINK_EXCEED");
++                      break;
++              case HT_EVENT_COH_FAMILY_FEUD:
++                      printk(log_level, "HT_EVENT_COH_FAMILY_FEUD");
++                      break;
++              case HT_EVENT_COH_NODE_DISCOVERED:
++                      {
++                              printk(log_level, 
"HT_EVENT_COH_NODE_DISCOVERED");
++                              sHtEventCohNodeDiscovered *evt = 
(sHtEventCohNodeDiscovered*)pEventData0;
++                              printk(log_level, ": node %d link %d new node: 
%d",
++                                      evt->node, evt->link, evt->newNode);
++                              dump_event_detail = 0;
++                              break;
++                      }
++              case HT_EVENT_COH_MPCAP_MISMATCH:
++                      printk(log_level, "HT_EVENT_COH_MPCAP_MISMATCH");
++                      break;
++              case HT_EVENT_NCOH_EVENTS:
++                      printk(log_level, "HT_EVENT_NCOH_EVENTS");
++                      break;
++              case HT_EVENT_NCOH_BUID_EXCEED:
++                      printk(log_level, "HT_EVENT_NCOH_BUID_EXCEED");
++                      break;
++              case HT_EVENT_NCOH_LINK_EXCEED:
++                      printk(log_level, "HT_EVENT_NCOH_LINK_EXCEED");
++                      break;
++              case HT_EVENT_NCOH_BUS_MAX_EXCEED:
++                      printk(log_level, "HT_EVENT_NCOH_BUS_MAX_EXCEED");
++                      break;
++              case HT_EVENT_NCOH_CFG_MAP_EXCEED:
++                      printk(log_level, "HT_EVENT_NCOH_CFG_MAP_EXCEED");
++                      break;
++              case HT_EVENT_NCOH_DEVICE_FAILED:
++                      {
++                              printk(log_level, 
"HT_EVENT_NCOH_DEVICE_FAILED");
++                              sHtEventNcohDeviceFailed *evt = 
(sHtEventNcohDeviceFailed*)pEventData0;
++                              printk(log_level, ": node %d link %d depth: %d 
attemptedBUID: %d",
++                                      evt->node, evt->link, evt->depth, 
evt->attemptedBUID);
++                              dump_event_detail = 0;
++                              break;
++                      }
++              case HT_EVENT_NCOH_AUTO_DEPTH:
++                      {
++                              printk(log_level, "HT_EVENT_NCOH_AUTO_DEPTH");
++                              sHtEventNcohAutoDepth *evt = 
(sHtEventNcohAutoDepth*)pEventData0;
++                              printk(log_level, ": node %d link %d depth: %d",
++                                      evt->node, evt->link, evt->depth);
++                              dump_event_detail = 0;
++                              break;
++                      }
++              case HT_EVENT_OPT_EVENTS:
++                      printk(log_level, "HT_EVENT_OPT_EVENTS");
++                      break;
++              case HT_EVENT_OPT_REQUIRED_CAP_RETRY:
++                      printk(log_level, "HT_EVENT_OPT_REQUIRED_CAP_RETRY");
++                      break;
++              case HT_EVENT_OPT_REQUIRED_CAP_GEN3:
++                      printk(log_level, "HT_EVENT_OPT_REQUIRED_CAP_GEN3");
++                      break;
++              case HT_EVENT_HW_EVENTS:
++                      printk(log_level, "HT_EVENT_HW_EVENTS");
++                      break;
++              case HT_EVENT_HW_SYNCHFLOOD:
++                      printk(log_level, "HT_EVENT_HW_SYNCHFLOOD");
++                      break;
++              case HT_EVENT_HW_HTCRC:
++                      printk(log_level, "HT_EVENT_HW_HTCRC");
++                      break;
++              default:
++                      printk(log_level, "HT_EVENT_UNKNOWN");
++                      break;
++      }
++      printk(log_level, "\n");
++
++      if (dump_event_detail) {
++              printk(BIOS_DEBUG, " event class: %02x\n event: %04x\n data: ", 
evtClass, event);
++
++              for (i = 0; i < *pEventData0; i++) {
++                      printk(BIOS_DEBUG, " %02x ", *(pEventData0 + i));
++              }
++              printk(BIOS_DEBUG, "\n");
++      }
+ }
+ 
+ /**
+@@ -210,9 +326,10 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
+                               for (node = 0; node < node_count; node++) {
+                                       f3xe8 = 
pci_read_config32(NODE_PCI(node, 3), 0xe8);
+                                       uint8_t internal_node_number = ((f3xe8 
& 0xc0000000) >> 30);
+-                                      printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link\n", node, 
internal_node_number);
++                                      printk(BIOS_DEBUG, "amd_ht_fixup(): 
node %d (internal node ID %d): disabling defective HT link", node, 
internal_node_number);
+                                       if (internal_node_number == 0) {
+                                               uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0x98:0xd8) & 0x1;
++                                              printk(BIOS_DEBUG, " (L3 
connected: %d)\n", package_link_3_connected);
+                                               if (package_link_3_connected) {
+                                                       /* Set WidthIn and 
WidthOut to 0 */
+                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4);
+@@ -234,15 +351,21 @@ void amd_ht_fixup(struct sys_info *sysinfo) {
+                                               }
+                                       } else if (internal_node_number == 1) {
+                                               uint8_t 
package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), 
(fam15h)?0xf8:0xb8) & 0x1;
++                                              printk(BIOS_DEBUG, " (L3 
connected: %d)\n", package_link_3_connected);
+                                               if (package_link_3_connected) {
+                                                       /* Set WidthIn and 
WidthOut to 0 */
+                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4);
+                                                       dword &= ~0x77000000;
+                                                       
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4, dword);
+                                                       /* Set Ganged to 1 */
+-                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174);
++                                                      /* WARNING
++                                                       * The Family 15h BKDG 
states that 0x18c should be set,
++                                                       * however this is in 
error.  0x17c is the correct control
++                                                       * register (sublink 0) 
for these processors...
++                                                       */
++                                                      dword = 
pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x17c:0x174);
+                                                       dword |= 0x00000001;
+-                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174, dword);
++                                                      
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x17c:0x174, dword);
+                                               } else {
+                                                       /* Set ConnDly to 1 */
+                                                       dword = 
pci_read_config32(NODE_PCI(node, 0), 0x16c);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 1c9c568..ccdd0df 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -5443,6 +5443,7 @@ static void mct_InitialMCT_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStruc
+               cpu_divisor = (0x1 << cpu_did);
+               pMCTstat->TSCFreq = (100 * (cpu_fid + 0x10)) / cpu_divisor;
+ 
++              printk(BIOS_DEBUG, "mct_InitialMCT_D: 
mct_ForceNBPState0_En_Fam15\n");
+               mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat);
+       } else {
+               /* K10 BKDG v3.62 section 2.8.9.2 */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdfam10-Add-probe-filter-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdfam10-Add-probe-filter-support.patch
new file mode 100644
index 0000000..1a684e2
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdfam10-Add-probe-filter-support.patch
@@ -0,0 +1,282 @@
+From 7aca5c828dde51868dcf4c46ba19f5dc34aaf7d3 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 2 Aug 2015 21:06:39 -0500
+Subject: [PATCH 090/143] northbridge/amd/amdfam10: Add probe filter support
+
+Change-Id: I00a27a828260be8685ae622cfa5a4995add95a8e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c      |   13 ++
+ .../amd/family_10h-family_15h/model_10xxx_init.c   |   22 +++
+ src/northbridge/amd/amdfam10/northbridge.c         |  144 +++++++++++++++++++-
+ src/northbridge/amd/amdht/h3ncmn.c                 |   22 +++
+ 4 files changed, 200 insertions(+), 1 deletion(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index 4e5098e..7d303e0 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -445,6 +445,19 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct 
sys_info *sysinfo)
+ 
+               cpuSetAMDMSR(id.nodeid);
+ 
++              /* Set up probe filter support */
++              if (is_gt_rev_d()) {
++                      uint8_t node_count;
++                      node_count = (pci_read_config32(NODE_PCI(id.nodeid, 0), 
0x60) >> 4) & 0x7;
++                      node_count++;
++
++                      if (node_count > 1) {
++                              msr_t msr = rdmsr(BU_CFG2_MSR);
++                              msr.hi |= 1 << (42 - 32);
++                              wrmsr(BU_CFG2_MSR, msr);
++                      }
++              }
++
+ #if CONFIG_SET_FIDVID
+ #if CONFIG_LOGICAL_CPUS && CONFIG_SET_FIDVID_CORE0_ONLY
+               // Run on all AP for proper FID/VID setup.
+diff --git a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c 
b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
+index 8a61f13..5c590b8 100644
+--- a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
++++ b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
+@@ -54,6 +54,28 @@ static inline uint8_t is_fam15h(void)
+       return fam15h;
+ }
+ 
++static inline uint8_t is_gt_rev_d(void)
++{
++      uint8_t fam15h = 0;
++      uint8_t rev_gte_d = 0;
++      uint32_t family;
++      uint32_t model;
++
++      family = model = cpuid_eax(0x80000001);
++      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      if ((model >= 0x8) || fam15h)
++              /* Revision D or later */
++              rev_gte_d = 1;
++
++      return rev_gte_d;
++}
++
+ static volatile uint8_t 
fam15h_startup_flags[MAX_NODES_SUPPORTED][MAX_CORES_SUPPORTED] = {{ 0 }};
+ 
+ static void model_10xxx_init(device_t dev)
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 52b5ffb..808cd3a 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -30,10 +30,13 @@
+ #include <lib.h>
+ #include <smbios.h>
+ #include <cpu/cpu.h>
++#include <delay.h>
+ 
+ #include <cpu/x86/lapic.h>
++#include <cpu/x86/cache.h>
+ #include <cpu/amd/mtrr.h>
+ #include <cpu/amd/amdfam10_sysconf.h>
++#include <cpu/amd/model_10xxx_msr.h>
+ #include <cpu/amd/family_10h-family_15h/ram_calc.h>
+ 
+ #if CONFIG_LOGICAL_CPUS
+@@ -1527,7 +1530,7 @@ static void cpu_bus_scan(device_t dev)
+               if(i>=32) {
+                       busn--;
+                       devn-=32;
+-                      pbus = pci_domain->link_list->next);
++                      pbus = pci_domain->link_list->next;
+               }
+ #endif
+ 
+@@ -1647,8 +1650,147 @@ static void cpu_bus_scan(device_t dev)
+       }
+ }
+ 
++static void detect_and_enable_probe_filter(device_t dev)
++{
++      uint32_t dword;
++
++      uint8_t fam15h = 0;
++      uint8_t rev_gte_d = 0;
++      uint8_t dual_node = 0;
++      unsigned nb_cfg_54;
++      uint32_t f3xe8;
++      uint32_t family;
++      uint32_t model;
++
++      family = model = cpuid_eax(0x80000001);
++      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++
++      if (is_fam15h()) {
++              /* Family 15h or later */
++              fam15h = 1;
++              nb_cfg_54 = 1;
++      }
++
++      if ((model >= 0x8) || fam15h)
++              /* Revision D or later */
++              rev_gte_d = 1;
++
++      if (rev_gte_d)
++              /* Check for dual node capability */
++              if (f3xe8 & 0x20000000)
++                      dual_node = 1;
++
++      if (rev_gte_d && (sysconf.nodes > 1)) {
++              /* Enable the probe filter */
++              uint8_t i;
++              uint8_t pfmode = 0x0;
++
++              uint32_t f3x58[MAX_NODES_SUPPORTED];
++              uint32_t f3x5c[MAX_NODES_SUPPORTED];
++
++              printk(BIOS_DEBUG, "Enabling probe filter\n");
++
++              /* Disable L3 and DRAM scrubbers and configure system for probe 
filter support */
++              for (i = 0; i < sysconf.nodes; i++) {
++                      device_t f2x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
2));
++                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
++
++                      f3x58[i] = pci_read_config32(f3x_dev, 0x58);
++                      f3x5c[i] = pci_read_config32(f3x_dev, 0x5c);
++                      pci_write_config32(f3x_dev, 0x58, f3x58[i] & ~((0x1f << 
24) | 0x1f));
++                      pci_write_config32(f3x_dev, 0x5c, f3x5c[i] & ~0x1);
++
++                      dword = pci_read_config32(f2x_dev, 0x1b0);
++                      dword &= ~(0x7 << 8);   /* CohPrefPrbLmt = 0x0 */
++                      pci_write_config32(f2x_dev, 0x1b0, dword);
++
++                      msr_t msr = rdmsr_amd(BU_CFG2_MSR);
++                      msr.hi |= 1 << (42 - 32);
++                      wrmsr_amd(BU_CFG2_MSR, msr);
++
++                      if (is_fam15h()) {
++                              uint8_t subcache_size = 0x0;
++                              uint8_t pref_so_repl = 0x0;
++                              uint32_t f3x1c4 = pci_read_config32(f3x_dev, 
0x1c4);
++                              if ((f3x1c4 & 0xffff) == 0xcccc) {
++                                      subcache_size = 0x1;
++                                      pref_so_repl = 0x2;
++                                      pfmode = 0x3;
++                              } else {
++                                      pfmode = 0x2;
++                              }
++
++                              dword = pci_read_config32(f3x_dev, 0x1d4);
++                              dword |= 0x1 << 29;     /* PFLoIndexHashEn = 
0x1 */
++                              dword &= ~(0x3 << 20);  /* PFPreferredSORepl = 
pref_so_repl */
++                              dword |= (pref_so_repl & 0x3) << 20;
++                              dword |= 0x1 << 17;     /* PFWayHashEn = 0x1 */
++                              dword |= 0xf << 12;     /* PFSubCacheEn = 0xf */
++                              dword &= ~(0x3 << 10);  /* PFSubCacheSize3 = 
subcache_size */
++                              dword |= (subcache_size & 0x3) << 10;
++                              dword &= ~(0x3 << 8);   /* PFSubCacheSize2 = 
subcache_size */
++                              dword |= (subcache_size & 0x3) << 8;
++                              dword &= ~(0x3 << 6);   /* PFSubCacheSize1 = 
subcache_size */
++                              dword |= (subcache_size & 0x3) << 6;
++                              dword &= ~(0x3 << 4);   /* PFSubCacheSize0 = 
subcache_size */
++                              dword |= (subcache_size & 0x3) << 4;
++                              dword &= ~(0x3 << 2);   /* PFWayNum = 0x2 */
++                              dword |= 0x2 << 2;
++                              pci_write_config32(f3x_dev, 0x1d4, dword);
++                      } else {
++                              pfmode = 0x2;
++
++                              dword = pci_read_config32(f3x_dev, 0x1d4);
++                              dword |= 0x1 << 29;     /* PFLoIndexHashEn = 
0x1 */
++                              dword &= ~(0x3 << 20);  /* PFPreferredSORepl = 
0x2 */
++                              dword |= 0x2 << 20;
++                              dword |= 0xf << 12;     /* PFSubCacheEn = 0xf */
++                              dword &= ~(0x3 << 10);  /* PFSubCacheSize3 = 
0x0 */
++                              dword &= ~(0x3 << 8);   /* PFSubCacheSize2 = 
0x0 */
++                              dword &= ~(0x3 << 6);   /* PFSubCacheSize1 = 
0x0 */
++                              dword &= ~(0x3 << 4);   /* PFSubCacheSize0 = 
0x0 */
++                              dword &= ~(0x3 << 2);   /* PFWayNum = 0x2 */
++                              dword |= 0x2 << 2;
++                              pci_write_config32(f3x_dev, 0x1d4, dword);
++                      }
++              }
++
++              udelay(40);
++
++              disable_cache();
++              asm("wbinvd");
++              for (i = 0; i < sysconf.nodes; i++) {
++                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
++
++                      dword = pci_read_config32(f3x_dev, 0x1c4);
++                      dword |= (0x1 << 31);   /* L3TagInit = 1 */
++                      pci_write_config32(f3x_dev, 0x1c4, dword);
++                      do {
++                      } while (pci_read_config32(f3x_dev, 0x1c4) & (0x1 << 
31));
++
++                      dword = pci_read_config32(f3x_dev, 0x1d4);
++                      dword &= ~0x3;          /* PFMode = pfmode */
++                      dword |= pfmode & 0x3;
++                      pci_write_config32(f3x_dev, 0x1d4, dword);
++                      do {
++                      } while (!(pci_read_config32(f3x_dev, 0x1d4) & (0x1 << 
19)));
++              }
++              enable_cache();
++
++              /* Reenable L3 and DRAM scrubbers */
++              for (i = 0; i < sysconf.nodes; i++) {
++                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
++
++                      pci_write_config32(f3x_dev, 0x58, f3x58[i]);
++                      pci_write_config32(f3x_dev, 0x5c, f3x5c[i]);
++              }
++
++      }
++}
++
+ static void cpu_bus_init(device_t dev)
+ {
++      detect_and_enable_probe_filter(dev);
+       initialize_cpus(dev->link_list);
+ #if CONFIG_AMD_SB_CIMX
+       sb_After_Pci_Init();
+diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
+index 1026d0e..a27ee5b 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.c
++++ b/src/northbridge/amd/amdht/h3ncmn.c
+@@ -107,6 +107,28 @@ static inline uint8_t is_fam15h(void)
+       return fam15h;
+ }
+ 
++static inline uint8_t is_gt_rev_d(void)
++{
++      uint8_t fam15h = 0;
++      uint8_t rev_gte_d = 0;
++      uint32_t family;
++      uint32_t model;
++
++      family = model = cpuid_eax(0x80000001);
++      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
++      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
++
++      if (family >= 0x6f)
++              /* Family 15h or later */
++              fam15h = 1;
++
++      if ((model >= 0x8) || fam15h)
++              /* Revision D or later */
++              rev_gte_d = 1;
++
++      return rev_gte_d;
++}
++
+ 
/***************************************************************************//**
+  *
+  * SBDFO
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
 
b/resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
deleted file mode 100644
index c43e297..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
+++ /dev/null
@@ -1,338 +0,0 @@
-From 65404b72da34b2f786af5fa1901531e50f59d0d7 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 2 Aug 2015 21:23:02 -0500
-Subject: [PATCH 090/139] northbridge/amd/amdmct/mct_ddr3: Move K10D
- configuration into separate file
-
-Change-Id: Id45888f266fac7810a63fef43b8d7a0ee40cbf70
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/raminit_amdmct.c  |   1 +
- src/northbridge/amd/amdmct/amddefs.h           |   5 +-
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 133 ++++++++++++-------------
- src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c |   4 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctprod.c  |  65 ++++++++++++
- 5 files changed, 132 insertions(+), 76 deletions(-)
- create mode 100644 src/northbridge/amd/amdmct/mct_ddr3/mctprod.c
-
-diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-index cae228f..2cbe6b1 100644
---- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
-+++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
-@@ -379,6 +379,7 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t 
highest_rank_count, uint8
- #include "../amdmct/mct_ddr3/mctdqs_d.c"
- #include "../amdmct/mct_ddr3/mctsrc.c"
- #include "../amdmct/mct_ddr3/mctsdi.c"
-+#include "../amdmct/mct_ddr3/mctprod.c"
- #include "../amdmct/mct_ddr3/mctproc.c"
- #include "../amdmct/mct_ddr3/mctprob.c"
- #include "../amdmct/mct_ddr3/mcthwl.c"
-diff --git a/src/northbridge/amd/amdmct/amddefs.h 
b/src/northbridge/amd/amdmct/amddefs.h
-index 7aa4698..60d3c16 100644
---- a/src/northbridge/amd/amdmct/amddefs.h
-+++ b/src/northbridge/amd/amdmct/amddefs.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -115,7 +116,7 @@
- /*
-  * CPU HT PHY REGISTERS, FIELDS, AND MASKS
-  */
--#define HTPHY_OFFSET_MASK             0xE00001FF
-+#define HTPHY_OFFSET_MASK             0xE000FFFF
- #define HTPHY_WRITE_CMD                       0x40000000
- #define HTPHY_IS_COMPLETE_MASK                0x80000000
- #define HTPHY_DIRECT_MAP              0x20000000
-@@ -164,4 +165,4 @@
- #define AMD_PKGTYPE_S1gX 2
- #define AMD_PKGTYPE_G34 3
- #define AMD_PKGTYPE_ASB2 4
--#define AMD_PKGTYPE_C32 5
-\ No newline at end of file
-+#define AMD_PKGTYPE_C32 5
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 0b61106..1167976 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -182,6 +182,7 @@ static void SyncSetting(struct DCTStatStruc *pDCTstat);
- static uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm);
- static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
- static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
-+static void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat);
- 
- static void read_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay,
-                       uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
-@@ -2677,13 +2678,13 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
-       }
- 
-       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
--              /* Configure and enable prefetchers */
--              if (is_fam15h())
--                      dword = 0x0ce00f41;     /* BKDG recommended */
--              else
--                      dword = 0x0fe40fc0;     /* BKDG recommended */
--              dword |= MCCH_FlushWrOnStpGnt;  /* Set for S3 */
--              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);
-+              pDCTstat = pDCTstatA + Node;
-+
-+              /* Enable prefetchers */
-+              dword = Get_NB32(pDCTstat->dev_dct, 0x11c);     /* Memory 
Controller Configuration High */
-+              dword &= ~(0x1 << 13);                          /* PrefIoDis = 
0 */
-+              dword &= ~(0x1 << 12);                          /* PrefCpuDis = 
0 */
-+              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);      /* Memory 
Controller Configuration High */
-       }
- }
- 
-@@ -4925,31 +4926,33 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
-       Get_TrwtTO(pMCTstat, pDCTstat, dct);
-       Get_TrwtWB(pMCTstat, pDCTstat);
- 
--      reg = 0x8C;             /* Dram Timing Hi */
--      val = Get_NB32_DCT(dev, dct, reg);
--      val &= 0xffff0300;
--      dword = pDCTstat->TrwtTO;
--      val |= dword << 4;
--      dword = pDCTstat->Twrrd & 3;
--      val |= dword << 10;
--      dword = pDCTstat->Twrwr & 3;
--      val |= dword << 12;
--      dword = pDCTstat->Trdrd & 3;
--      val |= dword << 14;
--      dword = pDCTstat->TrwtWB;
--      val |= dword;
--      Set_NB32_DCT(dev, dct, reg, val);
--
--      reg = 0x78;
--      val = Get_NB32_DCT(dev, dct, reg);
--      val &= 0xFFFFC0FF;
--      dword = pDCTstat->Twrrd >> 2;
--      val |= dword << 8;
--      dword = pDCTstat->Twrwr >> 2;
--      val |= dword << 10;
--      dword = pDCTstat->Trdrd >> 2;
--      val |= dword << 12;
--      Set_NB32_DCT(dev, dct, reg, val);
-+      if (!is_fam15h()) {
-+              reg = 0x8c;             /* Dram Timing Hi */
-+              val = Get_NB32_DCT(dev, dct, reg);
-+              val &= 0xffff0300;
-+              dword = pDCTstat->TrwtTO;
-+              val |= dword << 4;
-+              dword = pDCTstat->Twrrd & 3;
-+              val |= dword << 10;
-+              dword = pDCTstat->Twrwr & 3;
-+              val |= dword << 12;
-+              dword = (pDCTstat->Trdrd - 0x3) & 3;
-+              val |= dword << 14;
-+              dword = pDCTstat->TrwtWB;
-+              val |= dword;
-+              Set_NB32_DCT(dev, dct, reg, val);
-+
-+              reg = 0x78;
-+              val = Get_NB32_DCT(dev, dct, reg);
-+              val &= 0xffffc0ff;
-+              dword = pDCTstat->Twrrd >> 2;
-+              val |= dword << 8;
-+              dword = pDCTstat->Twrwr >> 2;
-+              val |= dword << 10;
-+              dword = (pDCTstat->Trdrd - 0x3) >> 2;
-+              val |= dword << 12;
-+              Set_NB32_DCT(dev, dct, reg, val);
-+      }
- }
- 
- static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
-@@ -4960,6 +4963,8 @@ static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
-       Trdrd = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - 
pDCTstat->DqsRcvEnGrossMin) >> 1) + 1;
-       if (Trdrd > 8)
-               Trdrd = 8;
-+      if (Trdrd < 3)
-+              Trdrd = 3;
-       pDCTstat->Trdrd = Trdrd;
- }
- 
-@@ -5270,47 +5275,31 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
-               if (pDCTstat->NodePresent) {
-                       mct_PhyController_Config(pMCTstat, pDCTstat, 0);
-                       mct_PhyController_Config(pMCTstat, pDCTstat, 1);
--              }
--              if (!(pDCTstat->LogicalCPUID & AMD_DR_Dx)) { /* 
mct_checkForDxSupport */
--                      mct_ExtMCTConfig_Cx(pDCTstat);
--                      mct_ExtMCTConfig_Bx(pDCTstat);
--              } else {        /* For Dx CPU */
--                      val = 0x0CE00F00 | 1 << 29/* FlushWrOnStpGnt */;
--                      if (!(pDCTstat->GangedMode))
--                              val |= 0x20; /* MctWrLimit =  8 for Unganged 
mode */
--                      else
--                              val |= 0x40; /* MctWrLimit =  16 for ganged 
mode */
--                      Set_NB32(pDCTstat->dev_dct, 0x11C, val);
--
--                      val = Get_NB32(pDCTstat->dev_dct, 0x1B0);
--                      val &= 0xFFFFF8C0;
--                      val |= 0x101;   /* BKDG recommended settings */
--                      val |= 0x0FC00000; /* Agesa V5 */
--                      if (!(pDCTstat->GangedMode))
--                              val |= 1 << 12;
--                      else
--                              val &= ~(1 << 12);
- 
--                      val &= 0x0FFFFFFF;
-                       if (!is_fam15h()) {
--                              switch (pDCTstat->Speed) {
--                              case 4:
--                                      val |= 0x50000000; /* 5 for DDR800 */
--                                      break;
--                              case 5:
--                                      val |= 0x60000000; /* 6 for DDR1066 */
--                                      break;
--                              case 6:
--                                      val |= 0x80000000; /* 8 for DDR800 */
--                                      break;
--                              default:
--                                      val |= 0x90000000; /* 9 for DDR1600 */
--                                      break;
--                              }
--                      }
--                      Set_NB32(pDCTstat->dev_dct, 0x1B0, val);
-+                              /* Family 10h CPUs */
-+                              mct_ExtMCTConfig_Cx(pDCTstat);
-+                              mct_ExtMCTConfig_Bx(pDCTstat);
-+                              mct_ExtMCTConfig_Dx(pDCTstat);
-+                      } else {
-+                              /* Family 15h CPUs */
-+                              val = 0x0ce00f00 | 0x1 << 29;   /* 
FlushWrOnStpGnt */
-+                              val |= 0x10 << 2;               /* MctWrLimit = 
16 */
-+                              Set_NB32(pDCTstat->dev_dct, 0x11c, val);
-+
-+                              val = Get_NB32(pDCTstat->dev_dct, 0x1b0);
-+                              val &= ~0x3;                    /* 
AdapPrefMissRatio = 0x1 */
-+                              val |= 0x1;
-+                              val &= ~(0x3 << 2);             /* 
AdapPrefPositiveStep = 0x0 */
-+                              val &= ~(0x3 << 4);             /* 
AdapPrefNegativeStep = 0x0 */
-+                              val &= ~(0x7 << 8);             /* 
CohPrefPrbLmt = 0x1 */
-+                              val |= (0x1 << 8);
-+                              val |= (0x1 << 12);             /* 
EnSplitDctLimits = 0x1 */
-+                              val |= (0x7 << 22);             /* PrefFourConf 
= 0x7 */
-+                              val |= (0x7 << 25);             /* PrefFiveConf 
= 0x7 */
-+                              val &= ~(0xf << 28);            /* DcqBwThrotWm 
= 0x0 */
-+                              Set_NB32(pDCTstat->dev_dct, 0x1b0, val);
- 
--                      if (is_fam15h()) {
-                               uint8_t wm1;
-                               uint8_t wm2;
- 
-@@ -5341,11 +5330,11 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
-                                       break;
-                               }
- 
--                              val = Get_NB32(pDCTstat->dev_dct, 0x1B4);
-+                              val = Get_NB32(pDCTstat->dev_dct, 0x1b4);
-                               val &= ~(0x3ff);
-                               val |= ((wm2 & 0x1f) << 5);
-                               val |= (wm1 & 0x1f);
--                              Set_NB32(pDCTstat->dev_dct, 0x1B4, val);
-+                              Set_NB32(pDCTstat->dev_dct, 0x1b4, val);
-                       }
-               }
-       }
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
-index a1cdfa6..41f0946 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
-@@ -102,7 +102,7 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
-               BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask);
- 
-               for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) {
--                      reg = 0x40+(ChipSel<<2);        /*Dram CS Base 0 */
-+                      reg = 0x40 + (ChipSel<<2);      /* Dram CS Base 0 */
-                       val = Get_NB32_DCT(dev, dct, reg);
-                       if (val & 3) {
-                               val_lo = val & AddrLoMask;
-@@ -118,7 +118,7 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
-                               if(ChipSel & 1)
-                                       continue;
- 
--                              reg = 0x60 + ((ChipSel>>1)<<2); /*Dram CS Mask 
0 */
-+                              reg = 0x60 + ((ChipSel>>1)<<2); /* Dram CS Mask 
0 */
-                               val = Get_NB32_DCT(dev, dct, reg);
-                               val_lo = val & AddrLoMask;
-                               val_hi = val & AddrHiMask;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctprod.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctprod.c
-new file mode 100644
-index 0000000..2b62d4c
---- /dev/null
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctprod.c
-@@ -0,0 +1,65 @@
-+/*
-+ * This file is part of the coreboot project.
-+ *
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-+ * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; version 2 of the License.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc.
-+ */
-+
-+void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat)
-+{
-+      uint32_t dword;
-+
-+      if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
-+              dword = 0x0ce00f00 | 0x1 << 29; /* FlushWrOnStpGnt */
-+              if (!(pDCTstat->GangedMode))
-+                      dword |= 0x18 << 2;     /* MctWrLimit = 0x18 for 
unganged mode */
-+              else
-+                      dword |= 0x10 << 2;     /* MctWrLimit = 0x10 for ganged 
mode */
-+              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);
-+
-+              dword = Get_NB32(pDCTstat->dev_dct, 0x1b0);
-+              dword &= ~0x3;                  /* AdapPrefMissRatio = 0x1 */
-+              dword |= 0x1;
-+              dword &= ~(0x3 << 2);           /* AdapPrefPositiveStep = 0x0 */
-+              dword &= ~(0x3 << 4);           /* AdapPrefNegativeStep = 0x0 */
-+              dword &= ~(0x7 << 8);           /* CohPrefPrbLmt = 0x1 */
-+              dword |= (0x1 << 8);
-+              dword |= (0x7 << 22);           /* PrefFourConf = 0x7 */
-+              dword |= (0x7 << 25);           /* PrefFiveConf = 0x7 */
-+
-+              if (!(pDCTstat->GangedMode))
-+                      dword |= (0x1 << 12);   /* EnSplitDctLimits = 0x1 */
-+              else
-+                      dword &= ~(0x1 << 12);  /* EnSplitDctLimits = 0x0 */
-+
-+              dword &= ~(0xf << 28);          /* DcqBwThrotWm = ... */
-+              switch (pDCTstat->Speed) {
-+              case 4:
-+                      dword |= (0x5 << 28);   /* ...5 for DDR800 */
-+                      break;
-+              case 5:
-+                      dword |= (0x6 << 28);   /* ...6 for DDR1066 */
-+                      break;
-+              case 6:
-+                      dword |= (0x8 << 28);   /* ...8 for DDR800 */
-+                      break;
-+              default:
-+                      dword |= (0x9 << 28);   /* ...9 for DDR1600 */
-+                      break;
-+              }
-+              Set_NB32(pDCTstat->dev_dct, 0x1b0, dword);
-+      }
-+}
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0091-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
 
b/resources/libreboot/patch/kgpe-d16/0091-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
new file mode 100644
index 0000000..a6bf101
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0091-cpu-amd-family_10h-family_15h-Bring-initial-HT-regis.patch
@@ -0,0 +1,248 @@
+From 6e43fcda4e95ee0daa72f35fb46d10789da1fe7e Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 2 Aug 2015 21:18:29 -0500
+Subject: [PATCH 091/143] cpu/amd/family_10h-family_15h: Bring initial HT
+ register configuration in line with BKDG
+
+Change-Id: I009b6f478340e2dbfcda2b4534473d4397f9ecef
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h |  168 ++++++++++++++++++++------
+ 1 file changed, 133 insertions(+), 35 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index 513d169..1080cfc 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -388,44 +388,140 @@ static const struct {
+                                          [2] SyncOnUcEccEn = 1 */
+ 
+       /* XBAR buffer settings */
+-      { 3, 0x6c, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        0x00018052, 0x700780f7 },
++      { 3, 0x6c, AMD_FAM10_ALL & ~(AMD_DR_Dx), AMD_PTYPE_ALL,
++        0x00018052, 0x700780f7 },     /* IsocRspDBC = 0x0,
++                                         UpRspDBC = 0x1,
++                                         DatBuf24 = 0x1,
++                                         DnRspDBC = 0x1,
++                                         DnReqDBC = 0x1,
++                                         UpReqDBC = 0x2 */
++
++      /* XBAR buffer settings */
++      { 3, 0x6c, AMD_DR_Dx, AMD_PTYPE_ALL,
++        0x00028052, 0x700780f7 },     /* IsocRspDBC = 0x0,
++                                         UpRspDBC = 0x2,
++                                         DatBuf24 = 0x1,
++                                         DnRspDBC = 0x1,
++                                         DnReqDBC = 0x1,
++                                         UpReqDBC = 0x2 */
+ 
+       /* XBAR buffer settings */
+       { 3, 0x6c, AMD_FAM15_ALL, AMD_PTYPE_ALL,
+-        0x10010052, 0x700700f7 },
++        0x10010052, 0x700700f7 },     /* IsocRspDBC = 0x1,
++                                         UpRspDBC = 0x1,
++                                         DnRspDBC = 0x1,
++                                         DnReqDBC = 0x1,
++                                         UpReqDBC = 0x2 */
+ 
+       /* Errata 281 Workaround */
+-      { 3, 0x6C, ( AMD_DR_B0 | AMD_DR_B1),
++      { 3, 0x6c, (AMD_DR_B0 | AMD_DR_B1),
+         AMD_PTYPE_SVR, 0x00010094, 0x700780F7 },
+ 
+-      { 3, 0x6C, AMD_FAM10_ALL, AMD_PTYPE_UMA,
++      { 3, 0x6c, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x60018051, 0x700780F7 },
+ 
+-      { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        0x00041153, 0x777777F7 },
++      { 3, 0x70, AMD_FAM10_ALL & ~(AMD_DR_Dx), AMD_PTYPE_ALL,
++        0x00041153, 0x777777f7 },     /* IsocRspCBC = 0x0,
++                                         IsocPreqCBC = 0x0,
++                                         IsocReqCBC = 0x0,
++                                         UpRspCBC = 0x4,
++                                         DnPreqCBC = 0x1,
++                                         UpPreqCBC = 0x1,
++                                         DnRspCBC = 0x1,
++                                         DnReqCBC = 0x1,
++                                         UpReqCBC = 0x3 */
++
++      { 3, 0x70, AMD_DR_Dx, AMD_PTYPE_ALL,
++        0x00051153, 0x777777f7 },     /* IsocRspCBC = 0x0,
++                                         IsocPreqCBC = 0x0,
++                                         IsocReqCBC = 0x0,
++                                         UpRspCBC = 0x5,
++                                         DnPreqCBC = 0x1,
++                                         UpPreqCBC = 0x1,
++                                         DnRspCBC = 0x1,
++                                         DnReqCBC = 0x1,
++                                         UpReqCBC = 0x3 */
+ 
+       { 3, 0x70, AMD_FAM15_ALL, AMD_PTYPE_ALL,
+-        0x10171155, 0x777777f7 },
++        0x10171155, 0x777777f7 },     /* IsocRspCBC = 0x1,
++                                         IsocPreqCBC = 0x0,
++                                         IsocReqCBC = 0x1,
++                                         UpRspCBC = 0x7,
++                                         DnPreqCBC = 0x1,
++                                         UpPreqCBC = 0x1,
++                                         DnRspCBC = 0x1,
++                                         DnReqCBC = 0x1,
++                                         UpReqCBC = 0x5 */
+ 
+       { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+-        0x61221151, 0x777777F7 },
++        0x61221151, 0x777777f7 },     /* IsocRspCBC = 0x6,
++                                         IsocPreqCBC = 0x1,
++                                         IsocReqCBC = 0x2,
++                                         UpRspCBC = 0x2,
++                                         DnPreqCBC = 0x1,
++                                         UpPreqCBC = 0x1,
++                                         DnRspCBC = 0x1,
++                                         DnReqCBC = 0x1,
++                                         UpReqCBC = 0x1 */
++
++      { 3, 0x74, AMD_FAM10_ALL, ~AMD_PTYPE_UMA,
++        0x00081111, 0xf7ff7777 },     /* DRReqCBC = 0x0,
++                                         IsocPreqCBC = 0x0,
++                                         IsocReqCBC = 0x0,
++                                         ProbeCBC = 0x8,
++                                         DnPreqCBC = 0x1,
++                                         UpPreqCBC = 0x1,
++                                         DnReqCBC = 0x1,
++                                         UpReqCBC = 0x1 */
+ 
+       { 3, 0x74, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+-        0x00080101, 0x000F7777 },
++        0x00480101, 0xf7ff7777 },     /* DRReqCBC = 0x0,
++                                         IsocPreqCBC = 0x0,
++                                         IsocReqCBC = 0x4,
++                                         ProbeCBC = 0x8,
++                                         DnPreqCBC = 0x0,
++                                         UpPreqCBC = 0x1,
++                                         DnReqCBC = 0x0,
++                                         UpReqCBC = 0x1 */
+ 
+       { 3, 0x74, AMD_FAM15_ALL, AMD_PTYPE_ALL,
+-        0x00172111, 0x77ff7777 },
+-
+-      { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+-        0x00090914, 0x707FFF1F },
++        0x00172111, 0xf7ff7777 },     /* DRReqCBC = 0x0,
++                                         IsocPreqCBC = 0x0,
++                                         IsocReqCBC = 0x1,
++                                         ProbeCBC = 0x7,
++                                         DnPreqCBC = 0x2,
++                                         UpPreqCBC = 0x1,
++                                         DnReqCBC = 0x1,
++                                         UpReqCBC = 0x1 */
++
++      { 3, 0x7c, AMD_FAM10_ALL & ~(AMD_DR_Dx), AMD_PTYPE_ALL,
++       0x00090914, 0x707fff1f },      /* XBar2SriFreeListCBInc = 0x0,
++                                         Sri2XbarFreeRspDBC = 0x0,
++                                         Sri2XbarFreeXreqDBC = 0x9,
++                                         Sri2XbarFreeRspCBC = 0x0,
++                                         Sri2XbarFreeXreqCBC = 0x9,
++                                         Xbar2SriFreeListCBC = 0x14 */
++
++      { 3, 0x7c, AMD_DR_Dx, AMD_PTYPE_ALL,
++       0x00090a18, 0x707fff1f },      /* XBar2SriFreeListCBInc = 0x0,
++                                         Sri2XbarFreeRspDBC = 0x0,
++                                         Sri2XbarFreeXreqDBC = 0x9,
++                                         Sri2XbarFreeRspCBC = 0x0,
++                                         Sri2XbarFreeXreqCBC = 0x9,
++                                         Xbar2SriFreeListCBC = 0x14 */
+ 
+       /* Errata 281 Workaround */
+       { 3, 0x7C, ( AMD_DR_B0 | AMD_DR_B1),
+        AMD_PTYPE_SVR, 0x00144514, 0x707FFF1F },
+ 
+-      { 3, 0x7C, AMD_FAM15_ALL, AMD_PTYPE_ALL,
+-        0x040d0f16, 0x07ffff1f },
++      { 3, 0x7c, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x040d0f16, 0x77ffff1f },     /* XBar2SriFreeListCBInc = 0x0,
++                                         SrqExtFreeListBC = 0x8,
++                                         Sri2XbarFreeRspDBC = 0x0,
++                                         Sri2XbarFreeXreqDBC = 0xd,
++                                         Sri2XbarFreeRspCBC = 0x0,
++                                         Sri2XbarFreeXreqCBC = 0xf,
++                                         Xbar2SriFreeListCBC = 0x16 */
+ 
+       { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x00070814, 0x007FFF1F },
+@@ -647,18 +743,16 @@ static const struct {
+         0x00004400, 0x00006400 },     /* HT_PHY_DLL_REG */
+ 
+       { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+-        0x00000000, 0x000000FF },     /* Provide clear setting for logical
+-                                         completeness */
++        0x0000005a, 0x000000ff },     /* Use common "safe" setting for K10 */
+ 
+       { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+-        0x00000000, 0x000000FF },     /* Provide clear setting for logical
+-                                         completeness */
++        0x0000005a, 0x000000ff },     /* Use common "safe" setting for K10 */
+ 
+       { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
+-        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
++        0x0000006d, 0x000000ff },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
+ 
+       { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
+-        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
++        0x0000006d, 0x000000ff },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
+ 
+       /* Link Phy Receiver Loop Filter Registers */
+       { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+@@ -681,24 +775,29 @@ static const struct {
+         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
+                                         [20:16] RttIndex = 04h */
+ 
+-/* FIXME
+- * Causes lockups for some reason when more than one package is installed
+- * Debug and reactivate!
+- */
+-// #if 0
+       { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+-        0x00000000, 0x000000FF },     /* Provide clear setting for logical
+-                                         completeness */
++        0x00000a2a, 0x000000ff },     /* P0RcvRdPtr = 0xa,
++                                         P0XmtRdPtr = 0x2
++                                         P1RcvRdPtr = 0xa
++                                         P1XmtRdPtr = 0x0 */
+ 
+       { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+-        0x00000000, 0x000000FF },     /* Provide clear setting for logical
+-                                         completeness */
++        0x00000a2a, 0x000000ff },     /* P0RcvRdPtr = 0xa,
++                                         P0XmtRdPtr = 0x2
++                                         P1RcvRdPtr = 0xa
++                                         P1XmtRdPtr = 0x0 */
+ 
+       { 0xCF, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1,
+-        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
++        0x00000d4d, 0x000000ff },     /* P0RcvRdPtr = 0xd,
++                                         P0XmtRdPtr = 0x4
++                                         P1RcvRdPtr = 0xd
++                                         P1XmtRdPtr = 0x0 */
+ 
+       { 0xDF, AMD_FAM15_ALL, AMD_PTYPE_ALL,  HTPHY_LINKTYPE_HT1,
+-        0x0000006D, 0x000000FF },     /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */
++        0x00000d4d, 0x000000ff },     /* P0RcvRdPtr = 0xd,
++                                         P0XmtRdPtr = 0x4
++                                         P1RcvRdPtr = 0xd
++                                         P1XmtRdPtr = 0x0 */
+ 
+       /* Link Phy Receiver Loop Filter Registers */
+       { 0xD1, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
+@@ -719,6 +818,5 @@ static const struct {
+ 
+       { 0xC0, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
+         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
+-                                        [20:16] RttIndex = 04h */
+-// #endif
++                                         [20:16] RttIndex = 04h */
+ };
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0091-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0091-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
deleted file mode 100644
index 82d8664..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0091-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 201dd98f77ab10c305a0a165494f3e10cc105d5d Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 2 Aug 2015 21:28:31 -0500
-Subject: [PATCH 091/139] mainboard/asus/kgpe-d16: Fix I/O link detection
-
-Change-Id: Ibefc9dc2e1e0267389eb8d716408bae6026ce084
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/romstage.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index 3504126..2b222f5 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -552,7 +552,8 @@ BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 
**List)
- {
-       /* Force BUID to 0 */
-       static const u8 swaplist[] = {0, 0, 0xFF, 0, 0xFF};
--      if ((node == 0) && (link == 1)) {       /* BSP SB link */
-+      if ((is_fam15h() && (node == 0) && (link == 1))                 /* 
Family 15h BSP SB link */
-+              || (!is_fam15h() && (node == 0) && (link == 3))) {      /* 
Family 10h BSP SB link */
-               *List = swaplist;
-               return 1;
-       }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0092-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
 
b/resources/libreboot/patch/kgpe-d16/0092-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
deleted file mode 100644
index 2f8039b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0092-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
+++ /dev/null
@@ -1,139 +0,0 @@
-From 0e421105b63947e3a3dcbf7bf970e17af4519e6c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 2 Aug 2015 21:31:17 -0500
-Subject: [PATCH 092/139] cpu/amd/family_10h-family_15h: Set northbridge
- throttle values
-
-Change-Id: I6304b63708c65fedb9c2d46b8c862b7f0adf1102
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/init_cpus.c      | 21 +------
- .../amd/family_10h-family_15h/model_10xxx_init.c   | 66 ++++++++++++++++++++++
- 2 files changed, 67 insertions(+), 20 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 2bc54dc..9aadbcf 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -877,6 +877,7 @@ static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
-               else
-                       linktype |= HTPHY_LINKTYPE_UNGANGED;
-       }
-+
-       return linktype;
- }
- 
-@@ -972,26 +973,6 @@ void cpuSetAMDMSR(uint8_t node_id)
-       }
-       AMD_Errata298();
- 
--      if (revision & AMD_FAM15_ALL) {
--              uint32_t f5x80;
--              uint8_t enabled;
--              uint8_t compute_unit_count = 0;
--              f5x80 = pci_read_config32(NODE_PCI(node_id, 5), 0x80);
--              enabled = f5x80 & 0xf;
--              if (enabled == 0x1)
--                      compute_unit_count = 1;
--              if (enabled == 0x3)
--                      compute_unit_count = 2;
--              if (enabled == 0x7)
--                      compute_unit_count = 3;
--              if (enabled == 0xf)
--                      compute_unit_count = 4;
--              msr = rdmsr(BU_CFG2);
--              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
--              msr.lo |= (((compute_unit_count - 1) & 0x3) << 6);
--              wrmsr(BU_CFG2, msr);
--      }
--
-       /* Revision C0 and above */
-       if (revision & AMD_OR_C0) {
-               uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 
0x1fc);
-diff --git a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c 
b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
-index 8a61f13..7319539 100644
---- a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
-+++ b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
-@@ -54,6 +54,28 @@ static inline uint8_t is_fam15h(void)
-       return fam15h;
- }
- 
-+static inline uint8_t is_gt_rev_d(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint8_t rev_gte_d = 0;
-+      uint32_t family;
-+      uint32_t model;
-+
-+      family = model = cpuid_eax(0x80000001);
-+      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      if ((model >= 0x8) || fam15h)
-+              /* Revision D or later */
-+              rev_gte_d = 1;
-+
-+      return rev_gte_d;
-+}
-+
- static volatile uint8_t 
fam15h_startup_flags[MAX_NODES_SUPPORTED][MAX_CORES_SUPPORTED] = {{ 0 }};
- 
- static void model_10xxx_init(device_t dev)
-@@ -136,6 +158,50 @@ static void model_10xxx_init(device_t dev)
-       printk(BIOS_DEBUG, "siblings = %02d, ", siblings);
- #endif
- 
-+      /* Set bus unit configuration */
-+      if (is_fam15h()) {
-+              uint32_t f5x80;
-+              uint8_t enabled;
-+              uint8_t compute_unit_count = 0;
-+              f5x80 = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18 + 
id.nodeid, 5)), 0x80);
-+              enabled = f5x80 & 0xf;
-+              if (enabled == 0x1)
-+                      compute_unit_count = 1;
-+              if (enabled == 0x3)
-+                      compute_unit_count = 2;
-+              if (enabled == 0x7)
-+                      compute_unit_count = 3;
-+              if (enabled == 0xf)
-+                      compute_unit_count = 4;
-+              msr = rdmsr(BU_CFG2_MSR);
-+              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
-+              msr.lo |= (((compute_unit_count - 1) & 0x3) << 6);
-+              wrmsr(BU_CFG2_MSR, msr);
-+      } else {
-+              uint32_t f0x60;
-+              uint32_t f0x160;
-+              uint8_t core_count = 0;
-+              uint8_t node_count = 0;
-+              f0x60 = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18 + 
id.nodeid, 0)), 0x60);
-+              core_count = (f0x60 >> 16) & 0x1f;
-+              node_count = ((f0x60 >> 4) & 0x7) + 1;
-+              if (is_gt_rev_d()) {
-+                      f0x160 = pci_read_config32(dev_find_slot(0, 
PCI_DEVFN(0x18 + id.nodeid, 0)), 0x160);
-+                      core_count |= ((f0x160 >> 16) & 0x7) << 5;
-+              }
-+              core_count++;
-+              core_count /= node_count;
-+              msr = rdmsr(BU_CFG2_MSR);
-+              if (is_gt_rev_d()) {
-+                      msr.hi &= ~(0x3 << (36 - 32));                  /* 
ThrottleNbInterface[3:2] */
-+                      msr.hi |= ((((core_count - 1) >> 2) & 0x3) << (36 - 
32));
-+              }
-+              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
-+              msr.lo |= (((core_count - 1) & 0x3) << 6);
-+              msr.lo &= ~(0x1 << 24);                         /* WcPlusDis = 
0 */
-+              wrmsr(BU_CFG2_MSR, msr);
-+      }
-+
-       /* Disable Cf8ExtCfg */
-       msr = rdmsr(NB_CFG_MSR);
-       msr.hi &= ~(1 << (46 - 32));
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0092-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
 
b/resources/libreboot/patch/kgpe-d16/0092-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
new file mode 100644
index 0000000..9343916
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0092-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch
@@ -0,0 +1,336 @@
+From 3971a27fdb1e98badb9a4368c241e7820ae7ba45 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 2 Aug 2015 21:23:02 -0500
+Subject: [PATCH 092/143] northbridge/amd/amdmct/mct_ddr3: Move K10D
+ configuration into separate file
+
+Change-Id: Id45888f266fac7810a63fef43b8d7a0ee40cbf70
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/raminit_amdmct.c  |    1 +
+ src/northbridge/amd/amdmct/amddefs.h           |    5 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  131 +++++++++++-------------
+ src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c |    4 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctprod.c  |   65 ++++++++++++
+ 5 files changed, 130 insertions(+), 76 deletions(-)
+ create mode 100644 src/northbridge/amd/amdmct/mct_ddr3/mctprod.c
+
+diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c 
b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+index cae228f..2cbe6b1 100644
+--- a/src/northbridge/amd/amdfam10/raminit_amdmct.c
++++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c
+@@ -379,6 +379,7 @@ static uint16_t mct_MaxLoadFreq(uint8_t count, uint8_t 
highest_rank_count, uint8
+ #include "../amdmct/mct_ddr3/mctdqs_d.c"
+ #include "../amdmct/mct_ddr3/mctsrc.c"
+ #include "../amdmct/mct_ddr3/mctsdi.c"
++#include "../amdmct/mct_ddr3/mctprod.c"
+ #include "../amdmct/mct_ddr3/mctproc.c"
+ #include "../amdmct/mct_ddr3/mctprob.c"
+ #include "../amdmct/mct_ddr3/mcthwl.c"
+diff --git a/src/northbridge/amd/amdmct/amddefs.h 
b/src/northbridge/amd/amdmct/amddefs.h
+index 7aa4698..60d3c16 100644
+--- a/src/northbridge/amd/amdmct/amddefs.h
++++ b/src/northbridge/amd/amdmct/amddefs.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -115,7 +116,7 @@
+ /*
+  * CPU HT PHY REGISTERS, FIELDS, AND MASKS
+  */
+-#define HTPHY_OFFSET_MASK             0xE00001FF
++#define HTPHY_OFFSET_MASK             0xE000FFFF
+ #define HTPHY_WRITE_CMD                       0x40000000
+ #define HTPHY_IS_COMPLETE_MASK                0x80000000
+ #define HTPHY_DIRECT_MAP              0x20000000
+@@ -164,4 +165,4 @@
+ #define AMD_PKGTYPE_S1gX 2
+ #define AMD_PKGTYPE_G34 3
+ #define AMD_PKGTYPE_ASB2 4
+-#define AMD_PKGTYPE_C32 5
+\ No newline at end of file
++#define AMD_PKGTYPE_C32 5
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index ccdd0df..1167976 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -182,6 +182,7 @@ static void SyncSetting(struct DCTStatStruc *pDCTstat);
+ static uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm);
+ static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat);
+ static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat);
++static void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat);
+ 
+ static void read_dqs_receiver_enable_control_registers(uint16_t* 
current_total_delay,
+                       uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
+@@ -2679,13 +2680,11 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
+       for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+               pDCTstat = pDCTstatA + Node;
+ 
+-              /* Configure and enable prefetchers */
+-              if (is_fam15h())
+-                      dword = 0x0ce00f41;     /* BKDG recommended */
+-              else
+-                      dword = 0x0fe40fc0;     /* BKDG recommended */
+-              dword |= MCCH_FlushWrOnStpGnt;  /* Set for S3 */
+-              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);
++              /* Enable prefetchers */
++              dword = Get_NB32(pDCTstat->dev_dct, 0x11c);     /* Memory 
Controller Configuration High */
++              dword &= ~(0x1 << 13);                          /* PrefIoDis = 
0 */
++              dword &= ~(0x1 << 12);                          /* PrefCpuDis = 
0 */
++              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);      /* Memory 
Controller Configuration High */
+       }
+ }
+ 
+@@ -4927,31 +4926,33 @@ static void Set_OtherTiming(struct MCTStatStruc 
*pMCTstat,
+       Get_TrwtTO(pMCTstat, pDCTstat, dct);
+       Get_TrwtWB(pMCTstat, pDCTstat);
+ 
+-      reg = 0x8C;             /* Dram Timing Hi */
+-      val = Get_NB32_DCT(dev, dct, reg);
+-      val &= 0xffff0300;
+-      dword = pDCTstat->TrwtTO;
+-      val |= dword << 4;
+-      dword = pDCTstat->Twrrd & 3;
+-      val |= dword << 10;
+-      dword = pDCTstat->Twrwr & 3;
+-      val |= dword << 12;
+-      dword = pDCTstat->Trdrd & 3;
+-      val |= dword << 14;
+-      dword = pDCTstat->TrwtWB;
+-      val |= dword;
+-      Set_NB32_DCT(dev, dct, reg, val);
+-
+-      reg = 0x78;
+-      val = Get_NB32_DCT(dev, dct, reg);
+-      val &= 0xFFFFC0FF;
+-      dword = pDCTstat->Twrrd >> 2;
+-      val |= dword << 8;
+-      dword = pDCTstat->Twrwr >> 2;
+-      val |= dword << 10;
+-      dword = pDCTstat->Trdrd >> 2;
+-      val |= dword << 12;
+-      Set_NB32_DCT(dev, dct, reg, val);
++      if (!is_fam15h()) {
++              reg = 0x8c;             /* Dram Timing Hi */
++              val = Get_NB32_DCT(dev, dct, reg);
++              val &= 0xffff0300;
++              dword = pDCTstat->TrwtTO;
++              val |= dword << 4;
++              dword = pDCTstat->Twrrd & 3;
++              val |= dword << 10;
++              dword = pDCTstat->Twrwr & 3;
++              val |= dword << 12;
++              dword = (pDCTstat->Trdrd - 0x3) & 3;
++              val |= dword << 14;
++              dword = pDCTstat->TrwtWB;
++              val |= dword;
++              Set_NB32_DCT(dev, dct, reg, val);
++
++              reg = 0x78;
++              val = Get_NB32_DCT(dev, dct, reg);
++              val &= 0xffffc0ff;
++              dword = pDCTstat->Twrrd >> 2;
++              val |= dword << 8;
++              dword = pDCTstat->Twrwr >> 2;
++              val |= dword << 10;
++              dword = (pDCTstat->Trdrd - 0x3) >> 2;
++              val |= dword << 12;
++              Set_NB32_DCT(dev, dct, reg, val);
++      }
+ }
+ 
+ static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+@@ -4962,6 +4963,8 @@ static void Get_Trdrd(struct MCTStatStruc *pMCTstat,
+       Trdrd = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - 
pDCTstat->DqsRcvEnGrossMin) >> 1) + 1;
+       if (Trdrd > 8)
+               Trdrd = 8;
++      if (Trdrd < 3)
++              Trdrd = 3;
+       pDCTstat->Trdrd = Trdrd;
+ }
+ 
+@@ -5272,47 +5275,31 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
+               if (pDCTstat->NodePresent) {
+                       mct_PhyController_Config(pMCTstat, pDCTstat, 0);
+                       mct_PhyController_Config(pMCTstat, pDCTstat, 1);
+-              }
+-              if (!(pDCTstat->LogicalCPUID & AMD_DR_Dx)) { /* 
mct_checkForDxSupport */
+-                      mct_ExtMCTConfig_Cx(pDCTstat);
+-                      mct_ExtMCTConfig_Bx(pDCTstat);
+-              } else {        /* For Dx CPU */
+-                      val = 0x0CE00F00 | 1 << 29/* FlushWrOnStpGnt */;
+-                      if (!(pDCTstat->GangedMode))
+-                              val |= 0x20; /* MctWrLimit =  8 for Unganged 
mode */
+-                      else
+-                              val |= 0x40; /* MctWrLimit =  16 for ganged 
mode */
+-                      Set_NB32(pDCTstat->dev_dct, 0x11C, val);
+-
+-                      val = Get_NB32(pDCTstat->dev_dct, 0x1B0);
+-                      val &= 0xFFFFF8C0;
+-                      val |= 0x101;   /* BKDG recommended settings */
+-                      val |= 0x0FC00000; /* Agesa V5 */
+-                      if (!(pDCTstat->GangedMode))
+-                              val |= 1 << 12;
+-                      else
+-                              val &= ~(1 << 12);
+ 
+-                      val &= 0x0FFFFFFF;
+                       if (!is_fam15h()) {
+-                              switch (pDCTstat->Speed) {
+-                              case 4:
+-                                      val |= 0x50000000; /* 5 for DDR800 */
+-                                      break;
+-                              case 5:
+-                                      val |= 0x60000000; /* 6 for DDR1066 */
+-                                      break;
+-                              case 6:
+-                                      val |= 0x80000000; /* 8 for DDR800 */
+-                                      break;
+-                              default:
+-                                      val |= 0x90000000; /* 9 for DDR1600 */
+-                                      break;
+-                              }
+-                      }
+-                      Set_NB32(pDCTstat->dev_dct, 0x1B0, val);
++                              /* Family 10h CPUs */
++                              mct_ExtMCTConfig_Cx(pDCTstat);
++                              mct_ExtMCTConfig_Bx(pDCTstat);
++                              mct_ExtMCTConfig_Dx(pDCTstat);
++                      } else {
++                              /* Family 15h CPUs */
++                              val = 0x0ce00f00 | 0x1 << 29;   /* 
FlushWrOnStpGnt */
++                              val |= 0x10 << 2;               /* MctWrLimit = 
16 */
++                              Set_NB32(pDCTstat->dev_dct, 0x11c, val);
++
++                              val = Get_NB32(pDCTstat->dev_dct, 0x1b0);
++                              val &= ~0x3;                    /* 
AdapPrefMissRatio = 0x1 */
++                              val |= 0x1;
++                              val &= ~(0x3 << 2);             /* 
AdapPrefPositiveStep = 0x0 */
++                              val &= ~(0x3 << 4);             /* 
AdapPrefNegativeStep = 0x0 */
++                              val &= ~(0x7 << 8);             /* 
CohPrefPrbLmt = 0x1 */
++                              val |= (0x1 << 8);
++                              val |= (0x1 << 12);             /* 
EnSplitDctLimits = 0x1 */
++                              val |= (0x7 << 22);             /* PrefFourConf 
= 0x7 */
++                              val |= (0x7 << 25);             /* PrefFiveConf 
= 0x7 */
++                              val &= ~(0xf << 28);            /* DcqBwThrotWm 
= 0x0 */
++                              Set_NB32(pDCTstat->dev_dct, 0x1b0, val);
+ 
+-                      if (is_fam15h()) {
+                               uint8_t wm1;
+                               uint8_t wm2;
+ 
+@@ -5343,11 +5330,11 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
+                                       break;
+                               }
+ 
+-                              val = Get_NB32(pDCTstat->dev_dct, 0x1B4);
++                              val = Get_NB32(pDCTstat->dev_dct, 0x1b4);
+                               val &= ~(0x3ff);
+                               val |= ((wm2 & 0x1f) << 5);
+                               val |= (wm1 & 0x1f);
+-                              Set_NB32(pDCTstat->dev_dct, 0x1B4, val);
++                              Set_NB32(pDCTstat->dev_dct, 0x1b4, val);
+                       }
+               }
+       }
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
+index a1cdfa6..41f0946 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
+@@ -102,7 +102,7 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+               BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask);
+ 
+               for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) {
+-                      reg = 0x40+(ChipSel<<2);        /*Dram CS Base 0 */
++                      reg = 0x40 + (ChipSel<<2);      /* Dram CS Base 0 */
+                       val = Get_NB32_DCT(dev, dct, reg);
+                       if (val & 3) {
+                               val_lo = val & AddrLoMask;
+@@ -118,7 +118,7 @@ void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
+                               if(ChipSel & 1)
+                                       continue;
+ 
+-                              reg = 0x60 + ((ChipSel>>1)<<2); /*Dram CS Mask 
0 */
++                              reg = 0x60 + ((ChipSel>>1)<<2); /* Dram CS Mask 
0 */
+                               val = Get_NB32_DCT(dev, dct, reg);
+                               val_lo = val & AddrLoMask;
+                               val_hi = val & AddrHiMask;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctprod.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctprod.c
+new file mode 100644
+index 0000000..2b62d4c
+--- /dev/null
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctprod.c
+@@ -0,0 +1,65 @@
++/*
++ * This file is part of the coreboot project.
++ *
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
++ * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc.
++ */
++
++void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat)
++{
++      uint32_t dword;
++
++      if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
++              dword = 0x0ce00f00 | 0x1 << 29; /* FlushWrOnStpGnt */
++              if (!(pDCTstat->GangedMode))
++                      dword |= 0x18 << 2;     /* MctWrLimit = 0x18 for 
unganged mode */
++              else
++                      dword |= 0x10 << 2;     /* MctWrLimit = 0x10 for ganged 
mode */
++              Set_NB32(pDCTstat->dev_dct, 0x11c, dword);
++
++              dword = Get_NB32(pDCTstat->dev_dct, 0x1b0);
++              dword &= ~0x3;                  /* AdapPrefMissRatio = 0x1 */
++              dword |= 0x1;
++              dword &= ~(0x3 << 2);           /* AdapPrefPositiveStep = 0x0 */
++              dword &= ~(0x3 << 4);           /* AdapPrefNegativeStep = 0x0 */
++              dword &= ~(0x7 << 8);           /* CohPrefPrbLmt = 0x1 */
++              dword |= (0x1 << 8);
++              dword |= (0x7 << 22);           /* PrefFourConf = 0x7 */
++              dword |= (0x7 << 25);           /* PrefFiveConf = 0x7 */
++
++              if (!(pDCTstat->GangedMode))
++                      dword |= (0x1 << 12);   /* EnSplitDctLimits = 0x1 */
++              else
++                      dword &= ~(0x1 << 12);  /* EnSplitDctLimits = 0x0 */
++
++              dword &= ~(0xf << 28);          /* DcqBwThrotWm = ... */
++              switch (pDCTstat->Speed) {
++              case 4:
++                      dword |= (0x5 << 28);   /* ...5 for DDR800 */
++                      break;
++              case 5:
++                      dword |= (0x6 << 28);   /* ...6 for DDR1066 */
++                      break;
++              case 6:
++                      dword |= (0x8 << 28);   /* ...8 for DDR800 */
++                      break;
++              default:
++                      dword |= (0x9 << 28);   /* ...9 for DDR1600 */
++                      break;
++              }
++              Set_NB32(pDCTstat->dev_dct, 0x1b0, dword);
++      }
++}
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0093-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
 
b/resources/libreboot/patch/kgpe-d16/0093-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
deleted file mode 100644
index b446e30..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0093-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
+++ /dev/null
@@ -1,64 +0,0 @@
-From a50e4e220003702aaa83f8b852aa819975e07788 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 2 Aug 2015 21:31:48 -0500
-Subject: [PATCH 093/139] cpu/amd/family_10h-family_15h: Fix incorrect revision
- detection
-
-Change-Id: I7a881a94d62ed455415f9dfc887fd698ac919429
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/fidvid.c | 10 +++++-----
- 1 file changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
-index 471456a..ed8cafa 100644
---- a/src/cpu/amd/family_10h-family_15h/fidvid.c
-+++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
-@@ -375,7 +375,7 @@ static void recalculateVsSlamTimeSettingOnCorePre(device_t 
dev)
-       pci_write_config32(dev, 0xd8, dtemp);
- }
- 
--static u32 nb_clk_did(int node, u32 cpuRev,u8 procPkg) {
-+static u32 nb_clk_did(int node, uint64_t cpuRev, uint8_t procPkg) {
-         u8 link0isGen3 = 0;
-         u8 offset;
-         if (AMD_CpuFindCapability(node, 0, &offset)) {
-@@ -446,7 +446,7 @@ static u32 power_up_down(int node, u8 procPkg) {
-         return dword;
- }
- 
--static void config_clk_power_ctrl_reg0(int node, u32 cpuRev, u8 procPkg) {
-+static void config_clk_power_ctrl_reg0(int node, uint64_t cpuRev, uint8_t 
procPkg) {
-               device_t dev = NODE_PCI(node, 3);
- 
-       /* Program fields in Clock Power/Control register0 (F3xD4) */
-@@ -471,7 +471,7 @@ static void config_clk_power_ctrl_reg0(int node, u32 
cpuRev, u8 procPkg) {
- 
- }
- 
--static void config_power_ctrl_misc_reg(device_t dev,u32 cpuRev, u8 procPkg) {
-+static void config_power_ctrl_misc_reg(device_t dev, uint64_t cpuRev, uint8_t 
procPkg) {
-       /* check PVI/SVI */
-       u32 dword = pci_read_config32(dev, 0xa0);
- 
-@@ -504,7 +504,7 @@ static void config_power_ctrl_misc_reg(device_t dev,u32 
cpuRev, u8 procPkg) {
-       pci_write_config32(dev, 0xa0, dword);
- }
- 
--static void config_nb_syn_ptr_adj(device_t dev, u32 cpuRev) {
-+static void config_nb_syn_ptr_adj(device_t dev, uint64_t cpuRev) {
-       /* Note the following settings are additional from the ported
-        * function setFidVidRegs()
-        */
-@@ -526,7 +526,7 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 
cpuRev) {
-       pci_write_config32(dev, 0xdc, dword);
- }
- 
--static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 
procPkg) {
-+static void config_acpi_pwr_state_ctrl_regs(device_t dev, uint64_t cpuRev, 
uint8_t procPkg) {
-       if (is_fam15h()) {
-               /* Family 15h BKDG Rev. 3.14 D18F3x80 recommended settings */
-               pci_write_config32(dev, 0x80, 0xe20be281);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0093-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
 
b/resources/libreboot/patch/kgpe-d16/0093-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
new file mode 100644
index 0000000..9c9ae8f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0093-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch
@@ -0,0 +1,28 @@
+From 0f5bc1acfc0274968095f9fc7c68299632788f1d Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 2 Aug 2015 21:28:31 -0500
+Subject: [PATCH 093/143] mainboard/asus/kgpe-d16: Fix I/O link detection
+
+Change-Id: Ibefc9dc2e1e0267389eb8d716408bae6026ce084
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/romstage.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index f80fb8c..5d4005d 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -552,7 +552,8 @@ BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 
**List)
+ {
+       /* Force BUID to 0 */
+       static const u8 swaplist[] = {0, 0, 0xFF, 0, 0xFF};
+-      if ((node == 0) && (link == 1)) {       /* BSP SB link */
++      if ((is_fam15h() && (node == 0) && (link == 1))                 /* 
Family 15h BSP SB link */
++              || (!is_fam15h() && (node == 0) && (link == 3))) {      /* 
Family 10h BSP SB link */
+               *List = swaplist;
+               return 1;
+       }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0094-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
 
b/resources/libreboot/patch/kgpe-d16/0094-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
new file mode 100644
index 0000000..ac80918
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0094-cpu-amd-family_10h-family_15h-Set-northbridge-thrott.patch
@@ -0,0 +1,110 @@
+From 518f3db1ecce1fe883074b133eb19e3575098f3a Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 2 Aug 2015 21:31:17 -0500
+Subject: [PATCH 094/143] cpu/amd/family_10h-family_15h: Set northbridge
+ throttle values
+
+Change-Id: I6304b63708c65fedb9c2d46b8c862b7f0adf1102
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c      |   21 +---------
+ .../amd/family_10h-family_15h/model_10xxx_init.c   |   44 ++++++++++++++++++++
+ 2 files changed, 45 insertions(+), 20 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index 7d303e0..d770f38 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -877,6 +877,7 @@ static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
+               else
+                       linktype |= HTPHY_LINKTYPE_UNGANGED;
+       }
++
+       return linktype;
+ }
+ 
+@@ -971,26 +972,6 @@ void cpuSetAMDMSR(uint8_t node_id)
+       }
+       AMD_Errata298();
+ 
+-      if (revision & AMD_FAM15_ALL) {
+-              uint32_t f5x80;
+-              uint8_t enabled;
+-              uint8_t compute_unit_count = 0;
+-              f5x80 = pci_read_config32(NODE_PCI(node_id, 5), 0x80);
+-              enabled = f5x80 & 0xf;
+-              if (enabled == 0x1)
+-                      compute_unit_count = 1;
+-              if (enabled == 0x3)
+-                      compute_unit_count = 2;
+-              if (enabled == 0x7)
+-                      compute_unit_count = 3;
+-              if (enabled == 0xf)
+-                      compute_unit_count = 4;
+-              msr = rdmsr(BU_CFG2);
+-              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
+-              msr.lo |= (((compute_unit_count - 1) & 0x3) << 6);
+-              wrmsr(BU_CFG2, msr);
+-      }
+-
+       /* Revision C0 and above */
+       if (revision & AMD_OR_C0) {
+               uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 
0x1fc);
+diff --git a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c 
b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
+index 5c590b8..7319539 100644
+--- a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
++++ b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c
+@@ -158,6 +158,50 @@ static void model_10xxx_init(device_t dev)
+       printk(BIOS_DEBUG, "siblings = %02d, ", siblings);
+ #endif
+ 
++      /* Set bus unit configuration */
++      if (is_fam15h()) {
++              uint32_t f5x80;
++              uint8_t enabled;
++              uint8_t compute_unit_count = 0;
++              f5x80 = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18 + 
id.nodeid, 5)), 0x80);
++              enabled = f5x80 & 0xf;
++              if (enabled == 0x1)
++                      compute_unit_count = 1;
++              if (enabled == 0x3)
++                      compute_unit_count = 2;
++              if (enabled == 0x7)
++                      compute_unit_count = 3;
++              if (enabled == 0xf)
++                      compute_unit_count = 4;
++              msr = rdmsr(BU_CFG2_MSR);
++              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
++              msr.lo |= (((compute_unit_count - 1) & 0x3) << 6);
++              wrmsr(BU_CFG2_MSR, msr);
++      } else {
++              uint32_t f0x60;
++              uint32_t f0x160;
++              uint8_t core_count = 0;
++              uint8_t node_count = 0;
++              f0x60 = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18 + 
id.nodeid, 0)), 0x60);
++              core_count = (f0x60 >> 16) & 0x1f;
++              node_count = ((f0x60 >> 4) & 0x7) + 1;
++              if (is_gt_rev_d()) {
++                      f0x160 = pci_read_config32(dev_find_slot(0, 
PCI_DEVFN(0x18 + id.nodeid, 0)), 0x160);
++                      core_count |= ((f0x160 >> 16) & 0x7) << 5;
++              }
++              core_count++;
++              core_count /= node_count;
++              msr = rdmsr(BU_CFG2_MSR);
++              if (is_gt_rev_d()) {
++                      msr.hi &= ~(0x3 << (36 - 32));                  /* 
ThrottleNbInterface[3:2] */
++                      msr.hi |= ((((core_count - 1) >> 2) & 0x3) << (36 - 
32));
++              }
++              msr.lo &= ~(0x3 << 6);                          /* 
ThrottleNbInterface[1:0] */
++              msr.lo |= (((core_count - 1) & 0x3) << 6);
++              msr.lo &= ~(0x1 << 24);                         /* WcPlusDis = 
0 */
++              wrmsr(BU_CFG2_MSR, msr);
++      }
++
+       /* Disable Cf8ExtCfg */
+       msr = rdmsr(NB_CFG_MSR);
+       msr.hi &= ~(1 << (46 - 32));
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0094-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
 
b/resources/libreboot/patch/kgpe-d16/0094-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
deleted file mode 100644
index 55957a1..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0094-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
+++ /dev/null
@@ -1,561 +0,0 @@
-From 60d2c9d712e8d53b871961ca50d1a9d06a65051f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 2 Aug 2015 21:36:24 -0500
-Subject: [PATCH 094/139] northbridge/amd/amdht: Add support for HT3 2.8GHz and
- up link frequencies
-
-Change-Id: Ifa1592d26ba7deb034046fd3f2a15149117d9a76
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h |   8 ++-
- src/mainboard/asus/kgpe-d16/cmos.layout      |  30 ++++----
- src/northbridge/amd/amdht/h3ffeat.h          |   6 +-
- src/northbridge/amd/amdht/h3finit.c          |  93 ++++++++++++++----------
- src/northbridge/amd/amdht/h3finit.h          |  18 +++--
- src/northbridge/amd/amdht/h3ncmn.c           | 104 ++++++++++++++++++++-------
- src/northbridge/amd/amdht/h3ncmn.h           |   3 +-
- 7 files changed, 177 insertions(+), 85 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index 1080cfc..bff2efd 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -290,7 +290,13 @@ static const struct {
- 
-       /* Link Global Retry Control Register */
-       { 0, 0x150, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
--        0x00073900, 0x00073F00 },
-+        0x00073900, 0x00073f70 },     /* TotalRetryAttempts = 0x7,
-+                                         HtRetryCrcDatInsDynEn = 0x1,
-+                                         HtRetryCrcCmdPackDynEn = 0x1,
-+                                         HtRetryCrcDatIns = 0x4,
-+                                         HtRetryCrcCmdPack = 0x1,
-+                                         ForceErrType = 0x0,
-+                                         MultRetryErr = 0x0 */
- 
-       /*  Errata 351
-        * System software should program the Link Extended Control 
Registers[LS2En]
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index f705af2..ec803b6 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -125,21 +125,21 @@ enumerations
- 10    21    42ms
- 10    22    84ms
- 11    0     Auto
--11    1     2.6GHz
--11    2     2.4GHz
--11    3     2.2GHz
--11    4     2.0GHz
--11    5     1.8GHz
--11    6     1.6GHz
--11    7     1.4GHz
--11    8     1.2GHz
--11    9     1.0GHz
--11    10    800MHz
--11    11    600MHz
--11    12    500MHz
--11    13    400MHz
--11    14    300MHz
--11    15    200MHz
-+11    1     3.2GHz
-+11    2     3.0GHz
-+11    3     2.8GHz
-+11    4     2.6GHz
-+11    5     2.4GHz
-+11    6     2.2GHz
-+11    7     2.0GHz
-+11    8     1.8GHz
-+11    9     1.6GHz
-+11    10    1.4GHz
-+11    11    1.2GHz
-+11    12    1.0GHz
-+11    13    800MHz
-+11    14    600MHz
-+11    15    500MHz
- 12    0     1.5V
- 12    1     1.35V
- 12    2     1.25V
-diff --git a/src/northbridge/amd/amdht/h3ffeat.h 
b/src/northbridge/amd/amdht/h3ffeat.h
-index 5d9550b..5dc9916 100644
---- a/src/northbridge/amd/amdht/h3ffeat.h
-+++ b/src/northbridge/amd/amdht/h3ffeat.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -62,6 +63,7 @@
- #define HTHOST_LINK_CAPABILITY_REG            0x00
- #define HTHOST_LINK_CONTROL_REG               0x04
- #define HTHOST_FREQ_REV_REG                   0x08
-+#define HTHOST_FREQ_REV_REG_2                 0x1c
-       #define HT_HOST_REV_REV3                0x60
- #define HTHOST_FEATURE_CAP_REG                        0x0C
- #define HTHOST_BUFFER_COUNT_REG               0x10
-@@ -127,10 +129,10 @@ typedef struct
- 
-       /* This section is for keeping track of capabilities and possible 
configurations */
-       BOOL RegangCap;
--      u16 PrvFrequencyCap;
-+      uint32_t PrvFrequencyCap;
-       u8 PrvWidthInCap;
-       u8 PrvWidthOutCap;
--      u16 CompositeFrequencyCap;
-+      uint32_t CompositeFrequencyCap;
- 
- } sPortDescriptor;
- 
-diff --git a/src/northbridge/amd/amdht/h3finit.c 
b/src/northbridge/amd/amdht/h3finit.c
-index 82bf885..14f348f 100644
---- a/src/northbridge/amd/amdht/h3finit.c
-+++ b/src/northbridge/amd/amdht/h3finit.c
-@@ -52,28 +52,32 @@
- #define APIC_Base_BSP 8
- #define APIC_Base     0x1b
- 
--#define NVRAM_LIMIT_HT_SPEED_200  0xf
--#define NVRAM_LIMIT_HT_SPEED_300  0xe
--#define NVRAM_LIMIT_HT_SPEED_400  0xd
--#define NVRAM_LIMIT_HT_SPEED_500  0xc
--#define NVRAM_LIMIT_HT_SPEED_600  0xb
--#define NVRAM_LIMIT_HT_SPEED_800  0xa
--#define NVRAM_LIMIT_HT_SPEED_1000 0x9
--#define NVRAM_LIMIT_HT_SPEED_1200 0x8
--#define NVRAM_LIMIT_HT_SPEED_1400 0x7
--#define NVRAM_LIMIT_HT_SPEED_1600 0x6
--#define NVRAM_LIMIT_HT_SPEED_1800 0x5
--#define NVRAM_LIMIT_HT_SPEED_2000 0x4
--#define NVRAM_LIMIT_HT_SPEED_2200 0x3
--#define NVRAM_LIMIT_HT_SPEED_2400 0x2
--#define NVRAM_LIMIT_HT_SPEED_2600 0x1
-+#define NVRAM_LIMIT_HT_SPEED_200  0x12
-+#define NVRAM_LIMIT_HT_SPEED_300  0x11
-+#define NVRAM_LIMIT_HT_SPEED_400  0x10
-+#define NVRAM_LIMIT_HT_SPEED_500  0xf
-+#define NVRAM_LIMIT_HT_SPEED_600  0xe
-+#define NVRAM_LIMIT_HT_SPEED_800  0xd
-+#define NVRAM_LIMIT_HT_SPEED_1000 0xc
-+#define NVRAM_LIMIT_HT_SPEED_1200 0xb
-+#define NVRAM_LIMIT_HT_SPEED_1400 0xa
-+#define NVRAM_LIMIT_HT_SPEED_1600 0x9
-+#define NVRAM_LIMIT_HT_SPEED_1800 0x8
-+#define NVRAM_LIMIT_HT_SPEED_2000 0x7
-+#define NVRAM_LIMIT_HT_SPEED_2200 0x6
-+#define NVRAM_LIMIT_HT_SPEED_2400 0x5
-+#define NVRAM_LIMIT_HT_SPEED_2600 0x4
-+#define NVRAM_LIMIT_HT_SPEED_2800 0x3
-+#define NVRAM_LIMIT_HT_SPEED_3000 0x2
-+#define NVRAM_LIMIT_HT_SPEED_3200 0x1
- #define NVRAM_LIMIT_HT_SPEED_AUTO 0x0
- 
--static const uint16_t ht_speed_limit[16] =
--      {0xFFFF, 0x7FFF, 0x3FFF, 0x1FFF,
--       0x0FFF, 0x07FF, 0x03FF, 0x01FF,
--       0x00FF, 0x007F, 0x003F, 0x001F,
--       0x000F, 0x0007, 0x0003, 0x0001};
-+static const uint32_t ht_speed_limit[20] =
-+      {0xFFFFF, 0xFFFFF, 0x7FFFF, 0x3FFFF,
-+       0x0FFFF, 0x07FFF, 0x03FFF, 0x01FFF,
-+       0x00FFF, 0x007FF, 0x003FF, 0x001FF,
-+       0x000FF, 0x0007F, 0x0003F, 0x0001F,
-+       0x0000F, 0x00007, 0x00003, 0x00001};
- 
- static const struct ht_speed_limit_map_t {
-       uint16_t mhz;
-@@ -95,9 +99,12 @@ static const struct ht_speed_limit_map_t {
-       {2200, NVRAM_LIMIT_HT_SPEED_2200},
-       {2400, NVRAM_LIMIT_HT_SPEED_2400},
-       {2600, NVRAM_LIMIT_HT_SPEED_2600},
-+      {2800, NVRAM_LIMIT_HT_SPEED_2800},
-+      {3000, NVRAM_LIMIT_HT_SPEED_3000},
-+      {3200, NVRAM_LIMIT_HT_SPEED_3200},
- };
- 
--static const uint16_t ht_speed_mhz_to_hw(uint16_t mhz)
-+static const uint32_t ht_speed_mhz_to_hw(uint16_t mhz)
- {
-       size_t i;
-       for (i = 0; i < ARRAY_SIZE(ht_speed_limit_map); i++)
-@@ -456,7 +463,7 @@ static void htDiscoveryFloodFill(sMainData *pDat)
-               /* Set currentNode's NodeID field to currentNode */
-               pDat->nb->writeNodeID(currentNode, currentNode, pDat->nb);
- 
--              /* Enable routing tables on currentNode*/
-+              /* Enable routing tables on currentNode */
-               pDat->nb->enableRoutingTables(currentNode, pDat->nb);
- 
-               for (currentLinkID = 0; currentLinkID < pDat->nb->maxLinks; 
currentLinkID++)
-@@ -1431,19 +1438,30 @@ static void regangLinks(sMainData *pDat)
- static void selectOptimalWidthAndFrequency(sMainData *pDat)
- {
-       u8 i, j;
--      u32 temp;
--      u16 cbPCBFreqLimit;
--      u16 cbPCBFreqLimit_NVRAM;
-+      uint32_t temp;
-+      uint32_t cbPCBFreqLimit;
-+      uint32_t cbPCBFreqLimit_NVRAM;
-       u8 cbPCBABDownstreamWidth;
-       u8 cbPCBBAUpstreamWidth;
- 
--      cbPCBFreqLimit_NVRAM = 0xFFFF;
-+      cbPCBFreqLimit_NVRAM = 0xfffff;
-       if (get_option(&temp, "hypertransport_speed_limit") == CB_SUCCESS)
-               cbPCBFreqLimit_NVRAM = ht_speed_limit[temp & 0xf];
- 
-+      if (!is_fam15h()) {
-+              /* FIXME
-+               * By default limit frequency to 2.6 GHz as there are residual
-+               * problems with HT v3.1 implementation on at least some Socket 
G34
-+               * mainboards / Fam10h CPUs.
-+               * Debug the issues and reenable this...
-+               */
-+              if (cbPCBFreqLimit_NVRAM > 0xffff)
-+                      cbPCBFreqLimit_NVRAM = 0xffff;
-+      }
-+
-       for (i = 0; i < pDat->TotalLinks*2; i += 2)
-       {
--              cbPCBFreqLimit = 0xFFFF;                // Maximum allowed by 
autoconfiguration
-+              cbPCBFreqLimit = 0xfffff;               // Maximum allowed by 
autoconfiguration
-               if (pDat->HtBlock->ht_link_configuration)
-                       cbPCBFreqLimit = 
ht_speed_mhz_to_hw(pDat->HtBlock->ht_link_configuration->ht_speed_limit);
-               cbPCBFreqLimit = min(cbPCBFreqLimit, cbPCBFreqLimit_NVRAM);
-@@ -1488,17 +1506,18 @@ static void selectOptimalWidthAndFrequency(sMainData 
*pDat)
-                       }
-               }
- 
--
-               temp = pDat->PortList[i].PrvFrequencyCap;
-               temp &= pDat->PortList[i+1].PrvFrequencyCap;
-               temp &= cbPCBFreqLimit;
--              pDat->PortList[i].CompositeFrequencyCap = (u16)temp;
--              pDat->PortList[i+1].CompositeFrequencyCap = (u16)temp;
-+              pDat->PortList[i].CompositeFrequencyCap = temp;
-+              pDat->PortList[i+1].CompositeFrequencyCap = temp;
- 
-               ASSERT (temp != 0);
--              for (j = 15; ; j--)
-+              for (j = 19; ; j--)
-               {
--                      if (temp & ((u32)1 << j))
-+                      if ((j == 16) || (j == 15))
-+                              continue;
-+                      if (temp & ((uint32_t)1 << j))
-                               break;
-               }
- 
-@@ -1642,12 +1661,14 @@ static void hammerSublinkFixup(sMainData *pDat)
-                                       /*  Remove hiFreq from the list of 
valid frequencies */
-                                       temp = temp & ~((uint32)1 << hiFreq);
-                                       ASSERT (temp != 0);
--                                      
pDat->PortList[hiIndex].CompositeFrequencyCap = (uint16)temp;
--                                      
pDat->PortList[hiIndex+1].CompositeFrequencyCap = (uint16)temp;
-+                                      
pDat->PortList[hiIndex].CompositeFrequencyCap = temp;
-+                                      
pDat->PortList[hiIndex+1].CompositeFrequencyCap = temp;
- 
--                                      for (k = 15; ; k--)
-+                                      for (k = 19; ; k--)
-                                       {
--                                              if (temp & ((u32)1 << k))
-+                                              if ((j == 16) || (j == 15))
-+                                                      continue;
-+                                              if (temp & ((uint32_t)1 << k))
-                                                       break;
-                                       }
- 
-diff --git a/src/northbridge/amd/amdht/h3finit.h 
b/src/northbridge/amd/amdht/h3finit.h
-index 58065b3..462f3e3 100644
---- a/src/northbridge/amd/amdht/h3finit.h
-+++ b/src/northbridge/amd/amdht/h3finit.h
-@@ -53,6 +53,9 @@
- #define HT_FREQUENCY_2200M    12
- #define HT_FREQUENCY_2400M    13
- #define HT_FREQUENCY_2600M    14
-+#define HT_FREQUENCY_2800M    17
-+#define HT_FREQUENCY_3000M    18
-+#define HT_FREQUENCY_3200M    19
- 
- /* Frequency Limit equates for call backs which take a frequency supported 
mask. */
- #define HT_FREQUENCY_LIMIT_200M       1
-@@ -69,6 +72,9 @@
- #define HT_FREQUENCY_LIMIT_2200M      0x1FFF
- #define HT_FREQUENCY_LIMIT_2400M      0x3FFF
- #define HT_FREQUENCY_LIMIT_2600M      0x7FFF
-+#define HT_FREQUENCY_LIMIT_2800M      0x3FFFF
-+#define HT_FREQUENCY_LIMIT_3000M      0x7FFFF
-+#define HT_FREQUENCY_LIMIT_3200M      0xFFFFF
- 
- /*
-  * Event Notify definitions
-@@ -224,7 +230,7 @@ typedef struct {
-        *      @param[in]  u8  Link      = The Device's link number (0 or 1)
-        *      @param[in,out] u8*  LinkWidthIn  = modify to change the Link 
Witdh In
-        *      @param[in,out] u8*  LinkWidthOut  = modify to change the Link 
Witdh Out
--       *      @param[in,out] u16* FreqCap = modify to change the link's 
frequency capability
-+       *      @param[in,out] u32* FreqCap = modify to change the link's 
frequency capability
-        *
-        * 
---------------------------------------------------------------------------------------
-        */
-@@ -239,7 +245,7 @@ typedef struct {
-               u8 Link,
-               u8 *LinkWidthIn,
-               u8 *LinkWidthOut,
--              u16 *FreqCap
-+              u32 *FreqCap
-       );
- 
-       
/**----------------------------------------------------------------------------------------
-@@ -262,7 +268,7 @@ typedef struct {
-        *      @param[in]  u8  linkB  = The link on that node
-        *      @param[in,out]  u8*  ABLinkWidthLimit = modify to change the 
Link Witdh In
-        *      @param[in,out]  u8*  BALinkWidthLimit = modify to change the 
Link Witdh Out
--       *      @param[in,out]  u16* PCBFreqCap  = modify to change the link's 
frequency capability
-+       *      @param[in,out]  u32* PCBFreqCap  = modify to change the link's 
frequency capability
-        *
-        * 
---------------------------------------------------------------------------------------
-        */
-@@ -273,7 +279,7 @@ typedef struct {
-               u8 LinkB,
-               u8 *ABLinkWidthLimit,
-               u8 *BALinkWidthLimit,
--              u16 *PCBFreqCap
-+              u32 *PCBFreqCap
-       );
- 
-       
/**----------------------------------------------------------------------------------------
-@@ -295,7 +301,7 @@ typedef struct {
-        *      @param[in]  u8  Depth  = The depth in the I/O chain from the 
Host
-        *      @param[in,out]  u8* DownstreamLinkWidthLimit = modify to change 
the Link Witdh In
-        *      @param[in,out]  u8* UpstreamLinkWidthLimit  = modify to change 
the Link Witdh Out
--       *      @param[in,out]  u16* PCBFreqCap = modify to change the link's 
frequency capability
-+       *      @param[in,out]  u32* PCBFreqCap = modify to change the link's 
frequency capability
-        *
-        * 
---------------------------------------------------------------------------------------
-        */
-@@ -305,7 +311,7 @@ typedef struct {
-               u8 Depth,
-               u8 *DownstreamLinkWidthLimit,
-               u8 *UpstreamLinkWidthLimit,
--              u16 *PCBFreqCap
-+              u32 *PCBFreqCap
-       );
- 
-       
/**----------------------------------------------------------------------------------------
-diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
-index 1026d0e..e03e5eb 100644
---- a/src/northbridge/amd/amdht/h3ncmn.c
-+++ b/src/northbridge/amd/amdht/h3ncmn.c
-@@ -107,6 +107,28 @@ static inline uint8_t is_fam15h(void)
-       return fam15h;
- }
- 
-+static inline uint8_t is_gt_rev_d(void)
-+{
-+      uint8_t fam15h = 0;
-+      uint8_t rev_gte_d = 0;
-+      uint32_t family;
-+      uint32_t model;
-+
-+      family = model = cpuid_eax(0x80000001);
-+      model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
-+      family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-+
-+      if (family >= 0x6f)
-+              /* Family 15h or later */
-+              fam15h = 1;
-+
-+      if ((model >= 0x8) || fam15h)
-+              /* Revision D or later */
-+              rev_gte_d = 1;
-+
-+      return rev_gte_d;
-+}
-+
- 
/***************************************************************************//**
-  *
-  * SBDFO
-@@ -1292,7 +1314,7 @@ static u8 convertWidthToBits(u8 value, cNorthBridge *nb)
-  *    @return  Frequency mask
-  *
-  
******************************************************************************/
--static u16 ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
-+static uint32_t ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
- {
-       /* only up to HT1 speeds */
-       return (HT_FREQUENCY_LIMIT_HT1_ONLY);
-@@ -1313,26 +1335,43 @@ static u16 ht1NorthBridgeFreqMask(u8 node, 
cNorthBridge *nb)
-  *    @return  = Frequency mask
-  *
-  
******************************************************************************/
--static u16 fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
-+static uint32_t fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
- {
-       u8 nbCOF;
--      u16 supported;
-+      uint32_t supported;
- 
-       nbCOF = getMinNbCOF();
-       /*
-        * nbCOF is minimum northbridge speed in hundreds of MHz.
-        * HT can not go faster than the minimum speed of the northbridge.
-        */
--      if ((nbCOF >= 6) && (nbCOF <= 26))
-+      if ((nbCOF >= 6) && (nbCOF < 10))
-       {
-+              /* Generation 1 HT link frequency */
-               /* Convert frequency to bit and all less significant bits,
-                * by setting next power of 2 and subtracting 1.
-                */
--              supported = ((u16)1 << ((nbCOF >> 1) + 2)) - 1;
-+              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
-       }
--      else if (nbCOF > 26)
-+      else if ((nbCOF >= 10) && (nbCOF <= 32))
-       {
--              supported = HT_FREQUENCY_LIMIT_2600M;
-+              /* Generation 3 HT link frequency
-+               * Assume error retry is enabled on all Gen 3 links
-+               */
-+              if (is_gt_rev_d()) {
-+                      nbCOF *= 2;
-+                      if (nbCOF > 32)
-+                              nbCOF = 32;
-+              }
-+
-+              /* Convert frequency to bit and all less significant bits,
-+               * by setting next power of 2 and subtracting 1.
-+               */
-+              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
-+      }
-+      else if (nbCOF > 32)
-+      {
-+              supported = HT_FREQUENCY_LIMIT_3200M;
-       }
-       /* unlikely cases, but include as a defensive measure, also avoid trick 
above */
-       else if (nbCOF == 4)
-@@ -1387,8 +1426,13 @@ static void gatherLinkData(sMainData *pDat, 
cNorthBridge *nb)
-                       pDat->PortList[i].PrvWidthInCap = 
convertBitsToWidth((u8)temp, pDat->nb);
- 
-                       AmdPCIReadBits(linkBase + HTHOST_FREQ_REV_REG, 31, 16, 
&temp);
--                      pDat->PortList[i].PrvFrequencyCap = (u16)temp & 0x7FFF
--                              & 
nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb); /*  Mask off bit 
15, reserved value */
-+                      pDat->PortList[i].PrvFrequencyCap = temp & 0x7FFF       
/*  Mask off bit 15, reserved value */
-+                              & 
nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb);
-+                      if (is_gt_rev_d()) {
-+                              AmdPCIReadBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 15, 1, &temp);
-+                              temp &= 0x7;    /* Mask off reserved values */
-+                              pDat->PortList[i].PrvFrequencyCap |= (temp << 
17);
-+                      }
-               }
-               else
-               {
-@@ -1445,7 +1489,7 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
- {
-       u8 i;
-       SBDFO linkBase;
--      u32 temp, widthin, widthout, bits;
-+      u32 temp, temp2, frequency_index, widthin, widthout, bits;
- 
-       for (i = 0; i < pDat->TotalLinks*2; i++)
-       {
-@@ -1506,10 +1550,19 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
-               temp = pDat->PortList[i].SelFrequency;
-               if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
-               {
--                      ASSERT((temp >= HT_FREQUENCY_600M && temp <= 
HT_FREQUENCY_2600M)
-+                      ASSERT((temp >= HT_FREQUENCY_600M && temp <= 
HT_FREQUENCY_3200M)
-                               || (temp == HT_FREQUENCY_200M) || (temp == 
HT_FREQUENCY_400M));
-+                      frequency_index = temp;
-+                      if (temp > 0xf) {
-+                              temp2 = (temp >> 4) & 0x1;
-+                              temp &= 0xf;
-+                      } else {
-+                              temp2 = 0x0;
-+                      }
-+                      if (is_gt_rev_d())
-+                              AmdPCIWriteBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 0, 0, &temp2);
-                       AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, 
&temp);
--                      if (temp > HT_FREQUENCY_1000M) /*  Gen1 = 200MHz -> 
1000MHz, Gen3 = 1200MHz -> 2600MHz */
-+                      if (frequency_index > HT_FREQUENCY_1000M) /*  Gen1 = 
200MHz -> 1000MHz, Gen3 = 1200MHz -> 3200MHz */
-                       {
-                               /* Enable  for Gen3 frequencies */
-                               temp = 1;
-@@ -1519,27 +1572,27 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
-                               /* Disable  for Gen1 frequencies */
-                               temp = 0;
-                       }
--                              /* HT3 retry mode enable / disable */
--                              
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
--                                                      
makePCIBusFromNode(pDat->PortList[i].NodeID),
--                                                      
makePCIDeviceFromNode(pDat->PortList[i].NodeID),
--                                                      CPU_HTNB_FUNC_00,
--                                                      
REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link),
--                                                      0, 0, &temp);
--                              /* and Scrambling enable / disable */
--                              
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
-+                      /* HT3 retry mode enable / disable */
-+                      
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
-                                               
makePCIBusFromNode(pDat->PortList[i].NodeID),
-                                               
makePCIDeviceFromNode(pDat->PortList[i].NodeID),
-                                               CPU_HTNB_FUNC_00,
--                                              REG_HT_LINK_EXT_CONTROL0_0X170 
+ 4*pDat->PortList[i].Link),
--                                              3, 3, &temp);
-+                                              REG_HT_LINK_RETRY0_0X130 + 
4*pDat->PortList[i].Link),
-+                                              0, 0, &temp);
-+                      /* and Scrambling enable / disable */
-+                      
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
-+                                      
makePCIBusFromNode(pDat->PortList[i].NodeID),
-+                                      
makePCIDeviceFromNode(pDat->PortList[i].NodeID),
-+                                      CPU_HTNB_FUNC_00,
-+                                      REG_HT_LINK_EXT_CONTROL0_0X170 + 
4*pDat->PortList[i].Link),
-+                                      3, 3, &temp);
-               }
-               else
-               {
-                       SBDFO currentPtr;
-                       BOOL isFound;
- 
--                      ASSERT(temp <= HT_FREQUENCY_2600M);
-+                      ASSERT(temp <= HT_FREQUENCY_3200M);
-                       /* Write the frequency setting */
-                       AmdPCIWriteBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 11, 
8, &temp);
- 
-@@ -1700,6 +1753,9 @@ static void fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 
link, u8 req, u8 preq, u8
-       /* Probe Command Buffers */
-       temp = prb;
-       AmdPCIWriteBits(currentPtr, 15, 12, &temp);
-+      /* LockBc */
-+      temp = 1;
-+      AmdPCIWriteBits(currentPtr, 31, 31, &temp);
- }
- #endif /* HT_BUILD_NC_ONLY */
- 
-diff --git a/src/northbridge/amd/amdht/h3ncmn.h 
b/src/northbridge/amd/amdht/h3ncmn.h
-index 7f8f4d1..5795e9a 100644
---- a/src/northbridge/amd/amdht/h3ncmn.h
-+++ b/src/northbridge/amd/amdht/h3ncmn.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -107,7 +108,7 @@ struct cNorthBridge
-       /* Public Interfaces for northbridge clients, Optimization */
-       u8 (*convertBitsToWidth)(u8 value, cNorthBridge *nb);
-       u8 (*convertWidthToBits)(u8 value, cNorthBridge *nb);
--      u16 (*northBridgeFreqMask)(u8 node, cNorthBridge *nb);
-+      uint32_t (*northBridgeFreqMask)(u8 node, cNorthBridge *nb);
-       void (*gatherLinkData)(sMainData *pDat, cNorthBridge *nb);
-       void (*setLinkData)(sMainData *pDat, cNorthBridge *nb);
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0095-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
 
b/resources/libreboot/patch/kgpe-d16/0095-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
deleted file mode 100644
index 2cb270a..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0095-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
+++ /dev/null
@@ -1,124 +0,0 @@
-From 7a203388d1cc86037723fb307efa37cfb9dd87ea Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 7 Aug 2015 19:04:49 -0500
-Subject: [PATCH 095/139] amd/family_10h-family_15h: Fix poor performance on
- Family 15h CPUs
-
-Change-Id: Ieb1f1fb5653651c98764de79636669802578d5f9
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h  | 13 ++++++--
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 45 +++++++++++++++++++++++++--
- 2 files changed, 52 insertions(+), 6 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index bff2efd..4868c5c 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -535,15 +535,15 @@ static const struct {
-       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0x00800756, 0x00F3FFFF },
- 
--      { 3, 0x140, AMD_FAM15_ALL, AMD_PTYPE_ALL,
--        0x00a11755, 0x00f3ffff },
--
-       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x00C37756, 0x00F3FFFF },
- 
-       { 3, 0x144, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x00000036, 0x000000FF },
- 
-+      { 3, 0x140, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00a11755, 0x00f3ffff },
-+
-       /* Errata 281 Workaround */
-       { 3, 0x144, ( AMD_DR_B0 | AMD_DR_B1),
-        AMD_PTYPE_SVR, 0x00000001, 0x0000000F },
-@@ -555,6 +555,13 @@ static const struct {
-       { 3, 0x148, AMD_FAM10_ALL, AMD_PTYPE_UMA,
-         0x8000052A, 0xD5FFFFFF },
- 
-+      /* Core Interface Buffer Count */
-+      { 3, 0x1a0, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00034004, 0x00037007 },     /* CpuToNbFreeBufCnt = 0x3,
-+                                         L3ToSriReqCBC = 0x4,
-+                                         L3FreeListCBC = default,
-+                                         CpuCmdBufCnt = 0x4 */
-+
-       /* ACPI Power State Control Reg1 */
-       { 3, 0x80, AMD_FAM10_ALL, AMD_PTYPE_ALL,
-         0xE6002200, 0xFFFFFFFF },
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 9aadbcf..d1a93e7 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -847,8 +847,9 @@ static BOOL AMD_CpuFindCapability(u8 node, u8 cap_count, 
u8 * offset)
-  */
- static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
- {
--      u32 val;
--      u32 linktype = 0;
-+      uint32_t val;
-+      uint32_t val2;
-+      uint32_t linktype = 0;
- 
-       /* Check connect, init and coherency */
-       val = pci_read_config32(NODE_PCI(node, 0), regoff + 0x18);
-@@ -863,8 +864,13 @@ static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
-       if (linktype) {
-               /* Check gen3 */
-               val = pci_read_config32(NODE_PCI(node, 0), regoff + 0x08);
-+              val = (val >> 8) & 0xf;
-+              if (is_gt_rev_d()) {
-+                      val2 = pci_read_config32(NODE_PCI(node, 0), regoff + 
0x1c);
-+                      val |= (val2 & 0x1) << 4;
-+              }
- 
--              if (((val >> 8) & 0x0F) > 6)
-+              if (val > 6)
-                       linktype |= HTPHY_LINKTYPE_HT3;
-               else
-                       linktype |= HTPHY_LINKTYPE_HT1;
-@@ -1150,6 +1156,39 @@ static void cpuSetAMDPCI(u8 node)
-               pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
-       }
- 
-+      if (revision & AMD_FAM15_ALL) {
-+              uint32_t f5x80;
-+              uint8_t cu_enabled;
-+              uint8_t compute_unit_count = 0;
-+              uint8_t compute_unit_buffer_count;
-+
-+              /* Determine the number of active compute units on this node */
-+              f5x80 = pci_read_config32(NODE_PCI(node, 5), 0x80);
-+              cu_enabled = f5x80 & 0xf;
-+              if (cu_enabled == 0x1)
-+                      compute_unit_count = 1;
-+              if (cu_enabled == 0x3)
-+                      compute_unit_count = 2;
-+              if (cu_enabled == 0x7)
-+                      compute_unit_count = 3;
-+              if (cu_enabled == 0xf)
-+                      compute_unit_count = 4;
-+
-+              if (compute_unit_count == 1)
-+                      compute_unit_buffer_count = 0x1c;
-+              else if (compute_unit_count == 2)
-+                      compute_unit_buffer_count = 0x18;
-+              else if (compute_unit_count == 3)
-+                      compute_unit_buffer_count = 0x14;
-+              else
-+                      compute_unit_buffer_count = 0x10;
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0x1a0);
-+              dword &= ~(0x1f << 4);                  /* L3FreeListCBC = 
compute_unit_buffer_count */
-+              dword |= (compute_unit_buffer_count << 4);
-+              pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
-+      }
-+
-       printk(BIOS_DEBUG, " done\n");
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0095-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
 
b/resources/libreboot/patch/kgpe-d16/0095-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
new file mode 100644
index 0000000..90c5132
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0095-cpu-amd-family_10h-family_15h-Fix-incorrect-revision.patch
@@ -0,0 +1,64 @@
+From ba93fcaf7408e3e00c01056f9257c94b82302382 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 2 Aug 2015 21:31:48 -0500
+Subject: [PATCH 095/143] cpu/amd/family_10h-family_15h: Fix incorrect
+ revision detection
+
+Change-Id: I7a881a94d62ed455415f9dfc887fd698ac919429
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/fidvid.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
+index d99c37f..7453ad4 100644
+--- a/src/cpu/amd/family_10h-family_15h/fidvid.c
++++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
+@@ -375,7 +375,7 @@ static void recalculateVsSlamTimeSettingOnCorePre(device_t 
dev)
+       pci_write_config32(dev, 0xd8, dtemp);
+ }
+ 
+-static u32 nb_clk_did(int node, u32 cpuRev,u8 procPkg) {
++static u32 nb_clk_did(int node, uint64_t cpuRev, uint8_t procPkg) {
+         u8 link0isGen3 = 0;
+         u8 offset;
+         if (AMD_CpuFindCapability(node, 0, &offset)) {
+@@ -446,7 +446,7 @@ static u32 power_up_down(int node, u8 procPkg) {
+         return dword;
+ }
+ 
+-static void config_clk_power_ctrl_reg0(int node, u32 cpuRev, u8 procPkg) {
++static void config_clk_power_ctrl_reg0(int node, uint64_t cpuRev, uint8_t 
procPkg) {
+               device_t dev = NODE_PCI(node, 3);
+ 
+       /* Program fields in Clock Power/Control register0 (F3xD4) */
+@@ -471,7 +471,7 @@ static void config_clk_power_ctrl_reg0(int node, u32 
cpuRev, u8 procPkg) {
+ 
+ }
+ 
+-static void config_power_ctrl_misc_reg(device_t dev,u32 cpuRev, u8 procPkg) {
++static void config_power_ctrl_misc_reg(device_t dev, uint64_t cpuRev, uint8_t 
procPkg) {
+       /* check PVI/SVI */
+       u32 dword = pci_read_config32(dev, 0xa0);
+ 
+@@ -504,7 +504,7 @@ static void config_power_ctrl_misc_reg(device_t dev,u32 
cpuRev, u8 procPkg) {
+       pci_write_config32(dev, 0xa0, dword);
+ }
+ 
+-static void config_nb_syn_ptr_adj(device_t dev, u32 cpuRev) {
++static void config_nb_syn_ptr_adj(device_t dev, uint64_t cpuRev) {
+       /* Note the following settings are additional from the ported
+        * function setFidVidRegs()
+        */
+@@ -526,7 +526,7 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 
cpuRev) {
+       pci_write_config32(dev, 0xdc, dword);
+ }
+ 
+-static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 
procPkg) {
++static void config_acpi_pwr_state_ctrl_regs(device_t dev, uint64_t cpuRev, 
uint8_t procPkg) {
+       if (is_fam15h()) {
+               /* Family 15h BKDG Rev. 3.14 D18F3x80 recommended settings */
+               pci_write_config32(dev, 0x80, 0xe20be281);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0096-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0096-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
deleted file mode 100644
index 0688150..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0096-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
+++ /dev/null
@@ -1,1089 +0,0 @@
-From 144073db29e770d85d01cbd6b093793aa951862f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 7 Aug 2015 19:05:29 -0500
-Subject: [PATCH 096/139] amd/amdmct/mct_ddr3: Fix poor performance on Family
- 15h CPUs
-
-Change-Id: Ib6bc197e43e40ba2b923b1eb1229bacafc8be360
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 370 +++++++++++++++++++++----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |   1 +
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |  65 ++++-
- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c  |  49 +++-
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   | 195 ++++++++++++-
- src/northbridge/amd/amdmct/mct_ddr3/mctwl.c    |   4 +
- 6 files changed, 604 insertions(+), 80 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 1167976..2ca65ca 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -36,6 +36,8 @@
-  * supported.
-  */
- 
-+// #define DEBUG_DIMM_SPD 1
-+
- static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstatA);
- static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
-@@ -172,7 +174,8 @@ static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u32 MrsChipSel);
- static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat, u8 dimm);
--static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 
misc2);
-+static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat,
-+                                      uint8_t dct, uint32_t misc2, uint32_t 
DramControl);
- static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat);
- static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstatA, uint8_t 
Pass);
-@@ -1360,6 +1363,8 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
- static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct)
- {
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       uint32_t dev;
-       uint32_t reg;
-       uint32_t dword;
-@@ -1382,6 +1387,8 @@ static void set_2t_configuration(struct MCTStatStruc 
*pMCTstat,
-       else
-               dword &= ~(0x1 << 20);          /* Clear 2T CMD mode */
-       Set_NB32_DCT(dev, dct, reg, dword);
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- static void precise_ndelay_fam15(struct MCTStatStruc *pMCTstat, uint32_t 
nanoseconds) {
-@@ -2002,6 +2009,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               /* Disable training mode */
-               uint8_t lane;
-               uint8_t dimm;
-+              uint16_t sword;
-               uint8_t receiver;
-               uint8_t max_lane;
-               uint8_t ecc_enabled;
-@@ -2016,21 +2024,37 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
-               uint16_t twrwrdd;
-               uint16_t cdd_twrwrdd;
-               uint16_t twrrd;
-+              uint16_t cdd_twrrd;
-+              uint16_t cdd_trwtto;
-               uint16_t trwtto;
-               uint8_t first_dimm;
-               uint16_t delay;
-               uint16_t delay2;
-+              uint8_t min_value;
-+              uint8_t write_early;
-               uint8_t read_odt_delay;
-               uint8_t write_odt_delay;
-+              uint8_t buffer_data_delay;
-+              int16_t latency_difference;
-               uint16_t difference;
-               uint16_t current_total_delay_1[MAX_BYTE_LANES];
-               uint16_t current_total_delay_2[MAX_BYTE_LANES];
-+              uint8_t ddr_voltage_index;
-+              uint8_t max_dimms_installable;
- 
-               /* FIXME
-                * This should be platform configurable
-                */
-               uint8_t dimm_event_l_pin_support = 0;
- 
-+              if (pDCTstat->DIMMValidDCT[dct] == 0)
-+                      ddr_voltage_index = 1;
-+              else
-+                      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, 
dct);
-+
-+              ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
-+              max_dimms_installable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-+
-               ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs);
-               if (ecc_enabled)
-                       max_lane = 9;
-@@ -2064,6 +2088,24 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               else
-                       write_odt_delay = 0;
- 
-+              dword = (Get_NB32_DCT(dev, dct, 0xa8) >> 24) & 0x3;
-+              write_early = dword / 2;
-+
-+              latency_difference = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
-+              dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
-+              latency_difference -= dword;
-+
-+              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* LRDIMM */
-+
-+                      /* TODO
-+                       * Implement LRDIMM support
-+                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.5
-+                       */
-+              } else {
-+                      buffer_data_delay = 0;
-+              }
-+
-               /* TODO:
-                * Adjust trdrdsddc if four-rank DIMMs are installed per
-                * section 2.10.5.5.1 of the Family 15h BKDG.
-@@ -2099,7 +2141,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               }
- 
-               /* Convert the difference to MEMCLKs */
--              cdd_trdrddd = (((cdd_trdrddd >> 5) & 0x1f) + 1) / 2;
-+              cdd_trdrddd = (((cdd_trdrddd + (1 << 6) - 1) >> 6) & 0xf);
- 
-               /* Calculate Trdrddd */
-               delay = (read_odt_delay + 3) * 2;
-@@ -2145,7 +2187,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               }
- 
-               /* Convert the difference to MEMCLKs */
--              cdd_twrwrdd = (((cdd_twrwrdd >> 5) & 0x1f) + 1) / 2;
-+              cdd_twrwrdd = (((cdd_twrwrdd + (1 << 6) - 1) >> 6) & 0xf);
- 
-               /* Calculate Twrwrdd */
-               delay = (write_odt_delay + 3) * 2;
-@@ -2164,6 +2206,107 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
-               dword &= ~(0x1 << 18);                                  /* 
DisAutoRefresh = 0 */
-               Set_NB32_DCT(dev, dct, 0x8c, dword);                    /* DRAM 
Timing High */
- 
-+              /* Configure power saving options */
-+              dword = Get_NB32_DCT(dev, dct, 0xa8);                   /* Dram 
Miscellaneous 2 */
-+              dword |= (0x1 << 22);                                   /* 
PrtlChPDEnhEn = 0x1 */
-+              dword |= (0x1 << 21);                                   /* 
AggrPDEn = 0x1 */
-+              Set_NB32_DCT(dev, dct, 0xa8, dword);                    /* Dram 
Miscellaneous 2 */
-+
-+              /* Configure partial power down delay */
-+              dword = Get_NB32(dev, 0x244);                           /* DRAM 
Controller Miscellaneous 3 */
-+              dword &= ~0xf;                                          /* 
PrtlChPDDynDly = 0x2 */
-+              dword |= 0x2;
-+              Set_NB32(dev, 0x244, dword);                            /* DRAM 
Controller Miscellaneous 3 */
-+
-+              /* Configure power save delays */
-+              delay = 0xa;
-+              delay2 = 0x3;
-+
-+              /* Family 15h BKDG Table 214 */
-+              if ((pDCTstat->Status & (1 << SB_Registered))
-+                      || (pDCTstat->Status & (1 << SB_LoadReduced))) {
-+                      if (memclk_index <= 0x6) {
-+                              if (ddr_voltage_index < 0x4)
-+                                      /* 1.5 or 1.35V */
-+                                      delay2 = 0x3;
-+                              else
-+                                      /* 1.25V */
-+                                      delay2 = 0x4;
-+                      }
-+                      else if ((memclk_index == 0xa)
-+                              || (memclk_index == 0xe))
-+                              delay2 = 0x4;
-+                      else if (memclk_index == 0x12)
-+                              delay2 = 0x5;
-+                      else if (memclk_index == 0x16)
-+                              delay2 = 0x6;
-+              } else {
-+                      if (memclk_index <= 0x6)
-+                              delay2 = 0x3;
-+                      else if ((memclk_index == 0xa)
-+                              || (memclk_index == 0xe))
-+                              delay2 = 0x4;
-+                      else if (memclk_index == 0x12)
-+                              delay2 = 0x5;
-+                      else if (memclk_index == 0x16)
-+                              delay2 = 0x6;
-+              }
-+
-+              /* Family 15h BKDG Table 215 */
-+              if (memclk_index <= 0x6)
-+                      delay = 0xa;
-+              else if (memclk_index == 0xa)
-+                      delay = 0xd;
-+              else if (memclk_index == 0xe)
-+                      delay = 0x10;
-+              else if (memclk_index == 0x12)
-+                      delay = 0x14;
-+              else if (memclk_index == 0x16)
-+                      delay = 0x17;
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x248);                  /* Dram 
Power Management 0 */
-+              dword &= ~(0x3f << 24);                                 /* 
AggrPDDelay = 0x0 */
-+              dword &= ~(0x3f << 16);                                 /* 
PchgPDEnDelay = 0x1 */
-+              dword |= (0x1 << 16);
-+              dword &= ~(0x1f << 8);                                  /* 
Txpdll = delay */
-+              dword |= ((delay & 0x1f) << 8);
-+              dword &= ~0xf;                                          /* Txp 
= delay2 */
-+              dword |= delay2 & 0xf;
-+              Set_NB32_DCT(dev, dct, 0x248, dword);                   /* Dram 
Power Management 0 */
-+
-+              /* Family 15h BKDG Table 216 */
-+              if (memclk_index <= 0x6) {
-+                      delay = 0x5;
-+                      delay2 = 0x3;
-+              }
-+              else if (memclk_index == 0xa) {
-+                      delay = 0x6;
-+                      delay2 = 0x3;
-+              }
-+              else if (memclk_index == 0xe) {
-+                      delay = 0x7;
-+                      delay2 = 0x4;
-+              }
-+              else if (memclk_index == 0x12) {
-+                      delay = 0x8;
-+                      delay2 = 0x4;
-+              }
-+              else if (memclk_index == 0x16) {
-+                      delay = 0xa;
-+                      delay2 = 0x5;
-+              }
-+
-+              dword = Get_NB32_DCT(dev, dct, 0x24c);                  /* Dram 
Power Management 1 */
-+              dword &= ~(0x3f << 24);                                 /* 
Tcksrx = delay */
-+              dword |= ((delay & 0x3f) << 24);
-+              dword &= ~(0x3f << 16);                                 /* 
Tcksre = delay */
-+              dword |= ((delay & 0x3f) << 16);
-+              dword &= ~(0x3f << 8);                                  /* 
Tckesr = delay2 + 1 */
-+              dword |= (((delay2 + 1) & 0x3f) << 8);
-+              dword &= ~0xf;                                          /* Tpd 
= delay2 */
-+              dword |= delay2 & 0xf;
-+              Set_NB32_DCT(dev, dct, 0x24c, dword);                   /* Dram 
Power Management 1 */
-+
-               dword = Get_NB32_DCT(dev, dct, 0x94);                   /* DRAM 
Configuration High */
-               dword |= (0xf << 24);                                   /* 
DcqBypassMax = 0xf */
-               dword |= (0x1 << 22);                                   /* 
BankSwizzleMode = 1 */
-@@ -2216,15 +2359,98 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
-                       }
-               }
- 
--              /* TODO
--               * Calculate Twrrd per section 2.10.5.5.3 of the Family 15h BKDG
--               */
--              twrrd = 0xb;
-+              /* Calculate the Critical Delay Difference for Twrrd */
-+              cdd_twrrd = 0;
-+              for (receiver = 0; receiver < 8; receiver += 2) {
-+                      dimm = (receiver >> 1);
- 
--              /* TODO
--               * Calculate TrwtTO per section 2.10.5.5.4 of the Family 15h 
BKDG
--               */
--              trwtto = 0x16;
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
-+                              continue;
-+
-+                      
read_dqs_write_timing_control_registers(current_total_delay_1, dev, dct, dimm, 
index_reg);
-+                      
read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, 
dimm, index_reg);
-+
-+                      for (lane = 0; lane < max_lane; lane++) {
-+                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
-+                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
-+                              else
-+                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
-+
-+                              if (difference > cdd_twrrd)
-+                                      cdd_twrrd = difference;
-+                      }
-+              }
-+
-+              /* Convert the difference to MEMCLKs */
-+              cdd_twrrd = (((cdd_twrrd + (1 << 6) - 1) >> 6) & 0xf);
-+
-+              /* Fam15h BKDG section 2.10.5.5.3 */
-+              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* LRDIMM */
-+
-+                      /* TODO
-+                       * Implement LRDIMM support
-+                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.5
-+                       */
-+                      twrrd = 0xb;
-+              } else {
-+                      sword = (((int16_t)cdd_twrrd + 1 - 
((int16_t)write_early * 2)) + 1) / 2;
-+                      if (sword < 0)
-+                              sword = 0;
-+                      if (((uint16_t)sword) > write_odt_delay)
-+                              dword = sword;
-+                      else
-+                              dword = write_odt_delay;
-+                      dword += 3;
-+                      if (latency_difference < dword) {
-+                              dword -= latency_difference;
-+                              if (dword < 1)
-+                                      twrrd = 1;
-+                              else
-+                                      twrrd = dword;
-+                      } else {
-+                              twrrd = 1;
-+                      }
-+              }
-+
-+              /* Calculate the Critical Delay Difference for TrwtTO */
-+              cdd_trwtto = 0;
-+              for (receiver = 0; receiver < 8; receiver += 2) {
-+                      dimm = (receiver >> 1);
-+
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
-+                              continue;
-+
-+                      
read_dqs_receiver_enable_control_registers(current_total_delay_1, dev, dct, 
dimm, index_reg);
-+                      
read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, 
index_reg);
-+
-+                      for (lane = 0; lane < max_lane; lane++) {
-+                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
-+                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
-+                              else
-+                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
-+
-+                              if (difference > cdd_trwtto)
-+                                      cdd_trwtto = difference;
-+                      }
-+              }
-+
-+              /* Convert the difference to MEMCLKs */
-+              cdd_trwtto = (((cdd_trwtto + (1 << 6) - 1) >> 6) & 0xf);
-+
-+              /* Fam15h BKDG section 2.10.5.5.4 */
-+              if (max_dimms_installable == 1)
-+                      min_value = 0;
-+              else
-+                      min_value = read_odt_delay + buffer_data_delay;
-+              sword = (((int16_t)cdd_trwtto - 1 + ((int16_t)write_early * 2)) 
+ 1) / 2;
-+              sword += latency_difference + 3;
-+              if (sword < 0)
-+                      sword = 0;
-+              if (((uint16_t)sword) > min_value)
-+                      trwtto = (uint16_t)sword;
-+              else
-+                      trwtto = min_value;
- 
-               dword = Get_NB32_DCT(dev, dct, 0xa4);                   /* DRAM 
Controller Temperature Throttle */
-               dword &= ~(0x1 << 11);                                  /* 
BwCapEn = 0 */
-@@ -2235,6 +2461,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               dword = Get_NB32_DCT(dev, dct, 0x110);                  /* DRAM 
Controller Select Low */
-               dword &= ~(0x1 << 2);                                   /* 
DctSelIntLvEn = interleave_channels */
-               dword |= (interleave_channels & 0x1) << 2;
-+              dword |= (0x3 << 6);                                    /* 
DctSelIntLvAddr = 0x3 */
-               Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
- 
-               /* NOTE
-@@ -2242,22 +2469,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-                * otherwise semi-random lockups will occur due to 
misconfigured scrubbing hardware!
-                */
- 
--              /* FIXME
--               * The BKDG-recommended settings cause memory corruption on the 
ASUS KGPE-D16.
--               * Investigate and fix...
--               */
--#if 0
--              /* Fam15h BKDG section 2.10.5.5.1 */
--              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
--              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0x1 */
--              dword |= (0x1 << 24);
--              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = trdrdsddc */
--              dword |= ((trdrdsddc & 0xf) << 16);
--              dword &= ~(0xf);                                        /* 
TrdrdDd = trdrddd */
--              dword |= (trdrddd & 0xf);
--              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
--#endif
--
-               /* Fam15h BKDG section 2.10.5.5.2 */
-               dword = Get_NB32_DCT(dev, dct, 0x214);                  /* DRAM 
Timing 4 */
-               dword &= ~(0xf << 16);                                  /* 
TwrwrSdSc = 0x1 */
-@@ -2270,8 +2481,14 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
- 
-               /* Fam15h BKDG section 2.10.5.5.3 */
-               dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
-+              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0x1 */
-+              dword |= (0x1 << 24);
-+              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = trdrdsddc */
-+              dword |= ((trdrdsddc & 0xf) << 16);
-               dword &= ~(0xf << 8);                                   /* 
Twrrd = twrrd */
-               dword |= ((twrrd & 0xf) << 8);
-+              dword &= ~(0xf);                                        /* 
TrdrdDd = trdrddd */
-+              dword |= (trdrddd & 0xf);
-               Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
- 
-               /* Fam15h BKDG section 2.10.5.5.4 */
-@@ -2282,12 +2499,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
-               dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
-               Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
- 
--              /* Configure partial power down delay */
--              dword = Get_NB32(dev, 0x244);                           /* DRAM 
Controller Miscellaneous 3 */
--              dword &= ~0xf;                                          /* 
PrtlChPDDynDly = 0x2 */
--              dword |= 0x2;
--              Set_NB32(dev, 0x244, dword);                            /* DRAM 
Controller Miscellaneous 3 */
--
-               /* Enable prefetchers */
-               dword = Get_NB32(dev, 0x11c);                           /* 
Memory Controller Configuration High */
-               dword &= ~(0x1 << 13);                                  /* 
PrefIoDis = 0 */
-@@ -2376,6 +2587,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
- 
-               mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
- 
-+              TrainMaxRdLatency_En_D(pMCTstat, pDCTstatA);
-+
-               if (is_fam15h())
-                       exit_training_mode_fam15(pMCTstat, pDCTstatA);
-               else
-@@ -2953,6 +3166,13 @@ static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
-       }
- 
-       while(reg < reg_end) {
-+              if ((reg & 0xFF) == 0x84) {
-+                      if (is_fam15h()) {
-+                              val = Get_NB32_DCT(dev, dct, reg);
-+                              val &= ~(0x1 << 23);    /* Clear PchgPDModeSel 
*/
-+                              val &= ~0x3;            /* Clear BurstCtrl */
-+                      }
-+              }
-               if ((reg & 0xFF) == 0x90) {
-                       if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
-                               val = Get_NB32_DCT(dev, dct, reg); /* get 
DRAMConfigLow */
-@@ -3071,14 +3291,30 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
- 
-       /* Convert  DRAM CycleTiming values and store into DCT structure */
-       byte = pDCTstat->DIMMAutoSpeed;
--      if (byte == 7)
--              tCK16x = 20;
--      else if (byte == 6)
--              tCK16x = 24;
--      else if (byte == 5)
--              tCK16x = 30;
--      else
--              tCK16x = 40;
-+      if (is_fam15h()) {
-+              if (byte == 0x16)
-+                      tCK16x = 17;
-+              else if (byte == 0x12)
-+                      tCK16x = 20;
-+              else if (byte == 0xe)
-+                      tCK16x = 24;
-+              else if (byte == 0xa)
-+                      tCK16x = 30;
-+              else if (byte == 0x6)
-+                      tCK16x = 40;
-+              else
-+                      tCK16x = 48;
-+      }
-+      else {
-+              if (byte == 7)
-+                      tCK16x = 20;
-+              else if (byte == 6)
-+                      tCK16x = 24;
-+              else if (byte == 5)
-+                      tCK16x = 30;
-+              else
-+                      tCK16x = 40;
-+      }
- 
-       /* Notes:
-        1. All secondary time values given in SPDs are in binary with units of 
ns.
-@@ -3111,7 +3347,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-               val = Max_TrpT;
-       pDCTstat->Trp = val;
- 
--      /*Trrd*/
-+      /* Trrd */
-       pDCTstat->DIMMTrrd = Trrd;
-       val = Trrd / tCK16x;
-       if (Trrd % tCK16x) {    /* round up number of busclocks */
-@@ -3229,21 +3465,31 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
- 
-               dword = Get_NB32_DCT(dev, dct, 0x200);                          
/* DRAM Timing 0 */
-               dword &= ~(0x3f1f1f1f);
--              dword |= ((pDCTstat->Tras + 0xf) & 0x3f) << 24;                 
/* Tras */
--              dword |= ((pDCTstat->Trp + 0x5) & 0x1f) << 16;                  
/* Trp */
--              dword |= ((pDCTstat->Trcd + 0x5) & 0x1f) << 8;                  
/* Trcd */
-+              dword |= (pDCTstat->Tras & 0x3f) << 24;                         
/* Tras */
-+              val = pDCTstat->Trp;
-+              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
-+              dword |= (val & 0x1f) << 16;                                    
/* Trp */
-+              dword |= (pDCTstat->Trcd & 0x1f) << 8;                          
/* Trcd */
-               dword |= (pDCTstat->CASL & 0x1f);                               
/* Tcl */
-               Set_NB32_DCT(dev, dct, 0x200, dword);                           
/* DRAM Timing 0 */
- 
-               dword = Get_NB32_DCT(dev, dct, 0x204);                          
/* DRAM Timing 1 */
-               dword &= ~(0x0f3f0f3f);
--              dword |= ((pDCTstat->Trtp + 0x4) & 0xf) << 24;                  
/* Trtp */
--              if (pDCTstat->Tfaw != 0)
--                      dword |= ((((pDCTstat->Tfaw - 0x1) * 2) + 0x10) & 0x3f) 
<< 16;  /* FourActWindow */
--              dword |= ((pDCTstat->Trrd + 0x4) & 0xf) << 8;                   
/* Trrd */
--              dword |= ((pDCTstat->Trc + 0xb) & 0x3f);                        
/* Trc */
-+              dword |= (pDCTstat->Trtp & 0xf) << 24;                          
/* Trtp */
-+              if (pDCTstat->Tfaw != 0) {
-+                      val = pDCTstat->Tfaw;
-+                      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
-+                      if ((val > 0x5) && (val < 0x2b))
-+                              dword |= (val & 0x3f) << 16;                    
/* FourActWindow */
-+              }
-+              dword |= (pDCTstat->Trrd & 0xf) << 8;                           
/* Trrd */
-+              dword |= (pDCTstat->Trc & 0x3f);                                
/* Trc */
-               Set_NB32_DCT(dev, dct, 0x204, dword);                           
/* DRAM Timing 1 */
- 
-+              /* Trfc0-Trfc3 */
-+              for (i=0; i<4; i++)
-+                      if (pDCTstat->Trfc[i] == 0x0)
-+                              pDCTstat->Trfc[i] = 0x4;
-               dword = Get_NB32_DCT(dev, dct, 0x208);                          
/* DRAM Timing 2 */
-               dword &= ~(0x07070707);
-               dword |= (pDCTstat->Trfc[3] & 0x7) << 24;                       
/* Trfc3 */
-@@ -3254,14 +3500,14 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
- 
-               dword = Get_NB32_DCT(dev, dct, 0x20c);                          
/* DRAM Timing 3 */
-               dword &= ~(0x00000f00);
--              dword |= ((pDCTstat->Twtr + 0x4) & 0xf) << 8;                   
/* Twtr */
-+              dword |= (pDCTstat->Twtr & 0xf) << 8;                           
/* Twtr */
-               dword &= ~(0x0000001f);
-               dword |= (Tcwl & 0x1f);                                         
/* Tcwl */
-               Set_NB32_DCT(dev, dct, 0x20c, dword);                           
/* DRAM Timing 3 */
- 
-               dword = Get_NB32_DCT(dev, dct, 0x22c);                          
/* DRAM Timing 10 */
-               dword &= ~(0x0000001f);
--              dword |= ((pDCTstat->Twr + 0x4) & 0x1f);                        
/* Twr */
-+              dword |= (pDCTstat->Twr & 0x1f);                                
/* Twr */
-               Set_NB32_DCT(dev, dct, 0x22c, dword);                           
/* DRAM Timing 10 */
- 
-               if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
-@@ -3857,6 +4103,8 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-               }
-       }
- 
-+      DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, 
DramConfigMisc2, DramControl);
-+
-       printk(BIOS_DEBUG, "AutoConfig_D: DramControl:     %08x\n", 
DramControl);
-       printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo:    %08x\n", 
DramTimingLo);
-       printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc:  %08x\n", 
DramConfigMisc);
-@@ -3868,7 +4116,6 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
-       Set_NB32_DCT(dev, dct, 0x78, DramControl);
-       Set_NB32_DCT(dev, dct, 0x88, DramTimingLo);
-       Set_NB32_DCT(dev, dct, 0xa0, DramConfigMisc);
--      DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, 
DramConfigMisc2);
-       Set_NB32_DCT(dev, dct, 0xa8, DramConfigMisc2);
-       Set_NB32_DCT(dev, dct, 0x90, DramConfigLo);
-       ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
-@@ -5239,6 +5486,16 @@ static void mct_PhyController_Config(struct 
MCTStatStruc *pMCTstat,
-       u32 dev = pDCTstat->dev_dct;
- 
-       if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3 | 
AMD_FAM15_ALL)) {
-+              if (is_fam15h()) {
-+                      /* Set F2x[1, 0]98_x0D0F0F13 DllDisEarlyU and 
DllDisEarlyL to save power */
-+                      for (index = 0; index < 0x9; index++) {
-+                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0013 | (index << 8));
-+                              dword |= (0x1 << 1);                            
/* DllDisEarlyU = 1 */
-+                              dword |= 0x1;                                   
/* DllDisEarlyL = 1 */
-+                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0013 | (index << 8), dword);
-+                      }
-+              }
-+
-               if (pDCTstat->Dimmx4Present == 0) {
-                       /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 
0]98_x0D0F0F13 for
-                        * additional power saving when x4 DIMMs are not 
present.
-@@ -5283,8 +5540,9 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
-                               mct_ExtMCTConfig_Dx(pDCTstat);
-                       } else {
-                               /* Family 15h CPUs */
--                              val = 0x0ce00f00 | 0x1 << 29;   /* 
FlushWrOnStpGnt */
--                              val |= 0x10 << 2;               /* MctWrLimit = 
16 */
-+                              val = 0x0ce00f00;               /* 
FlushWrOnStpGnt = 0x0 */
-+                              val |= 0x10 << 2;               /* MctWrLimit = 
0x10 */
-+                              val |= 0x1;                     /* DctWrLimit = 
0x1 */
-                               Set_NB32(pDCTstat->dev_dct, 0x11c, val);
- 
-                               val = Get_NB32(pDCTstat->dev_dct, 0x1b0);
-@@ -6524,8 +6782,8 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
- 
-       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
-       if (is_fam15h()) {
--              dword |= DramMRS;
-               dword &= ~0x00800003;
-+              dword |= DramMRS;
-       } else {
-               dword &= ~0x00fc2f8f;
-               dword |= DramMRS;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index 486b16c..ec5658e 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -988,6 +988,7 @@ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat
- uint64_t mctGetLogicalCPUID(u32 Node);
- u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
- void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA, u8 Pass);
-+void TrainMaxRdLatency_En_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA);
- void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
- void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index c70fa6d..c520515 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -24,6 +24,9 @@ static void 
write_dqs_receiver_enable_control_registers(uint16_t* current_total_
- static void read_read_dqs_timing_control_registers(uint16_t* 
current_total_delay,
-                       uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
- 
-+static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat);
-+
- static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u16 like,
-                               u8 scale, u8 ChipSel);
-@@ -218,6 +221,27 @@ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
-       }
- }
- 
-+void TrainMaxRdLatency_En_D(struct MCTStatStruc *pMCTstat,
-+                      struct DCTStatStruc *pDCTstatA)
-+{
-+      uint8_t node;
-+      struct DCTStatStruc *pDCTstat;
-+
-+      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
-+              pDCTstat = pDCTstatA + node;
-+
-+              if (pDCTstat->DCTSysLimit) {
-+                      if (is_fam15h()) {
-+                              dqsTrainMaxRdLatency_SW_Fam15(pMCTstat, 
pDCTstat);
-+                      } else {
-+                              /* FIXME
-+                               * Implement Family 10h MaxRdLatency training
-+                               */
-+                      }
-+              }
-+      }
-+}
-+
- static void SetEccDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
- {
-@@ -898,7 +922,7 @@ static void TrainDQSRdWrPos_D_Fam10(struct MCTStatStruc 
*pMCTstat,
-  * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.5
-  */
- static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
--                              struct DCTStatStruc *pDCTstat, uint8_t dct)
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t calc_min)
- {
-       uint8_t dimm;
-       uint8_t lane;
-@@ -942,7 +966,8 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-               p += (9 - dword);
- 
-               /* 2.10.5.8.5 (4) */
--              p += 5;
-+              if (!calc_min)
-+                      p += 5;
- 
-               /* 2.10.5.8.5 (5) */
-               dword = Get_NB32_DCT(dev, dct, 0xa8);
-@@ -969,7 +994,8 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-               p += (max_delay >> 5);
- 
-               /* 2.10.5.8.5 (8) */
--              p += 5;
-+              if (!calc_min)
-+                      p += 5;
- 
-               /* 2.10.5.8.5 (9) */
-               t += 800;
-@@ -980,13 +1006,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-               n = (((((uint64_t)p * 
1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + 
((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
- 
-               /* 2.10.5.8.5 (11) */
--              n -= 1;
-+              if (!calc_min)
-+                      n -= 1;
- 
-               /* 2.10.5.8.5 (12) */
--              dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210);
--              dword &= ~(0x3ff << 22);
--              dword |= (((n - 1) & 0x3ff) << 22);
--              Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
-+              if (!calc_min) {
-+                      dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 
0x210);
-+                      dword &= ~(0x3ff << 22);
-+                      dword |= (((n - 1) & 0x3ff) << 22);
-+                      Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, 
dword);
-+              }
- 
-               /* Save result for later use */
-               pDCTstat->CH_MaxRdLat[dct] = n - 1;
-@@ -1107,6 +1136,9 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
-       } else if (lane < 8) {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
-+      } else if (lane == 0xff) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
-+              Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
-       } else {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-@@ -1114,8 +1146,9 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
- 
-       dword = Get_NB32_DCT(dev, dct, 0x27c);
-       dword &= ~(0xff);                               /* EccMask = 0 */
--      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
--              dword |= 0xff;                          /* EccMask = 0xff */
-+      if (lane != 0xff)
-+              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
-+                      dword |= 0xff;                  /* EccMask = 0xff */
-       Set_NB32_DCT(dev, dct, 0x27c, dword);
- 
-       dword = Get_NB32_DCT(dev, dct, 0x270);
-@@ -1184,6 +1217,9 @@ static void write_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
-       } else if (lane < 8) {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
-+      } else if (lane == 0xff) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
-+              Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
-       } else {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-@@ -1191,8 +1227,9 @@ static void write_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
- 
-       dword = Get_NB32_DCT(dev, dct, 0x27c);
-       dword &= ~(0xff);                               /* EccMask = 0 */
--      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
--              dword |= 0xff;                          /* EccMask = 0xff */
-+      if (lane != 0xff)
-+              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
-+                      dword |= 0xff;                  /* EccMask = 0xff */
-       Set_NB32_DCT(dev, dct, 0x27c, dword);
- 
-       dword = Get_NB32_DCT(dev, dct, 0x270);
-@@ -1278,7 +1315,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-       uint32_t dev = pDCTstat->dev_dct;
- 
-       /* Calculate and program MaxRdLatency */
--      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct);
-+      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0);
- 
-       Errors = 0;
-       dual_rank = 0;
-@@ -1636,7 +1673,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                                       
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
- 
-                                       /* Calculate and program MaxRdLatency */
--                                      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, 
pDCTstat, dct);
-+                                      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, 
pDCTstat, dct, 0);
- 
-                                       /* 2.10.5.8.3 (4 B) */
-                                       
dqs_results_array[current_phy_phase_delay[lane]] = 
TrainDQSRdWrPos_D_Fam15(pMCTstat, pDCTstat, dct, Receiver, Receiver + 2, lane, 
lane + 1);
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-index 738304e..3da28b3 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
-@@ -19,7 +19,8 @@
-  */
- 
- /* mct_SetDramConfigMisc2_Cx & mct_SetDramConfigMisc2_Dx */
--u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2)
-+u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat,
-+                              uint8_t dct, uint32_t misc2, uint32_t 
DramControl)
- {
-       u32 val;
- 
-@@ -28,17 +29,47 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
-       if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
-               uint8_t cs_mux_45;
-               uint8_t cs_mux_67;
-+              uint32_t f2x80;
- 
--              /* BKDG v3.14 Table 200 / Table 201 */
--              if (MaxDimmsInstallable < 3) {
--                      cs_mux_45 = 1;
--                      cs_mux_67 = 1;
--              } else {
-+              misc2 &= ~(0x1 << 28);                  /* FastSelfRefEntryDis 
= 0x0 */
-+              if (MaxDimmsInstallable == 3) {
-+                      /* FIXME 3 DIMMS per channel unimplemented */
-                       cs_mux_45 = 0;
-+              } else {
-+                      uint32_t f2x60 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
0x60);
-+                      f2x80 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x80);
-+                      if ((((f2x80 & 0xf) == 0x7) || ((f2x80 & 0xf) == 0x9))
-+                              && ((f2x60 & 0x3) == 0x3))
-+                              cs_mux_45 = 1;
-+                      else if ((((f2x80 & 0xa) == 0x7) || ((f2x80 & 0xb) == 
0x9))
-+                              && ((f2x60 & 0x3) > 0x1))
-+                              cs_mux_45 = 1;
-+                      else
-+                              cs_mux_45 = 0;
-+              }
-+
-+              if (MaxDimmsInstallable == 1) {
-+                      cs_mux_67 = 0;
-+              } else if (MaxDimmsInstallable == 2) {
-+                      uint32_t f2x64 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
0x64);
-+                      f2x80 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x80);
-+                      if (((((f2x80 >> 4) & 0xf) == 0x7) || (((f2x80 >> 4) & 
0xf) == 0x9))
-+                              && ((f2x64 & 0x3) == 0x3))
-+                              cs_mux_67 = 1;
-+                      else if (((((f2x80 >> 4) & 0xa) == 0x7) || (((f2x80 >> 
4) & 0xb) == 0x9))
-+                              && ((f2x64 & 0x3) > 0x1))
-+                              cs_mux_67 = 1;
-+                      else
-+                              cs_mux_67 = 0;
-+              } else {
-+                      /* FIXME 3 DIMMS per channel unimplemented */
-                       cs_mux_67 = 0;
-               }
--              misc2 |= (cs_mux_45 & 0x1) << 26;
--              misc2 |= (cs_mux_67 & 0x1) << 27;
-+
-+              misc2 &= ~(0x1 << 27);          /* CsMux67 = cs_mux_67 */
-+              misc2 |= ((cs_mux_67 & 0x1) << 27);
-+              misc2 &= ~(0x1 << 26);          /* CsMux45 = cs_mux_45 */
-+              misc2 |= ((cs_mux_45 & 0x1) << 26);
-       } else if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
-               if (pDCTstat->Status & (1 << SB_Registered)) {
-                       misc2 |= 1 << SubMemclkRegDly;
-@@ -50,8 +81,8 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 
dct, u32 misc2)
- 
-               if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
-                       misc2 |= 1 << OdtSwizzle;
--              val = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x78);
- 
-+              val = DramControl;
-               val &= 7;
-               val = ((~val) & 0xff) + 1;
-               val += 6;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 707e6a9..3ede104 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -1424,7 +1424,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
-       }
- 
-       /* Calculate and program MaxRdLatency */
--      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel);
-+      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel, 0);
- 
-       if(_DisableDramECC) {
-               mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
-@@ -1487,6 +1487,199 @@ static void dqsTrainRcvrEn_SW_Fam15(struct 
MCTStatStruc *pMCTstat,
-       printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
- }
- 
-+static void write_max_read_latency_to_registers(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint16_t latency)
-+{
-+      uint32_t dword;
-+      uint8_t nb_pstate;
-+
-+      for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
-+              dword = Get_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, 
nb_pstate, 0x210);
-+              dword &= ~(0x3ff << 22);
-+              dword |= ((latency & 0x3ff) << 22);
-+              Set_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, nb_pstate, 0x210, 
dword);
-+      }
-+}
-+
-+/* DQS MaxRdLatency Training (Family 15h)
-+ * Algorithm detailed in:
-+ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.5.1
-+ * This algorithm runs at the highest supported MEMCLK.
-+ */
-+static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat,
-+                              struct DCTStatStruc *pDCTstat)
-+{
-+      u8 Channel;
-+      u8 Addl_Index = 0;
-+      u8 Receiver;
-+      u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
-+      u32 Errors;
-+
-+      u32 dev;
-+      u32 index_reg;
-+      u32 ch_start, ch_end;
-+      u32 msr;
-+      u32 cr4;
-+      u32 lo, hi;
-+
-+      uint32_t dword;
-+      uint8_t dimm;
-+      uint8_t lane;
-+      uint8_t mem_clk;
-+      uint32_t nb_clk;
-+      uint8_t nb_pstate;
-+      uint16_t current_total_delay[MAX_BYTE_LANES];
-+      uint16_t current_rdqs_total_delay[MAX_BYTE_LANES];
-+      uint8_t current_worst_case_total_delay_dimm;
-+      uint16_t current_worst_case_total_delay_value;
-+
-+      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
-+
-+      print_debug_dqs("\nTrainMaxRdLatency: Node", pDCTstat->Node_ID, 0);
-+
-+      dev = pDCTstat->dev_dct;
-+      index_reg = 0x98;
-+      ch_start = 0;
-+      ch_end = 2;
-+
-+      cr4 = read_cr4();
-+      if(cr4 & ( 1 << 9)) {   /* save the old value */
-+              _SSE2 = 1;
-+      }
-+      cr4 |= (1 << 9);        /* OSFXSR enable SSE2 */
-+      write_cr4(cr4);
-+
-+      msr = HWCR;
-+      _RDMSR(msr, &lo, &hi);
-+      /* FIXME: Why use SSEDIS */
-+      if(lo & (1 << 17)) {    /* save the old value */
-+              _Wrap32Dis = 1;
-+      }
-+      lo |= (1 << 17);        /* HWCR.wrap32dis */
-+      lo &= ~(1 << 15);       /* SSEDIS */
-+      _WRMSR(msr, lo, hi);    /* Setting wrap32dis allows 64-bit memory 
references in real mode */
-+
-+      _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
-+
-+      Errors = 0;
-+      dev = pDCTstat->dev_dct;
-+
-+      for (Channel = 0; Channel < 2; Channel++) {
-+              print_debug_dqs("\tTrainMaxRdLatency51: Node ", 
pDCTstat->Node_ID, 1);
-+              print_debug_dqs("\tTrainMaxRdLatency51: Channel ", Channel, 1);
-+              pDCTstat->Channel = Channel;
-+
-+              if (pDCTstat->DIMMValidDCT[Channel] == 0)
-+                      continue;
-+
-+              mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
-+
-+              Receiver = mct_InitReceiver_D(pDCTstat, Channel);
-+
-+              /* Find DIMM with worst case receiver enable delays */
-+              current_worst_case_total_delay_dimm = 0;
-+              current_worst_case_total_delay_value = 0;
-+
-+              /* There are four receiver pairs, loosely associated with 
chipselects.
-+               * This is essentially looping over each DIMM.
-+               */
-+              for (; Receiver < 8; Receiver += 2) {
-+                      Addl_Index = (Receiver >> 1) * 3 + 0x10;
-+                      dimm = (Receiver >> 1);
-+
-+                      print_debug_dqs("\t\tTrainMaxRdLatency52: index ", 
Addl_Index, 2);
-+
-+                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
-+                              continue;
-+                      }
-+
-+                      /* Retrieve the total delay values from pass 1 of DQS 
receiver enable training */
-+                      
read_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
-+                      
read_read_dqs_timing_control_registers(current_rdqs_total_delay, dev, Channel, 
dimm, index_reg);
-+
-+                      for (lane = 0; lane < 8; lane++) {
-+                              current_total_delay[lane] += 
current_rdqs_total_delay[lane];
-+                              if (current_total_delay[lane] > 
current_worst_case_total_delay_value) {
-+                                      current_worst_case_total_delay_dimm = 
dimm;
-+                                      current_worst_case_total_delay_value = 
current_total_delay[lane];
-+                              }
-+                      }
-+
-+#if DQS_TRAIN_DEBUG > 0
-+                      for (lane = 0; lane < 8; lane++)
-+                              print_debug_dqs_pair("\t\tTrainMaxRdLatency56: 
Lane ", lane, " current_total_delay ", current_total_delay[lane], 2);
-+#endif
-+              }
-+
-+              /* 2.10.5.8.5.1.1 */
-+              Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel, 1);
-+
-+              /* 2.10.5.8.5.1.[2,3]
-+               * Write the DRAM training pattern to the test address
-+               */
-+              write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, current_worst_case_total_delay_dimm << 1, 0xff);
-+
-+              /* 2.10.5.8.5.1.4
-+               * Incrementally test each MaxRdLatency candidate
-+               */
-+              for (; pDCTstat->CH_MaxRdLat[Channel] < 0x3ff; 
pDCTstat->CH_MaxRdLat[Channel]++) {
-+                      write_max_read_latency_to_registers(pMCTstat, pDCTstat, 
Channel, pDCTstat->CH_MaxRdLat[Channel]);
-+                      read_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff);
-+                      dword = Get_NB32_DCT(dev, Channel, 0x268) & 0x3ffff;
-+                      if (!dword)
-+                              break;
-+                      Set_NB32_index_wait_DCT(dev, Channel, index_reg, 
0x00000050, 0x13131313);
-+              }
-+
-+              /* 2.10.5.8.5.1.5 */
-+              nb_pstate = 0;
-+              mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
-+              if (fam15h_freq_tab[mem_clk] == 0) {
-+                      return;
-+              }
-+              dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 
4)));               /* Retrieve NbDid, NbFid */
-+              nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) 
& 0x1)?2:1);
-+
-+              pDCTstat->CH_MaxRdLat[Channel]++;
-+              pDCTstat->CH_MaxRdLat[Channel] += ((((uint64_t)15 * 
100000000000ULL) / ((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL))
-+                                                       * ((uint64_t)nb_clk * 
1000)) / 1000000000ULL;
-+
-+              write_max_read_latency_to_registers(pMCTstat, pDCTstat, 
Channel, pDCTstat->CH_MaxRdLat[Channel]);
-+      }
-+
-+      if(_DisableDramECC) {
-+              mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
-+      }
-+
-+      if(!_Wrap32Dis) {
-+              msr = HWCR;
-+              _RDMSR(msr, &lo, &hi);
-+              lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
-+              _WRMSR(msr, lo, hi);
-+      }
-+      if(!_SSE2){
-+              cr4 = read_cr4();
-+              cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
-+              write_cr4(cr4);
-+      }
-+
-+#if DQS_TRAIN_DEBUG > 0
-+      {
-+              u8 ChannelDTD;
-+              printk(BIOS_DEBUG, "TrainMaxRdLatency: CH_MaxRdLat:\n");
-+              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
-+                      printk(BIOS_DEBUG, "Channel:%x: %x\n",
-+                             ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]);
-+              }
-+      }
-+#endif
-+
-+      printk(BIOS_DEBUG, "TrainMaxRdLatency: Status %x\n", pDCTstat->Status);
-+      printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrStatus %x\n", 
pDCTstat->ErrStatus);
-+      printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrCode %x\n", 
pDCTstat->ErrCode);
-+      printk(BIOS_DEBUG, "TrainMaxRdLatency: Done\n\n");
-+}
-+
- u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct)
- {
-       if (pDCTstat->DIMMValidDCT[dct] == 0 ) {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-index 3153e46..28cc8f6 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
-@@ -172,6 +172,8 @@ static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
- static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
-                                       struct DCTStatStruc *pDCTstat)
- {
-+      printk(BIOS_DEBUG, "%s: Start\n", __func__);
-+
-       uint8_t DCT0Present;
-       uint8_t DCT1Present;
-       uint32_t dword;
-@@ -313,6 +315,8 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
-                       mct_Wait(15000);        /* Wait for 750us */
-               }
-       }
-+
-+      printk(BIOS_DEBUG, "%s: Done\n", __func__);
- }
- 
- /*
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0096-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
 
b/resources/libreboot/patch/kgpe-d16/0096-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
new file mode 100644
index 0000000..579b106
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0096-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch
@@ -0,0 +1,532 @@
+From e6a4225860ce1c83c5489fc2169fb7dc22225462 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 2 Aug 2015 21:36:24 -0500
+Subject: [PATCH 096/143] northbridge/amd/amdht: Add support for HT3 2.8GHz
+ and up link frequencies
+
+Change-Id: Ifa1592d26ba7deb034046fd3f2a15149117d9a76
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h |    8 ++-
+ src/mainboard/asus/kgpe-d16/cmos.layout      |   30 ++++-----
+ src/northbridge/amd/amdht/h3ffeat.h          |    6 +-
+ src/northbridge/amd/amdht/h3finit.c          |   93 ++++++++++++++++----------
+ src/northbridge/amd/amdht/h3finit.h          |   18 +++--
+ src/northbridge/amd/amdht/h3ncmn.c           |   82 ++++++++++++++++-------
+ src/northbridge/amd/amdht/h3ncmn.h           |    3 +-
+ 7 files changed, 155 insertions(+), 85 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index 1080cfc..bff2efd 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -290,7 +290,13 @@ static const struct {
+ 
+       /* Link Global Retry Control Register */
+       { 0, 0x150, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+-        0x00073900, 0x00073F00 },
++        0x00073900, 0x00073f70 },     /* TotalRetryAttempts = 0x7,
++                                         HtRetryCrcDatInsDynEn = 0x1,
++                                         HtRetryCrcCmdPackDynEn = 0x1,
++                                         HtRetryCrcDatIns = 0x4,
++                                         HtRetryCrcCmdPack = 0x1,
++                                         ForceErrType = 0x0,
++                                         MultRetryErr = 0x0 */
+ 
+       /*  Errata 351
+        * System software should program the Link Extended Control 
Registers[LS2En]
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index f705af2..ec803b6 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -125,21 +125,21 @@ enumerations
+ 10    21    42ms
+ 10    22    84ms
+ 11    0     Auto
+-11    1     2.6GHz
+-11    2     2.4GHz
+-11    3     2.2GHz
+-11    4     2.0GHz
+-11    5     1.8GHz
+-11    6     1.6GHz
+-11    7     1.4GHz
+-11    8     1.2GHz
+-11    9     1.0GHz
+-11    10    800MHz
+-11    11    600MHz
+-11    12    500MHz
+-11    13    400MHz
+-11    14    300MHz
+-11    15    200MHz
++11    1     3.2GHz
++11    2     3.0GHz
++11    3     2.8GHz
++11    4     2.6GHz
++11    5     2.4GHz
++11    6     2.2GHz
++11    7     2.0GHz
++11    8     1.8GHz
++11    9     1.6GHz
++11    10    1.4GHz
++11    11    1.2GHz
++11    12    1.0GHz
++11    13    800MHz
++11    14    600MHz
++11    15    500MHz
+ 12    0     1.5V
+ 12    1     1.35V
+ 12    2     1.25V
+diff --git a/src/northbridge/amd/amdht/h3ffeat.h 
b/src/northbridge/amd/amdht/h3ffeat.h
+index 5d9550b..5dc9916 100644
+--- a/src/northbridge/amd/amdht/h3ffeat.h
++++ b/src/northbridge/amd/amdht/h3ffeat.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -62,6 +63,7 @@
+ #define HTHOST_LINK_CAPABILITY_REG            0x00
+ #define HTHOST_LINK_CONTROL_REG               0x04
+ #define HTHOST_FREQ_REV_REG                   0x08
++#define HTHOST_FREQ_REV_REG_2                 0x1c
+       #define HT_HOST_REV_REV3                0x60
+ #define HTHOST_FEATURE_CAP_REG                        0x0C
+ #define HTHOST_BUFFER_COUNT_REG               0x10
+@@ -127,10 +129,10 @@ typedef struct
+ 
+       /* This section is for keeping track of capabilities and possible 
configurations */
+       BOOL RegangCap;
+-      u16 PrvFrequencyCap;
++      uint32_t PrvFrequencyCap;
+       u8 PrvWidthInCap;
+       u8 PrvWidthOutCap;
+-      u16 CompositeFrequencyCap;
++      uint32_t CompositeFrequencyCap;
+ 
+ } sPortDescriptor;
+ 
+diff --git a/src/northbridge/amd/amdht/h3finit.c 
b/src/northbridge/amd/amdht/h3finit.c
+index 82bf885..14f348f 100644
+--- a/src/northbridge/amd/amdht/h3finit.c
++++ b/src/northbridge/amd/amdht/h3finit.c
+@@ -52,28 +52,32 @@
+ #define APIC_Base_BSP 8
+ #define APIC_Base     0x1b
+ 
+-#define NVRAM_LIMIT_HT_SPEED_200  0xf
+-#define NVRAM_LIMIT_HT_SPEED_300  0xe
+-#define NVRAM_LIMIT_HT_SPEED_400  0xd
+-#define NVRAM_LIMIT_HT_SPEED_500  0xc
+-#define NVRAM_LIMIT_HT_SPEED_600  0xb
+-#define NVRAM_LIMIT_HT_SPEED_800  0xa
+-#define NVRAM_LIMIT_HT_SPEED_1000 0x9
+-#define NVRAM_LIMIT_HT_SPEED_1200 0x8
+-#define NVRAM_LIMIT_HT_SPEED_1400 0x7
+-#define NVRAM_LIMIT_HT_SPEED_1600 0x6
+-#define NVRAM_LIMIT_HT_SPEED_1800 0x5
+-#define NVRAM_LIMIT_HT_SPEED_2000 0x4
+-#define NVRAM_LIMIT_HT_SPEED_2200 0x3
+-#define NVRAM_LIMIT_HT_SPEED_2400 0x2
+-#define NVRAM_LIMIT_HT_SPEED_2600 0x1
++#define NVRAM_LIMIT_HT_SPEED_200  0x12
++#define NVRAM_LIMIT_HT_SPEED_300  0x11
++#define NVRAM_LIMIT_HT_SPEED_400  0x10
++#define NVRAM_LIMIT_HT_SPEED_500  0xf
++#define NVRAM_LIMIT_HT_SPEED_600  0xe
++#define NVRAM_LIMIT_HT_SPEED_800  0xd
++#define NVRAM_LIMIT_HT_SPEED_1000 0xc
++#define NVRAM_LIMIT_HT_SPEED_1200 0xb
++#define NVRAM_LIMIT_HT_SPEED_1400 0xa
++#define NVRAM_LIMIT_HT_SPEED_1600 0x9
++#define NVRAM_LIMIT_HT_SPEED_1800 0x8
++#define NVRAM_LIMIT_HT_SPEED_2000 0x7
++#define NVRAM_LIMIT_HT_SPEED_2200 0x6
++#define NVRAM_LIMIT_HT_SPEED_2400 0x5
++#define NVRAM_LIMIT_HT_SPEED_2600 0x4
++#define NVRAM_LIMIT_HT_SPEED_2800 0x3
++#define NVRAM_LIMIT_HT_SPEED_3000 0x2
++#define NVRAM_LIMIT_HT_SPEED_3200 0x1
+ #define NVRAM_LIMIT_HT_SPEED_AUTO 0x0
+ 
+-static const uint16_t ht_speed_limit[16] =
+-      {0xFFFF, 0x7FFF, 0x3FFF, 0x1FFF,
+-       0x0FFF, 0x07FF, 0x03FF, 0x01FF,
+-       0x00FF, 0x007F, 0x003F, 0x001F,
+-       0x000F, 0x0007, 0x0003, 0x0001};
++static const uint32_t ht_speed_limit[20] =
++      {0xFFFFF, 0xFFFFF, 0x7FFFF, 0x3FFFF,
++       0x0FFFF, 0x07FFF, 0x03FFF, 0x01FFF,
++       0x00FFF, 0x007FF, 0x003FF, 0x001FF,
++       0x000FF, 0x0007F, 0x0003F, 0x0001F,
++       0x0000F, 0x00007, 0x00003, 0x00001};
+ 
+ static const struct ht_speed_limit_map_t {
+       uint16_t mhz;
+@@ -95,9 +99,12 @@ static const struct ht_speed_limit_map_t {
+       {2200, NVRAM_LIMIT_HT_SPEED_2200},
+       {2400, NVRAM_LIMIT_HT_SPEED_2400},
+       {2600, NVRAM_LIMIT_HT_SPEED_2600},
++      {2800, NVRAM_LIMIT_HT_SPEED_2800},
++      {3000, NVRAM_LIMIT_HT_SPEED_3000},
++      {3200, NVRAM_LIMIT_HT_SPEED_3200},
+ };
+ 
+-static const uint16_t ht_speed_mhz_to_hw(uint16_t mhz)
++static const uint32_t ht_speed_mhz_to_hw(uint16_t mhz)
+ {
+       size_t i;
+       for (i = 0; i < ARRAY_SIZE(ht_speed_limit_map); i++)
+@@ -456,7 +463,7 @@ static void htDiscoveryFloodFill(sMainData *pDat)
+               /* Set currentNode's NodeID field to currentNode */
+               pDat->nb->writeNodeID(currentNode, currentNode, pDat->nb);
+ 
+-              /* Enable routing tables on currentNode*/
++              /* Enable routing tables on currentNode */
+               pDat->nb->enableRoutingTables(currentNode, pDat->nb);
+ 
+               for (currentLinkID = 0; currentLinkID < pDat->nb->maxLinks; 
currentLinkID++)
+@@ -1431,19 +1438,30 @@ static void regangLinks(sMainData *pDat)
+ static void selectOptimalWidthAndFrequency(sMainData *pDat)
+ {
+       u8 i, j;
+-      u32 temp;
+-      u16 cbPCBFreqLimit;
+-      u16 cbPCBFreqLimit_NVRAM;
++      uint32_t temp;
++      uint32_t cbPCBFreqLimit;
++      uint32_t cbPCBFreqLimit_NVRAM;
+       u8 cbPCBABDownstreamWidth;
+       u8 cbPCBBAUpstreamWidth;
+ 
+-      cbPCBFreqLimit_NVRAM = 0xFFFF;
++      cbPCBFreqLimit_NVRAM = 0xfffff;
+       if (get_option(&temp, "hypertransport_speed_limit") == CB_SUCCESS)
+               cbPCBFreqLimit_NVRAM = ht_speed_limit[temp & 0xf];
+ 
++      if (!is_fam15h()) {
++              /* FIXME
++               * By default limit frequency to 2.6 GHz as there are residual
++               * problems with HT v3.1 implementation on at least some Socket 
G34
++               * mainboards / Fam10h CPUs.
++               * Debug the issues and reenable this...
++               */
++              if (cbPCBFreqLimit_NVRAM > 0xffff)
++                      cbPCBFreqLimit_NVRAM = 0xffff;
++      }
++
+       for (i = 0; i < pDat->TotalLinks*2; i += 2)
+       {
+-              cbPCBFreqLimit = 0xFFFF;                // Maximum allowed by 
autoconfiguration
++              cbPCBFreqLimit = 0xfffff;               // Maximum allowed by 
autoconfiguration
+               if (pDat->HtBlock->ht_link_configuration)
+                       cbPCBFreqLimit = 
ht_speed_mhz_to_hw(pDat->HtBlock->ht_link_configuration->ht_speed_limit);
+               cbPCBFreqLimit = min(cbPCBFreqLimit, cbPCBFreqLimit_NVRAM);
+@@ -1488,17 +1506,18 @@ static void selectOptimalWidthAndFrequency(sMainData 
*pDat)
+                       }
+               }
+ 
+-
+               temp = pDat->PortList[i].PrvFrequencyCap;
+               temp &= pDat->PortList[i+1].PrvFrequencyCap;
+               temp &= cbPCBFreqLimit;
+-              pDat->PortList[i].CompositeFrequencyCap = (u16)temp;
+-              pDat->PortList[i+1].CompositeFrequencyCap = (u16)temp;
++              pDat->PortList[i].CompositeFrequencyCap = temp;
++              pDat->PortList[i+1].CompositeFrequencyCap = temp;
+ 
+               ASSERT (temp != 0);
+-              for (j = 15; ; j--)
++              for (j = 19; ; j--)
+               {
+-                      if (temp & ((u32)1 << j))
++                      if ((j == 16) || (j == 15))
++                              continue;
++                      if (temp & ((uint32_t)1 << j))
+                               break;
+               }
+ 
+@@ -1642,12 +1661,14 @@ static void hammerSublinkFixup(sMainData *pDat)
+                                       /*  Remove hiFreq from the list of 
valid frequencies */
+                                       temp = temp & ~((uint32)1 << hiFreq);
+                                       ASSERT (temp != 0);
+-                                      
pDat->PortList[hiIndex].CompositeFrequencyCap = (uint16)temp;
+-                                      
pDat->PortList[hiIndex+1].CompositeFrequencyCap = (uint16)temp;
++                                      
pDat->PortList[hiIndex].CompositeFrequencyCap = temp;
++                                      
pDat->PortList[hiIndex+1].CompositeFrequencyCap = temp;
+ 
+-                                      for (k = 15; ; k--)
++                                      for (k = 19; ; k--)
+                                       {
+-                                              if (temp & ((u32)1 << k))
++                                              if ((j == 16) || (j == 15))
++                                                      continue;
++                                              if (temp & ((uint32_t)1 << k))
+                                                       break;
+                                       }
+ 
+diff --git a/src/northbridge/amd/amdht/h3finit.h 
b/src/northbridge/amd/amdht/h3finit.h
+index 58065b3..462f3e3 100644
+--- a/src/northbridge/amd/amdht/h3finit.h
++++ b/src/northbridge/amd/amdht/h3finit.h
+@@ -53,6 +53,9 @@
+ #define HT_FREQUENCY_2200M    12
+ #define HT_FREQUENCY_2400M    13
+ #define HT_FREQUENCY_2600M    14
++#define HT_FREQUENCY_2800M    17
++#define HT_FREQUENCY_3000M    18
++#define HT_FREQUENCY_3200M    19
+ 
+ /* Frequency Limit equates for call backs which take a frequency supported 
mask. */
+ #define HT_FREQUENCY_LIMIT_200M       1
+@@ -69,6 +72,9 @@
+ #define HT_FREQUENCY_LIMIT_2200M      0x1FFF
+ #define HT_FREQUENCY_LIMIT_2400M      0x3FFF
+ #define HT_FREQUENCY_LIMIT_2600M      0x7FFF
++#define HT_FREQUENCY_LIMIT_2800M      0x3FFFF
++#define HT_FREQUENCY_LIMIT_3000M      0x7FFFF
++#define HT_FREQUENCY_LIMIT_3200M      0xFFFFF
+ 
+ /*
+  * Event Notify definitions
+@@ -224,7 +230,7 @@ typedef struct {
+        *      @param[in]  u8  Link      = The Device's link number (0 or 1)
+        *      @param[in,out] u8*  LinkWidthIn  = modify to change the Link 
Witdh In
+        *      @param[in,out] u8*  LinkWidthOut  = modify to change the Link 
Witdh Out
+-       *      @param[in,out] u16* FreqCap = modify to change the link's 
frequency capability
++       *      @param[in,out] u32* FreqCap = modify to change the link's 
frequency capability
+        *
+        * 
---------------------------------------------------------------------------------------
+        */
+@@ -239,7 +245,7 @@ typedef struct {
+               u8 Link,
+               u8 *LinkWidthIn,
+               u8 *LinkWidthOut,
+-              u16 *FreqCap
++              u32 *FreqCap
+       );
+ 
+       
/**----------------------------------------------------------------------------------------
+@@ -262,7 +268,7 @@ typedef struct {
+        *      @param[in]  u8  linkB  = The link on that node
+        *      @param[in,out]  u8*  ABLinkWidthLimit = modify to change the 
Link Witdh In
+        *      @param[in,out]  u8*  BALinkWidthLimit = modify to change the 
Link Witdh Out
+-       *      @param[in,out]  u16* PCBFreqCap  = modify to change the link's 
frequency capability
++       *      @param[in,out]  u32* PCBFreqCap  = modify to change the link's 
frequency capability
+        *
+        * 
---------------------------------------------------------------------------------------
+        */
+@@ -273,7 +279,7 @@ typedef struct {
+               u8 LinkB,
+               u8 *ABLinkWidthLimit,
+               u8 *BALinkWidthLimit,
+-              u16 *PCBFreqCap
++              u32 *PCBFreqCap
+       );
+ 
+       
/**----------------------------------------------------------------------------------------
+@@ -295,7 +301,7 @@ typedef struct {
+        *      @param[in]  u8  Depth  = The depth in the I/O chain from the 
Host
+        *      @param[in,out]  u8* DownstreamLinkWidthLimit = modify to change 
the Link Witdh In
+        *      @param[in,out]  u8* UpstreamLinkWidthLimit  = modify to change 
the Link Witdh Out
+-       *      @param[in,out]  u16* PCBFreqCap = modify to change the link's 
frequency capability
++       *      @param[in,out]  u32* PCBFreqCap = modify to change the link's 
frequency capability
+        *
+        * 
---------------------------------------------------------------------------------------
+        */
+@@ -305,7 +311,7 @@ typedef struct {
+               u8 Depth,
+               u8 *DownstreamLinkWidthLimit,
+               u8 *UpstreamLinkWidthLimit,
+-              u16 *PCBFreqCap
++              u32 *PCBFreqCap
+       );
+ 
+       
/**----------------------------------------------------------------------------------------
+diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
+index a27ee5b..e03e5eb 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.c
++++ b/src/northbridge/amd/amdht/h3ncmn.c
+@@ -1314,7 +1314,7 @@ static u8 convertWidthToBits(u8 value, cNorthBridge *nb)
+  *    @return  Frequency mask
+  *
+  
******************************************************************************/
+-static u16 ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
++static uint32_t ht1NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
+ {
+       /* only up to HT1 speeds */
+       return (HT_FREQUENCY_LIMIT_HT1_ONLY);
+@@ -1335,26 +1335,43 @@ static u16 ht1NorthBridgeFreqMask(u8 node, 
cNorthBridge *nb)
+  *    @return  = Frequency mask
+  *
+  
******************************************************************************/
+-static u16 fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
++static uint32_t fam10NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
+ {
+       u8 nbCOF;
+-      u16 supported;
++      uint32_t supported;
+ 
+       nbCOF = getMinNbCOF();
+       /*
+        * nbCOF is minimum northbridge speed in hundreds of MHz.
+        * HT can not go faster than the minimum speed of the northbridge.
+        */
+-      if ((nbCOF >= 6) && (nbCOF <= 26))
++      if ((nbCOF >= 6) && (nbCOF < 10))
+       {
++              /* Generation 1 HT link frequency */
+               /* Convert frequency to bit and all less significant bits,
+                * by setting next power of 2 and subtracting 1.
+                */
+-              supported = ((u16)1 << ((nbCOF >> 1) + 2)) - 1;
++              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
+       }
+-      else if (nbCOF > 26)
++      else if ((nbCOF >= 10) && (nbCOF <= 32))
+       {
+-              supported = HT_FREQUENCY_LIMIT_2600M;
++              /* Generation 3 HT link frequency
++               * Assume error retry is enabled on all Gen 3 links
++               */
++              if (is_gt_rev_d()) {
++                      nbCOF *= 2;
++                      if (nbCOF > 32)
++                              nbCOF = 32;
++              }
++
++              /* Convert frequency to bit and all less significant bits,
++               * by setting next power of 2 and subtracting 1.
++               */
++              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
++      }
++      else if (nbCOF > 32)
++      {
++              supported = HT_FREQUENCY_LIMIT_3200M;
+       }
+       /* unlikely cases, but include as a defensive measure, also avoid trick 
above */
+       else if (nbCOF == 4)
+@@ -1409,8 +1426,13 @@ static void gatherLinkData(sMainData *pDat, 
cNorthBridge *nb)
+                       pDat->PortList[i].PrvWidthInCap = 
convertBitsToWidth((u8)temp, pDat->nb);
+ 
+                       AmdPCIReadBits(linkBase + HTHOST_FREQ_REV_REG, 31, 16, 
&temp);
+-                      pDat->PortList[i].PrvFrequencyCap = (u16)temp & 0x7FFF
+-                              & 
nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb); /*  Mask off bit 
15, reserved value */
++                      pDat->PortList[i].PrvFrequencyCap = temp & 0x7FFF       
/*  Mask off bit 15, reserved value */
++                              & 
nb->northBridgeFreqMask(pDat->PortList[i].NodeID, pDat->nb);
++                      if (is_gt_rev_d()) {
++                              AmdPCIReadBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 15, 1, &temp);
++                              temp &= 0x7;    /* Mask off reserved values */
++                              pDat->PortList[i].PrvFrequencyCap |= (temp << 
17);
++                      }
+               }
+               else
+               {
+@@ -1467,7 +1489,7 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
+ {
+       u8 i;
+       SBDFO linkBase;
+-      u32 temp, widthin, widthout, bits;
++      u32 temp, temp2, frequency_index, widthin, widthout, bits;
+ 
+       for (i = 0; i < pDat->TotalLinks*2; i++)
+       {
+@@ -1528,10 +1550,19 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
+               temp = pDat->PortList[i].SelFrequency;
+               if (pDat->PortList[i].Type == PORTLIST_TYPE_CPU)
+               {
+-                      ASSERT((temp >= HT_FREQUENCY_600M && temp <= 
HT_FREQUENCY_2600M)
++                      ASSERT((temp >= HT_FREQUENCY_600M && temp <= 
HT_FREQUENCY_3200M)
+                               || (temp == HT_FREQUENCY_200M) || (temp == 
HT_FREQUENCY_400M));
++                      frequency_index = temp;
++                      if (temp > 0xf) {
++                              temp2 = (temp >> 4) & 0x1;
++                              temp &= 0xf;
++                      } else {
++                              temp2 = 0x0;
++                      }
++                      if (is_gt_rev_d())
++                              AmdPCIWriteBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 0, 0, &temp2);
+                       AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, 
&temp);
+-                      if (temp > HT_FREQUENCY_1000M) /*  Gen1 = 200MHz -> 
1000MHz, Gen3 = 1200MHz -> 2600MHz */
++                      if (frequency_index > HT_FREQUENCY_1000M) /*  Gen1 = 
200MHz -> 1000MHz, Gen3 = 1200MHz -> 3200MHz */
+                       {
+                               /* Enable  for Gen3 frequencies */
+                               temp = 1;
+@@ -1541,27 +1572,27 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
+                               /* Disable  for Gen1 frequencies */
+                               temp = 0;
+                       }
+-                              /* HT3 retry mode enable / disable */
+-                              
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
+-                                                      
makePCIBusFromNode(pDat->PortList[i].NodeID),
+-                                                      
makePCIDeviceFromNode(pDat->PortList[i].NodeID),
+-                                                      CPU_HTNB_FUNC_00,
+-                                                      
REG_HT_LINK_RETRY0_0X130 + 4*pDat->PortList[i].Link),
+-                                                      0, 0, &temp);
+-                              /* and Scrambling enable / disable */
+-                              
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
++                      /* HT3 retry mode enable / disable */
++                      
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
+                                               
makePCIBusFromNode(pDat->PortList[i].NodeID),
+                                               
makePCIDeviceFromNode(pDat->PortList[i].NodeID),
+                                               CPU_HTNB_FUNC_00,
+-                                              REG_HT_LINK_EXT_CONTROL0_0X170 
+ 4*pDat->PortList[i].Link),
+-                                              3, 3, &temp);
++                                              REG_HT_LINK_RETRY0_0X130 + 
4*pDat->PortList[i].Link),
++                                              0, 0, &temp);
++                      /* and Scrambling enable / disable */
++                      
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
++                                      
makePCIBusFromNode(pDat->PortList[i].NodeID),
++                                      
makePCIDeviceFromNode(pDat->PortList[i].NodeID),
++                                      CPU_HTNB_FUNC_00,
++                                      REG_HT_LINK_EXT_CONTROL0_0X170 + 
4*pDat->PortList[i].Link),
++                                      3, 3, &temp);
+               }
+               else
+               {
+                       SBDFO currentPtr;
+                       BOOL isFound;
+ 
+-                      ASSERT(temp <= HT_FREQUENCY_2600M);
++                      ASSERT(temp <= HT_FREQUENCY_3200M);
+                       /* Write the frequency setting */
+                       AmdPCIWriteBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 11, 
8, &temp);
+ 
+@@ -1722,6 +1753,9 @@ static void fam0fWriteHTLinkCmdBufferAlloc(u8 node, u8 
link, u8 req, u8 preq, u8
+       /* Probe Command Buffers */
+       temp = prb;
+       AmdPCIWriteBits(currentPtr, 15, 12, &temp);
++      /* LockBc */
++      temp = 1;
++      AmdPCIWriteBits(currentPtr, 31, 31, &temp);
+ }
+ #endif /* HT_BUILD_NC_ONLY */
+ 
+diff --git a/src/northbridge/amd/amdht/h3ncmn.h 
b/src/northbridge/amd/amdht/h3ncmn.h
+index 7f8f4d1..5795e9a 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.h
++++ b/src/northbridge/amd/amdht/h3ncmn.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -107,7 +108,7 @@ struct cNorthBridge
+       /* Public Interfaces for northbridge clients, Optimization */
+       u8 (*convertBitsToWidth)(u8 value, cNorthBridge *nb);
+       u8 (*convertWidthToBits)(u8 value, cNorthBridge *nb);
+-      u16 (*northBridgeFreqMask)(u8 node, cNorthBridge *nb);
++      uint32_t (*northBridgeFreqMask)(u8 node, cNorthBridge *nb);
+       void (*gatherLinkData)(sMainData *pDat, cNorthBridge *nb);
+       void (*setLinkData)(sMainData *pDat, cNorthBridge *nb);
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0097-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
 
b/resources/libreboot/patch/kgpe-d16/0097-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
new file mode 100644
index 0000000..2afd17d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0097-amd-family_10h-family_15h-Fix-poor-performance-on-Fa.patch
@@ -0,0 +1,124 @@
+From 92145a02934f4e8d3044f734b001af21bdf50962 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 7 Aug 2015 19:04:49 -0500
+Subject: [PATCH 097/143] amd/family_10h-family_15h: Fix poor performance on
+ Family 15h CPUs
+
+Change-Id: Ieb1f1fb5653651c98764de79636669802578d5f9
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h  |   13 +++++--
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |   45 +++++++++++++++++++++++--
+ 2 files changed, 52 insertions(+), 6 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index bff2efd..4868c5c 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -535,15 +535,15 @@ static const struct {
+       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0x00800756, 0x00F3FFFF },
+ 
+-      { 3, 0x140, AMD_FAM15_ALL, AMD_PTYPE_ALL,
+-        0x00a11755, 0x00f3ffff },
+-
+       { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x00C37756, 0x00F3FFFF },
+ 
+       { 3, 0x144, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x00000036, 0x000000FF },
+ 
++      { 3, 0x140, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00a11755, 0x00f3ffff },
++
+       /* Errata 281 Workaround */
+       { 3, 0x144, ( AMD_DR_B0 | AMD_DR_B1),
+        AMD_PTYPE_SVR, 0x00000001, 0x0000000F },
+@@ -555,6 +555,13 @@ static const struct {
+       { 3, 0x148, AMD_FAM10_ALL, AMD_PTYPE_UMA,
+         0x8000052A, 0xD5FFFFFF },
+ 
++      /* Core Interface Buffer Count */
++      { 3, 0x1a0, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00034004, 0x00037007 },     /* CpuToNbFreeBufCnt = 0x3,
++                                         L3ToSriReqCBC = 0x4,
++                                         L3FreeListCBC = default,
++                                         CpuCmdBufCnt = 0x4 */
++
+       /* ACPI Power State Control Reg1 */
+       { 3, 0x80, AMD_FAM10_ALL, AMD_PTYPE_ALL,
+         0xE6002200, 0xFFFFFFFF },
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index d770f38..67893ca1 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -847,8 +847,9 @@ static BOOL AMD_CpuFindCapability(u8 node, u8 cap_count, 
u8 * offset)
+  */
+ static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
+ {
+-      u32 val;
+-      u32 linktype = 0;
++      uint32_t val;
++      uint32_t val2;
++      uint32_t linktype = 0;
+ 
+       /* Check connect, init and coherency */
+       val = pci_read_config32(NODE_PCI(node, 0), regoff + 0x18);
+@@ -863,8 +864,13 @@ static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
+       if (linktype) {
+               /* Check gen3 */
+               val = pci_read_config32(NODE_PCI(node, 0), regoff + 0x08);
++              val = (val >> 8) & 0xf;
++              if (is_gt_rev_d()) {
++                      val2 = pci_read_config32(NODE_PCI(node, 0), regoff + 
0x1c);
++                      val |= (val2 & 0x1) << 4;
++              }
+ 
+-              if (((val >> 8) & 0x0F) > 6)
++              if (val > 6)
+                       linktype |= HTPHY_LINKTYPE_HT3;
+               else
+                       linktype |= HTPHY_LINKTYPE_HT1;
+@@ -1151,6 +1157,39 @@ static void cpuSetAMDPCI(u8 node)
+               pci_write_config32(NODE_PCI(node, 3), 0xd4, dword);
+       }
+ 
++      if (revision & AMD_FAM15_ALL) {
++              uint32_t f5x80;
++              uint8_t cu_enabled;
++              uint8_t compute_unit_count = 0;
++              uint8_t compute_unit_buffer_count;
++
++              /* Determine the number of active compute units on this node */
++              f5x80 = pci_read_config32(NODE_PCI(node, 5), 0x80);
++              cu_enabled = f5x80 & 0xf;
++              if (cu_enabled == 0x1)
++                      compute_unit_count = 1;
++              if (cu_enabled == 0x3)
++                      compute_unit_count = 2;
++              if (cu_enabled == 0x7)
++                      compute_unit_count = 3;
++              if (cu_enabled == 0xf)
++                      compute_unit_count = 4;
++
++              if (compute_unit_count == 1)
++                      compute_unit_buffer_count = 0x1c;
++              else if (compute_unit_count == 2)
++                      compute_unit_buffer_count = 0x18;
++              else if (compute_unit_count == 3)
++                      compute_unit_buffer_count = 0x14;
++              else
++                      compute_unit_buffer_count = 0x10;
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0x1a0);
++              dword &= ~(0x1f << 4);                  /* L3FreeListCBC = 
compute_unit_buffer_count */
++              dword |= (compute_unit_buffer_count << 4);
++              pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
++      }
++
+       printk(BIOS_DEBUG, " done\n");
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0097-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
 
b/resources/libreboot/patch/kgpe-d16/0097-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
deleted file mode 100644
index 57d5ede..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0097-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From b9bcbf70cef87afd830e156d5081839fc066b89c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 7 Aug 2015 19:05:45 -0500
-Subject: [PATCH 097/139] northbridge/amd/amdht: Fix poor performance on Family
- 15h CPUs
-
-Change-Id: I37db191c144c81aba5d4a1e6291db5669a35a31a
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdht/h3ncmn.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
-index e03e5eb..e377ff2 100644
---- a/src/northbridge/amd/amdht/h3ncmn.c
-+++ b/src/northbridge/amd/amdht/h3ncmn.c
-@@ -1559,6 +1559,10 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
-                       } else {
-                               temp2 = 0x0;
-                       }
-+                      /* NOTE
-+                       * The Family 15h BKDG Rev. 3.14 is wrong
-+                       * Freq[4] must be set before Freq[3:0], otherwise the 
register writes will be ignored!
-+                       */
-                       if (is_gt_rev_d())
-                               AmdPCIWriteBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 0, 0, &temp2);
-                       AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, 
&temp);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0098-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0098-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
new file mode 100644
index 0000000..e2b5340
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0098-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch
@@ -0,0 +1,1089 @@
+From 4899f50dac5ae0c4bb9b4fa67e223f245085920c Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 7 Aug 2015 19:05:29 -0500
+Subject: [PATCH 098/143] amd/amdmct/mct_ddr3: Fix poor performance on Family
+ 15h CPUs
+
+Change-Id: Ib6bc197e43e40ba2b923b1eb1229bacafc8be360
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  370 ++++++++++++++++++++----
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |    1 +
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   65 ++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctproc.c  |   49 +++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |  195 ++++++++++++-
+ src/northbridge/amd/amdmct/mct_ddr3/mctwl.c    |    4 +
+ 6 files changed, 604 insertions(+), 80 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 1167976..2ca65ca 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -36,6 +36,8 @@
+  * supported.
+  */
+ 
++// #define DEBUG_DIMM_SPD 1
++
+ static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA);
+ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+@@ -172,7 +174,8 @@ static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dct, 
u32 MrsChipSel);
+ static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat, u8 dimm);
+-static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 
misc2);
++static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat,
++                                      uint8_t dct, uint32_t misc2, uint32_t 
DramControl);
+ static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat);
+ static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstatA, uint8_t 
Pass);
+@@ -1360,6 +1363,8 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+ static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+ {
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       uint32_t dev;
+       uint32_t reg;
+       uint32_t dword;
+@@ -1382,6 +1387,8 @@ static void set_2t_configuration(struct MCTStatStruc 
*pMCTstat,
+       else
+               dword &= ~(0x1 << 20);          /* Clear 2T CMD mode */
+       Set_NB32_DCT(dev, dct, reg, dword);
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ static void precise_ndelay_fam15(struct MCTStatStruc *pMCTstat, uint32_t 
nanoseconds) {
+@@ -2002,6 +2009,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               /* Disable training mode */
+               uint8_t lane;
+               uint8_t dimm;
++              uint16_t sword;
+               uint8_t receiver;
+               uint8_t max_lane;
+               uint8_t ecc_enabled;
+@@ -2016,21 +2024,37 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
+               uint16_t twrwrdd;
+               uint16_t cdd_twrwrdd;
+               uint16_t twrrd;
++              uint16_t cdd_twrrd;
++              uint16_t cdd_trwtto;
+               uint16_t trwtto;
+               uint8_t first_dimm;
+               uint16_t delay;
+               uint16_t delay2;
++              uint8_t min_value;
++              uint8_t write_early;
+               uint8_t read_odt_delay;
+               uint8_t write_odt_delay;
++              uint8_t buffer_data_delay;
++              int16_t latency_difference;
+               uint16_t difference;
+               uint16_t current_total_delay_1[MAX_BYTE_LANES];
+               uint16_t current_total_delay_2[MAX_BYTE_LANES];
++              uint8_t ddr_voltage_index;
++              uint8_t max_dimms_installable;
+ 
+               /* FIXME
+                * This should be platform configurable
+                */
+               uint8_t dimm_event_l_pin_support = 0;
+ 
++              if (pDCTstat->DIMMValidDCT[dct] == 0)
++                      ddr_voltage_index = 1;
++              else
++                      ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, 
dct);
++
++              ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct);
++              max_dimms_installable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
++
+               ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs);
+               if (ecc_enabled)
+                       max_lane = 9;
+@@ -2064,6 +2088,24 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               else
+                       write_odt_delay = 0;
+ 
++              dword = (Get_NB32_DCT(dev, dct, 0xa8) >> 24) & 0x3;
++              write_early = dword / 2;
++
++              latency_difference = Get_NB32_DCT(dev, dct, 0x200) & 0x1f;
++              dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f;
++              latency_difference -= dword;
++
++              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* LRDIMM */
++
++                      /* TODO
++                       * Implement LRDIMM support
++                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.5
++                       */
++              } else {
++                      buffer_data_delay = 0;
++              }
++
+               /* TODO:
+                * Adjust trdrdsddc if four-rank DIMMs are installed per
+                * section 2.10.5.5.1 of the Family 15h BKDG.
+@@ -2099,7 +2141,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               }
+ 
+               /* Convert the difference to MEMCLKs */
+-              cdd_trdrddd = (((cdd_trdrddd >> 5) & 0x1f) + 1) / 2;
++              cdd_trdrddd = (((cdd_trdrddd + (1 << 6) - 1) >> 6) & 0xf);
+ 
+               /* Calculate Trdrddd */
+               delay = (read_odt_delay + 3) * 2;
+@@ -2145,7 +2187,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               }
+ 
+               /* Convert the difference to MEMCLKs */
+-              cdd_twrwrdd = (((cdd_twrwrdd >> 5) & 0x1f) + 1) / 2;
++              cdd_twrwrdd = (((cdd_twrwrdd + (1 << 6) - 1) >> 6) & 0xf);
+ 
+               /* Calculate Twrwrdd */
+               delay = (write_odt_delay + 3) * 2;
+@@ -2164,6 +2206,107 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
+               dword &= ~(0x1 << 18);                                  /* 
DisAutoRefresh = 0 */
+               Set_NB32_DCT(dev, dct, 0x8c, dword);                    /* DRAM 
Timing High */
+ 
++              /* Configure power saving options */
++              dword = Get_NB32_DCT(dev, dct, 0xa8);                   /* Dram 
Miscellaneous 2 */
++              dword |= (0x1 << 22);                                   /* 
PrtlChPDEnhEn = 0x1 */
++              dword |= (0x1 << 21);                                   /* 
AggrPDEn = 0x1 */
++              Set_NB32_DCT(dev, dct, 0xa8, dword);                    /* Dram 
Miscellaneous 2 */
++
++              /* Configure partial power down delay */
++              dword = Get_NB32(dev, 0x244);                           /* DRAM 
Controller Miscellaneous 3 */
++              dword &= ~0xf;                                          /* 
PrtlChPDDynDly = 0x2 */
++              dword |= 0x2;
++              Set_NB32(dev, 0x244, dword);                            /* DRAM 
Controller Miscellaneous 3 */
++
++              /* Configure power save delays */
++              delay = 0xa;
++              delay2 = 0x3;
++
++              /* Family 15h BKDG Table 214 */
++              if ((pDCTstat->Status & (1 << SB_Registered))
++                      || (pDCTstat->Status & (1 << SB_LoadReduced))) {
++                      if (memclk_index <= 0x6) {
++                              if (ddr_voltage_index < 0x4)
++                                      /* 1.5 or 1.35V */
++                                      delay2 = 0x3;
++                              else
++                                      /* 1.25V */
++                                      delay2 = 0x4;
++                      }
++                      else if ((memclk_index == 0xa)
++                              || (memclk_index == 0xe))
++                              delay2 = 0x4;
++                      else if (memclk_index == 0x12)
++                              delay2 = 0x5;
++                      else if (memclk_index == 0x16)
++                              delay2 = 0x6;
++              } else {
++                      if (memclk_index <= 0x6)
++                              delay2 = 0x3;
++                      else if ((memclk_index == 0xa)
++                              || (memclk_index == 0xe))
++                              delay2 = 0x4;
++                      else if (memclk_index == 0x12)
++                              delay2 = 0x5;
++                      else if (memclk_index == 0x16)
++                              delay2 = 0x6;
++              }
++
++              /* Family 15h BKDG Table 215 */
++              if (memclk_index <= 0x6)
++                      delay = 0xa;
++              else if (memclk_index == 0xa)
++                      delay = 0xd;
++              else if (memclk_index == 0xe)
++                      delay = 0x10;
++              else if (memclk_index == 0x12)
++                      delay = 0x14;
++              else if (memclk_index == 0x16)
++                      delay = 0x17;
++
++              dword = Get_NB32_DCT(dev, dct, 0x248);                  /* Dram 
Power Management 0 */
++              dword &= ~(0x3f << 24);                                 /* 
AggrPDDelay = 0x0 */
++              dword &= ~(0x3f << 16);                                 /* 
PchgPDEnDelay = 0x1 */
++              dword |= (0x1 << 16);
++              dword &= ~(0x1f << 8);                                  /* 
Txpdll = delay */
++              dword |= ((delay & 0x1f) << 8);
++              dword &= ~0xf;                                          /* Txp 
= delay2 */
++              dword |= delay2 & 0xf;
++              Set_NB32_DCT(dev, dct, 0x248, dword);                   /* Dram 
Power Management 0 */
++
++              /* Family 15h BKDG Table 216 */
++              if (memclk_index <= 0x6) {
++                      delay = 0x5;
++                      delay2 = 0x3;
++              }
++              else if (memclk_index == 0xa) {
++                      delay = 0x6;
++                      delay2 = 0x3;
++              }
++              else if (memclk_index == 0xe) {
++                      delay = 0x7;
++                      delay2 = 0x4;
++              }
++              else if (memclk_index == 0x12) {
++                      delay = 0x8;
++                      delay2 = 0x4;
++              }
++              else if (memclk_index == 0x16) {
++                      delay = 0xa;
++                      delay2 = 0x5;
++              }
++
++              dword = Get_NB32_DCT(dev, dct, 0x24c);                  /* Dram 
Power Management 1 */
++              dword &= ~(0x3f << 24);                                 /* 
Tcksrx = delay */
++              dword |= ((delay & 0x3f) << 24);
++              dword &= ~(0x3f << 16);                                 /* 
Tcksre = delay */
++              dword |= ((delay & 0x3f) << 16);
++              dword &= ~(0x3f << 8);                                  /* 
Tckesr = delay2 + 1 */
++              dword |= (((delay2 + 1) & 0x3f) << 8);
++              dword &= ~0xf;                                          /* Tpd 
= delay2 */
++              dword |= delay2 & 0xf;
++              Set_NB32_DCT(dev, dct, 0x24c, dword);                   /* Dram 
Power Management 1 */
++
+               dword = Get_NB32_DCT(dev, dct, 0x94);                   /* DRAM 
Configuration High */
+               dword |= (0xf << 24);                                   /* 
DcqBypassMax = 0xf */
+               dword |= (0x1 << 22);                                   /* 
BankSwizzleMode = 1 */
+@@ -2216,15 +2359,98 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
+                       }
+               }
+ 
+-              /* TODO
+-               * Calculate Twrrd per section 2.10.5.5.3 of the Family 15h BKDG
+-               */
+-              twrrd = 0xb;
++              /* Calculate the Critical Delay Difference for Twrrd */
++              cdd_twrrd = 0;
++              for (receiver = 0; receiver < 8; receiver += 2) {
++                      dimm = (receiver >> 1);
+ 
+-              /* TODO
+-               * Calculate TrwtTO per section 2.10.5.5.4 of the Family 15h 
BKDG
+-               */
+-              trwtto = 0x16;
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
++                              continue;
++
++                      
read_dqs_write_timing_control_registers(current_total_delay_1, dev, dct, dimm, 
index_reg);
++                      
read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, 
dimm, index_reg);
++
++                      for (lane = 0; lane < max_lane; lane++) {
++                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
++                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
++                              else
++                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
++
++                              if (difference > cdd_twrrd)
++                                      cdd_twrrd = difference;
++                      }
++              }
++
++              /* Convert the difference to MEMCLKs */
++              cdd_twrrd = (((cdd_twrrd + (1 << 6) - 1) >> 6) & 0xf);
++
++              /* Fam15h BKDG section 2.10.5.5.3 */
++              if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* LRDIMM */
++
++                      /* TODO
++                       * Implement LRDIMM support
++                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.5
++                       */
++                      twrrd = 0xb;
++              } else {
++                      sword = (((int16_t)cdd_twrrd + 1 - 
((int16_t)write_early * 2)) + 1) / 2;
++                      if (sword < 0)
++                              sword = 0;
++                      if (((uint16_t)sword) > write_odt_delay)
++                              dword = sword;
++                      else
++                              dword = write_odt_delay;
++                      dword += 3;
++                      if (latency_difference < dword) {
++                              dword -= latency_difference;
++                              if (dword < 1)
++                                      twrrd = 1;
++                              else
++                                      twrrd = dword;
++                      } else {
++                              twrrd = 1;
++                      }
++              }
++
++              /* Calculate the Critical Delay Difference for TrwtTO */
++              cdd_trwtto = 0;
++              for (receiver = 0; receiver < 8; receiver += 2) {
++                      dimm = (receiver >> 1);
++
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, 
receiver))
++                              continue;
++
++                      
read_dqs_receiver_enable_control_registers(current_total_delay_1, dev, dct, 
dimm, index_reg);
++                      
read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, 
index_reg);
++
++                      for (lane = 0; lane < max_lane; lane++) {
++                              if (current_total_delay_1[lane] > 
current_total_delay_2[lane])
++                                      difference = 
current_total_delay_1[lane] - current_total_delay_2[lane];
++                              else
++                                      difference = 
current_total_delay_2[lane] - current_total_delay_1[lane];
++
++                              if (difference > cdd_trwtto)
++                                      cdd_trwtto = difference;
++                      }
++              }
++
++              /* Convert the difference to MEMCLKs */
++              cdd_trwtto = (((cdd_trwtto + (1 << 6) - 1) >> 6) & 0xf);
++
++              /* Fam15h BKDG section 2.10.5.5.4 */
++              if (max_dimms_installable == 1)
++                      min_value = 0;
++              else
++                      min_value = read_odt_delay + buffer_data_delay;
++              sword = (((int16_t)cdd_trwtto - 1 + ((int16_t)write_early * 2)) 
+ 1) / 2;
++              sword += latency_difference + 3;
++              if (sword < 0)
++                      sword = 0;
++              if (((uint16_t)sword) > min_value)
++                      trwtto = (uint16_t)sword;
++              else
++                      trwtto = min_value;
+ 
+               dword = Get_NB32_DCT(dev, dct, 0xa4);                   /* DRAM 
Controller Temperature Throttle */
+               dword &= ~(0x1 << 11);                                  /* 
BwCapEn = 0 */
+@@ -2235,6 +2461,7 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               dword = Get_NB32_DCT(dev, dct, 0x110);                  /* DRAM 
Controller Select Low */
+               dword &= ~(0x1 << 2);                                   /* 
DctSelIntLvEn = interleave_channels */
+               dword |= (interleave_channels & 0x1) << 2;
++              dword |= (0x3 << 6);                                    /* 
DctSelIntLvAddr = 0x3 */
+               Set_NB32_DCT(dev, dct, 0x110, dword);                   /* DRAM 
Controller Select Low */
+ 
+               /* NOTE
+@@ -2242,22 +2469,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+                * otherwise semi-random lockups will occur due to 
misconfigured scrubbing hardware!
+                */
+ 
+-              /* FIXME
+-               * The BKDG-recommended settings cause memory corruption on the 
ASUS KGPE-D16.
+-               * Investigate and fix...
+-               */
+-#if 0
+-              /* Fam15h BKDG section 2.10.5.5.1 */
+-              dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
+-              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0x1 */
+-              dword |= (0x1 << 24);
+-              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = trdrdsddc */
+-              dword |= ((trdrdsddc & 0xf) << 16);
+-              dword &= ~(0xf);                                        /* 
TrdrdDd = trdrddd */
+-              dword |= (trdrddd & 0xf);
+-              Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
+-#endif
+-
+               /* Fam15h BKDG section 2.10.5.5.2 */
+               dword = Get_NB32_DCT(dev, dct, 0x214);                  /* DRAM 
Timing 4 */
+               dword &= ~(0xf << 16);                                  /* 
TwrwrSdSc = 0x1 */
+@@ -2270,8 +2481,14 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+ 
+               /* Fam15h BKDG section 2.10.5.5.3 */
+               dword = Get_NB32_DCT(dev, dct, 0x218);                  /* DRAM 
Timing 5 */
++              dword &= ~(0xf << 24);                                  /* 
TrdrdSdSc = 0x1 */
++              dword |= (0x1 << 24);
++              dword &= ~(0xf << 16);                                  /* 
TrdrdSdDc = trdrdsddc */
++              dword |= ((trdrdsddc & 0xf) << 16);
+               dword &= ~(0xf << 8);                                   /* 
Twrrd = twrrd */
+               dword |= ((twrrd & 0xf) << 8);
++              dword &= ~(0xf);                                        /* 
TrdrdDd = trdrddd */
++              dword |= (trdrddd & 0xf);
+               Set_NB32_DCT(dev, dct, 0x218, dword);                   /* DRAM 
Timing 5 */
+ 
+               /* Fam15h BKDG section 2.10.5.5.4 */
+@@ -2282,12 +2499,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc 
*pMCTstat,
+               dword |= ((((dword >> 8) & 0x1f) + 1) << 16);
+               Set_NB32_DCT(dev, dct, 0x21c, dword);                   /* DRAM 
Timing 6 */
+ 
+-              /* Configure partial power down delay */
+-              dword = Get_NB32(dev, 0x244);                           /* DRAM 
Controller Miscellaneous 3 */
+-              dword &= ~0xf;                                          /* 
PrtlChPDDynDly = 0x2 */
+-              dword |= 0x2;
+-              Set_NB32(dev, 0x244, dword);                            /* DRAM 
Controller Miscellaneous 3 */
+-
+               /* Enable prefetchers */
+               dword = Get_NB32(dev, 0x11c);                           /* 
Memory Controller Configuration High */
+               dword &= ~(0x1 << 13);                                  /* 
PrefIoDis = 0 */
+@@ -2376,6 +2587,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
+ 
+               mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
+ 
++              TrainMaxRdLatency_En_D(pMCTstat, pDCTstatA);
++
+               if (is_fam15h())
+                       exit_training_mode_fam15(pMCTstat, pDCTstatA);
+               else
+@@ -2953,6 +3166,13 @@ static void ClearDCT_D(struct MCTStatStruc *pMCTstat,
+       }
+ 
+       while(reg < reg_end) {
++              if ((reg & 0xFF) == 0x84) {
++                      if (is_fam15h()) {
++                              val = Get_NB32_DCT(dev, dct, reg);
++                              val &= ~(0x1 << 23);    /* Clear PchgPDModeSel 
*/
++                              val &= ~0x3;            /* Clear BurstCtrl */
++                      }
++              }
+               if ((reg & 0xFF) == 0x90) {
+                       if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+                               val = Get_NB32_DCT(dev, dct, reg); /* get 
DRAMConfigLow */
+@@ -3071,14 +3291,30 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ 
+       /* Convert  DRAM CycleTiming values and store into DCT structure */
+       byte = pDCTstat->DIMMAutoSpeed;
+-      if (byte == 7)
+-              tCK16x = 20;
+-      else if (byte == 6)
+-              tCK16x = 24;
+-      else if (byte == 5)
+-              tCK16x = 30;
+-      else
+-              tCK16x = 40;
++      if (is_fam15h()) {
++              if (byte == 0x16)
++                      tCK16x = 17;
++              else if (byte == 0x12)
++                      tCK16x = 20;
++              else if (byte == 0xe)
++                      tCK16x = 24;
++              else if (byte == 0xa)
++                      tCK16x = 30;
++              else if (byte == 0x6)
++                      tCK16x = 40;
++              else
++                      tCK16x = 48;
++      }
++      else {
++              if (byte == 7)
++                      tCK16x = 20;
++              else if (byte == 6)
++                      tCK16x = 24;
++              else if (byte == 5)
++                      tCK16x = 30;
++              else
++                      tCK16x = 40;
++      }
+ 
+       /* Notes:
+        1. All secondary time values given in SPDs are in binary with units of 
ns.
+@@ -3111,7 +3347,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+               val = Max_TrpT;
+       pDCTstat->Trp = val;
+ 
+-      /*Trrd*/
++      /* Trrd */
+       pDCTstat->DIMMTrrd = Trrd;
+       val = Trrd / tCK16x;
+       if (Trrd % tCK16x) {    /* round up number of busclocks */
+@@ -3229,21 +3465,31 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ 
+               dword = Get_NB32_DCT(dev, dct, 0x200);                          
/* DRAM Timing 0 */
+               dword &= ~(0x3f1f1f1f);
+-              dword |= ((pDCTstat->Tras + 0xf) & 0x3f) << 24;                 
/* Tras */
+-              dword |= ((pDCTstat->Trp + 0x5) & 0x1f) << 16;                  
/* Trp */
+-              dword |= ((pDCTstat->Trcd + 0x5) & 0x1f) << 8;                  
/* Trcd */
++              dword |= (pDCTstat->Tras & 0x3f) << 24;                         
/* Tras */
++              val = pDCTstat->Trp;
++              val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
++              dword |= (val & 0x1f) << 16;                                    
/* Trp */
++              dword |= (pDCTstat->Trcd & 0x1f) << 8;                          
/* Trcd */
+               dword |= (pDCTstat->CASL & 0x1f);                               
/* Tcl */
+               Set_NB32_DCT(dev, dct, 0x200, dword);                           
/* DRAM Timing 0 */
+ 
+               dword = Get_NB32_DCT(dev, dct, 0x204);                          
/* DRAM Timing 1 */
+               dword &= ~(0x0f3f0f3f);
+-              dword |= ((pDCTstat->Trtp + 0x4) & 0xf) << 24;                  
/* Trtp */
+-              if (pDCTstat->Tfaw != 0)
+-                      dword |= ((((pDCTstat->Tfaw - 0x1) * 2) + 0x10) & 0x3f) 
<< 16;  /* FourActWindow */
+-              dword |= ((pDCTstat->Trrd + 0x4) & 0xf) << 8;                   
/* Trrd */
+-              dword |= ((pDCTstat->Trc + 0xb) & 0x3f);                        
/* Trc */
++              dword |= (pDCTstat->Trtp & 0xf) << 24;                          
/* Trtp */
++              if (pDCTstat->Tfaw != 0) {
++                      val = pDCTstat->Tfaw;
++                      val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val);
++                      if ((val > 0x5) && (val < 0x2b))
++                              dword |= (val & 0x3f) << 16;                    
/* FourActWindow */
++              }
++              dword |= (pDCTstat->Trrd & 0xf) << 8;                           
/* Trrd */
++              dword |= (pDCTstat->Trc & 0x3f);                                
/* Trc */
+               Set_NB32_DCT(dev, dct, 0x204, dword);                           
/* DRAM Timing 1 */
+ 
++              /* Trfc0-Trfc3 */
++              for (i=0; i<4; i++)
++                      if (pDCTstat->Trfc[i] == 0x0)
++                              pDCTstat->Trfc[i] = 0x4;
+               dword = Get_NB32_DCT(dev, dct, 0x208);                          
/* DRAM Timing 2 */
+               dword &= ~(0x07070707);
+               dword |= (pDCTstat->Trfc[3] & 0x7) << 24;                       
/* Trfc3 */
+@@ -3254,14 +3500,14 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+ 
+               dword = Get_NB32_DCT(dev, dct, 0x20c);                          
/* DRAM Timing 3 */
+               dword &= ~(0x00000f00);
+-              dword |= ((pDCTstat->Twtr + 0x4) & 0xf) << 8;                   
/* Twtr */
++              dword |= (pDCTstat->Twtr & 0xf) << 8;                           
/* Twtr */
+               dword &= ~(0x0000001f);
+               dword |= (Tcwl & 0x1f);                                         
/* Tcwl */
+               Set_NB32_DCT(dev, dct, 0x20c, dword);                           
/* DRAM Timing 3 */
+ 
+               dword = Get_NB32_DCT(dev, dct, 0x22c);                          
/* DRAM Timing 10 */
+               dword &= ~(0x0000001f);
+-              dword |= ((pDCTstat->Twr + 0x4) & 0x1f);                        
/* Twr */
++              dword |= (pDCTstat->Twr & 0x1f);                                
/* Twr */
+               Set_NB32_DCT(dev, dct, 0x22c, dword);                           
/* DRAM Timing 10 */
+ 
+               if (pDCTstat->Speed > 
mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) {
+@@ -3857,6 +4103,8 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+               }
+       }
+ 
++      DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, 
DramConfigMisc2, DramControl);
++
+       printk(BIOS_DEBUG, "AutoConfig_D: DramControl:     %08x\n", 
DramControl);
+       printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo:    %08x\n", 
DramTimingLo);
+       printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc:  %08x\n", 
DramConfigMisc);
+@@ -3868,7 +4116,6 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat,
+       Set_NB32_DCT(dev, dct, 0x78, DramControl);
+       Set_NB32_DCT(dev, dct, 0x88, DramTimingLo);
+       Set_NB32_DCT(dev, dct, 0xa0, DramConfigMisc);
+-      DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, 
DramConfigMisc2);
+       Set_NB32_DCT(dev, dct, 0xa8, DramConfigMisc2);
+       Set_NB32_DCT(dev, dct, 0x90, DramConfigLo);
+       ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
+@@ -5239,6 +5486,16 @@ static void mct_PhyController_Config(struct 
MCTStatStruc *pMCTstat,
+       u32 dev = pDCTstat->dev_dct;
+ 
+       if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3 | 
AMD_FAM15_ALL)) {
++              if (is_fam15h()) {
++                      /* Set F2x[1, 0]98_x0D0F0F13 DllDisEarlyU and 
DllDisEarlyL to save power */
++                      for (index = 0; index < 0x9; index++) {
++                              dword = Get_NB32_index_wait_DCT(dev, dct, 
index_reg, 0x0d0f0013 | (index << 8));
++                              dword |= (0x1 << 1);                            
/* DllDisEarlyU = 1 */
++                              dword |= 0x1;                                   
/* DllDisEarlyL = 1 */
++                              Set_NB32_index_wait_DCT(dev, dct, index_reg, 
0x0d0f0013 | (index << 8), dword);
++                      }
++              }
++
+               if (pDCTstat->Dimmx4Present == 0) {
+                       /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 
0]98_x0D0F0F13 for
+                        * additional power saving when x4 DIMMs are not 
present.
+@@ -5283,8 +5540,9 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+                               mct_ExtMCTConfig_Dx(pDCTstat);
+                       } else {
+                               /* Family 15h CPUs */
+-                              val = 0x0ce00f00 | 0x1 << 29;   /* 
FlushWrOnStpGnt */
+-                              val |= 0x10 << 2;               /* MctWrLimit = 
16 */
++                              val = 0x0ce00f00;               /* 
FlushWrOnStpGnt = 0x0 */
++                              val |= 0x10 << 2;               /* MctWrLimit = 
0x10 */
++                              val |= 0x1;                     /* DctWrLimit = 
0x1 */
+                               Set_NB32(pDCTstat->dev_dct, 0x11c, val);
+ 
+                               val = Get_NB32(pDCTstat->dev_dct, 0x1b0);
+@@ -6524,8 +6782,8 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat,
+ 
+       dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84);
+       if (is_fam15h()) {
+-              dword |= DramMRS;
+               dword &= ~0x00800003;
++              dword |= DramMRS;
+       } else {
+               dword &= ~0x00fc2f8f;
+               dword |= DramMRS;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index 486b16c..ec5658e 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -988,6 +988,7 @@ void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat
+ uint64_t mctGetLogicalCPUID(u32 Node);
+ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
+ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA, u8 Pass);
++void TrainMaxRdLatency_En_D(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstatA);
+ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+ void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstatA);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index c70fa6d..c520515 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -24,6 +24,9 @@ static void 
write_dqs_receiver_enable_control_registers(uint16_t* current_total_
+ static void read_read_dqs_timing_control_registers(uint16_t* 
current_total_delay,
+                       uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t 
index_reg);
+ 
++static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat);
++
+ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u16 like,
+                               u8 scale, u8 ChipSel);
+@@ -218,6 +221,27 @@ void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat,
+       }
+ }
+ 
++void TrainMaxRdLatency_En_D(struct MCTStatStruc *pMCTstat,
++                      struct DCTStatStruc *pDCTstatA)
++{
++      uint8_t node;
++      struct DCTStatStruc *pDCTstat;
++
++      for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
++              pDCTstat = pDCTstatA + node;
++
++              if (pDCTstat->DCTSysLimit) {
++                      if (is_fam15h()) {
++                              dqsTrainMaxRdLatency_SW_Fam15(pMCTstat, 
pDCTstat);
++                      } else {
++                              /* FIXME
++                               * Implement Family 10h MaxRdLatency training
++                               */
++                      }
++              }
++      }
++}
++
+ static void SetEccDQSRdWrPos_D_Fam10(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 ChipSel)
+ {
+@@ -898,7 +922,7 @@ static void TrainDQSRdWrPos_D_Fam10(struct MCTStatStruc 
*pMCTstat,
+  * Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.8.5
+  */
+ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
+-                              struct DCTStatStruc *pDCTstat, uint8_t dct)
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t calc_min)
+ {
+       uint8_t dimm;
+       uint8_t lane;
+@@ -942,7 +966,8 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+               p += (9 - dword);
+ 
+               /* 2.10.5.8.5 (4) */
+-              p += 5;
++              if (!calc_min)
++                      p += 5;
+ 
+               /* 2.10.5.8.5 (5) */
+               dword = Get_NB32_DCT(dev, dct, 0xa8);
+@@ -969,7 +994,8 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+               p += (max_delay >> 5);
+ 
+               /* 2.10.5.8.5 (8) */
+-              p += 5;
++              if (!calc_min)
++                      p += 5;
+ 
+               /* 2.10.5.8.5 (9) */
+               t += 800;
+@@ -980,13 +1006,16 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+               n = (((((uint64_t)p * 
1000000000000ULL)/(((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL) * 2)) + 
((uint64_t)t)) * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
+ 
+               /* 2.10.5.8.5 (11) */
+-              n -= 1;
++              if (!calc_min)
++                      n -= 1;
+ 
+               /* 2.10.5.8.5 (12) */
+-              dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210);
+-              dword &= ~(0x3ff << 22);
+-              dword |= (((n - 1) & 0x3ff) << 22);
+-              Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, dword);
++              if (!calc_min) {
++                      dword = Get_NB32_DCT_NBPstate(dev, dct, nb_pstate, 
0x210);
++                      dword &= ~(0x3ff << 22);
++                      dword |= (((n - 1) & 0x3ff) << 22);
++                      Set_NB32_DCT_NBPstate(dev, dct, nb_pstate, 0x210, 
dword);
++              }
+ 
+               /* Save result for later use */
+               pDCTstat->CH_MaxRdLat[dct] = n - 1;
+@@ -1107,6 +1136,9 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+       } else if (lane < 8) {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
++      } else if (lane == 0xff) {
++              Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
++              Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
+       } else {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
+@@ -1114,8 +1146,9 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+ 
+       dword = Get_NB32_DCT(dev, dct, 0x27c);
+       dword &= ~(0xff);                               /* EccMask = 0 */
+-      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
+-              dword |= 0xff;                          /* EccMask = 0xff */
++      if (lane != 0xff)
++              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
++                      dword |= 0xff;                  /* EccMask = 0xff */
+       Set_NB32_DCT(dev, dct, 0x27c, dword);
+ 
+       dword = Get_NB32_DCT(dev, dct, 0x270);
+@@ -1184,6 +1217,9 @@ static void write_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+       } else if (lane < 8) {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
++      } else if (lane == 0xff) {
++              Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
++              Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
+       } else {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
+@@ -1191,8 +1227,9 @@ static void write_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+ 
+       dword = Get_NB32_DCT(dev, dct, 0x27c);
+       dword &= ~(0xff);                               /* EccMask = 0 */
+-      if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
+-              dword |= 0xff;                          /* EccMask = 0xff */
++      if (lane != 0xff)
++              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
++                      dword |= 0xff;                  /* EccMask = 0xff */
+       Set_NB32_DCT(dev, dct, 0x27c, dword);
+ 
+       dword = Get_NB32_DCT(dev, dct, 0x270);
+@@ -1278,7 +1315,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+       uint32_t dev = pDCTstat->dev_dct;
+ 
+       /* Calculate and program MaxRdLatency */
+-      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct);
++      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, dct, 0);
+ 
+       Errors = 0;
+       dual_rank = 0;
+@@ -1636,7 +1673,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                                       
write_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, 
dimm, index_reg);
+ 
+                                       /* Calculate and program MaxRdLatency */
+-                                      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, 
pDCTstat, dct);
++                                      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, 
pDCTstat, dct, 0);
+ 
+                                       /* 2.10.5.8.3 (4 B) */
+                                       
dqs_results_array[current_phy_phase_delay[lane]] = 
TrainDQSRdWrPos_D_Fam15(pMCTstat, pDCTstat, dct, Receiver, Receiver + 2, lane, 
lane + 1);
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+index 738304e..3da28b3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+@@ -19,7 +19,8 @@
+  */
+ 
+ /* mct_SetDramConfigMisc2_Cx & mct_SetDramConfigMisc2_Dx */
+-u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2)
++u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat,
++                              uint8_t dct, uint32_t misc2, uint32_t 
DramControl)
+ {
+       u32 val;
+ 
+@@ -28,17 +29,47 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, 
u8 dct, u32 misc2)
+       if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) {
+               uint8_t cs_mux_45;
+               uint8_t cs_mux_67;
++              uint32_t f2x80;
+ 
+-              /* BKDG v3.14 Table 200 / Table 201 */
+-              if (MaxDimmsInstallable < 3) {
+-                      cs_mux_45 = 1;
+-                      cs_mux_67 = 1;
+-              } else {
++              misc2 &= ~(0x1 << 28);                  /* FastSelfRefEntryDis 
= 0x0 */
++              if (MaxDimmsInstallable == 3) {
++                      /* FIXME 3 DIMMS per channel unimplemented */
+                       cs_mux_45 = 0;
++              } else {
++                      uint32_t f2x60 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
0x60);
++                      f2x80 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x80);
++                      if ((((f2x80 & 0xf) == 0x7) || ((f2x80 & 0xf) == 0x9))
++                              && ((f2x60 & 0x3) == 0x3))
++                              cs_mux_45 = 1;
++                      else if ((((f2x80 & 0xa) == 0x7) || ((f2x80 & 0xb) == 
0x9))
++                              && ((f2x60 & 0x3) > 0x1))
++                              cs_mux_45 = 1;
++                      else
++                              cs_mux_45 = 0;
++              }
++
++              if (MaxDimmsInstallable == 1) {
++                      cs_mux_67 = 0;
++              } else if (MaxDimmsInstallable == 2) {
++                      uint32_t f2x64 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 
0x64);
++                      f2x80 = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x80);
++                      if (((((f2x80 >> 4) & 0xf) == 0x7) || (((f2x80 >> 4) & 
0xf) == 0x9))
++                              && ((f2x64 & 0x3) == 0x3))
++                              cs_mux_67 = 1;
++                      else if (((((f2x80 >> 4) & 0xa) == 0x7) || (((f2x80 >> 
4) & 0xb) == 0x9))
++                              && ((f2x64 & 0x3) > 0x1))
++                              cs_mux_67 = 1;
++                      else
++                              cs_mux_67 = 0;
++              } else {
++                      /* FIXME 3 DIMMS per channel unimplemented */
+                       cs_mux_67 = 0;
+               }
+-              misc2 |= (cs_mux_45 & 0x1) << 26;
+-              misc2 |= (cs_mux_67 & 0x1) << 27;
++
++              misc2 &= ~(0x1 << 27);          /* CsMux67 = cs_mux_67 */
++              misc2 |= ((cs_mux_67 & 0x1) << 27);
++              misc2 &= ~(0x1 << 26);          /* CsMux45 = cs_mux_45 */
++              misc2 |= ((cs_mux_45 & 0x1) << 26);
+       } else if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
+               if (pDCTstat->Status & (1 << SB_Registered)) {
+                       misc2 |= 1 << SubMemclkRegDly;
+@@ -50,8 +81,8 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 
dct, u32 misc2)
+ 
+               if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
+                       misc2 |= 1 << OdtSwizzle;
+-              val = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x78);
+ 
++              val = DramControl;
+               val &= 7;
+               val = ((~val) & 0xff) + 1;
+               val += 6;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 707e6a9..3ede104 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -1424,7 +1424,7 @@ static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc 
*pMCTstat,
+       }
+ 
+       /* Calculate and program MaxRdLatency */
+-      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel);
++      Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel, 0);
+ 
+       if(_DisableDramECC) {
+               mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
+@@ -1487,6 +1487,199 @@ static void dqsTrainRcvrEn_SW_Fam15(struct 
MCTStatStruc *pMCTstat,
+       printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
+ }
+ 
++static void write_max_read_latency_to_registers(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint16_t latency)
++{
++      uint32_t dword;
++      uint8_t nb_pstate;
++
++      for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
++              dword = Get_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, 
nb_pstate, 0x210);
++              dword &= ~(0x3ff << 22);
++              dword |= ((latency & 0x3ff) << 22);
++              Set_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, nb_pstate, 0x210, 
dword);
++      }
++}
++
++/* DQS MaxRdLatency Training (Family 15h)
++ * Algorithm detailed in:
++ * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.5.1
++ * This algorithm runs at the highest supported MEMCLK.
++ */
++static void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat,
++                              struct DCTStatStruc *pDCTstat)
++{
++      u8 Channel;
++      u8 Addl_Index = 0;
++      u8 Receiver;
++      u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
++      u32 Errors;
++
++      u32 dev;
++      u32 index_reg;
++      u32 ch_start, ch_end;
++      u32 msr;
++      u32 cr4;
++      u32 lo, hi;
++
++      uint32_t dword;
++      uint8_t dimm;
++      uint8_t lane;
++      uint8_t mem_clk;
++      uint32_t nb_clk;
++      uint8_t nb_pstate;
++      uint16_t current_total_delay[MAX_BYTE_LANES];
++      uint16_t current_rdqs_total_delay[MAX_BYTE_LANES];
++      uint8_t current_worst_case_total_delay_dimm;
++      uint16_t current_worst_case_total_delay_value;
++
++      uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 
0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
++
++      print_debug_dqs("\nTrainMaxRdLatency: Node", pDCTstat->Node_ID, 0);
++
++      dev = pDCTstat->dev_dct;
++      index_reg = 0x98;
++      ch_start = 0;
++      ch_end = 2;
++
++      cr4 = read_cr4();
++      if(cr4 & ( 1 << 9)) {   /* save the old value */
++              _SSE2 = 1;
++      }
++      cr4 |= (1 << 9);        /* OSFXSR enable SSE2 */
++      write_cr4(cr4);
++
++      msr = HWCR;
++      _RDMSR(msr, &lo, &hi);
++      /* FIXME: Why use SSEDIS */
++      if(lo & (1 << 17)) {    /* save the old value */
++              _Wrap32Dis = 1;
++      }
++      lo |= (1 << 17);        /* HWCR.wrap32dis */
++      lo &= ~(1 << 15);       /* SSEDIS */
++      _WRMSR(msr, lo, hi);    /* Setting wrap32dis allows 64-bit memory 
references in real mode */
++
++      _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
++
++      Errors = 0;
++      dev = pDCTstat->dev_dct;
++
++      for (Channel = 0; Channel < 2; Channel++) {
++              print_debug_dqs("\tTrainMaxRdLatency51: Node ", 
pDCTstat->Node_ID, 1);
++              print_debug_dqs("\tTrainMaxRdLatency51: Channel ", Channel, 1);
++              pDCTstat->Channel = Channel;
++
++              if (pDCTstat->DIMMValidDCT[Channel] == 0)
++                      continue;
++
++              mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
++
++              Receiver = mct_InitReceiver_D(pDCTstat, Channel);
++
++              /* Find DIMM with worst case receiver enable delays */
++              current_worst_case_total_delay_dimm = 0;
++              current_worst_case_total_delay_value = 0;
++
++              /* There are four receiver pairs, loosely associated with 
chipselects.
++               * This is essentially looping over each DIMM.
++               */
++              for (; Receiver < 8; Receiver += 2) {
++                      Addl_Index = (Receiver >> 1) * 3 + 0x10;
++                      dimm = (Receiver >> 1);
++
++                      print_debug_dqs("\t\tTrainMaxRdLatency52: index ", 
Addl_Index, 2);
++
++                      if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, 
Receiver)) {
++                              continue;
++                      }
++
++                      /* Retrieve the total delay values from pass 1 of DQS 
receiver enable training */
++                      
read_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, 
dimm, index_reg);
++                      
read_read_dqs_timing_control_registers(current_rdqs_total_delay, dev, Channel, 
dimm, index_reg);
++
++                      for (lane = 0; lane < 8; lane++) {
++                              current_total_delay[lane] += 
current_rdqs_total_delay[lane];
++                              if (current_total_delay[lane] > 
current_worst_case_total_delay_value) {
++                                      current_worst_case_total_delay_dimm = 
dimm;
++                                      current_worst_case_total_delay_value = 
current_total_delay[lane];
++                              }
++                      }
++
++#if DQS_TRAIN_DEBUG > 0
++                      for (lane = 0; lane < 8; lane++)
++                              print_debug_dqs_pair("\t\tTrainMaxRdLatency56: 
Lane ", lane, " current_total_delay ", current_total_delay[lane], 2);
++#endif
++              }
++
++              /* 2.10.5.8.5.1.1 */
++              Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel, 1);
++
++              /* 2.10.5.8.5.1.[2,3]
++               * Write the DRAM training pattern to the test address
++               */
++              write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, current_worst_case_total_delay_dimm << 1, 0xff);
++
++              /* 2.10.5.8.5.1.4
++               * Incrementally test each MaxRdLatency candidate
++               */
++              for (; pDCTstat->CH_MaxRdLat[Channel] < 0x3ff; 
pDCTstat->CH_MaxRdLat[Channel]++) {
++                      write_max_read_latency_to_registers(pMCTstat, pDCTstat, 
Channel, pDCTstat->CH_MaxRdLat[Channel]);
++                      read_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff);
++                      dword = Get_NB32_DCT(dev, Channel, 0x268) & 0x3ffff;
++                      if (!dword)
++                              break;
++                      Set_NB32_index_wait_DCT(dev, Channel, index_reg, 
0x00000050, 0x13131313);
++              }
++
++              /* 2.10.5.8.5.1.5 */
++              nb_pstate = 0;
++              mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
++              if (fam15h_freq_tab[mem_clk] == 0) {
++                      return;
++              }
++              dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 
4)));               /* Retrieve NbDid, NbFid */
++              nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) 
& 0x1)?2:1);
++
++              pDCTstat->CH_MaxRdLat[Channel]++;
++              pDCTstat->CH_MaxRdLat[Channel] += ((((uint64_t)15 * 
100000000000ULL) / ((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL))
++                                                       * ((uint64_t)nb_clk * 
1000)) / 1000000000ULL;
++
++              write_max_read_latency_to_registers(pMCTstat, pDCTstat, 
Channel, pDCTstat->CH_MaxRdLat[Channel]);
++      }
++
++      if(_DisableDramECC) {
++              mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
++      }
++
++      if(!_Wrap32Dis) {
++              msr = HWCR;
++              _RDMSR(msr, &lo, &hi);
++              lo &= ~(1<<17);         /* restore HWCR.wrap32dis */
++              _WRMSR(msr, lo, hi);
++      }
++      if(!_SSE2){
++              cr4 = read_cr4();
++              cr4 &= ~(1<<9);         /* restore cr4.OSFXSR */
++              write_cr4(cr4);
++      }
++
++#if DQS_TRAIN_DEBUG > 0
++      {
++              u8 ChannelDTD;
++              printk(BIOS_DEBUG, "TrainMaxRdLatency: CH_MaxRdLat:\n");
++              for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) {
++                      printk(BIOS_DEBUG, "Channel:%x: %x\n",
++                             ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]);
++              }
++      }
++#endif
++
++      printk(BIOS_DEBUG, "TrainMaxRdLatency: Status %x\n", pDCTstat->Status);
++      printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrStatus %x\n", 
pDCTstat->ErrStatus);
++      printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrCode %x\n", 
pDCTstat->ErrCode);
++      printk(BIOS_DEBUG, "TrainMaxRdLatency: Done\n\n");
++}
++
+ u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+       if (pDCTstat->DIMMValidDCT[dct] == 0 ) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+index 3153e46..28cc8f6 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
+@@ -172,6 +172,8 @@ static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
+ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+                                       struct DCTStatStruc *pDCTstat)
+ {
++      printk(BIOS_DEBUG, "%s: Start\n", __func__);
++
+       uint8_t DCT0Present;
+       uint8_t DCT1Present;
+       uint32_t dword;
+@@ -313,6 +315,8 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
+                       mct_Wait(15000);        /* Wait for 750us */
+               }
+       }
++
++      printk(BIOS_DEBUG, "%s: Done\n", __func__);
+ }
+ 
+ /*
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0098-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
 
b/resources/libreboot/patch/kgpe-d16/0098-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
deleted file mode 100644
index f107a68..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0098-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From 4d494c630bc75c675cae9cae68d6d0b44fcd1e22 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 7 Aug 2015 19:06:09 -0500
-Subject: [PATCH 098/139] northbridge/amd/amdfam10: Fix poor performance on
- Family 15h CPUs
-
-Change-Id: I193749bc767b7c1139de7cd67622a7b03298009b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/nb_control.c  |  4 ++--
- src/northbridge/amd/amdfam10/northbridge.c | 21 +++++++++++++++++++++
- 2 files changed, 23 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/nb_control.c 
b/src/northbridge/amd/amdfam10/nb_control.c
-index f95b6f8..8e8dd57 100644
---- a/src/northbridge/amd/amdfam10/nb_control.c
-+++ b/src/northbridge/amd/amdfam10/nb_control.c
-@@ -60,10 +60,10 @@ static void nb_control_init(struct device *dev)
-       pci_write_config32(dev, 0xe0, dword);
- 
-       /* Configure northbridge P-states */
--      dword = pci_read_config32(dev, 0xe0);
-+      dword = pci_read_config32(dev, 0x170);
-       dword &= ~(0x7 << 9);                   /* NbPstateThreshold = 
compute_unit_count */
-       dword |= (compute_unit_count & 0x7) << 9;
--      pci_write_config32(dev, 0xe0, dword);
-+      pci_write_config32(dev, 0x170, dword);
- 
-       printk(BIOS_DEBUG, "done.\n");
- }
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index cdb8afa..9f132c7 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -1759,6 +1759,8 @@ static void detect_and_enable_probe_filter(device_t dev)
- 
-               disable_cache();
-               asm("wbinvd");
-+
-+              /* Enable probe filter */
-               for (i = 0; i < sysconf.nodes; i++) {
-                       device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
- 
-@@ -1775,6 +1777,25 @@ static void detect_and_enable_probe_filter(device_t dev)
-                       do {
-                       } while (!(pci_read_config32(f3x_dev, 0x1d4) & (0x1 << 
19)));
-               }
-+
-+              if (is_fam15h()) {
-+                      printk(BIOS_DEBUG, "Enabling ATM mode\n");
-+
-+                      /* Enable ATM mode */
-+                      for (i = 0; i < sysconf.nodes; i++) {
-+                              device_t f0x_dev = dev_find_slot(0, 
PCI_DEVFN(0x18 + i, 0));
-+                              device_t f3x_dev = dev_find_slot(0, 
PCI_DEVFN(0x18 + i, 3));
-+
-+                              dword = pci_read_config32(f0x_dev, 0x68);
-+                              dword |= (0x1 << 12);   /* ATMModeEn = 1 */
-+                              pci_write_config32(f0x_dev, 0x68, dword);
-+
-+                              dword = pci_read_config32(f3x_dev, 0x1b8);
-+                              dword |= (0x1 << 27);   /* L3ATMModeEn = 1 */
-+                              pci_write_config32(f3x_dev, 0x1b8, dword);
-+                      }
-+              }
-+
-               enable_cache();
- 
-               /* Reenable L3 and DRAM scrubbers */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0099-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
 
b/resources/libreboot/patch/kgpe-d16/0099-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
deleted file mode 100644
index 2cbd57e..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0099-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From fd637f3c6c5a176a18cf44bbd163dd61cabd8fb1 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 7 Aug 2015 23:58:28 -0500
-Subject: [PATCH 099/139] cpu/amd/family_10h-family_15h: Configure NB register
- 2
-
-Change-Id: I55cfc96a197514212b2a4c344d3513396ebc2ad4
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index 4868c5c..5ab4335 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -621,6 +621,14 @@ static const struct {
-                                          [5] DisPciCfgCpuMstAbtRsp = 1,
-                                          [1] SyncFloodOnUsPwDataErr = 1 */
- 
-+      /* NB Configuration 2 */
-+      { 3, 0x188, AMD_DR_GT_B0, AMD_PTYPE_ALL,
-+        0x00000010, 0x00000010 },     /* EnStpGntOnFlushMaskWakeup = 0x1 */
-+
-+      /* NB Configuration 2 */
-+      { 3, 0x188, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000200, 0x00000200 },     /* DisL3HiPriFreeListAlloc = 0x1 */
-+
-       /* errata 346 - Fam10 C2, C3
-        *  System software should set F3x188[22] to 1b. */
-       { 3, 0x188, AMD_DR_Cx, AMD_PTYPE_ALL,
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0099-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
 
b/resources/libreboot/patch/kgpe-d16/0099-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
new file mode 100644
index 0000000..be85fe7
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0099-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch
@@ -0,0 +1,30 @@
+From e17ac6e74b96102528fa4915d6cebcb55f8e5db0 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 7 Aug 2015 19:05:45 -0500
+Subject: [PATCH 099/143] northbridge/amd/amdht: Fix poor performance on
+ Family 15h CPUs
+
+Change-Id: I37db191c144c81aba5d4a1e6291db5669a35a31a
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdht/h3ncmn.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
+index e03e5eb..e377ff2 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.c
++++ b/src/northbridge/amd/amdht/h3ncmn.c
+@@ -1559,6 +1559,10 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
+                       } else {
+                               temp2 = 0x0;
+                       }
++                      /* NOTE
++                       * The Family 15h BKDG Rev. 3.14 is wrong
++                       * Freq[4] must be set before Freq[3:0], otherwise the 
register writes will be ignored!
++                       */
+                       if (is_gt_rev_d())
+                               AmdPCIWriteBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 0, 0, &temp2);
+                       AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, 
&temp);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0100-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
 
b/resources/libreboot/patch/kgpe-d16/0100-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
deleted file mode 100644
index d37c376..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0100-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
+++ /dev/null
@@ -1,344 +0,0 @@
-From e1db05e5568333c634db8052d4dc37d60b61121f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 7 Aug 2015 23:59:17 -0500
-Subject: [PATCH 100/139] cpu/amd/family_10h-family_15h: Set up link XCS token
- counts on Family 15h
-
-Change-Id: I4cf6549234041c395a18a89332d95f20a596fc3e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 304 ++++++++++++++++++++++++++
- 1 file changed, 304 insertions(+)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index d1a93e7..10c676f 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -1056,6 +1056,12 @@ static void cpuSetAMDPCI(u8 node)
-       uint32_t dword;
-       uint64_t revision;
- 
-+      /* FIXME
-+       * This should be configurable
-+       */
-+      uint8_t sockets = 2;
-+      uint8_t sockets_populated = 2;
-+
-       printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node);
- 
-       revision = mctGetLogicalCPUID(node);
-@@ -1162,6 +1168,15 @@ static void cpuSetAMDPCI(u8 node)
-               uint8_t compute_unit_count = 0;
-               uint8_t compute_unit_buffer_count;
- 
-+              uint32_t f3xe8;
-+              uint8_t dual_node = 0;
-+
-+              f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
-+
-+              /* Check for dual node capability */
-+              if (f3xe8 & 0x20000000)
-+                      dual_node = 1;
-+
-               /* Determine the number of active compute units on this node */
-               f5x80 = pci_read_config32(NODE_PCI(node, 5), 0x80);
-               cu_enabled = f5x80 & 0xf;
-@@ -1187,6 +1202,295 @@ static void cpuSetAMDPCI(u8 node)
-               dword &= ~(0x1f << 4);                  /* L3FreeListCBC = 
compute_unit_buffer_count */
-               dword |= (compute_unit_buffer_count << 4);
-               pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
-+
-+              /* Set up the Link to XCS Token Counts */
-+              uint8_t isoc_rsp_tok_1;
-+              uint8_t isoc_preq_tok_1;
-+              uint8_t isoc_req_tok_1;
-+              uint8_t probe_tok_1;
-+              uint8_t rsp_tok_1;
-+              uint8_t preq_tok_1;
-+              uint8_t req_tok_1;
-+              uint8_t isoc_rsp_tok_0;
-+              uint8_t isoc_preq_tok_0;
-+              uint8_t isoc_req_tok_0;
-+              uint8_t free_tokens;
-+              uint8_t probe_tok_0;
-+              uint8_t rsp_tok_0;
-+              uint8_t preq_tok_0;
-+              uint8_t req_tok_0;
-+
-+              uint8_t link;
-+              uint8_t ganged;
-+              uint8_t iolink;
-+              uint8_t probe_filter_enabled = !!dual_node;
-+              for (link = 0; link < 4; link++) {
-+                      if (AMD_CpuFindCapability(node, link, &offset)) {
-+                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
-+                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
-+
-+                              /* Set defaults */
-+                              isoc_rsp_tok_1 = 0;
-+                              isoc_preq_tok_1 = 0;
-+                              isoc_req_tok_1 = 0;
-+                              probe_tok_1 = !ganged;
-+                              rsp_tok_1 = !ganged;
-+                              preq_tok_1 = !ganged;
-+                              req_tok_1 = !ganged;
-+                              isoc_rsp_tok_0 = 0;
-+                              isoc_preq_tok_0 = 0;
-+                              isoc_req_tok_0 = 0;
-+                              free_tokens = 0;
-+                              probe_tok_0 = ((ganged)?2:1);
-+                              rsp_tok_0 = ((ganged)?2:1);
-+                              preq_tok_0 = ((ganged)?2:1);
-+                              req_tok_0 = ((ganged)?2:1);
-+
-+                              if (!iolink && ganged) {
-+                                      if (!dual_node) {
-+                                              isoc_rsp_tok_1 = 0;
-+                                              isoc_preq_tok_1 = 0;
-+                                              isoc_req_tok_1 = 0;
-+                                              probe_tok_1 = 0;
-+                                              rsp_tok_1 = 0;
-+                                              preq_tok_1 = 0;
-+                                              req_tok_1 = 0;
-+                                              isoc_rsp_tok_0 = 0;
-+                                              isoc_preq_tok_0 = 0;
-+                                              isoc_req_tok_0 = 1;
-+                                              free_tokens = 3;
-+                                              probe_tok_0 = 2;
-+                                              rsp_tok_0 = 2;
-+                                              preq_tok_0 = 2;
-+                                              req_tok_0 = 2;
-+                                      } else {
-+                                              if ((sockets == 1)
-+                                                      || ((sockets == 2) && 
(sockets_populated == 1))) {
-+                                                      isoc_rsp_tok_1 = 0;
-+                                                      isoc_preq_tok_1 = 0;
-+                                                      isoc_req_tok_1 = 0;
-+                                                      probe_tok_1 = 0;
-+                                                      rsp_tok_1 = 0;
-+                                                      preq_tok_1 = 0;
-+                                                      req_tok_1 = 0;
-+                                                      isoc_rsp_tok_0 = 0;
-+                                                      isoc_preq_tok_0 = 0;
-+                                                      isoc_req_tok_0 = 1;
-+                                                      free_tokens = 0;
-+                                                      probe_tok_0 = 2;
-+                                                      rsp_tok_0 = 2;
-+                                                      preq_tok_0 = 2;
-+                                                      req_tok_0 = 2;
-+                                              } else if (((sockets == 2) && 
(sockets_populated == 2))
-+                                                      || ((sockets == 4) && 
(sockets_populated == 2))) {
-+                                                      isoc_rsp_tok_1 = 0;
-+                                                      isoc_preq_tok_1 = 0;
-+                                                      isoc_req_tok_1 = 0;
-+                                                      probe_tok_1 = 0;
-+                                                      rsp_tok_1 = 0;
-+                                                      preq_tok_1 = 0;
-+                                                      req_tok_1 = 0;
-+                                                      isoc_rsp_tok_0 = 0;
-+                                                      isoc_preq_tok_0 = 0;
-+                                                      isoc_req_tok_0 = 1;
-+                                                      free_tokens = 0;
-+                                                      probe_tok_0 = 1;
-+                                                      rsp_tok_0 = 2;
-+                                                      preq_tok_0 = 2;
-+                                                      req_tok_0 = 2;
-+                                              } else if ((sockets == 4) && 
(sockets_populated == 4)) {
-+                                                      isoc_rsp_tok_1 = 0;
-+                                                      isoc_preq_tok_1 = 0;
-+                                                      isoc_req_tok_1 = 0;
-+                                                      probe_tok_1 = 0;
-+                                                      rsp_tok_1 = 0;
-+                                                      preq_tok_1 = 0;
-+                                                      req_tok_1 = 0;
-+                                                      isoc_rsp_tok_0 = 0;
-+                                                      isoc_preq_tok_0 = 0;
-+                                                      isoc_req_tok_0 = 1;
-+                                                      free_tokens = 0;
-+                                                      probe_tok_0 = 2;
-+                                                      rsp_tok_0 = 1;
-+                                                      preq_tok_0 = 1;
-+                                                      req_tok_0 = 2;
-+                                              }
-+                                      }
-+                              } else if (!iolink && !ganged) {
-+                                      if ((sockets == 1)
-+                                              || ((sockets == 2) && 
(sockets_populated == 1))) {
-+                                              if (probe_filter_enabled) {
-+                                                      isoc_rsp_tok_1 = 0;
-+                                                      isoc_preq_tok_1 = 0;
-+                                                      isoc_req_tok_1 = 0;
-+                                                      probe_tok_1 = 1;
-+                                                      rsp_tok_1 = 1;
-+                                                      preq_tok_1 = 1;
-+                                                      req_tok_1 = 1;
-+                                                      isoc_rsp_tok_0 = 0;
-+                                                      isoc_preq_tok_0 = 0;
-+                                                      isoc_req_tok_0 = 1;
-+                                                      free_tokens = 0;
-+                                                      probe_tok_0 = 1;
-+                                                      rsp_tok_0 = 2;
-+                                                      preq_tok_0 = 1;
-+                                                      req_tok_0 = 1;
-+                                              } else {
-+                                                      isoc_rsp_tok_1 = 0;
-+                                                      isoc_preq_tok_1 = 0;
-+                                                      isoc_req_tok_1 = 0;
-+                                                      probe_tok_1 = 1;
-+                                                      rsp_tok_1 = 1;
-+                                                      preq_tok_1 = 1;
-+                                                      req_tok_1 = 1;
-+                                                      isoc_rsp_tok_0 = 0;
-+                                                      isoc_preq_tok_0 = 0;
-+                                                      isoc_req_tok_0 = 1;
-+                                                      free_tokens = 0;
-+                                                      probe_tok_0 = 1;
-+                                                      rsp_tok_0 = 1;
-+                                                      preq_tok_0 = 1;
-+                                                      req_tok_0 = 1;
-+                                              }
-+                                      } else if ((sockets == 2) && 
(sockets_populated == 2)) {
-+                                              isoc_rsp_tok_1 = 0;
-+                                              isoc_preq_tok_1 = 0;
-+                                              isoc_req_tok_1 = 1;
-+                                              probe_tok_1 = 1;
-+                                              rsp_tok_1 = 1;
-+                                              preq_tok_1 = 1;
-+                                              req_tok_1 = 1;
-+                                              isoc_rsp_tok_0 = 0;
-+                                              isoc_preq_tok_0 = 0;
-+                                              isoc_req_tok_0 = 1;
-+                                              free_tokens = 2;
-+                                              probe_tok_0 = 1;
-+                                              rsp_tok_0 = 1;
-+                                              preq_tok_0 = 1;
-+                                              req_tok_0 = 1;
-+                                      } else if ((sockets == 4) && 
(sockets_populated == 2)) {
-+                                              isoc_rsp_tok_1 = 0;
-+                                              isoc_preq_tok_1 = 0;
-+                                              isoc_req_tok_1 = 1;
-+                                              probe_tok_1 = 1;
-+                                              rsp_tok_1 = 1;
-+                                              preq_tok_1 = 1;
-+                                              req_tok_1 = 1;
-+                                              isoc_rsp_tok_0 = 0;
-+                                              isoc_preq_tok_0 = 0;
-+                                              isoc_req_tok_0 = 1;
-+                                              free_tokens = 4;
-+                                              probe_tok_0 = 1;
-+                                              rsp_tok_0 = 1;
-+                                              preq_tok_0 = 1;
-+                                              req_tok_0 = 1;
-+                                      } else if ((sockets == 4) && 
(sockets_populated == 4)) {
-+                                              isoc_rsp_tok_1 = 0;
-+                                              isoc_preq_tok_1 = 0;
-+                                              isoc_req_tok_1 = 1;
-+                                              probe_tok_1 = 1;
-+                                              rsp_tok_1 = 1;
-+                                              preq_tok_1 = 1;
-+                                              req_tok_1 = 1;
-+                                              isoc_rsp_tok_0 = 0;
-+                                              isoc_preq_tok_0 = 0;
-+                                              isoc_req_tok_0 = 1;
-+                                              free_tokens = 0;
-+                                              probe_tok_0 = 1;
-+                                              rsp_tok_0 = 1;
-+                                              preq_tok_0 = 1;
-+                                              req_tok_0 = 1;
-+                                      }
-+                              } else if (iolink && ganged) {
-+                                      if (!dual_node) {
-+                                              isoc_rsp_tok_1 = 0;
-+                                              isoc_preq_tok_1 = 0;
-+                                              isoc_req_tok_1 = 0;
-+                                              probe_tok_1 = 0;
-+                                              rsp_tok_1 = 0;
-+                                              preq_tok_1 = 0;
-+                                              req_tok_1 = 0;
-+                                              isoc_rsp_tok_0 = 0;
-+                                              isoc_preq_tok_0 = 0;
-+                                              isoc_req_tok_0 = 1;
-+                                              free_tokens = 3;
-+                                              probe_tok_0 = 0;
-+                                              rsp_tok_0 = 2;
-+                                              preq_tok_0 = 2;
-+                                              req_tok_0 = 2;
-+                                      } else if ((sockets == 1)
-+                                              || (sockets == 2)
-+                                              || ((sockets == 4) && 
(sockets_populated == 2))) {
-+                                              isoc_rsp_tok_1 = 0;
-+                                              isoc_preq_tok_1 = 0;
-+                                              isoc_req_tok_1 = 0;
-+                                              probe_tok_1 = 0;
-+                                              rsp_tok_1 = 0;
-+                                              preq_tok_1 = 0;
-+                                              req_tok_1 = 0;
-+                                              isoc_rsp_tok_0 = 0;
-+                                              isoc_preq_tok_0 = 0;
-+                                              isoc_req_tok_0 = 1;
-+                                              free_tokens = 0;
-+                                              probe_tok_0 = 0;
-+                                              rsp_tok_0 = 2;
-+                                              preq_tok_0 = 2;
-+                                              req_tok_0 = 2;
-+                                      } else if ((sockets == 4) && 
(sockets_populated == 4)) {
-+                                              isoc_rsp_tok_1 = 0;
-+                                              isoc_preq_tok_1 = 0;
-+                                              isoc_req_tok_1 = 0;
-+                                              probe_tok_1 = 0;
-+                                              rsp_tok_1 = 0;
-+                                              preq_tok_1 = 0;
-+                                              req_tok_1 = 0;
-+                                              isoc_rsp_tok_0 = 0;
-+                                              isoc_preq_tok_0 = 0;
-+                                              isoc_req_tok_0 = 2;
-+                                              free_tokens = 0;
-+                                              probe_tok_0 = 2;
-+                                              rsp_tok_0 = 2;
-+                                              preq_tok_0 = 2;
-+                                              req_tok_0 = 2;
-+                                      }
-+                              }
-+
-+                              dword = pci_read_config32(NODE_PCI(node, 3), 
(link << 2) + 0x148);
-+                              dword &= ~(0x3 << 30);                  /* 
FreeTok[3:2] = free_tokens[3:2] */
-+                              dword |= (((free_tokens >> 2) & 0x3) << 30);
-+                              dword &= ~(0x1 << 28);                  /* 
IsocRspTok1 = isoc_rsp_tok_1 */
-+                              dword |= (((isoc_rsp_tok_1) & 0x1) << 28);
-+                              dword &= ~(0x1 << 26);                  /* 
IsocPreqTok1 = isoc_preq_tok_1 */
-+                              dword |= (((isoc_preq_tok_1) & 0x1) << 26);
-+                              dword &= ~(0x1 << 24);                  /* 
IsocReqTok1 = isoc_req_tok_1 */
-+                              dword |= (((isoc_req_tok_1) & 0x1) << 24);
-+                              dword &= ~(0x3 << 22);                  /* 
ProbeTok1 = probe_tok_1 */
-+                              dword |= (((probe_tok_1) & 0x3) << 22);
-+                              dword &= ~(0x3 << 20);                  /* 
RspTok1 = rsp_tok_1 */
-+                              dword |= (((rsp_tok_1) & 0x3) << 20);
-+                              dword &= ~(0x3 << 18);                  /* 
PReqTok1 = preq_tok_1 */
-+                              dword |= (((preq_tok_1) & 0x3) << 18);
-+                              dword &= ~(0x3 << 16);                  /* 
ReqTok1 = req_tok_1 */
-+                              dword |= (((req_tok_1) & 0x3) << 16);
-+                              dword &= ~(0x3 << 14);                  /* 
FreeTok[1:0] = free_tokens[1:0] */
-+                              dword |= (((free_tokens) & 0x3) << 14);
-+                              dword &= ~(0x3 << 12);                  /* 
IsocRspTok0 = isoc_rsp_tok_0 */
-+                              dword |= (((isoc_rsp_tok_0) & 0x3) << 12);
-+                              dword &= ~(0x3 << 10);                  /* 
IsocPreqTok0 = isoc_preq_tok_0 */
-+                              dword |= (((isoc_preq_tok_0) & 0x3) << 10);
-+                              dword &= ~(0x3 << 8);                   /* 
IsocReqTok0 = isoc_req_tok_0 */
-+                              dword |= (((isoc_req_tok_0) & 0x3) << 8);
-+                              dword &= ~(0x3 << 6);                   /* 
ProbeTok0 = probe_tok_0 */
-+                              dword |= (((probe_tok_0) & 0x3) << 6);
-+                              dword &= ~(0x3 << 4);                   /* 
RspTok0 = rsp_tok_0 */
-+                              dword |= (((rsp_tok_0) & 0x3) << 4);
-+                              dword &= ~(0x3 << 2);                   /* 
PReqTok0 = preq_tok_0 */
-+                              dword |= (((preq_tok_0) & 0x3) << 2);
-+                              dword &= ~(0x3 << 0);                   /* 
ReqTok0 = req_tok_0 */
-+                              dword |= (((req_tok_0) & 0x3) << 0);
-+                              pci_write_config32(NODE_PCI(node, 3), (link << 
2) + 0x148, dword);
-+                      }
-+              }
-       }
- 
-       printk(BIOS_DEBUG, " done\n");
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0100-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
 
b/resources/libreboot/patch/kgpe-d16/0100-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
new file mode 100644
index 0000000..cca5d53
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0100-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch
@@ -0,0 +1,72 @@
+From 718c44eb4a990acd5aedd7a57bacf43ebb7c76a6 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 7 Aug 2015 19:06:09 -0500
+Subject: [PATCH 100/143] northbridge/amd/amdfam10: Fix poor performance on
+ Family 15h CPUs
+
+Change-Id: I193749bc767b7c1139de7cd67622a7b03298009b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/nb_control.c  |    4 ++--
+ src/northbridge/amd/amdfam10/northbridge.c |   21 +++++++++++++++++++++
+ 2 files changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/nb_control.c 
b/src/northbridge/amd/amdfam10/nb_control.c
+index f95b6f8..8e8dd57 100644
+--- a/src/northbridge/amd/amdfam10/nb_control.c
++++ b/src/northbridge/amd/amdfam10/nb_control.c
+@@ -60,10 +60,10 @@ static void nb_control_init(struct device *dev)
+       pci_write_config32(dev, 0xe0, dword);
+ 
+       /* Configure northbridge P-states */
+-      dword = pci_read_config32(dev, 0xe0);
++      dword = pci_read_config32(dev, 0x170);
+       dword &= ~(0x7 << 9);                   /* NbPstateThreshold = 
compute_unit_count */
+       dword |= (compute_unit_count & 0x7) << 9;
+-      pci_write_config32(dev, 0xe0, dword);
++      pci_write_config32(dev, 0x170, dword);
+ 
+       printk(BIOS_DEBUG, "done.\n");
+ }
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 808cd3a..3a899c8 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -1759,6 +1759,8 @@ static void detect_and_enable_probe_filter(device_t dev)
+ 
+               disable_cache();
+               asm("wbinvd");
++
++              /* Enable probe filter */
+               for (i = 0; i < sysconf.nodes; i++) {
+                       device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
+ 
+@@ -1775,6 +1777,25 @@ static void detect_and_enable_probe_filter(device_t dev)
+                       do {
+                       } while (!(pci_read_config32(f3x_dev, 0x1d4) & (0x1 << 
19)));
+               }
++
++              if (is_fam15h()) {
++                      printk(BIOS_DEBUG, "Enabling ATM mode\n");
++
++                      /* Enable ATM mode */
++                      for (i = 0; i < sysconf.nodes; i++) {
++                              device_t f0x_dev = dev_find_slot(0, 
PCI_DEVFN(0x18 + i, 0));
++                              device_t f3x_dev = dev_find_slot(0, 
PCI_DEVFN(0x18 + i, 3));
++
++                              dword = pci_read_config32(f0x_dev, 0x68);
++                              dword |= (0x1 << 12);   /* ATMModeEn = 1 */
++                              pci_write_config32(f0x_dev, 0x68, dword);
++
++                              dword = pci_read_config32(f3x_dev, 0x1b8);
++                              dword |= (0x1 << 27);   /* L3ATMModeEn = 1 */
++                              pci_write_config32(f3x_dev, 0x1b8, dword);
++                      }
++              }
++
+               enable_cache();
+ 
+               /* Reenable L3 and DRAM scrubbers */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0101-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
 
b/resources/libreboot/patch/kgpe-d16/0101-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
new file mode 100644
index 0000000..4dfb898
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0101-cpu-amd-family_10h-family_15h-Configure-NB-register-.patch
@@ -0,0 +1,34 @@
+From 4d83ab44b211bd6c7e0c96e23de9f413f0927875 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 7 Aug 2015 23:58:28 -0500
+Subject: [PATCH 101/143] cpu/amd/family_10h-family_15h: Configure NB register
+ 2
+
+Change-Id: I55cfc96a197514212b2a4c344d3513396ebc2ad4
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index 4868c5c..5ab4335 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -621,6 +621,14 @@ static const struct {
+                                          [5] DisPciCfgCpuMstAbtRsp = 1,
+                                          [1] SyncFloodOnUsPwDataErr = 1 */
+ 
++      /* NB Configuration 2 */
++      { 3, 0x188, AMD_DR_GT_B0, AMD_PTYPE_ALL,
++        0x00000010, 0x00000010 },     /* EnStpGntOnFlushMaskWakeup = 0x1 */
++
++      /* NB Configuration 2 */
++      { 3, 0x188, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000200, 0x00000200 },     /* DisL3HiPriFreeListAlloc = 0x1 */
++
+       /* errata 346 - Fam10 C2, C3
+        *  System software should set F3x188[22] to 1b. */
+       { 3, 0x188, AMD_DR_Cx, AMD_PTYPE_ALL,
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0101-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
 
b/resources/libreboot/patch/kgpe-d16/0101-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
deleted file mode 100644
index ef1533d..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0101-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From bb67f00d05bf8ff2d9643100878e3743302d43c1 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 7 Aug 2015 23:59:33 -0500
-Subject: [PATCH 101/139] northbridge/amd/amdmct/mct_ddr3: Force retraining on
- every boot
-
-Change-Id: I017e0dd5120110124d5b5d5276befef6f7740614
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 2ca65ca..330f37f 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1735,6 +1735,16 @@ restartinit:
-                                       allow_config_restore = 0;
-               }
- 
-+              /* FIXME
-+               * Stability issues have arisen on multiple Family 15h systems
-+               * when configuration restoration is enabled.  In all cases 
these
-+               * stability issues resolved by allowing the RAM to go through a
-+               * full training cycle.
-+               *
-+               * Debug and reenable this!
-+               */
-+              allow_config_restore = 0;
-+
-               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
-                       struct DCTStatStruc *pDCTstat;
-                       pDCTstat = pDCTstatA + Node;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0102-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
 
b/resources/libreboot/patch/kgpe-d16/0102-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
new file mode 100644
index 0000000..086b9e4
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0102-cpu-amd-family_10h-family_15h-Set-up-link-XCS-token-.patch
@@ -0,0 +1,344 @@
+From 89f102b6b680c94a31ff812bba7be5016e15580a Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 7 Aug 2015 23:59:17 -0500
+Subject: [PATCH 102/143] cpu/amd/family_10h-family_15h: Set up link XCS token
+ counts on Family 15h
+
+Change-Id: I4cf6549234041c395a18a89332d95f20a596fc3e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |  304 +++++++++++++++++++++++++
+ 1 file changed, 304 insertions(+)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index 67893ca1..e93c15b 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -1057,6 +1057,12 @@ static void cpuSetAMDPCI(u8 node)
+       uint32_t dword;
+       uint64_t revision;
+ 
++      /* FIXME
++       * This should be configurable
++       */
++      uint8_t sockets = 2;
++      uint8_t sockets_populated = 2;
++
+       printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node);
+ 
+       revision = mctGetLogicalCPUID(node);
+@@ -1163,6 +1169,15 @@ static void cpuSetAMDPCI(u8 node)
+               uint8_t compute_unit_count = 0;
+               uint8_t compute_unit_buffer_count;
+ 
++              uint32_t f3xe8;
++              uint8_t dual_node = 0;
++
++              f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
++
++              /* Check for dual node capability */
++              if (f3xe8 & 0x20000000)
++                      dual_node = 1;
++
+               /* Determine the number of active compute units on this node */
+               f5x80 = pci_read_config32(NODE_PCI(node, 5), 0x80);
+               cu_enabled = f5x80 & 0xf;
+@@ -1188,6 +1203,295 @@ static void cpuSetAMDPCI(u8 node)
+               dword &= ~(0x1f << 4);                  /* L3FreeListCBC = 
compute_unit_buffer_count */
+               dword |= (compute_unit_buffer_count << 4);
+               pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
++
++              /* Set up the Link to XCS Token Counts */
++              uint8_t isoc_rsp_tok_1;
++              uint8_t isoc_preq_tok_1;
++              uint8_t isoc_req_tok_1;
++              uint8_t probe_tok_1;
++              uint8_t rsp_tok_1;
++              uint8_t preq_tok_1;
++              uint8_t req_tok_1;
++              uint8_t isoc_rsp_tok_0;
++              uint8_t isoc_preq_tok_0;
++              uint8_t isoc_req_tok_0;
++              uint8_t free_tokens;
++              uint8_t probe_tok_0;
++              uint8_t rsp_tok_0;
++              uint8_t preq_tok_0;
++              uint8_t req_tok_0;
++
++              uint8_t link;
++              uint8_t ganged;
++              uint8_t iolink;
++              uint8_t probe_filter_enabled = !!dual_node;
++              for (link = 0; link < 4; link++) {
++                      if (AMD_CpuFindCapability(node, link, &offset)) {
++                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
++                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
++
++                              /* Set defaults */
++                              isoc_rsp_tok_1 = 0;
++                              isoc_preq_tok_1 = 0;
++                              isoc_req_tok_1 = 0;
++                              probe_tok_1 = !ganged;
++                              rsp_tok_1 = !ganged;
++                              preq_tok_1 = !ganged;
++                              req_tok_1 = !ganged;
++                              isoc_rsp_tok_0 = 0;
++                              isoc_preq_tok_0 = 0;
++                              isoc_req_tok_0 = 0;
++                              free_tokens = 0;
++                              probe_tok_0 = ((ganged)?2:1);
++                              rsp_tok_0 = ((ganged)?2:1);
++                              preq_tok_0 = ((ganged)?2:1);
++                              req_tok_0 = ((ganged)?2:1);
++
++                              if (!iolink && ganged) {
++                                      if (!dual_node) {
++                                              isoc_rsp_tok_1 = 0;
++                                              isoc_preq_tok_1 = 0;
++                                              isoc_req_tok_1 = 0;
++                                              probe_tok_1 = 0;
++                                              rsp_tok_1 = 0;
++                                              preq_tok_1 = 0;
++                                              req_tok_1 = 0;
++                                              isoc_rsp_tok_0 = 0;
++                                              isoc_preq_tok_0 = 0;
++                                              isoc_req_tok_0 = 1;
++                                              free_tokens = 3;
++                                              probe_tok_0 = 2;
++                                              rsp_tok_0 = 2;
++                                              preq_tok_0 = 2;
++                                              req_tok_0 = 2;
++                                      } else {
++                                              if ((sockets == 1)
++                                                      || ((sockets == 2) && 
(sockets_populated == 1))) {
++                                                      isoc_rsp_tok_1 = 0;
++                                                      isoc_preq_tok_1 = 0;
++                                                      isoc_req_tok_1 = 0;
++                                                      probe_tok_1 = 0;
++                                                      rsp_tok_1 = 0;
++                                                      preq_tok_1 = 0;
++                                                      req_tok_1 = 0;
++                                                      isoc_rsp_tok_0 = 0;
++                                                      isoc_preq_tok_0 = 0;
++                                                      isoc_req_tok_0 = 1;
++                                                      free_tokens = 0;
++                                                      probe_tok_0 = 2;
++                                                      rsp_tok_0 = 2;
++                                                      preq_tok_0 = 2;
++                                                      req_tok_0 = 2;
++                                              } else if (((sockets == 2) && 
(sockets_populated == 2))
++                                                      || ((sockets == 4) && 
(sockets_populated == 2))) {
++                                                      isoc_rsp_tok_1 = 0;
++                                                      isoc_preq_tok_1 = 0;
++                                                      isoc_req_tok_1 = 0;
++                                                      probe_tok_1 = 0;
++                                                      rsp_tok_1 = 0;
++                                                      preq_tok_1 = 0;
++                                                      req_tok_1 = 0;
++                                                      isoc_rsp_tok_0 = 0;
++                                                      isoc_preq_tok_0 = 0;
++                                                      isoc_req_tok_0 = 1;
++                                                      free_tokens = 0;
++                                                      probe_tok_0 = 1;
++                                                      rsp_tok_0 = 2;
++                                                      preq_tok_0 = 2;
++                                                      req_tok_0 = 2;
++                                              } else if ((sockets == 4) && 
(sockets_populated == 4)) {
++                                                      isoc_rsp_tok_1 = 0;
++                                                      isoc_preq_tok_1 = 0;
++                                                      isoc_req_tok_1 = 0;
++                                                      probe_tok_1 = 0;
++                                                      rsp_tok_1 = 0;
++                                                      preq_tok_1 = 0;
++                                                      req_tok_1 = 0;
++                                                      isoc_rsp_tok_0 = 0;
++                                                      isoc_preq_tok_0 = 0;
++                                                      isoc_req_tok_0 = 1;
++                                                      free_tokens = 0;
++                                                      probe_tok_0 = 2;
++                                                      rsp_tok_0 = 1;
++                                                      preq_tok_0 = 1;
++                                                      req_tok_0 = 2;
++                                              }
++                                      }
++                              } else if (!iolink && !ganged) {
++                                      if ((sockets == 1)
++                                              || ((sockets == 2) && 
(sockets_populated == 1))) {
++                                              if (probe_filter_enabled) {
++                                                      isoc_rsp_tok_1 = 0;
++                                                      isoc_preq_tok_1 = 0;
++                                                      isoc_req_tok_1 = 0;
++                                                      probe_tok_1 = 1;
++                                                      rsp_tok_1 = 1;
++                                                      preq_tok_1 = 1;
++                                                      req_tok_1 = 1;
++                                                      isoc_rsp_tok_0 = 0;
++                                                      isoc_preq_tok_0 = 0;
++                                                      isoc_req_tok_0 = 1;
++                                                      free_tokens = 0;
++                                                      probe_tok_0 = 1;
++                                                      rsp_tok_0 = 2;
++                                                      preq_tok_0 = 1;
++                                                      req_tok_0 = 1;
++                                              } else {
++                                                      isoc_rsp_tok_1 = 0;
++                                                      isoc_preq_tok_1 = 0;
++                                                      isoc_req_tok_1 = 0;
++                                                      probe_tok_1 = 1;
++                                                      rsp_tok_1 = 1;
++                                                      preq_tok_1 = 1;
++                                                      req_tok_1 = 1;
++                                                      isoc_rsp_tok_0 = 0;
++                                                      isoc_preq_tok_0 = 0;
++                                                      isoc_req_tok_0 = 1;
++                                                      free_tokens = 0;
++                                                      probe_tok_0 = 1;
++                                                      rsp_tok_0 = 1;
++                                                      preq_tok_0 = 1;
++                                                      req_tok_0 = 1;
++                                              }
++                                      } else if ((sockets == 2) && 
(sockets_populated == 2)) {
++                                              isoc_rsp_tok_1 = 0;
++                                              isoc_preq_tok_1 = 0;
++                                              isoc_req_tok_1 = 1;
++                                              probe_tok_1 = 1;
++                                              rsp_tok_1 = 1;
++                                              preq_tok_1 = 1;
++                                              req_tok_1 = 1;
++                                              isoc_rsp_tok_0 = 0;
++                                              isoc_preq_tok_0 = 0;
++                                              isoc_req_tok_0 = 1;
++                                              free_tokens = 2;
++                                              probe_tok_0 = 1;
++                                              rsp_tok_0 = 1;
++                                              preq_tok_0 = 1;
++                                              req_tok_0 = 1;
++                                      } else if ((sockets == 4) && 
(sockets_populated == 2)) {
++                                              isoc_rsp_tok_1 = 0;
++                                              isoc_preq_tok_1 = 0;
++                                              isoc_req_tok_1 = 1;
++                                              probe_tok_1 = 1;
++                                              rsp_tok_1 = 1;
++                                              preq_tok_1 = 1;
++                                              req_tok_1 = 1;
++                                              isoc_rsp_tok_0 = 0;
++                                              isoc_preq_tok_0 = 0;
++                                              isoc_req_tok_0 = 1;
++                                              free_tokens = 4;
++                                              probe_tok_0 = 1;
++                                              rsp_tok_0 = 1;
++                                              preq_tok_0 = 1;
++                                              req_tok_0 = 1;
++                                      } else if ((sockets == 4) && 
(sockets_populated == 4)) {
++                                              isoc_rsp_tok_1 = 0;
++                                              isoc_preq_tok_1 = 0;
++                                              isoc_req_tok_1 = 1;
++                                              probe_tok_1 = 1;
++                                              rsp_tok_1 = 1;
++                                              preq_tok_1 = 1;
++                                              req_tok_1 = 1;
++                                              isoc_rsp_tok_0 = 0;
++                                              isoc_preq_tok_0 = 0;
++                                              isoc_req_tok_0 = 1;
++                                              free_tokens = 0;
++                                              probe_tok_0 = 1;
++                                              rsp_tok_0 = 1;
++                                              preq_tok_0 = 1;
++                                              req_tok_0 = 1;
++                                      }
++                              } else if (iolink && ganged) {
++                                      if (!dual_node) {
++                                              isoc_rsp_tok_1 = 0;
++                                              isoc_preq_tok_1 = 0;
++                                              isoc_req_tok_1 = 0;
++                                              probe_tok_1 = 0;
++                                              rsp_tok_1 = 0;
++                                              preq_tok_1 = 0;
++                                              req_tok_1 = 0;
++                                              isoc_rsp_tok_0 = 0;
++                                              isoc_preq_tok_0 = 0;
++                                              isoc_req_tok_0 = 1;
++                                              free_tokens = 3;
++                                              probe_tok_0 = 0;
++                                              rsp_tok_0 = 2;
++                                              preq_tok_0 = 2;
++                                              req_tok_0 = 2;
++                                      } else if ((sockets == 1)
++                                              || (sockets == 2)
++                                              || ((sockets == 4) && 
(sockets_populated == 2))) {
++                                              isoc_rsp_tok_1 = 0;
++                                              isoc_preq_tok_1 = 0;
++                                              isoc_req_tok_1 = 0;
++                                              probe_tok_1 = 0;
++                                              rsp_tok_1 = 0;
++                                              preq_tok_1 = 0;
++                                              req_tok_1 = 0;
++                                              isoc_rsp_tok_0 = 0;
++                                              isoc_preq_tok_0 = 0;
++                                              isoc_req_tok_0 = 1;
++                                              free_tokens = 0;
++                                              probe_tok_0 = 0;
++                                              rsp_tok_0 = 2;
++                                              preq_tok_0 = 2;
++                                              req_tok_0 = 2;
++                                      } else if ((sockets == 4) && 
(sockets_populated == 4)) {
++                                              isoc_rsp_tok_1 = 0;
++                                              isoc_preq_tok_1 = 0;
++                                              isoc_req_tok_1 = 0;
++                                              probe_tok_1 = 0;
++                                              rsp_tok_1 = 0;
++                                              preq_tok_1 = 0;
++                                              req_tok_1 = 0;
++                                              isoc_rsp_tok_0 = 0;
++                                              isoc_preq_tok_0 = 0;
++                                              isoc_req_tok_0 = 2;
++                                              free_tokens = 0;
++                                              probe_tok_0 = 2;
++                                              rsp_tok_0 = 2;
++                                              preq_tok_0 = 2;
++                                              req_tok_0 = 2;
++                                      }
++                              }
++
++                              dword = pci_read_config32(NODE_PCI(node, 3), 
(link << 2) + 0x148);
++                              dword &= ~(0x3 << 30);                  /* 
FreeTok[3:2] = free_tokens[3:2] */
++                              dword |= (((free_tokens >> 2) & 0x3) << 30);
++                              dword &= ~(0x1 << 28);                  /* 
IsocRspTok1 = isoc_rsp_tok_1 */
++                              dword |= (((isoc_rsp_tok_1) & 0x1) << 28);
++                              dword &= ~(0x1 << 26);                  /* 
IsocPreqTok1 = isoc_preq_tok_1 */
++                              dword |= (((isoc_preq_tok_1) & 0x1) << 26);
++                              dword &= ~(0x1 << 24);                  /* 
IsocReqTok1 = isoc_req_tok_1 */
++                              dword |= (((isoc_req_tok_1) & 0x1) << 24);
++                              dword &= ~(0x3 << 22);                  /* 
ProbeTok1 = probe_tok_1 */
++                              dword |= (((probe_tok_1) & 0x3) << 22);
++                              dword &= ~(0x3 << 20);                  /* 
RspTok1 = rsp_tok_1 */
++                              dword |= (((rsp_tok_1) & 0x3) << 20);
++                              dword &= ~(0x3 << 18);                  /* 
PReqTok1 = preq_tok_1 */
++                              dword |= (((preq_tok_1) & 0x3) << 18);
++                              dword &= ~(0x3 << 16);                  /* 
ReqTok1 = req_tok_1 */
++                              dword |= (((req_tok_1) & 0x3) << 16);
++                              dword &= ~(0x3 << 14);                  /* 
FreeTok[1:0] = free_tokens[1:0] */
++                              dword |= (((free_tokens) & 0x3) << 14);
++                              dword &= ~(0x3 << 12);                  /* 
IsocRspTok0 = isoc_rsp_tok_0 */
++                              dword |= (((isoc_rsp_tok_0) & 0x3) << 12);
++                              dword &= ~(0x3 << 10);                  /* 
IsocPreqTok0 = isoc_preq_tok_0 */
++                              dword |= (((isoc_preq_tok_0) & 0x3) << 10);
++                              dword &= ~(0x3 << 8);                   /* 
IsocReqTok0 = isoc_req_tok_0 */
++                              dword |= (((isoc_req_tok_0) & 0x3) << 8);
++                              dword &= ~(0x3 << 6);                   /* 
ProbeTok0 = probe_tok_0 */
++                              dword |= (((probe_tok_0) & 0x3) << 6);
++                              dword &= ~(0x3 << 4);                   /* 
RspTok0 = rsp_tok_0 */
++                              dword |= (((rsp_tok_0) & 0x3) << 4);
++                              dword &= ~(0x3 << 2);                   /* 
PReqTok0 = preq_tok_0 */
++                              dword |= (((preq_tok_0) & 0x3) << 2);
++                              dword &= ~(0x3 << 0);                   /* 
ReqTok0 = req_tok_0 */
++                              dword |= (((req_tok_0) & 0x3) << 0);
++                              pci_write_config32(NODE_PCI(node, 3), (link << 
2) + 0x148, dword);
++                      }
++              }
+       }
+ 
+       printk(BIOS_DEBUG, " done\n");
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0102-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
 
b/resources/libreboot/patch/kgpe-d16/0102-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
deleted file mode 100644
index a1d226e..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0102-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 26dce9855e0edd8faae94f12d81ed59322d318ae Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 8 Aug 2015 02:40:58 -0500
-Subject: [PATCH 102/139] northbridge/amd/amdfam10: Fix invalid NUMA table
-
-Change-Id: I99c200382b52a99687daf266a84873d9ae2df025
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/acpi.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/northbridge/amd/amdfam10/acpi.c 
b/src/northbridge/amd/amdfam10/acpi.c
-index 92433bb..23cf086 100644
---- a/src/northbridge/amd/amdfam10/acpi.c
-+++ b/src/northbridge/amd/amdfam10/acpi.c
-@@ -106,7 +106,8 @@ static void set_srat_mem(void *gp, struct device *dev, 
struct resource *res)
-       }
- 
-       // need to figure out NV
--      state->current += acpi_create_srat_mem((acpi_srat_mem_t 
*)state->current, (res->index & 0xf), basek, sizek, 1);
-+      if (res->index > 0xf)
-+              state->current += acpi_create_srat_mem((acpi_srat_mem_t 
*)state->current, (res->index & 0xf), basek, sizek, 1);
- }
- 
- static unsigned long acpi_fill_srat(unsigned long current)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
 
b/resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
deleted file mode 100644
index 15836d4..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
+++ /dev/null
@@ -1,123 +0,0 @@
-From 1f667d55b99e81e636572d9f3ac9498ef782536c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 8 Aug 2015 20:29:27 -0500
-Subject: [PATCH 103/139] northbridge/amd/amdfam10: Add Family 15h cache
- partitioning support
-
-Change-Id: Ie4e28dd886aaa1c586b0919c5fe87ef1696f47e9
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/northbridge.c | 94 ++++++++++++++++++++++++++++++
- 1 file changed, 94 insertions(+)
-
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 9f132c7..8ad5200 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -1809,9 +1809,103 @@ static void detect_and_enable_probe_filter(device_t 
dev)
-       }
- }
- 
-+static void detect_and_enable_cache_partitioning(device_t dev)
-+{
-+      uint8_t i;
-+      uint32_t dword;
-+
-+      if (is_fam15h()) {
-+              printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n");
-+
-+              uint32_t f5x80;
-+              uint8_t cu_enabled;
-+              uint8_t compute_unit_count = 0;
-+
-+              uint32_t f3xe8;
-+              uint8_t dual_node = 0;
-+
-+              for (i = 0; i < sysconf.nodes; i++) {
-+                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
-+                      device_t f4x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
4));
-+                      device_t f5x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
5));
-+
-+                      f3xe8 = pci_read_config32(f3x_dev, 0xe8);
-+
-+                      /* Check for dual node capability */
-+                      if (f3xe8 & 0x20000000)
-+                              dual_node = 1;
-+
-+                      /* Determine the number of active compute units on this 
node */
-+                      f5x80 = pci_read_config32(f5x_dev, 0x80);
-+                      cu_enabled = f5x80 & 0xf;
-+                      if (cu_enabled == 0x1)
-+                              compute_unit_count = 1;
-+                      if (cu_enabled == 0x3)
-+                              compute_unit_count = 2;
-+                      if (cu_enabled == 0x7)
-+                              compute_unit_count = 3;
-+                      if (cu_enabled == 0xf)
-+                              compute_unit_count = 4;
-+
-+                      /* Disable BAN mode */
-+                      dword = pci_read_config32(f3x_dev, 0x1b8);
-+                      dword &= ~(0x7 << 19);  /* L3BanMode = 0x0 */
-+                      pci_write_config32(f3x_dev, 0x1b8, dword);
-+
-+                      /* Set up cache mapping */
-+                      dword = pci_read_config32(f4x_dev, 0x1d4);
-+                      if (compute_unit_count == 1) {
-+                              dword |= 0xf;           /* 
ComputeUnit0SubCacheEn = 0xf */
-+                      }
-+                      if (compute_unit_count == 2) {
-+                              dword &= ~(0xf << 4);   /* 
ComputeUnit1SubCacheEn = 0xc */
-+                              dword |= (0xc << 4);
-+                              dword &= ~0xf;          /* 
ComputeUnit0SubCacheEn = 0x3 */
-+                              dword |= 0x3;
-+                      }
-+                      if (compute_unit_count == 3) {
-+                              dword &= ~(0xf << 8);   /* 
ComputeUnit2SubCacheEn = 0x8 */
-+                              dword |= (0x8 << 8);
-+                              dword &= ~(0xf << 4);   /* 
ComputeUnit1SubCacheEn = 0x4 */
-+                              dword |= (0x4 << 4);
-+                              dword &= ~0xf;          /* 
ComputeUnit0SubCacheEn = 0x3 */
-+                              dword |= 0x3;
-+                      }
-+                      if (compute_unit_count == 4) {
-+                              dword &= ~(0xf << 12);  /* 
ComputeUnit3SubCacheEn = 0x8 */
-+                              dword |= (0x8 << 12);
-+                              dword &= ~(0xf << 8);   /* 
ComputeUnit2SubCacheEn = 0x4 */
-+                              dword |= (0x4 << 8);
-+                              dword &= ~(0xf << 4);   /* 
ComputeUnit1SubCacheEn = 0x2 */
-+                              dword |= (0x2 << 4);
-+                              dword &= ~0xf;          /* 
ComputeUnit0SubCacheEn = 0x1 */
-+                              dword |= 0x1;
-+                      }
-+                      pci_write_config32(f4x_dev, 0x1d4, dword);
-+
-+                      /* Enable cache partitioning */
-+                      pci_write_config32(f4x_dev, 0x1d4, dword);
-+                      if (compute_unit_count == 1) {
-+                              dword &= ~(0xf << 26);  /* 
MaskUpdateForComputeUnit = 0x1 */
-+                              dword |= (0x1 << 26);
-+                      } else if (compute_unit_count == 2) {
-+                              dword &= ~(0xf << 26);  /* 
MaskUpdateForComputeUnit = 0x3 */
-+                              dword |= (0x3 << 26);
-+                      } else if (compute_unit_count == 3) {
-+                              dword &= ~(0xf << 26);  /* 
MaskUpdateForComputeUnit = 0x7 */
-+                              dword |= (0x7 << 26);
-+                      } else if (compute_unit_count == 4) {
-+                              dword |= (0xf << 26);   /* 
MaskUpdateForComputeUnit = 0xf */
-+                      }
-+                      pci_write_config32(f4x_dev, 0x1d4, dword);
-+              }
-+      }
-+}
-+
- static void cpu_bus_init(device_t dev)
- {
-       detect_and_enable_probe_filter(dev);
-+      detect_and_enable_cache_partitioning(dev);
-       initialize_cpus(dev->link_list);
- #if CONFIG_AMD_SB_CIMX
-       sb_After_Pci_Init();
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
 
b/resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
new file mode 100644
index 0000000..16413ff
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch
@@ -0,0 +1,36 @@
+From d43547a64111da6fb4cba322c8675176bddf8622 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 7 Aug 2015 23:59:33 -0500
+Subject: [PATCH 103/143] northbridge/amd/amdmct/mct_ddr3: Force retraining on
+ every boot
+
+Change-Id: I017e0dd5120110124d5b5d5276befef6f7740614
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |   10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 2ca65ca..330f37f 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1735,6 +1735,16 @@ restartinit:
+                                       allow_config_restore = 0;
+               }
+ 
++              /* FIXME
++               * Stability issues have arisen on multiple Family 15h systems
++               * when configuration restoration is enabled.  In all cases 
these
++               * stability issues resolved by allowing the RAM to go through a
++               * full training cycle.
++               *
++               * Debug and reenable this!
++               */
++              allow_config_restore = 0;
++
+               for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+                       struct DCTStatStruc *pDCTstat;
+                       pDCTstat = pDCTstatA + Node;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0104-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
 
b/resources/libreboot/patch/kgpe-d16/0104-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
deleted file mode 100644
index 829e470..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0104-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From bcdb6fab80939ee9b9d599343460edcb31fd386f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 8 Aug 2015 20:29:55 -0500
-Subject: [PATCH 104/139] amd/amdmct/mct_ddr3: Set prefetch double stride to
- improve performance
-
-Change-Id: I34ad85388c6b71f0d44bee13afd663e0b84545cd
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 1 +
- 1 file changed, 1 insertion(+)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 330f37f..de6c79c 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -5563,6 +5563,7 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
-                               val &= ~(0x7 << 8);             /* 
CohPrefPrbLmt = 0x1 */
-                               val |= (0x1 << 8);
-                               val |= (0x1 << 12);             /* 
EnSplitDctLimits = 0x1 */
-+                              val |= (0x1 << 20);             /* DblPrefEn = 
0x1 */
-                               val |= (0x7 << 22);             /* PrefFourConf 
= 0x7 */
-                               val |= (0x7 << 25);             /* PrefFiveConf 
= 0x7 */
-                               val &= ~(0xf << 28);            /* DcqBwThrotWm 
= 0x0 */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0104-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
 
b/resources/libreboot/patch/kgpe-d16/0104-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
new file mode 100644
index 0000000..273fe30
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0104-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch
@@ -0,0 +1,28 @@
+From 9b2c0953c5b51968d3ec9a41585196adb743a177 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 8 Aug 2015 02:40:58 -0500
+Subject: [PATCH 104/143] northbridge/amd/amdfam10: Fix invalid NUMA table
+
+Change-Id: I99c200382b52a99687daf266a84873d9ae2df025
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/acpi.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/northbridge/amd/amdfam10/acpi.c 
b/src/northbridge/amd/amdfam10/acpi.c
+index 92433bb..23cf086 100644
+--- a/src/northbridge/amd/amdfam10/acpi.c
++++ b/src/northbridge/amd/amdfam10/acpi.c
+@@ -106,7 +106,8 @@ static void set_srat_mem(void *gp, struct device *dev, 
struct resource *res)
+       }
+ 
+       // need to figure out NV
+-      state->current += acpi_create_srat_mem((acpi_srat_mem_t 
*)state->current, (res->index & 0xf), basek, sizek, 1);
++      if (res->index > 0xf)
++              state->current += acpi_create_srat_mem((acpi_srat_mem_t 
*)state->current, (res->index & 0xf), basek, sizek, 1);
+ }
+ 
+ static unsigned long acpi_fill_srat(unsigned long current)
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0105-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
 
b/resources/libreboot/patch/kgpe-d16/0105-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
deleted file mode 100644
index bcf7c48..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0105-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
+++ /dev/null
@@ -1,192 +0,0 @@
-From 442969b0213becab817ad626597c1c7eeaf15ebc Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 8 Aug 2015 20:30:36 -0500
-Subject: [PATCH 105/139] cpu/amd/family_10h-family_15h: Set up Family 15h Link
- Base Channel Buffer Count registers
-
-Change-Id: I8d616a64a5a9cf0b51288535f5050c6866d0996b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 159 +++++++++++++++++++++++++-
- 1 file changed, 155 insertions(+), 4 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 10c676f..63ad346 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -1203,6 +1203,161 @@ static void cpuSetAMDPCI(u8 node)
-               dword |= (compute_unit_buffer_count << 4);
-               pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
- 
-+              uint8_t link;
-+              uint8_t ganged;
-+              uint8_t iolink;
-+              uint8_t probe_filter_enabled = !!dual_node;
-+
-+              /* Set up the Link Base Channel Buffer Count */
-+              uint8_t isoc_rsp_data;
-+              uint8_t isoc_np_req_data;
-+              uint8_t isoc_rsp_cmd;
-+              uint8_t isoc_preq;
-+              uint8_t isoc_np_req_cmd;
-+              uint8_t free_data;
-+              uint8_t free_cmd;
-+              uint8_t rsp_data;
-+              uint8_t np_req_data;
-+              uint8_t probe_cmd;
-+              uint8_t rsp_cmd;
-+              uint8_t preq;
-+              uint8_t np_req_cmd;
-+
-+              for (link = 0; link < 4; link++) {
-+                      if (AMD_CpuFindCapability(node, link, &offset)) {
-+                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
-+                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
-+
-+                              if (!iolink && ganged) {
-+                                      if (probe_filter_enabled) {
-+                                              isoc_rsp_data = 0;
-+                                              isoc_np_req_data = 0;
-+                                              isoc_rsp_cmd = 0;
-+                                              isoc_preq = 0;
-+                                              isoc_np_req_cmd = 1;
-+                                              free_data = 0;
-+                                              free_cmd = 8;
-+                                              rsp_data = 3;
-+                                              np_req_data = 3;
-+                                              probe_cmd = 4;
-+                                              rsp_cmd = 9;
-+                                              preq = 2;
-+                                              np_req_cmd = 8;
-+                                      } else {
-+                                              isoc_rsp_data = 0;
-+                                              isoc_np_req_data = 0;
-+                                              isoc_rsp_cmd = 0;
-+                                              isoc_preq = 0;
-+                                              isoc_np_req_cmd = 1;
-+                                              free_data = 0;
-+                                              free_cmd = 8;
-+                                              rsp_data = 3;
-+                                              np_req_data = 3;
-+                                              probe_cmd = 8;
-+                                              rsp_cmd = 9;
-+                                              preq = 2;
-+                                              np_req_cmd = 4;
-+                                      }
-+                              } else if (!iolink && !ganged) {
-+                                      if (probe_filter_enabled) {
-+                                              isoc_rsp_data = 0;
-+                                              isoc_np_req_data = 0;
-+                                              isoc_rsp_cmd = 0;
-+                                              isoc_preq = 0;
-+                                              isoc_np_req_cmd = 1;
-+                                              free_data = 0;
-+                                              free_cmd = 8;
-+                                              rsp_data = 3;
-+                                              np_req_data = 3;
-+                                              probe_cmd = 4;
-+                                              rsp_cmd = 9;
-+                                              preq = 2;
-+                                              np_req_cmd = 8;
-+                                      } else {
-+                                              isoc_rsp_data = 0;
-+                                              isoc_np_req_data = 0;
-+                                              isoc_rsp_cmd = 0;
-+                                              isoc_preq = 0;
-+                                              isoc_np_req_cmd = 1;
-+                                              free_data = 0;
-+                                              free_cmd = 4;
-+                                              rsp_data = 3;
-+                                              np_req_data = 3;
-+                                              probe_cmd = 4;
-+                                              rsp_cmd = 9;
-+                                              preq = 2;
-+                                              np_req_cmd = 4;
-+                                      }
-+                              } else if (iolink && ganged) {
-+                                      isoc_rsp_data = 0;
-+                                      isoc_np_req_data = 0;
-+                                      isoc_rsp_cmd = 0;
-+                                      isoc_preq = 0;
-+                                      isoc_np_req_cmd = 1;
-+                                      free_data = 0;
-+                                      free_cmd = 8;
-+                                      rsp_data = 1;
-+                                      np_req_data = 0;
-+                                      probe_cmd = 0;
-+                                      rsp_cmd = 2;
-+                                      preq = 7;
-+                                      np_req_cmd = 14;
-+                              } else {
-+                                      /* FIXME
-+                                       * This is an educated guess as the 
BKDG does not specify
-+                                       * the appropriate buffer counts for 
this case!
-+                                       */
-+                                      isoc_rsp_data = 0;
-+                                      isoc_np_req_data = 0;
-+                                      isoc_rsp_cmd = 0;
-+                                      isoc_preq = 0;
-+                                      isoc_np_req_cmd = 1;
-+                                      free_data = 1;
-+                                      free_cmd = 8;
-+                                      rsp_data = 1;
-+                                      np_req_data = 1;
-+                                      probe_cmd = 0;
-+                                      rsp_cmd = 2;
-+                                      preq = 4;
-+                                      np_req_cmd = 12;
-+                              }
-+
-+                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x94);
-+                              dword &= ~(0x3 << 27);                  /* 
IsocRspData = isoc_rsp_data */
-+                              dword |= ((isoc_rsp_data & 0x3) << 27);
-+                              dword &= ~(0x3 << 25);                  /* 
IsocNpReqData = isoc_np_req_data */
-+                              dword |= ((isoc_np_req_data & 0x3) << 25);
-+                              dword &= ~(0x7 << 22);                  /* 
IsocRspCmd = isoc_rsp_cmd */
-+                              dword |= ((isoc_rsp_cmd & 0x7) << 22);
-+                              dword &= ~(0x7 << 19);                  /* 
IsocPReq = isoc_preq */
-+                              dword |= ((isoc_preq & 0x7) << 19);
-+                              dword &= ~(0x7 << 16);                  /* 
IsocNpReqCmd = isoc_np_req_cmd */
-+                              dword |= ((isoc_np_req_cmd & 0x7) << 16);
-+                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x94, dword);
-+
-+                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x90);
-+                              dword &= ~(0x1 << 31);                  /* 
LockBc = 0x1 */
-+                              dword |= ((0x1 & 0x1) << 31);
-+                              dword &= ~(0x7 << 25);                  /* 
FreeData = free_data */
-+                              dword |= ((free_data & 0x7) << 25);
-+                              dword &= ~(0x1f << 20);                 /* 
FreeCmd = free_cmd */
-+                              dword |= ((free_cmd & 0x1f) << 20);
-+                              dword &= ~(0x3 << 18);                  /* 
RspData = rsp_data */
-+                              dword |= ((rsp_data & 0x3) << 18);
-+                              dword &= ~(0x3 << 16);                  /* 
NpReqData = np_req_data */
-+                              dword |= ((np_req_data & 0x3) << 16);
-+                              dword &= ~(0xf << 12);                  /* 
ProbeCmd = probe_cmd */
-+                              dword |= ((probe_cmd & 0xf) << 12);
-+                              dword &= ~(0xf << 8);                   /* 
RspCmd = rsp_cmd */
-+                              dword |= ((rsp_cmd & 0xf) << 8);
-+                              dword &= ~(0x7 << 5);                   /* PReq 
= preq */
-+                              dword |= ((preq & 0x7) << 5);
-+                              dword &= ~(0x1f << 0);                  /* 
NpReqCmd = np_req_cmd */
-+                              dword |= ((np_req_cmd & 0x1f) << 0);
-+                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x90, dword);
-+                      }
-+              }
-+
-               /* Set up the Link to XCS Token Counts */
-               uint8_t isoc_rsp_tok_1;
-               uint8_t isoc_preq_tok_1;
-@@ -1220,10 +1375,6 @@ static void cpuSetAMDPCI(u8 node)
-               uint8_t preq_tok_0;
-               uint8_t req_tok_0;
- 
--              uint8_t link;
--              uint8_t ganged;
--              uint8_t iolink;
--              uint8_t probe_filter_enabled = !!dual_node;
-               for (link = 0; link < 4; link++) {
-                       if (AMD_CpuFindCapability(node, link, &offset)) {
-                               ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0105-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
 
b/resources/libreboot/patch/kgpe-d16/0105-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
new file mode 100644
index 0000000..c75a505
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0105-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch
@@ -0,0 +1,123 @@
+From 87e62122ea2d2ee8c540be8694d90e182b71ea01 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 8 Aug 2015 20:29:27 -0500
+Subject: [PATCH 105/143] northbridge/amd/amdfam10: Add Family 15h cache
+ partitioning support
+
+Change-Id: Ie4e28dd886aaa1c586b0919c5fe87ef1696f47e9
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/northbridge.c |   94 ++++++++++++++++++++++++++++
+ 1 file changed, 94 insertions(+)
+
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 3a899c8..4826ea4 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -1809,9 +1809,103 @@ static void detect_and_enable_probe_filter(device_t 
dev)
+       }
+ }
+ 
++static void detect_and_enable_cache_partitioning(device_t dev)
++{
++      uint8_t i;
++      uint32_t dword;
++
++      if (is_fam15h()) {
++              printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n");
++
++              uint32_t f5x80;
++              uint8_t cu_enabled;
++              uint8_t compute_unit_count = 0;
++
++              uint32_t f3xe8;
++              uint8_t dual_node = 0;
++
++              for (i = 0; i < sysconf.nodes; i++) {
++                      device_t f3x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
3));
++                      device_t f4x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
4));
++                      device_t f5x_dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 
5));
++
++                      f3xe8 = pci_read_config32(f3x_dev, 0xe8);
++
++                      /* Check for dual node capability */
++                      if (f3xe8 & 0x20000000)
++                              dual_node = 1;
++
++                      /* Determine the number of active compute units on this 
node */
++                      f5x80 = pci_read_config32(f5x_dev, 0x80);
++                      cu_enabled = f5x80 & 0xf;
++                      if (cu_enabled == 0x1)
++                              compute_unit_count = 1;
++                      if (cu_enabled == 0x3)
++                              compute_unit_count = 2;
++                      if (cu_enabled == 0x7)
++                              compute_unit_count = 3;
++                      if (cu_enabled == 0xf)
++                              compute_unit_count = 4;
++
++                      /* Disable BAN mode */
++                      dword = pci_read_config32(f3x_dev, 0x1b8);
++                      dword &= ~(0x7 << 19);  /* L3BanMode = 0x0 */
++                      pci_write_config32(f3x_dev, 0x1b8, dword);
++
++                      /* Set up cache mapping */
++                      dword = pci_read_config32(f4x_dev, 0x1d4);
++                      if (compute_unit_count == 1) {
++                              dword |= 0xf;           /* 
ComputeUnit0SubCacheEn = 0xf */
++                      }
++                      if (compute_unit_count == 2) {
++                              dword &= ~(0xf << 4);   /* 
ComputeUnit1SubCacheEn = 0xc */
++                              dword |= (0xc << 4);
++                              dword &= ~0xf;          /* 
ComputeUnit0SubCacheEn = 0x3 */
++                              dword |= 0x3;
++                      }
++                      if (compute_unit_count == 3) {
++                              dword &= ~(0xf << 8);   /* 
ComputeUnit2SubCacheEn = 0x8 */
++                              dword |= (0x8 << 8);
++                              dword &= ~(0xf << 4);   /* 
ComputeUnit1SubCacheEn = 0x4 */
++                              dword |= (0x4 << 4);
++                              dword &= ~0xf;          /* 
ComputeUnit0SubCacheEn = 0x3 */
++                              dword |= 0x3;
++                      }
++                      if (compute_unit_count == 4) {
++                              dword &= ~(0xf << 12);  /* 
ComputeUnit3SubCacheEn = 0x8 */
++                              dword |= (0x8 << 12);
++                              dword &= ~(0xf << 8);   /* 
ComputeUnit2SubCacheEn = 0x4 */
++                              dword |= (0x4 << 8);
++                              dword &= ~(0xf << 4);   /* 
ComputeUnit1SubCacheEn = 0x2 */
++                              dword |= (0x2 << 4);
++                              dword &= ~0xf;          /* 
ComputeUnit0SubCacheEn = 0x1 */
++                              dword |= 0x1;
++                      }
++                      pci_write_config32(f4x_dev, 0x1d4, dword);
++
++                      /* Enable cache partitioning */
++                      pci_write_config32(f4x_dev, 0x1d4, dword);
++                      if (compute_unit_count == 1) {
++                              dword &= ~(0xf << 26);  /* 
MaskUpdateForComputeUnit = 0x1 */
++                              dword |= (0x1 << 26);
++                      } else if (compute_unit_count == 2) {
++                              dword &= ~(0xf << 26);  /* 
MaskUpdateForComputeUnit = 0x3 */
++                              dword |= (0x3 << 26);
++                      } else if (compute_unit_count == 3) {
++                              dword &= ~(0xf << 26);  /* 
MaskUpdateForComputeUnit = 0x7 */
++                              dword |= (0x7 << 26);
++                      } else if (compute_unit_count == 4) {
++                              dword |= (0xf << 26);   /* 
MaskUpdateForComputeUnit = 0xf */
++                      }
++                      pci_write_config32(f4x_dev, 0x1d4, dword);
++              }
++      }
++}
++
+ static void cpu_bus_init(device_t dev)
+ {
+       detect_and_enable_probe_filter(dev);
++      detect_and_enable_cache_partitioning(dev);
+       initialize_cpus(dev->link_list);
+ #if CONFIG_AMD_SB_CIMX
+       sb_After_Pci_Init();
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0106-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
 
b/resources/libreboot/patch/kgpe-d16/0106-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
new file mode 100644
index 0000000..2cf8048
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0106-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch
@@ -0,0 +1,27 @@
+From ea9a0276634c0d2ddfdcbe75e350416568453dae Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 8 Aug 2015 20:29:55 -0500
+Subject: [PATCH 106/143] amd/amdmct/mct_ddr3: Set prefetch double stride to
+ improve performance
+
+Change-Id: I34ad85388c6b71f0d44bee13afd663e0b84545cd
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 330f37f..de6c79c 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -5563,6 +5563,7 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+                               val &= ~(0x7 << 8);             /* 
CohPrefPrbLmt = 0x1 */
+                               val |= (0x1 << 8);
+                               val |= (0x1 << 12);             /* 
EnSplitDctLimits = 0x1 */
++                              val |= (0x1 << 20);             /* DblPrefEn = 
0x1 */
+                               val |= (0x7 << 22);             /* PrefFourConf 
= 0x7 */
+                               val |= (0x7 << 25);             /* PrefFiveConf 
= 0x7 */
+                               val &= ~(0xf << 28);            /* DcqBwThrotWm 
= 0x0 */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0106-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
 
b/resources/libreboot/patch/kgpe-d16/0106-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
deleted file mode 100644
index 8cfb82c..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0106-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
+++ /dev/null
@@ -1,43 +0,0 @@
-From c4c97a2bf72bf0547a6c587a7096620a0e28773d Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 8 Aug 2015 20:31:03 -0500
-Subject: [PATCH 106/139] cpu/amd/family_10h-family_15h: Set up cache controls
- on Family 15h to improve performance
-
-Change-Id: I3df571d8091c07ac1ee29bf16b5a68585fa9eed4
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h | 10 ++++++++--
- 1 file changed, 8 insertions(+), 2 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index 5ab4335..ce25b25 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -139,8 +139,9 @@ static const struct {
-         0x00000000, 1 << (42-32)},    /* Bx [PwcDisableWalkerSharing]=1 */
- 
-       { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL,
--        1 << 22, 0x00000000,
--        1 << 22, 0x00000000},         /* C0 or above [PfcDoubleStride]=1 */
-+        (0x3 << 20) | (0x1 << 22), 0x00000000,
-+        (0x3 << 20) | (0x1 << 22), 0x00000000},       /* C0 or above 
[PfcDoubleStride]=1,
-+                                                         PfcStrideMul]=0x3 */
- 
-       { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
-         0x00000000, 1 << (54-32),
-@@ -646,6 +647,11 @@ static const struct {
-        * System software should set F5x88[14] to 1b. */
-       { 5, 0x88, AMD_OR_B2, AMD_PTYPE_ALL,
-         1 << 14, 1 << 14 },
-+
-+      /* L3 Control 2 */
-+      { 3, 0x1b8, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000090, 0x000001d0 },     /* ImplRdProjDelayThresh = 0x2,
-+                                         ImplRdAnySubUnavail = 0x1 */
- };
- 
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
 
b/resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
new file mode 100644
index 0000000..e11a27d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-Family-15h-Link.patch
@@ -0,0 +1,192 @@
+From 9e1d2f70fb0e1d50c2314072b7fb019ed7cd283e Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 8 Aug 2015 20:30:36 -0500
+Subject: [PATCH 107/143] cpu/amd/family_10h-family_15h: Set up Family 15h
+ Link Base Channel Buffer Count registers
+
+Change-Id: I8d616a64a5a9cf0b51288535f5050c6866d0996b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |  159 ++++++++++++++++++++++++-
+ 1 file changed, 155 insertions(+), 4 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index e93c15b..59d745d 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -1204,6 +1204,161 @@ static void cpuSetAMDPCI(u8 node)
+               dword |= (compute_unit_buffer_count << 4);
+               pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
+ 
++              uint8_t link;
++              uint8_t ganged;
++              uint8_t iolink;
++              uint8_t probe_filter_enabled = !!dual_node;
++
++              /* Set up the Link Base Channel Buffer Count */
++              uint8_t isoc_rsp_data;
++              uint8_t isoc_np_req_data;
++              uint8_t isoc_rsp_cmd;
++              uint8_t isoc_preq;
++              uint8_t isoc_np_req_cmd;
++              uint8_t free_data;
++              uint8_t free_cmd;
++              uint8_t rsp_data;
++              uint8_t np_req_data;
++              uint8_t probe_cmd;
++              uint8_t rsp_cmd;
++              uint8_t preq;
++              uint8_t np_req_cmd;
++
++              for (link = 0; link < 4; link++) {
++                      if (AMD_CpuFindCapability(node, link, &offset)) {
++                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
++                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
++
++                              if (!iolink && ganged) {
++                                      if (probe_filter_enabled) {
++                                              isoc_rsp_data = 0;
++                                              isoc_np_req_data = 0;
++                                              isoc_rsp_cmd = 0;
++                                              isoc_preq = 0;
++                                              isoc_np_req_cmd = 1;
++                                              free_data = 0;
++                                              free_cmd = 8;
++                                              rsp_data = 3;
++                                              np_req_data = 3;
++                                              probe_cmd = 4;
++                                              rsp_cmd = 9;
++                                              preq = 2;
++                                              np_req_cmd = 8;
++                                      } else {
++                                              isoc_rsp_data = 0;
++                                              isoc_np_req_data = 0;
++                                              isoc_rsp_cmd = 0;
++                                              isoc_preq = 0;
++                                              isoc_np_req_cmd = 1;
++                                              free_data = 0;
++                                              free_cmd = 8;
++                                              rsp_data = 3;
++                                              np_req_data = 3;
++                                              probe_cmd = 8;
++                                              rsp_cmd = 9;
++                                              preq = 2;
++                                              np_req_cmd = 4;
++                                      }
++                              } else if (!iolink && !ganged) {
++                                      if (probe_filter_enabled) {
++                                              isoc_rsp_data = 0;
++                                              isoc_np_req_data = 0;
++                                              isoc_rsp_cmd = 0;
++                                              isoc_preq = 0;
++                                              isoc_np_req_cmd = 1;
++                                              free_data = 0;
++                                              free_cmd = 8;
++                                              rsp_data = 3;
++                                              np_req_data = 3;
++                                              probe_cmd = 4;
++                                              rsp_cmd = 9;
++                                              preq = 2;
++                                              np_req_cmd = 8;
++                                      } else {
++                                              isoc_rsp_data = 0;
++                                              isoc_np_req_data = 0;
++                                              isoc_rsp_cmd = 0;
++                                              isoc_preq = 0;
++                                              isoc_np_req_cmd = 1;
++                                              free_data = 0;
++                                              free_cmd = 4;
++                                              rsp_data = 3;
++                                              np_req_data = 3;
++                                              probe_cmd = 4;
++                                              rsp_cmd = 9;
++                                              preq = 2;
++                                              np_req_cmd = 4;
++                                      }
++                              } else if (iolink && ganged) {
++                                      isoc_rsp_data = 0;
++                                      isoc_np_req_data = 0;
++                                      isoc_rsp_cmd = 0;
++                                      isoc_preq = 0;
++                                      isoc_np_req_cmd = 1;
++                                      free_data = 0;
++                                      free_cmd = 8;
++                                      rsp_data = 1;
++                                      np_req_data = 0;
++                                      probe_cmd = 0;
++                                      rsp_cmd = 2;
++                                      preq = 7;
++                                      np_req_cmd = 14;
++                              } else {
++                                      /* FIXME
++                                       * This is an educated guess as the 
BKDG does not specify
++                                       * the appropriate buffer counts for 
this case!
++                                       */
++                                      isoc_rsp_data = 0;
++                                      isoc_np_req_data = 0;
++                                      isoc_rsp_cmd = 0;
++                                      isoc_preq = 0;
++                                      isoc_np_req_cmd = 1;
++                                      free_data = 1;
++                                      free_cmd = 8;
++                                      rsp_data = 1;
++                                      np_req_data = 1;
++                                      probe_cmd = 0;
++                                      rsp_cmd = 2;
++                                      preq = 4;
++                                      np_req_cmd = 12;
++                              }
++
++                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x94);
++                              dword &= ~(0x3 << 27);                  /* 
IsocRspData = isoc_rsp_data */
++                              dword |= ((isoc_rsp_data & 0x3) << 27);
++                              dword &= ~(0x3 << 25);                  /* 
IsocNpReqData = isoc_np_req_data */
++                              dword |= ((isoc_np_req_data & 0x3) << 25);
++                              dword &= ~(0x7 << 22);                  /* 
IsocRspCmd = isoc_rsp_cmd */
++                              dword |= ((isoc_rsp_cmd & 0x7) << 22);
++                              dword &= ~(0x7 << 19);                  /* 
IsocPReq = isoc_preq */
++                              dword |= ((isoc_preq & 0x7) << 19);
++                              dword &= ~(0x7 << 16);                  /* 
IsocNpReqCmd = isoc_np_req_cmd */
++                              dword |= ((isoc_np_req_cmd & 0x7) << 16);
++                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x94, dword);
++
++                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x90);
++                              dword &= ~(0x1 << 31);                  /* 
LockBc = 0x1 */
++                              dword |= ((0x1 & 0x1) << 31);
++                              dword &= ~(0x7 << 25);                  /* 
FreeData = free_data */
++                              dword |= ((free_data & 0x7) << 25);
++                              dword &= ~(0x1f << 20);                 /* 
FreeCmd = free_cmd */
++                              dword |= ((free_cmd & 0x1f) << 20);
++                              dword &= ~(0x3 << 18);                  /* 
RspData = rsp_data */
++                              dword |= ((rsp_data & 0x3) << 18);
++                              dword &= ~(0x3 << 16);                  /* 
NpReqData = np_req_data */
++                              dword |= ((np_req_data & 0x3) << 16);
++                              dword &= ~(0xf << 12);                  /* 
ProbeCmd = probe_cmd */
++                              dword |= ((probe_cmd & 0xf) << 12);
++                              dword &= ~(0xf << 8);                   /* 
RspCmd = rsp_cmd */
++                              dword |= ((rsp_cmd & 0xf) << 8);
++                              dword &= ~(0x7 << 5);                   /* PReq 
= preq */
++                              dword |= ((preq & 0x7) << 5);
++                              dword &= ~(0x1f << 0);                  /* 
NpReqCmd = np_req_cmd */
++                              dword |= ((np_req_cmd & 0x1f) << 0);
++                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x90, dword);
++                      }
++              }
++
+               /* Set up the Link to XCS Token Counts */
+               uint8_t isoc_rsp_tok_1;
+               uint8_t isoc_preq_tok_1;
+@@ -1221,10 +1376,6 @@ static void cpuSetAMDPCI(u8 node)
+               uint8_t preq_tok_0;
+               uint8_t req_tok_0;
+ 
+-              uint8_t link;
+-              uint8_t ganged;
+-              uint8_t iolink;
+-              uint8_t probe_filter_enabled = !!dual_node;
+               for (link = 0; link < 4; link++) {
+                       if (AMD_CpuFindCapability(node, link, &offset)) {
+                               ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
 
b/resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
deleted file mode 100644
index 6d2c7e6..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0107-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
+++ /dev/null
@@ -1,66 +0,0 @@
-From abac0edc90bff68cf30b60096c0db5214d8ef7f9 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sat, 8 Aug 2015 22:14:59 -0500
-Subject: [PATCH 107/139] cpu/amd/family_10h-family_15h: Set up SRI to XCS
- Token Count registers on Family 15h
-
-Change-Id: Ic992efad11d8e231ec85c793cf1e478bea0b9d3e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 40 +++++++++++++++++++++++++++
- 1 file changed, 40 insertions(+)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 63ad346..115338e 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -1642,6 +1642,46 @@ static void cpuSetAMDPCI(u8 node)
-                               pci_write_config32(NODE_PCI(node, 3), (link << 
2) + 0x148, dword);
-                       }
-               }
-+
-+              /* Set up the SRI to XCS Token Count */
-+              uint8_t free_tok;
-+              uint8_t up_rsp_tok;
-+
-+              /* Set defaults */
-+              free_tok = 0xa;
-+              up_rsp_tok = 0x3;
-+
-+              if (!dual_node) {
-+                      free_tok = 0xa;
-+                      up_rsp_tok = 0x3;
-+              } else {
-+                      if ((sockets == 1)
-+                              || ((sockets == 2) && (sockets_populated == 
1))) {
-+                              if (probe_filter_enabled) {
-+                                      free_tok = 0x9;
-+                                      up_rsp_tok = 0x3;
-+                              } else {
-+                                      free_tok = 0xa;
-+                                      up_rsp_tok = 0x3;
-+                              }
-+                      } else if ((sockets == 2) && (sockets_populated == 2)) {
-+                              free_tok = 0xb;
-+                              up_rsp_tok = 0x1;
-+                      } else if ((sockets == 4) && (sockets_populated == 2)) {
-+                              free_tok = 0xa;
-+                              up_rsp_tok = 0x3;
-+                      } else if ((sockets == 4) && (sockets_populated == 4)) {
-+                              free_tok = 0x9;
-+                              up_rsp_tok = 0x1;
-+                      }
-+              }
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0x140);
-+              dword &= ~(0xf << 20);                  /* FreeTok = free_tok */
-+              dword |= ((free_tok & 0xf) << 20);
-+              dword &= ~(0x3 << 8);                   /* UpRspTok = 
up_rsp_tok */
-+              dword |= ((up_rsp_tok & 0x3) << 8);
-+              pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
-       }
- 
-       printk(BIOS_DEBUG, " done\n");
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0108-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
 
b/resources/libreboot/patch/kgpe-d16/0108-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
deleted file mode 100644
index b160d2b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0108-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-From 4e4d10b69d13a3b15065bb2ee8f8c9b6a7d9ac89 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 9 Aug 2015 02:47:51 -0500
-Subject: [PATCH 108/139] amd/amdfam10: Control Family 15h cache partitioning
- and memory performance via nvram
-
-Change-Id: I3dd5d7f3640aee0395a68645c0242307605d3ce7
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h  |  5 ++---
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 13 +++++++++++++
- src/mainboard/asus/kgpe-d16/cmos.default      |  3 +++
- src/mainboard/asus/kgpe-d16/cmos.layout       |  9 +++++++--
- src/northbridge/amd/amdfam10/northbridge.c    | 22 ++++++++++++++++++++++
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   | 11 ++++++++++-
- 6 files changed, 57 insertions(+), 6 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index ce25b25..af59120 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -139,9 +139,8 @@ static const struct {
-         0x00000000, 1 << (42-32)},    /* Bx [PwcDisableWalkerSharing]=1 */
- 
-       { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL,
--        (0x3 << 20) | (0x1 << 22), 0x00000000,
--        (0x3 << 20) | (0x1 << 22), 0x00000000},       /* C0 or above 
[PfcDoubleStride]=1,
--                                                         PfcStrideMul]=0x3 */
-+        1 << 22, 0x00000000,
-+        1 << 22, 0x00000000},         /* C0 or above [PfcDoubleStride]=1 */
- 
-       { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
-         0x00000000, 1 << (54-32),
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 115338e..2234197 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -981,6 +981,13 @@ void cpuSetAMDMSR(uint8_t node_id)
- 
-       /* Revision C0 and above */
-       if (revision & AMD_OR_C0) {
-+              uint8_t enable_experimental_memory_speed_boost;
-+
-+              /* Check to see if cache partitioning is allowed */
-+              enable_experimental_memory_speed_boost = 0;
-+              if (get_option(&nvram, "experimental_memory_speed_boost") == 
CB_SUCCESS)
-+                      enable_experimental_memory_speed_boost = !!nvram;
-+
-               uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 
0x1fc);
-               msr = rdmsr(FP_CFG);
-               msr.hi &= ~(0x7 << (42-32));                    /* DiDtCfg4 */
-@@ -1000,6 +1007,12 @@ void cpuSetAMDMSR(uint8_t node_id)
-               msr.lo &= ~(0x1 << 16);                         /* DiDtMode */
-               msr.lo |= ((f3x1fc & 0x1) << 16);
-               wrmsr(FP_CFG, msr);
-+
-+              if (enable_experimental_memory_speed_boost) {
-+                      msr = rdmsr(BU_CFG3);
-+                      msr.lo |= (0x3 << 20);                  /* PfcStrideMul 
= 0x3 */
-+                      wrmsr(BU_CFG3, msr);
-+              }
-       }
- 
- #if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || 
IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index 9b30b00..0a898bd 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -20,6 +20,9 @@ cpu_cc6_state = Enable
- sata_ahci_mode = Enable
- sata_alpm = Disable
- maximum_p_state_limit = 0xf
-+probe_filter = Auto
-+l3_cache_partitioning = Disable
- ieee1394 = Enable
-+experimental_memory_speed_boost = Disable
- power_on_after_fail = On
- boot_option = Fallback
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index ec803b6..010d4db 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -49,8 +49,11 @@ entries
- 468          1       e       1        sata_alpm
- 469          4       h       0        maximum_p_state_limit
- 473          2       e       13       dimm_spd_checksum
--475          1       r       0        allow_spd_nvram_cache_restore
--477          1       e       1        ieee1394
-+475          1       e       14       probe_filter
-+476          1       e       1        l3_cache_partitioning
-+477          1       e       1        experimental_memory_speed_boost
-+478          1       r       0        allow_spd_nvram_cache_restore
-+479          1       e       1        ieee1394
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
- # Reserve the extended AMD configuration registers
-@@ -147,6 +150,8 @@ enumerations
- 13    0     Enforce
- 13    1     Ignore
- 13    2     Override
-+14    0     Disable
-+14    1     Auto
- 
- checksums
- 
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 8ad5200..58b0079 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -1654,6 +1654,17 @@ static void detect_and_enable_probe_filter(device_t dev)
- {
-       uint32_t dword;
- 
-+      uint8_t nvram;
-+      uint8_t enable_probe_filter;
-+
-+      /* Check to see if the probe filter is allowed */
-+      enable_probe_filter = 1;
-+      if (get_option(&nvram, "probe_filter") == CB_SUCCESS)
-+              enable_probe_filter = !!nvram;
-+
-+      if (!enable_probe_filter)
-+              return;
-+
-       uint8_t fam15h = 0;
-       uint8_t rev_gte_d = 0;
-       uint8_t dual_node = 0;
-@@ -1814,6 +1825,17 @@ static void 
detect_and_enable_cache_partitioning(device_t dev)
-       uint8_t i;
-       uint32_t dword;
- 
-+      uint8_t nvram;
-+      uint8_t enable_l3_cache_partitioning;
-+
-+      /* Check to see if cache partitioning is allowed */
-+      enable_l3_cache_partitioning = 0;
-+      if (get_option(&nvram, "l3_cache_partitioning") == CB_SUCCESS)
-+              enable_l3_cache_partitioning = !!nvram;
-+
-+      if (!enable_l3_cache_partitioning)
-+              return;
-+
-       if (is_fam15h()) {
-               printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n");
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index de6c79c..42630b9 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -5550,6 +5550,14 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
-                               mct_ExtMCTConfig_Dx(pDCTstat);
-                       } else {
-                               /* Family 15h CPUs */
-+                              uint8_t nvram;
-+                              uint8_t enable_experimental_memory_speed_boost;
-+
-+                              /* Check to see if cache partitioning is 
allowed */
-+                              enable_experimental_memory_speed_boost = 0;
-+                              if (get_option(&nvram, 
"experimental_memory_speed_boost") == CB_SUCCESS)
-+                                      enable_experimental_memory_speed_boost 
= !!nvram;
-+
-                               val = 0x0ce00f00;               /* 
FlushWrOnStpGnt = 0x0 */
-                               val |= 0x10 << 2;               /* MctWrLimit = 
0x10 */
-                               val |= 0x1;                     /* DctWrLimit = 
0x1 */
-@@ -5563,7 +5571,8 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
-                               val &= ~(0x7 << 8);             /* 
CohPrefPrbLmt = 0x1 */
-                               val |= (0x1 << 8);
-                               val |= (0x1 << 12);             /* 
EnSplitDctLimits = 0x1 */
--                              val |= (0x1 << 20);             /* DblPrefEn = 
0x1 */
-+                              if (enable_experimental_memory_speed_boost)
-+                                      val |= (0x1 << 20);     /* DblPrefEn = 
0x1 */
-                               val |= (0x7 << 22);             /* PrefFourConf 
= 0x7 */
-                               val |= (0x7 << 25);             /* PrefFiveConf 
= 0x7 */
-                               val &= ~(0xf << 28);            /* DcqBwThrotWm 
= 0x0 */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0108-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
 
b/resources/libreboot/patch/kgpe-d16/0108-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
new file mode 100644
index 0000000..5573e0e
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0108-cpu-amd-family_10h-family_15h-Set-up-cache-controls-.patch
@@ -0,0 +1,43 @@
+From acf2af4d866e51afce92092adf240c72d7193757 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 8 Aug 2015 20:31:03 -0500
+Subject: [PATCH 108/143] cpu/amd/family_10h-family_15h: Set up cache controls
+ on Family 15h to improve performance
+
+Change-Id: I3df571d8091c07ac1ee29bf16b5a68585fa9eed4
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h |   10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index 5ab4335..ce25b25 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -139,8 +139,9 @@ static const struct {
+         0x00000000, 1 << (42-32)},    /* Bx [PwcDisableWalkerSharing]=1 */
+ 
+       { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL,
+-        1 << 22, 0x00000000,
+-        1 << 22, 0x00000000},         /* C0 or above [PfcDoubleStride]=1 */
++        (0x3 << 20) | (0x1 << 22), 0x00000000,
++        (0x3 << 20) | (0x1 << 22), 0x00000000},       /* C0 or above 
[PfcDoubleStride]=1,
++                                                         PfcStrideMul]=0x3 */
+ 
+       { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
+         0x00000000, 1 << (54-32),
+@@ -646,6 +647,11 @@ static const struct {
+        * System software should set F5x88[14] to 1b. */
+       { 5, 0x88, AMD_OR_B2, AMD_PTYPE_ALL,
+         1 << 14, 1 << 14 },
++
++      /* L3 Control 2 */
++      { 3, 0x1b8, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000090, 0x000001d0 },     /* ImplRdProjDelayThresh = 0x2,
++                                         ImplRdAnySubUnavail = 0x1 */
+ };
+ 
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0109-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
 
b/resources/libreboot/patch/kgpe-d16/0109-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
new file mode 100644
index 0000000..79e297e
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0109-cpu-amd-family_10h-family_15h-Set-up-SRI-to-XCS-Toke.patch
@@ -0,0 +1,66 @@
+From 6e4bf582d1d1cf515f1dec738e02bb7e123ac227 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sat, 8 Aug 2015 22:14:59 -0500
+Subject: [PATCH 109/143] cpu/amd/family_10h-family_15h: Set up SRI to XCS
+ Token Count registers on Family 15h
+
+Change-Id: Ic992efad11d8e231ec85c793cf1e478bea0b9d3e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |   40 +++++++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index 59d745d..f4254f0 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -1643,6 +1643,46 @@ static void cpuSetAMDPCI(u8 node)
+                               pci_write_config32(NODE_PCI(node, 3), (link << 
2) + 0x148, dword);
+                       }
+               }
++
++              /* Set up the SRI to XCS Token Count */
++              uint8_t free_tok;
++              uint8_t up_rsp_tok;
++
++              /* Set defaults */
++              free_tok = 0xa;
++              up_rsp_tok = 0x3;
++
++              if (!dual_node) {
++                      free_tok = 0xa;
++                      up_rsp_tok = 0x3;
++              } else {
++                      if ((sockets == 1)
++                              || ((sockets == 2) && (sockets_populated == 
1))) {
++                              if (probe_filter_enabled) {
++                                      free_tok = 0x9;
++                                      up_rsp_tok = 0x3;
++                              } else {
++                                      free_tok = 0xa;
++                                      up_rsp_tok = 0x3;
++                              }
++                      } else if ((sockets == 2) && (sockets_populated == 2)) {
++                              free_tok = 0xb;
++                              up_rsp_tok = 0x1;
++                      } else if ((sockets == 4) && (sockets_populated == 2)) {
++                              free_tok = 0xa;
++                              up_rsp_tok = 0x3;
++                      } else if ((sockets == 4) && (sockets_populated == 4)) {
++                              free_tok = 0x9;
++                              up_rsp_tok = 0x1;
++                      }
++              }
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0x140);
++              dword &= ~(0xf << 20);                  /* FreeTok = free_tok */
++              dword |= ((free_tok & 0xf) << 20);
++              dword &= ~(0x3 << 8);                   /* UpRspTok = 
up_rsp_tok */
++              dword |= ((up_rsp_tok & 0x3) << 8);
++              pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
+       }
+ 
+       printk(BIOS_DEBUG, " done\n");
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0109-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
 
b/resources/libreboot/patch/kgpe-d16/0109-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
deleted file mode 100644
index f4d5b49..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0109-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
+++ /dev/null
@@ -1,272 +0,0 @@
-From e94372dfb597ff2d28047e5d63d22ee33e1db0c7 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 11 Aug 2015 17:47:48 -0500
-Subject: [PATCH 109/139] northbridge/amd/amdht: Add isochronous setup support
- for coherent fabric
-
-Change-Id: Idd7c9b94a65f856b0059e1d45f8719d9475771b6
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 59 +++++++++++++++++++++++++++
- src/northbridge/amd/amdht/h3ffeat.h           |  3 ++
- src/northbridge/amd/amdht/h3finit.c           | 34 ++++++++++++++-
- src/northbridge/amd/amdht/h3finit.h           |  4 +-
- src/northbridge/amd/amdht/h3ncmn.c            | 26 +++++++++++-
- 5 files changed, 122 insertions(+), 4 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 2234197..7a0701c 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -1697,6 +1697,65 @@ static void cpuSetAMDPCI(u8 node)
-               pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
-       }
- 
-+      uint8_t link;
-+      uint8_t isochronous;
-+      uint8_t isochronous_link_present;
-+
-+      /* Set up isochronous buffers if needed */
-+      isochronous_link_present = 0;
-+      for (link = 0; link < 4; link++) {
-+              if (AMD_CpuFindCapability(node, link, &offset)) {
-+                      isochronous = (pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x84) >> 12) & 0x1;
-+
-+                      if (isochronous)
-+                              isochronous_link_present = 1;
-+              }
-+      }
-+
-+      uint8_t free_tok;
-+      uint8_t up_rsp_cbc;
-+      uint8_t isoc_preq_cbc;
-+      uint8_t isoc_preq_tok;
-+      uint8_t xbar_to_sri_free_list_cbc;
-+      if (isochronous_link_present) {
-+              /* Adjust buffer counts */
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0x70);
-+              isoc_preq_cbc = (dword >> 24) & 0x7;
-+              up_rsp_cbc = (dword >> 16) & 0x7;
-+              up_rsp_cbc--;
-+              isoc_preq_cbc++;
-+              dword &= ~(0x7 << 24);                  /* IsocPreqCBC = 
isoc_preq_cbc */
-+              dword |= ((isoc_preq_cbc & 0x7) << 24);
-+              dword &= ~(0x7 << 16);                  /* UpRspCBC = 
up_rsp_cbc */
-+              dword |= ((up_rsp_cbc & 0x7) << 16);
-+              pci_write_config32(NODE_PCI(node, 3), 0x70, dword);
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0x74);
-+              isoc_preq_cbc = (dword >> 24) & 0x7;
-+              isoc_preq_cbc++;
-+              dword &= ~(0x7 << 24);                  /* IsocPreqCBC = 
isoc_preq_cbc */
-+              dword |= (isoc_preq_cbc & 0x7) << 24;
-+              pci_write_config32(NODE_PCI(node, 3), 0x74, dword);
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0x7c);
-+              xbar_to_sri_free_list_cbc = dword & 0x1f;
-+              xbar_to_sri_free_list_cbc--;
-+              dword &= ~0x1f;                         /* Xbar2SriFreeListCBC 
= xbar_to_sri_free_list_cbc */
-+              dword |= xbar_to_sri_free_list_cbc & 0x1f;
-+              pci_write_config32(NODE_PCI(node, 3), 0x7c, dword);
-+
-+              dword = pci_read_config32(NODE_PCI(node, 3), 0x140);
-+              free_tok = (dword >> 20) & 0xf;
-+              isoc_preq_tok = (dword >> 14) & 0x3;
-+              free_tok--;
-+              isoc_preq_tok++;
-+              dword &= ~(0xf << 20);                  /* FreeTok = free_tok */
-+              dword |= ((free_tok & 0xf) << 20);
-+              dword &= ~(0x3 << 14);                  /* IsocPreqTok = 
isoc_preq_tok */
-+              dword |= ((isoc_preq_tok & 0x3) << 14);
-+              pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
-+      }
-+
-       printk(BIOS_DEBUG, " done\n");
- }
- 
-diff --git a/src/northbridge/amd/amdht/h3ffeat.h 
b/src/northbridge/amd/amdht/h3ffeat.h
-index 5dc9916..c523b12 100644
---- a/src/northbridge/amd/amdht/h3ffeat.h
-+++ b/src/northbridge/amd/amdht/h3ffeat.h
-@@ -79,6 +79,7 @@
- #define HTSLAVE_LINK01_OFFSET                 4
- #define HTSLAVE_LINK_CONTROL_0_REG            4
- #define HTSLAVE_FREQ_REV_0_REG                        0xC
-+#define HTSLAVE_FEATURE_CAP_REG               0x10
- 
- /* HT3 gen Capability */
- #define IS_HT_GEN3_CAPABILITY(reg) \
-@@ -126,10 +127,12 @@ typedef struct
-       u8 SelWidthIn;
-       u8 SelWidthOut;
-       u8 SelFrequency;
-+      uint8_t enable_isochronous_mode;
- 
-       /* This section is for keeping track of capabilities and possible 
configurations */
-       BOOL RegangCap;
-       uint32_t PrvFrequencyCap;
-+      uint32_t PrvFeatureCap;
-       u8 PrvWidthInCap;
-       u8 PrvWidthOutCap;
-       uint32_t CompositeFrequencyCap;
-diff --git a/src/northbridge/amd/amdht/h3finit.c 
b/src/northbridge/amd/amdht/h3finit.c
-index 14f348f..9d1e7d7 100644
---- a/src/northbridge/amd/amdht/h3finit.c
-+++ b/src/northbridge/amd/amdht/h3finit.c
-@@ -1419,6 +1419,38 @@ static void regangLinks(sMainData *pDat)
- #endif /* HT_BUILD_NC_ONLY */
- }
- 
-+static void detectIoLinkIsochronousCapable(sMainData *pDat)
-+{
-+      uint8_t i;
-+      unsigned char iommu;
-+      uint8_t isochronous_capable = 0;
-+
-+      iommu = 1;
-+      get_option(&iommu, "iommu");
-+
-+      for (i = 0; i < pDat->TotalLinks*2; i += 2) {
-+              if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && 
(pDat->PortList[i+1].Type == PORTLIST_TYPE_IO)) {
-+                      if ((pDat->PortList[i].PrvFeatureCap & 0x1) && 
(pDat->PortList[i+1].PrvFeatureCap & 0x1)) {
-+                              pDat->PortList[i].enable_isochronous_mode = 1;
-+                              pDat->PortList[i+1].enable_isochronous_mode = 1;
-+                              isochronous_capable = 1;
-+                      } else {
-+                              pDat->PortList[i].enable_isochronous_mode = 0;
-+                              pDat->PortList[i+1].enable_isochronous_mode = 0;
-+                      }
-+              }
-+      }
-+
-+      if (isochronous_capable && iommu) {
-+              printk(BIOS_DEBUG, "Forcing HT links to isochronous mode due to 
enabled IOMMU\n");
-+              /* Isochronous mode must be set on all links if the IOMMU is 
enabled */
-+              for (i = 0; i < pDat->TotalLinks*2; i += 2) {
-+                      pDat->PortList[i].enable_isochronous_mode = 1;
-+                      pDat->PortList[i+1].enable_isochronous_mode = 1;
-+              }
-+      }
-+}
-+
- 
/*----------------------------------------------------------------------------------------
-  * void
-  * selectOptimalWidthAndFrequency(sMainData *pDat)
-@@ -1539,7 +1571,6 @@ static void selectOptimalWidthAndFrequency(sMainData 
*pDat)
-                       temp = cbPCBBAUpstreamWidth;
-               pDat->PortList[i].SelWidthIn = (u8)temp;
-               pDat->PortList[i+1].SelWidthOut = (u8)temp;
--
-       }
- }
- 
-@@ -1701,6 +1732,7 @@ static void linkOptimization(sMainData *pDat)
- {
-       pDat->nb->gatherLinkData(pDat, pDat->nb);
-       regangLinks(pDat);
-+      detectIoLinkIsochronousCapable(pDat);
-       selectOptimalWidthAndFrequency(pDat);
-       hammerSublinkFixup(pDat);
-       pDat->nb->setLinkData(pDat, pDat->nb);
-diff --git a/src/northbridge/amd/amdht/h3finit.h 
b/src/northbridge/amd/amdht/h3finit.h
-index 462f3e3..eef8fe7 100644
---- a/src/northbridge/amd/amdht/h3finit.h
-+++ b/src/northbridge/amd/amdht/h3finit.h
-@@ -231,6 +231,7 @@ typedef struct {
-        *      @param[in,out] u8*  LinkWidthIn  = modify to change the Link 
Witdh In
-        *      @param[in,out] u8*  LinkWidthOut  = modify to change the Link 
Witdh Out
-        *      @param[in,out] u32* FreqCap = modify to change the link's 
frequency capability
-+       *      @param[in,out] u32* FeatureCap = modify to change the link's 
feature capability
-        *
-        * 
---------------------------------------------------------------------------------------
-        */
-@@ -245,7 +246,8 @@ typedef struct {
-               u8 Link,
-               u8 *LinkWidthIn,
-               u8 *LinkWidthOut,
--              u32 *FreqCap
-+              u32 *FreqCap,
-+              u32 *FeatureCap
-       );
- 
-       
/**----------------------------------------------------------------------------------------
-diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
-index e377ff2..841fc0c 100644
---- a/src/northbridge/amd/amdht/h3ncmn.c
-+++ b/src/northbridge/amd/amdht/h3ncmn.c
-@@ -1433,12 +1433,15 @@ static void gatherLinkData(sMainData *pDat, 
cNorthBridge *nb)
-                               temp &= 0x7;    /* Mask off reserved values */
-                               pDat->PortList[i].PrvFrequencyCap |= (temp << 
17);
-                       }
-+
-+                      AmdPCIReadBits(linkBase + HTHOST_FEATURE_CAP_REG, 9, 0, 
&temp);
-+                      pDat->PortList[i].PrvFeatureCap = (u16)temp;
-               }
-               else
-               {
-                       linkBase = pDat->PortList[i].Pointer;
-                       if (pDat->PortList[i].Link == 1)
--                       linkBase += HTSLAVE_LINK01_OFFSET;
-+                              linkBase += HTSLAVE_LINK01_OFFSET;
- 
-                       AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 
22, 20, &temp);
-                       pDat->PortList[i].PrvWidthOutCap = 
convertBitsToWidth((u8)temp, pDat->nb);
-@@ -1449,6 +1452,9 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge 
*nb)
-                       AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 
16, &temp);
-                       pDat->PortList[i].PrvFrequencyCap = (u16)temp;
- 
-+                      AmdPCIReadBits(linkBase + HTSLAVE_FEATURE_CAP_REG, 7, 
0, &temp);
-+                      pDat->PortList[i].PrvFeatureCap = (u16)temp;
-+
-                       if (pDat->HtBlock->AMD_CB_DeviceCapOverride)
-                       {
-                               linkBase &= 0xFFFFF000;
-@@ -1465,7 +1471,8 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge 
*nb)
-                                       pDat->PortList[i].Link,
-                                       &(pDat->PortList[i].PrvWidthInCap),
-                                       &(pDat->PortList[i].PrvWidthOutCap),
--                                      &(pDat->PortList[i].PrvFrequencyCap));
-+                                      &(pDat->PortList[i].PrvFrequencyCap),
-+                                      &(pDat->PortList[i].PrvFeatureCap));
-                       }
-               }
-       }
-@@ -1566,6 +1573,14 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
-                       if (is_gt_rev_d())
-                               AmdPCIWriteBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 0, 0, &temp2);
-                       AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, 
&temp);
-+
-+                      /* Enable isochronous flow control mode if supported by 
chipset */
-+                      if (pDat->PortList[i].enable_isochronous_mode)
-+                              temp = 1;
-+                      else
-+                              temp = 0;
-+                      setHtControlRegisterBits(linkBase + 
HTHOST_LINK_CONTROL_REG, 12, 12, &temp);
-+
-                       if (frequency_index > HT_FREQUENCY_1000M) /*  Gen1 = 
200MHz -> 1000MHz, Gen3 = 1200MHz -> 3200MHz */
-                       {
-                               /* Enable  for Gen3 frequencies */
-@@ -1583,6 +1598,7 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
-                                               CPU_HTNB_FUNC_00,
-                                               REG_HT_LINK_RETRY0_0X130 + 
4*pDat->PortList[i].Link),
-                                               0, 0, &temp);
-+
-                       /* and Scrambling enable / disable */
-                       
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
-                                       
makePCIBusFromNode(pDat->PortList[i].NodeID),
-@@ -1621,6 +1637,12 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
-                               bits = 0;
-                       }
- 
-+                      /* Enable isochronous flow control mode if supported by 
chipset */
-+                      if (pDat->PortList[i].enable_isochronous_mode)
-+                              temp = 1;
-+                      else
-+                              temp = 0;
-+
-                       /* Retry Enable */
-                       isFound = FALSE;
-                       currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI 
Offset to 0 */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0110-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
 
b/resources/libreboot/patch/kgpe-d16/0110-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
new file mode 100644
index 0000000..b35a0c5
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0110-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch
@@ -0,0 +1,190 @@
+From ce44752d64232ea61ffa8747ffe0883229bd7df6 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 9 Aug 2015 02:47:51 -0500
+Subject: [PATCH 110/143] amd/amdfam10: Control Family 15h cache partitioning
+ and memory performance via nvram
+
+Change-Id: I3dd5d7f3640aee0395a68645c0242307605d3ce7
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h  |    5 ++---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |   16 ++++++++++++++--
+ src/mainboard/asus/kgpe-d16/cmos.default      |    3 +++
+ src/mainboard/asus/kgpe-d16/cmos.layout       |    9 +++++++--
+ src/northbridge/amd/amdfam10/northbridge.c    |   22 ++++++++++++++++++++++
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |   11 ++++++++++-
+ 6 files changed, 58 insertions(+), 8 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index ce25b25..af59120 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -139,9 +139,8 @@ static const struct {
+         0x00000000, 1 << (42-32)},    /* Bx [PwcDisableWalkerSharing]=1 */
+ 
+       { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL,
+-        (0x3 << 20) | (0x1 << 22), 0x00000000,
+-        (0x3 << 20) | (0x1 << 22), 0x00000000},       /* C0 or above 
[PfcDoubleStride]=1,
+-                                                         PfcStrideMul]=0x3 */
++        1 << 22, 0x00000000,
++        1 << 22, 0x00000000},         /* C0 or above [PfcDoubleStride]=1 */
+ 
+       { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL,
+         0x00000000, 1 << (54-32),
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index f4254f0..7dffcc0 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -956,6 +956,7 @@ void cpuSetAMDMSR(uint8_t node_id)
+        */
+       msr_t msr;
+       u8 i;
++      uint8_t nvram;
+       u32 platform;
+       uint64_t revision;
+       uint8_t enable_c_states;
+@@ -980,6 +981,13 @@ void cpuSetAMDMSR(uint8_t node_id)
+ 
+       /* Revision C0 and above */
+       if (revision & AMD_OR_C0) {
++              uint8_t enable_experimental_memory_speed_boost;
++
++              /* Check to see if cache partitioning is allowed */
++              enable_experimental_memory_speed_boost = 0;
++              if (get_option(&nvram, "experimental_memory_speed_boost") == 
CB_SUCCESS)
++                      enable_experimental_memory_speed_boost = !!nvram;
++
+               uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 
0x1fc);
+               msr = rdmsr(FP_CFG);
+               msr.hi &= ~(0x7 << (42-32));                    /* DiDtCfg4 */
+@@ -999,11 +1007,15 @@ void cpuSetAMDMSR(uint8_t node_id)
+               msr.lo &= ~(0x1 << 16);                         /* DiDtMode */
+               msr.lo |= ((f3x1fc & 0x1) << 16);
+               wrmsr(FP_CFG, msr);
++
++              if (enable_experimental_memory_speed_boost) {
++                      msr = rdmsr(BU_CFG3);
++                      msr.lo |= (0x3 << 20);                  /* PfcStrideMul 
= 0x3 */
++                      wrmsr(BU_CFG3, msr);
++              }
+       }
+ 
+ #if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) || 
IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB800)
+-      uint8_t nvram;
+-
+       if (revision & (AMD_DR_GT_D0 | AMD_FAM15_ALL)) {
+               /* Set up message triggered C1E */
+               msr = rdmsr(0xc0010055);
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index 9b30b00..0a898bd 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -20,6 +20,9 @@ cpu_cc6_state = Enable
+ sata_ahci_mode = Enable
+ sata_alpm = Disable
+ maximum_p_state_limit = 0xf
++probe_filter = Auto
++l3_cache_partitioning = Disable
+ ieee1394 = Enable
++experimental_memory_speed_boost = Disable
+ power_on_after_fail = On
+ boot_option = Fallback
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index ec803b6..010d4db 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -49,8 +49,11 @@ entries
+ 468          1       e       1        sata_alpm
+ 469          4       h       0        maximum_p_state_limit
+ 473          2       e       13       dimm_spd_checksum
+-475          1       r       0        allow_spd_nvram_cache_restore
+-477          1       e       1        ieee1394
++475          1       e       14       probe_filter
++476          1       e       1        l3_cache_partitioning
++477          1       e       1        experimental_memory_speed_boost
++478          1       r       0        allow_spd_nvram_cache_restore
++479          1       e       1        ieee1394
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+ # Reserve the extended AMD configuration registers
+@@ -147,6 +150,8 @@ enumerations
+ 13    0     Enforce
+ 13    1     Ignore
+ 13    2     Override
++14    0     Disable
++14    1     Auto
+ 
+ checksums
+ 
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 4826ea4..740fd79 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -1654,6 +1654,17 @@ static void detect_and_enable_probe_filter(device_t dev)
+ {
+       uint32_t dword;
+ 
++      uint8_t nvram;
++      uint8_t enable_probe_filter;
++
++      /* Check to see if the probe filter is allowed */
++      enable_probe_filter = 1;
++      if (get_option(&nvram, "probe_filter") == CB_SUCCESS)
++              enable_probe_filter = !!nvram;
++
++      if (!enable_probe_filter)
++              return;
++
+       uint8_t fam15h = 0;
+       uint8_t rev_gte_d = 0;
+       uint8_t dual_node = 0;
+@@ -1814,6 +1825,17 @@ static void 
detect_and_enable_cache_partitioning(device_t dev)
+       uint8_t i;
+       uint32_t dword;
+ 
++      uint8_t nvram;
++      uint8_t enable_l3_cache_partitioning;
++
++      /* Check to see if cache partitioning is allowed */
++      enable_l3_cache_partitioning = 0;
++      if (get_option(&nvram, "l3_cache_partitioning") == CB_SUCCESS)
++              enable_l3_cache_partitioning = !!nvram;
++
++      if (!enable_l3_cache_partitioning)
++              return;
++
+       if (is_fam15h()) {
+               printk(BIOS_DEBUG, "Enabling L3 cache partitioning\n");
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index de6c79c..42630b9 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -5550,6 +5550,14 @@ static void mct_FinalMCT_D(struct MCTStatStruc 
*pMCTstat,
+                               mct_ExtMCTConfig_Dx(pDCTstat);
+                       } else {
+                               /* Family 15h CPUs */
++                              uint8_t nvram;
++                              uint8_t enable_experimental_memory_speed_boost;
++
++                              /* Check to see if cache partitioning is 
allowed */
++                              enable_experimental_memory_speed_boost = 0;
++                              if (get_option(&nvram, 
"experimental_memory_speed_boost") == CB_SUCCESS)
++                                      enable_experimental_memory_speed_boost 
= !!nvram;
++
+                               val = 0x0ce00f00;               /* 
FlushWrOnStpGnt = 0x0 */
+                               val |= 0x10 << 2;               /* MctWrLimit = 
0x10 */
+                               val |= 0x1;                     /* DctWrLimit = 
0x1 */
+@@ -5563,7 +5571,8 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat,
+                               val &= ~(0x7 << 8);             /* 
CohPrefPrbLmt = 0x1 */
+                               val |= (0x1 << 8);
+                               val |= (0x1 << 12);             /* 
EnSplitDctLimits = 0x1 */
+-                              val |= (0x1 << 20);             /* DblPrefEn = 
0x1 */
++                              if (enable_experimental_memory_speed_boost)
++                                      val |= (0x1 << 20);     /* DblPrefEn = 
0x1 */
+                               val |= (0x7 << 22);             /* PrefFourConf 
= 0x7 */
+                               val |= (0x7 << 25);             /* PrefFiveConf 
= 0x7 */
+                               val &= ~(0xf << 28);            /* DcqBwThrotWm 
= 0x0 */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0110-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
 
b/resources/libreboot/patch/kgpe-d16/0110-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
deleted file mode 100644
index ea7cd3a..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0110-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
+++ /dev/null
@@ -1,121 +0,0 @@
-From f84ae61b0b82097f318c96ee5c198cf9495568e2 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 11 Aug 2015 17:48:32 -0500
-Subject: [PATCH 110/139] arch/x86/acpi: Add IVRS table generation routines
-
-Change-Id: Ia5d97d01dc9ddc45f81d998d126d592a915b4a75
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/arch/x86/acpi.c              | 25 +++++++++++++++++++++++++
- src/arch/x86/include/arch/acpi.h | 31 +++++++++++++++++++++++++++++++
- 2 files changed, 56 insertions(+)
-
-diff --git a/src/arch/x86/acpi.c b/src/arch/x86/acpi.c
-index 417a322..e73e5f2 100644
---- a/src/arch/x86/acpi.c
-+++ b/src/arch/x86/acpi.c
-@@ -6,6 +6,7 @@
-  *
-  * Copyright (C) 2004 SUSE LINUX AG
-  * Copyright (C) 2005-2009 coresystems GmbH
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * ACPI FADT, FACS, and DSDT table support added by
-  * Nick Barker <address@hidden>, and those portions
-@@ -506,6 +507,30 @@ void acpi_create_hpet(acpi_hpet_t *hpet)
-       header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
- }
- 
-+void acpi_create_ivrs(acpi_ivrs_t *ivrs,
-+                    unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, 
unsigned long current))
-+{
-+      acpi_header_t *header = &(ivrs->header);
-+      unsigned long current = (unsigned long)ivrs + sizeof(acpi_ivrs_t);
-+
-+      memset((void *)ivrs, 0, sizeof(acpi_ivrs_t));
-+
-+      /* Fill out header fields. */
-+      memcpy(header->signature, "IVRS", 4);
-+      memcpy(header->oem_id, OEM_ID, 6);
-+      memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
-+      memcpy(header->asl_compiler_id, ASLC, 4);
-+
-+      header->length = sizeof(acpi_ivrs_t);
-+      header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */
-+
-+      current = acpi_fill_ivrs(ivrs, current);
-+
-+      /* (Re)calculate length and checksum. */
-+      header->length = current - (unsigned long)ivrs;
-+      header->checksum = acpi_checksum((void *)ivrs, header->length);
-+}
-+
- unsigned long acpi_write_hpet(device_t device, unsigned long current, 
acpi_rsdp_t *rsdp)
- {
-       acpi_hpet_t *hpet;
-diff --git a/src/arch/x86/include/arch/acpi.h 
b/src/arch/x86/include/arch/acpi.h
-index 28f650c..7d583b8 100644
---- a/src/arch/x86/include/arch/acpi.h
-+++ b/src/arch/x86/include/arch/acpi.h
-@@ -4,6 +4,7 @@
-  * Copyright (C) 2004 SUSE LINUX AG
-  * Copyright (C) 2004 Nick Barker
-  * Copyright (C) 2008-2009 coresystems GmbH
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  * (Written by Stefan Reinauer <address@hidden>)
-  *
-  * This program is free software; you can redistribute it and/or modify
-@@ -194,6 +195,32 @@ typedef struct acpi_madt {
-       u32 flags;                      /* Multiple APIC flags */
- } __attribute__ ((packed)) acpi_madt_t;
- 
-+typedef struct acpi_ivrs_info {
-+} __attribute__ ((packed)) acpi_ivrs_info_t;
-+
-+/* IVRS IVHD (I/O Virtualization Hardware Definition Block) */
-+typedef struct acpi_ivrs_ivhd {
-+      uint8_t type;
-+      uint8_t flags;
-+      uint16_t length;
-+      uint16_t device_id;
-+      uint16_t capability_offset;
-+      uint32_t iommu_base_low;
-+      uint32_t iommu_base_high;
-+      uint16_t pci_segment_group;
-+      uint16_t iommu_info;
-+      uint32_t efr;
-+      uint8_t entry[0];
-+} __attribute__ ((packed)) acpi_ivrs_ivhd_t;
-+
-+/* IVRS (I/O Virtualization Reporting Structure) */
-+typedef struct acpi_ivrs {
-+      struct acpi_table_header header;
-+      uint32_t iv_info;
-+      uint32_t reserved[2];
-+      struct acpi_ivrs_ivhd ivhd;
-+} __attribute__ ((packed)) acpi_ivrs_t;
-+
- enum dev_scope_type {
-       SCOPE_PCI_ENDPOINT = 1,
-       SCOPE_PCI_SUB = 2,
-@@ -497,6 +524,7 @@ unsigned long fw_cfg_acpi_tables(unsigned long start);
- unsigned long write_acpi_tables(unsigned long addr);
- unsigned long acpi_fill_madt(unsigned long current);
- unsigned long acpi_fill_mcfg(unsigned long current);
-+unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current);
- void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char 
*oem_table_id);
- void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs, void *dsdt);
- #if IS_ENABLED(CONFIG_COMMON_FADT)
-@@ -535,6 +563,9 @@ void acpi_create_srat(acpi_srat_t *srat,
- void acpi_create_slit(acpi_slit_t *slit,
-                     unsigned long (*acpi_fill_slit)(unsigned long current));
- 
-+void acpi_create_ivrs(acpi_ivrs_t *ivrs,
-+                    unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, 
unsigned long current));
-+
- #if ENV_RAMSTAGE
- void acpi_create_hpet(acpi_hpet_t *hpet);
- unsigned long acpi_write_hpet(device_t device, unsigned long start, 
acpi_rsdp_t *rsdp);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0111-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
 
b/resources/libreboot/patch/kgpe-d16/0111-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
new file mode 100644
index 0000000..f57dbdf
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0111-northbridge-amd-amdht-Add-isochronous-setup-support-.patch
@@ -0,0 +1,279 @@
+From c6a6d7b4fc613a18511d8aeb0040a350d61920e7 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 11 Aug 2015 17:47:48 -0500
+Subject: [PATCH 111/143] northbridge/amd/amdht: Add isochronous setup support
+ for coherent fabric
+
+Change-Id: Idd7c9b94a65f856b0059e1d45f8719d9475771b6
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |   61 +++++++++++++++++++++++++
+ src/northbridge/amd/amdht/h3ffeat.h           |    3 ++
+ src/northbridge/amd/amdht/h3finit.c           |   35 +++++++++++++-
+ src/northbridge/amd/amdht/h3finit.h           |    4 +-
+ src/northbridge/amd/amdht/h3ncmn.c            |   30 +++++++++++-
+ 5 files changed, 129 insertions(+), 4 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index 7dffcc0..da6424f 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -1697,6 +1697,67 @@ static void cpuSetAMDPCI(u8 node)
+               pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
+       }
+ 
++      uint8_t link;
++      uint8_t isochronous;
++      uint8_t isochronous_link_present;
++
++      /* Set up isochronous buffers if needed */
++      isochronous_link_present = 0;
++      if (revision & AMD_FAM15_ALL) {
++              for (link = 0; link < 4; link++) {
++                      if (AMD_CpuFindCapability(node, link, &offset)) {
++                              isochronous = (pci_read_config32(NODE_PCI(node, 
0), (link * 0x20) + 0x84) >> 12) & 0x1;
++
++                              if (isochronous)
++                                      isochronous_link_present = 1;
++                      }
++              }
++      }
++
++      uint8_t free_tok;
++      uint8_t up_rsp_cbc;
++      uint8_t isoc_preq_cbc;
++      uint8_t isoc_preq_tok;
++      uint8_t xbar_to_sri_free_list_cbc;
++      if (isochronous_link_present) {
++              /* Adjust buffer counts */
++              dword = pci_read_config32(NODE_PCI(node, 3), 0x70);
++              isoc_preq_cbc = (dword >> 24) & 0x7;
++              up_rsp_cbc = (dword >> 16) & 0x7;
++              up_rsp_cbc--;
++              isoc_preq_cbc++;
++              dword &= ~(0x7 << 24);                  /* IsocPreqCBC = 
isoc_preq_cbc */
++              dword |= ((isoc_preq_cbc & 0x7) << 24);
++              dword &= ~(0x7 << 16);                  /* UpRspCBC = 
up_rsp_cbc */
++              dword |= ((up_rsp_cbc & 0x7) << 16);
++              pci_write_config32(NODE_PCI(node, 3), 0x70, dword);
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0x74);
++              isoc_preq_cbc = (dword >> 24) & 0x7;
++              isoc_preq_cbc++;
++              dword &= ~(0x7 << 24);                  /* IsocPreqCBC = 
isoc_preq_cbc */
++              dword |= (isoc_preq_cbc & 0x7) << 24;
++              pci_write_config32(NODE_PCI(node, 3), 0x74, dword);
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0x7c);
++              xbar_to_sri_free_list_cbc = dword & 0x1f;
++              xbar_to_sri_free_list_cbc--;
++              dword &= ~0x1f;                         /* Xbar2SriFreeListCBC 
= xbar_to_sri_free_list_cbc */
++              dword |= xbar_to_sri_free_list_cbc & 0x1f;
++              pci_write_config32(NODE_PCI(node, 3), 0x7c, dword);
++
++              dword = pci_read_config32(NODE_PCI(node, 3), 0x140);
++              free_tok = (dword >> 20) & 0xf;
++              isoc_preq_tok = (dword >> 14) & 0x3;
++              free_tok--;
++              isoc_preq_tok++;
++              dword &= ~(0xf << 20);                  /* FreeTok = free_tok */
++              dword |= ((free_tok & 0xf) << 20);
++              dword &= ~(0x3 << 14);                  /* IsocPreqTok = 
isoc_preq_tok */
++              dword |= ((isoc_preq_tok & 0x3) << 14);
++              pci_write_config32(NODE_PCI(node, 3), 0x140, dword);
++      }
++
+       printk(BIOS_DEBUG, " done\n");
+ }
+ 
+diff --git a/src/northbridge/amd/amdht/h3ffeat.h 
b/src/northbridge/amd/amdht/h3ffeat.h
+index 5dc9916..c523b12 100644
+--- a/src/northbridge/amd/amdht/h3ffeat.h
++++ b/src/northbridge/amd/amdht/h3ffeat.h
+@@ -79,6 +79,7 @@
+ #define HTSLAVE_LINK01_OFFSET                 4
+ #define HTSLAVE_LINK_CONTROL_0_REG            4
+ #define HTSLAVE_FREQ_REV_0_REG                        0xC
++#define HTSLAVE_FEATURE_CAP_REG               0x10
+ 
+ /* HT3 gen Capability */
+ #define IS_HT_GEN3_CAPABILITY(reg) \
+@@ -126,10 +127,12 @@ typedef struct
+       u8 SelWidthIn;
+       u8 SelWidthOut;
+       u8 SelFrequency;
++      uint8_t enable_isochronous_mode;
+ 
+       /* This section is for keeping track of capabilities and possible 
configurations */
+       BOOL RegangCap;
+       uint32_t PrvFrequencyCap;
++      uint32_t PrvFeatureCap;
+       u8 PrvWidthInCap;
+       u8 PrvWidthOutCap;
+       uint32_t CompositeFrequencyCap;
+diff --git a/src/northbridge/amd/amdht/h3finit.c 
b/src/northbridge/amd/amdht/h3finit.c
+index 14f348f..6b53d34 100644
+--- a/src/northbridge/amd/amdht/h3finit.c
++++ b/src/northbridge/amd/amdht/h3finit.c
+@@ -1419,6 +1419,38 @@ static void regangLinks(sMainData *pDat)
+ #endif /* HT_BUILD_NC_ONLY */
+ }
+ 
++static void detectIoLinkIsochronousCapable(sMainData *pDat)
++{
++      uint8_t i;
++      unsigned char iommu;
++      uint8_t isochronous_capable = 0;
++
++      iommu = 1;
++      get_option(&iommu, "iommu");
++
++      for (i = 0; i < pDat->TotalLinks*2; i += 2) {
++              if ((pDat->PortList[i].Type == PORTLIST_TYPE_CPU) && 
(pDat->PortList[i+1].Type == PORTLIST_TYPE_IO)) {
++                      if ((pDat->PortList[i].PrvFeatureCap & 0x1) && 
(pDat->PortList[i+1].PrvFeatureCap & 0x1)) {
++                              pDat->PortList[i].enable_isochronous_mode = 1;
++                              pDat->PortList[i+1].enable_isochronous_mode = 1;
++                              isochronous_capable = 1;
++                      } else {
++                              pDat->PortList[i].enable_isochronous_mode = 0;
++                              pDat->PortList[i+1].enable_isochronous_mode = 0;
++                      }
++              }
++      }
++
++      if (isochronous_capable && iommu) {
++              printk(BIOS_DEBUG, "Forcing HT links to isochronous mode due to 
enabled IOMMU\n");
++              /* Isochronous mode must be set on all links if the IOMMU is 
enabled */
++              for (i = 0; i < pDat->TotalLinks*2; i += 2) {
++                      pDat->PortList[i].enable_isochronous_mode = 1;
++                      pDat->PortList[i+1].enable_isochronous_mode = 1;
++              }
++      }
++}
++
+ 
/*----------------------------------------------------------------------------------------
+  * void
+  * selectOptimalWidthAndFrequency(sMainData *pDat)
+@@ -1539,7 +1571,6 @@ static void selectOptimalWidthAndFrequency(sMainData 
*pDat)
+                       temp = cbPCBBAUpstreamWidth;
+               pDat->PortList[i].SelWidthIn = (u8)temp;
+               pDat->PortList[i+1].SelWidthOut = (u8)temp;
+-
+       }
+ }
+ 
+@@ -1701,6 +1732,8 @@ static void linkOptimization(sMainData *pDat)
+ {
+       pDat->nb->gatherLinkData(pDat, pDat->nb);
+       regangLinks(pDat);
++      if (is_fam15h())
++              detectIoLinkIsochronousCapable(pDat);
+       selectOptimalWidthAndFrequency(pDat);
+       hammerSublinkFixup(pDat);
+       pDat->nb->setLinkData(pDat, pDat->nb);
+diff --git a/src/northbridge/amd/amdht/h3finit.h 
b/src/northbridge/amd/amdht/h3finit.h
+index 462f3e3..eef8fe7 100644
+--- a/src/northbridge/amd/amdht/h3finit.h
++++ b/src/northbridge/amd/amdht/h3finit.h
+@@ -231,6 +231,7 @@ typedef struct {
+        *      @param[in,out] u8*  LinkWidthIn  = modify to change the Link 
Witdh In
+        *      @param[in,out] u8*  LinkWidthOut  = modify to change the Link 
Witdh Out
+        *      @param[in,out] u32* FreqCap = modify to change the link's 
frequency capability
++       *      @param[in,out] u32* FeatureCap = modify to change the link's 
feature capability
+        *
+        * 
---------------------------------------------------------------------------------------
+        */
+@@ -245,7 +246,8 @@ typedef struct {
+               u8 Link,
+               u8 *LinkWidthIn,
+               u8 *LinkWidthOut,
+-              u32 *FreqCap
++              u32 *FreqCap,
++              u32 *FeatureCap
+       );
+ 
+       
/**----------------------------------------------------------------------------------------
+diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
+index e377ff2..369ce3e 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.c
++++ b/src/northbridge/amd/amdht/h3ncmn.c
+@@ -1433,12 +1433,15 @@ static void gatherLinkData(sMainData *pDat, 
cNorthBridge *nb)
+                               temp &= 0x7;    /* Mask off reserved values */
+                               pDat->PortList[i].PrvFrequencyCap |= (temp << 
17);
+                       }
++
++                      AmdPCIReadBits(linkBase + HTHOST_FEATURE_CAP_REG, 9, 0, 
&temp);
++                      pDat->PortList[i].PrvFeatureCap = (u16)temp;
+               }
+               else
+               {
+                       linkBase = pDat->PortList[i].Pointer;
+                       if (pDat->PortList[i].Link == 1)
+-                       linkBase += HTSLAVE_LINK01_OFFSET;
++                              linkBase += HTSLAVE_LINK01_OFFSET;
+ 
+                       AmdPCIReadBits(linkBase + HTSLAVE_LINK_CONTROL_0_REG, 
22, 20, &temp);
+                       pDat->PortList[i].PrvWidthOutCap = 
convertBitsToWidth((u8)temp, pDat->nb);
+@@ -1449,6 +1452,9 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge 
*nb)
+                       AmdPCIReadBits(linkBase + HTSLAVE_FREQ_REV_0_REG, 31, 
16, &temp);
+                       pDat->PortList[i].PrvFrequencyCap = (u16)temp;
+ 
++                      AmdPCIReadBits(linkBase + HTSLAVE_FEATURE_CAP_REG, 7, 
0, &temp);
++                      pDat->PortList[i].PrvFeatureCap = (u16)temp;
++
+                       if (pDat->HtBlock->AMD_CB_DeviceCapOverride)
+                       {
+                               linkBase &= 0xFFFFF000;
+@@ -1465,7 +1471,8 @@ static void gatherLinkData(sMainData *pDat, cNorthBridge 
*nb)
+                                       pDat->PortList[i].Link,
+                                       &(pDat->PortList[i].PrvWidthInCap),
+                                       &(pDat->PortList[i].PrvWidthOutCap),
+-                                      &(pDat->PortList[i].PrvFrequencyCap));
++                                      &(pDat->PortList[i].PrvFrequencyCap),
++                                      &(pDat->PortList[i].PrvFeatureCap));
+                       }
+               }
+       }
+@@ -1566,6 +1573,16 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
+                       if (is_gt_rev_d())
+                               AmdPCIWriteBits(linkBase + 
HTHOST_FREQ_REV_REG_2, 0, 0, &temp2);
+                       AmdPCIWriteBits(linkBase + HTHOST_FREQ_REV_REG, 11, 8, 
&temp);
++
++                      /* Enable isochronous flow control mode if supported by 
chipset */
++                      if (is_fam15h()) {
++                              if (pDat->PortList[i].enable_isochronous_mode)
++                                      temp = 1;
++                              else
++                                      temp = 0;
++                              setHtControlRegisterBits(linkBase + 
HTHOST_LINK_CONTROL_REG, 12, 12, &temp);
++                      }
++
+                       if (frequency_index > HT_FREQUENCY_1000M) /*  Gen1 = 
200MHz -> 1000MHz, Gen3 = 1200MHz -> 3200MHz */
+                       {
+                               /* Enable  for Gen3 frequencies */
+@@ -1583,6 +1600,7 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
+                                               CPU_HTNB_FUNC_00,
+                                               REG_HT_LINK_RETRY0_0X130 + 
4*pDat->PortList[i].Link),
+                                               0, 0, &temp);
++
+                       /* and Scrambling enable / disable */
+                       
AmdPCIWriteBits(MAKE_SBDFO(makePCISegmentFromNode(pDat->PortList[i].NodeID),
+                                       
makePCIBusFromNode(pDat->PortList[i].NodeID),
+@@ -1621,6 +1639,14 @@ static void setLinkData(sMainData *pDat, cNorthBridge 
*nb)
+                               bits = 0;
+                       }
+ 
++                      /* Enable isochronous flow control mode if supported by 
chipset */
++                      if (is_fam15h()) {
++                              if (pDat->PortList[i].enable_isochronous_mode)
++                                      temp = 1;
++                              else
++                                      temp = 0;
++                      }
++
+                       /* Retry Enable */
+                       isFound = FALSE;
+                       currentPtr = linkBase & (u32)0xFFFFF000; /* Set PCI 
Offset to 0 */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch
deleted file mode 100644
index 54f04d0..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0111-southbridge-amd-sr5650-Add-IOMMU-support.patch
+++ /dev/null
@@ -1,711 +0,0 @@
-From 274c926921dc0f24e15e09beed752f4927220fc6 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 11 Aug 2015 17:49:06 -0500
-Subject: [PATCH 111/139] southbridge/amd/sr5650: Add IOMMU support
-
-Change-Id: I2083d0c5653515c27d4626c62a6499b850f7547b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/include/device/pci_ids.h             |   1 +
- src/southbridge/amd/sr5650/cmn.h         |   3 +
- src/southbridge/amd/sr5650/early_setup.c |  50 +++-
- src/southbridge/amd/sr5650/sr5650.c      | 479 ++++++++++++++++++++++++++++++-
- src/southbridge/amd/sr5650/sr5650.h      |  14 +
- 5 files changed, 537 insertions(+), 10 deletions(-)
-
-diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
-index 664ac49..72f1ece 100644
---- a/src/include/device/pci_ids.h
-+++ b/src/include/device/pci_ids.h
-@@ -429,6 +429,7 @@
- #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV12    0x5A20
- #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV13    0x5A1E
- #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV8     0x5A21
-+#define PCI_DEVICE_ID_AMD_SR5650_IOMMU                0x5A23
- 
- #define PCI_DEVICE_ID_AMD_CZ_HDA        0x157A
- #define PCI_DEVICE_ID_AMD_CZ_LPC        0x790E
-diff --git a/src/southbridge/amd/sr5650/cmn.h 
b/src/southbridge/amd/sr5650/cmn.h
-index 23d25d5..a54bdc5 100644
---- a/src/southbridge/amd/sr5650/cmn.h
-+++ b/src/southbridge/amd/sr5650/cmn.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -26,6 +27,8 @@
- #define NBHTIU_INDEX  0x94 /* Note: It is different with RS690, whose HTIU 
index is 0xA8 */
- #define NBMC_INDEX    0xE8
- #define NBPCIE_INDEX          0xE0
-+#define L2CFG_INDEX   0xF0
-+#define L1CFG_INDEX   0xF8
- #define EXT_CONF_BASE_ADDRESS CONFIG_MMCONF_BASE_ADDRESS
- #define       TEMP_MMIO_BASE_ADDRESS  0xC0000000
- 
-diff --git a/src/southbridge/amd/sr5650/early_setup.c 
b/src/southbridge/amd/sr5650/early_setup.c
-index 62b0dab..e7cca06 100644
---- a/src/southbridge/amd/sr5650/early_setup.c
-+++ b/src/southbridge/amd/sr5650/early_setup.c
-@@ -24,6 +24,8 @@
- #include <arch/io.h>
- #include <console/console.h>
- #include <cpu/x86/msr.h>
-+#include <option.h>
-+#include <reset.h>
- #include "sr5650.h"
- #include "cmn.h"
- 
-@@ -271,6 +273,34 @@ void sr5650_htinit(void)
-               /* HT Buffer Allocation for Ganged Links!!! */
- #endif        /* CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || 
CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 */
-       }
-+
-+}
-+
-+/* Must be run immediately after HT setup is complete and first warm reset 
has occurred (if applicable)
-+ * Attempting to switch the NB into isochronous mode before the CPUs have 
engaged isochronous mode
-+ * will cause a system hard lockup...
-+ */
-+void sr5650_htinit_dect_and_enable_isochronous_link(void)
-+{
-+      device_t sr5650_f0;
-+      unsigned char iommu;
-+
-+      sr5650_f0 = PCI_DEV(0, 0, 0);
-+
-+      iommu = 1;
-+      get_option(&iommu, "iommu");
-+
-+      if (iommu) {
-+              /* Enable isochronous mode */
-+              set_nbcfg_enable_bits(sr5650_f0, 0xc8, 1 << 12, 1 << 12);
-+
-+              /* Apply pending changes */
-+              if (!((pci_read_config32(sr5650_f0, 0xc8) >> 12) & 0x1)) {
-+                      printk(BIOS_INFO, "...WARM RESET...\n\n\n");
-+                      soft_reset();
-+                      die("After soft_reset_x - shouldn't see this 
message!!!\n");
-+              }
-+      }
- }
- 
- #if CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 
/* save some spaces */
-@@ -335,8 +365,21 @@ static void sr5650_por_pcicfg_init(device_t nb_dev)
- *****************************************/
- static void sr5650_por_misc_index_init(device_t nb_dev)
- {
--      /* disable IOMMU */
--      set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0);
-+      unsigned char iommu;
-+
-+      iommu = 1;
-+      get_option(&iommu, "iommu");
-+
-+      if (iommu) {
-+              /* enable IOMMU */
-+              printk(BIOS_DEBUG, "Enabling IOMMU\n");
-+              set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x1);
-+      } else {
-+              /* disable IOMMU */
-+              printk(BIOS_DEBUG, "Disabling IOMMU\n");
-+              set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0);
-+      }
-+
-       /* NBMISCIND:0x75[29]= 1 Device ID for hotplug and PME message */
-       set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 29, 1 << 29);
-       set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 9, 1 << 9); /* no doc 
reference, comply with BTS */
-@@ -374,10 +417,11 @@ static void sr5650_por_misc_index_init(device_t nb_dev)
-        *   HIDE_NB_AGP_CAP  ([0], default=1)HIDE
-        *   HIDE_P2P_AGP_CAP ([1], default=1)HIDE
-        *   HIDE_NB_GART_BAR ([2], default=1)HIDE
-+       *   HIDE_MMCFG_BAR   ([3], default=1)SHOW
-        *   AGPMODE30        ([4], default=0)DISABLE
-        *   AGP30ENCHANCED   ([5], default=0)DISABLE
-        *   HIDE_AGP_CAP     ([8], default=1)ENABLE */
--      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 6);
-+      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 3 | 0 << 6);
- 
-       /* IOC_LAT_PERF_CNTR_CNTL */
-       set_nbmisc_enable_bits(nb_dev, 0x30, 0xFF, 0x00);
-diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
-index 6db1eb1..b296c47 100644
---- a/src/southbridge/amd/sr5650/sr5650.c
-+++ b/src/southbridge/amd/sr5650/sr5650.c
-@@ -26,7 +26,9 @@
- #include <device/pci_ops.h>
- #include <cpu/x86/msr.h>
- #include <cpu/amd/mtrr.h>
-+#include <stdlib.h>
- #include <delay.h>
-+#include <option.h>
- #include "sr5650.h"
- #include "cmn.h"
- 
-@@ -87,6 +89,26 @@ void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 
data)
-       nb_write_index((nb_dev), NBPCIE_INDEX, (index), (data));
- }
- 
-+uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index)
-+{
-+      return nb_read_index((nb_dev), L2CFG_INDEX, (index));
-+}
-+
-+void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data)
-+{
-+      nb_write_index((nb_dev), L2CFG_INDEX | (0x1 << 8), (index), (data));
-+}
-+
-+uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index)
-+{
-+      return nb_read_index((nb_dev), L1CFG_INDEX, (index));
-+}
-+
-+void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data)
-+{
-+      nb_write_index((nb_dev), L1CFG_INDEX | (0x1 << 31), (index), (data));
-+}
-+
- /***********************************************************
- * To access bar3 we need to program PCI MMIO 7 in K8.
- * in_out:
-@@ -286,6 +308,240 @@ u32 get_vid_did(device_t dev)
-       return pci_read_config32(dev, 0);
- }
- 
-+void detect_and_enable_iommu(device_t iommu_dev) {
-+      uint32_t dword;
-+      uint8_t l1_target;
-+      unsigned char iommu;
-+      void * mmio_base;
-+
-+      iommu = 1;
-+      get_option(&iommu, "iommu");
-+
-+      if (iommu) {
-+              printk(BIOS_DEBUG, "Initializing IOMMU\n");
-+
-+              device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-+
-+              if (!nb_dev) {
-+                      printk(BIOS_WARNING, "Unable to find SR5690 device!  
IOMMU NOT initialized\n");
-+                      return;
-+              }
-+
-+              mmio_base = (void*)(pci_read_config32(iommu_dev, 0x44) & 
0xffffc000);
-+
-+              // if (get_nb_rev(nb_dev) == REV_SR5650_A11) {
-+              //      dword = pci_read_config32(iommu_dev, 0x6c);
-+              //      dword &= ~(0x1 << 8);
-+              //      pci_write_config32(iommu_dev, 0x6c, dword);
-+              // }
-+
-+              dword = pci_read_config32(iommu_dev, 0x50);
-+              dword &= ~(0x1 << 22);
-+              pci_write_config32(iommu_dev, 0x50, dword);
-+
-+              dword = pci_read_config32(iommu_dev, 0x44);
-+              dword |= 0x1;
-+              pci_write_config32(iommu_dev, 0x44, dword);
-+
-+              write32((void*)(mmio_base + 0x8), 0x0);
-+              write32((void*)(mmio_base + 0xc), 0x08000000);
-+              write32((void*)(mmio_base + 0x10), 0x0);
-+              write32((void*)(mmio_base + 0x2008), 0x0);
-+              write32((void*)(mmio_base + 0x2010), 0x0);
-+
-+              /* IOMMU L1 initialization */
-+              for (l1_target = 0; l1_target < 6; l1_target++) {
-+                      dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) 
+ 0xc);
-+                      dword |= (0x7 << 28);
-+                      l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0xc, 
dword);
-+
-+                      dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) 
+ 0x7);
-+                      dword |= (0x1 << 5);
-+                      l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0x7, 
dword);
-+              }
-+
-+              /* IOMMU L2 initialization */
-+              dword = l2cfg_ind_read_index(nb_dev, 0xc);
-+              dword |= (0x7 << 29);
-+              l2cfg_ind_write_index(nb_dev, 0xc, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x10);
-+              dword &= ~(0x3 << 8);
-+              dword |= (0x2 << 8);
-+              l2cfg_ind_write_index(nb_dev, 0x10, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x14);
-+              dword &= ~(0x3 << 8);
-+              dword |= (0x2 << 8);
-+              l2cfg_ind_write_index(nb_dev, 0x14, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x18);
-+              dword &= ~(0x3 << 8);
-+              dword |= (0x2 << 8);
-+              l2cfg_ind_write_index(nb_dev, 0x18, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x1c);
-+              dword &= ~(0x3 << 8);
-+              dword |= (0x2 << 8);
-+              l2cfg_ind_write_index(nb_dev, 0x1c, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x50);
-+              dword &= ~(0x3 << 8);
-+              dword |= (0x2 << 8);
-+              l2cfg_ind_write_index(nb_dev, 0x50, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x10);
-+              dword |= (0x1 << 4);
-+              l2cfg_ind_write_index(nb_dev, 0x10, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x14);
-+              dword |= (0x1 << 4);
-+              l2cfg_ind_write_index(nb_dev, 0x14, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x18);
-+              dword |= (0x1 << 4);
-+              l2cfg_ind_write_index(nb_dev, 0x18, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x1c);
-+              dword |= (0x1 << 4);
-+              l2cfg_ind_write_index(nb_dev, 0x1c, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x50);
-+              dword |= (0x1 << 4);
-+              l2cfg_ind_write_index(nb_dev, 0x50, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x6);
-+              dword |= (0x1 << 7);
-+              l2cfg_ind_write_index(nb_dev, 0x6, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x44);
-+              dword |= (0x1 << 0);
-+              l2cfg_ind_write_index(nb_dev, 0x44, dword);
-+
-+//            if (get_nb_rev(nb_dev) == REV_SR5650_A21) {
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
-+                      dword |= (0x1 << 1);
-+                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x44);
-+                      dword |= (0x1 << 1);
-+                      l2cfg_ind_write_index(nb_dev, 0x44, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
-+                      dword |= (0x1 << 2);
-+                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
-+                      dword |= (0x1 << 3);
-+                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x44);
-+                      dword |= (0x1 << 3);
-+                      l2cfg_ind_write_index(nb_dev, 0x44, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
-+                      dword |= (0x1 << 4);
-+                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x6);
-+                      dword |= (0x1 << 5);
-+                      l2cfg_ind_write_index(nb_dev, 0x6, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x6);
-+                      dword |= (0x1 << 6);
-+                      l2cfg_ind_write_index(nb_dev, 0x6, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
-+                      dword |= (0x1 << 5);
-+                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x44);
-+                      dword |= (0x1 << 4);
-+                      l2cfg_ind_write_index(nb_dev, 0x44, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
-+                      dword |= (0x1 << 6);
-+                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
-+                      dword |= (0x1 << 7);
-+                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
-+
-+                      dword = l2cfg_ind_read_index(nb_dev, 0x6);
-+                      dword |= (0x1 << 8);
-+                      l2cfg_ind_write_index(nb_dev, 0x6, dword);
-+//            }
-+
-+              l2cfg_ind_write_index(nb_dev, 0x52, 0xf0000002);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x80);
-+              dword |= (0x1 << 0);
-+              l2cfg_ind_write_index(nb_dev, 0x80, dword);
-+
-+              dword = l2cfg_ind_read_index(nb_dev, 0x30);
-+              dword |= (0x1 << 0);
-+              l2cfg_ind_write_index(nb_dev, 0x30, dword);
-+      }
-+}
-+
-+void sr5650_iommu_read_resources(device_t dev)
-+{
-+      unsigned char iommu;
-+      struct resource *res;
-+
-+      iommu = 1;
-+      get_option(&iommu, "iommu");
-+
-+      /* Get the normal pci resources of this device */
-+      pci_dev_read_resources(dev);
-+
-+      if (iommu) {
-+              /* Request MMIO range allocation */
-+              res = new_resource(dev, 0x44);          /* IOMMU */
-+              res->base = 0x0;
-+              res->size = 0x4000;
-+              res->limit = 0xFFFFFFFFUL;              /* res->base + 
res->size -1; */
-+              res->align = 14;                        /* 16k alignment */
-+              res->gran = 14;
-+              res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE;
-+      }
-+
-+      compact_resources(dev);
-+}
-+
-+void sr5650_iommu_set_resources(device_t dev)
-+{
-+      unsigned char iommu;
-+      struct resource *res;
-+
-+      iommu = 1;
-+      get_option(&iommu, "iommu");
-+
-+      /* Get the normal pci resources of this device */
-+      pci_dev_read_resources(dev);
-+
-+      if (iommu) {
-+              /* Get the allocated range */
-+              res = find_resource(dev, 0x44);
-+
-+              if (res->base == 0) {
-+                      printk(BIOS_WARNING, "Unable to allocate MMIO range to 
IOMMU\n");
-+              }
-+
-+              /* Assign the range to hardware */
-+              pci_write_config32(dev, 0x44, res->base & 0xffffc000);
-+              pci_write_config32(dev, 0x48, 0x0);
-+      }
-+
-+      /* Run standard resource set routine */
-+      pci_dev_set_resources(dev);
-+}
-+
-+void sr5650_iommu_enable_resources(device_t dev)
-+{
-+      detect_and_enable_iommu(dev);
-+}
-+
- void sr5650_nb_pci_table(device_t nb_dev)
- {     /* NBPOR_InitPOR function. */
-       u8 temp8;
-@@ -365,13 +621,23 @@ void sr5650_enable(device_t dev)
-       dev_ind = dev->path.pci.devfn >> 3;
-       switch (dev_ind) {
-       case 0:         /* bus0, dev0, fun0; */
--              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n");
--              enable_pcie_bar3(nb_dev);       /* PCIEMiscInit */
--
--              config_gpp_core(nb_dev, sb_dev);
--              sr5650_gpp_sb_init(nb_dev, sb_dev, 8);
--
--              sr5650_nb_pci_table(nb_dev);
-+              switch (dev->path.pci.devfn & 0x7) {
-+                      case 0:
-+                              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n");
-+                              enable_pcie_bar3(nb_dev);       /* PCIEMiscInit 
*/
-+
-+                              config_gpp_core(nb_dev, sb_dev);
-+                              sr5650_gpp_sb_init(nb_dev, sb_dev, 8);
-+
-+                              sr5650_nb_pci_table(nb_dev);
-+                              break;
-+                      case 1:
-+                              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-1.\n");
-+                              break;
-+                      case 2:
-+                              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-2.\n");
-+                              break;
-+              }
-               break;
- 
-       case 2:         /* bus0, dev2,3 GPP1 */
-@@ -438,6 +704,205 @@ void sr5650_enable(device_t dev)
-       }
- }
- 
-+static void add_ivrs_device_entries(struct device *parent, struct device 
*dev, int depth, int linknum, int8_t *root_level, unsigned long *current, 
uint16_t *length)
-+{
-+      uint8_t *p;
-+      struct device *sibling;
-+      struct bus *link;
-+
-+      if (!root_level) {
-+              root_level = malloc(sizeof(int8_t));
-+              *root_level = -1;
-+      }
-+
-+      if (dev->path.type == DEVICE_PATH_PCI) {
-+              if ((dev->bus->secondary == 0x0) && (dev->path.pci.devfn == 
0x0))
-+                      *root_level = depth;
-+
-+              if (*root_level != -1) {
-+                      if (depth >= *root_level) {
-+                              if (dev->enabled) {
-+                                      if (depth == *root_level) {
-+                                              if (dev->path.pci.devfn < (0x1 
<< 3)) {
-+                                                      /* SR5690 control 
device */
-+                                              } else if ((dev->path.pci.devfn 
>= (0x1 << 3)) && (dev->path.pci.devfn < (0xe << 3))) {
-+                                                      /* SR5690 PCIe bridge 
device */
-+                                              } else {
-+                                                      if (dev->path.pci.devfn 
== (0x14 << 3)) {
-+                                                              /* SMBUS 
controller */
-+                                                              p = (uint8_t *) 
*current;
-+                                                              p[0] = 0x2;     
                /* Entry type */
-+                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
-+                                                              p[2] = 
dev->bus->secondary;     /* Bus */
-+                                                              p[3] = 0x97;    
                /* Data */
-+                                                              p[4] = 0x0;     
                /* Padding */
-+                                                              p[5] = 0x0;     
                /* Padding */
-+                                                              p[6] = 0x0;     
                /* Padding */
-+                                                              p[7] = 0x0;     
                /* Padding */
-+                                                              *length += 8;
-+                                                              *current += 8;
-+                                                      } else {
-+                                                              /* Other 
southbridge device */
-+                                                              p = (uint8_t *) 
*current;
-+                                                              p[0] = 0x2;     
                /* Entry type */
-+                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
-+                                                              p[2] = 
dev->bus->secondary;     /* Bus */
-+                                                              p[3] = 0x0;     
                /* Data */
-+                                                              p[4] = 0x0;     
                /* Padding */
-+                                                              p[5] = 0x0;     
                /* Padding */
-+                                                              p[6] = 0x0;     
                /* Padding */
-+                                                              p[7] = 0x0;     
                /* Padding */
-+                                                              *length += 8;
-+                                                              *current += 8;
-+                                                      }
-+                                              }
-+                                      } else {
-+                                              if ((dev->hdr_type & 0x7f) == 
PCI_HEADER_TYPE_NORMAL) {
-+                                                      /* Device behind bridge 
*/
-+                                                      if 
(pci_find_capability(dev, PCI_CAP_ID_PCIE)) {
-+                                                              /* Device is 
PCIe */
-+                                                              p = (uint8_t *) 
*current;
-+                                                              p[0] = 0x2;     
                /* Entry type */
-+                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
-+                                                              p[2] = 
dev->bus->secondary;     /* Bus */
-+                                                              p[3] = 0x0;     
                /* Data */
-+                                                              p[4] = 0x0;     
                /* Padding */
-+                                                              p[5] = 0x0;     
                /* Padding */
-+                                                              p[6] = 0x0;     
                /* Padding */
-+                                                              p[7] = 0x0;     
                /* Padding */
-+                                                              *length += 8;
-+                                                              *current += 8;
-+                                                      } else {
-+                                                              /* Device is 
legacy PCI or PCI-X */
-+                                                              p = (uint8_t *) 
*current;
-+                                                              p[0] = 0x42;    
                /* Entry type */
-+                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
-+                                                              p[2] = 
dev->bus->secondary;     /* Bus */
-+                                                              p[3] = 0x0;     
                /* Data */
-+                                                              p[4] = 0x0;     
                /* Reserved */
-+                                                              p[5] = 
parent->path.pci.devfn;  /* Device */
-+                                                              p[6] = 
parent->bus->secondary;  /* Bus */
-+                                                              p[7] = 0x0;     
                /* Reserved */
-+                                                              *length += 8;
-+                                                              *current += 8;
-+                                                      }
-+                                              }
-+                                      }
-+                              }
-+                      }
-+              }
-+      }
-+
-+      for (link = dev->link_list; link; link = link->next)
-+              for (sibling = link->children; sibling; sibling = 
sibling->sibling)
-+                      add_ivrs_device_entries(dev, sibling, depth + 1, depth, 
root_level, current, length);
-+
-+      free(root_level);
-+}
-+
-+static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current)
-+{
-+      uint8_t *p;
-+
-+      device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-+      if (!nb_dev) {
-+              printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 
device!  IVRS table not generated...\n");
-+              return (unsigned long)ivrs;
-+      }
-+
-+      device_t iommu_dev = dev_find_slot(0, PCI_DEVFN(0, 2));
-+      if (!iommu_dev) {
-+              printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 
IOMMU device!  IVRS table not generated...\n");
-+              return (unsigned long)ivrs;
-+      }
-+
-+      ivrs->iv_info = 0x0;
-+      ivrs->iv_info |= (0x40 << 15);  /* Maximum supported virtual address 
size */
-+      ivrs->iv_info |= (0x34 << 8);   /* Maximum supported physical address 
size */
-+
-+      ivrs->ivhd.type = 0x10;
-+      ivrs->ivhd.flags = 0x0e;
-+      // if (get_nb_rev(nb_dev) != REV_SR5650_A11) {
-+              ivrs->ivhd.flags |= 0x10;                               /* 
Enable ATS support on all revisions except A11 */
-+      // }
-+      ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd);
-+      ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8);     /* BDF 
<bus>:00.2 */
-+      ivrs->ivhd.capability_offset = 0x40;                            /* 
Capability block 0x40 (type 0xf, "Secure device") */
-+      ivrs->ivhd.iommu_base_low = pci_read_config32(iommu_dev, 0x44) & 
0xffffc000;
-+      ivrs->ivhd.iommu_base_high = pci_read_config32(iommu_dev, 0x48);
-+      ivrs->ivhd.pci_segment_group = 0x0;
-+      ivrs->ivhd.iommu_info = 0x0;
-+      ivrs->ivhd.iommu_info |= (0x14 << 8);
-+      ivrs->ivhd.efr = 0x0;
-+
-+      /* Describe HPET */
-+      p = (uint8_t *)current;
-+      p[0] = 0x48;                    /* Entry type */
-+      p[1] = 0;                       /* Device */
-+      p[2] = 0;                       /* Bus */
-+      p[3] = 0xd7;                    /* Data */
-+      p[4] = 0x0;                     /* HPET number */
-+      p[5] = 0x14 << 3;               /* HPET device */
-+      p[6] = nb_dev->bus->secondary;  /* HPET bus */
-+      p[7] = 0x2;                     /* Variety */
-+      ivrs->ivhd.length += 8;
-+      current += 8;
-+
-+      /* Describe PCI devices */
-+      add_ivrs_device_entries(NULL, all_devices, 0, -1, NULL, &current, 
&ivrs->ivhd.length);
-+
-+      /* Describe IOAPICs */
-+      unsigned long prev_current = current;
-+      current = acpi_fill_ivrs_ioapic(ivrs, current);
-+      ivrs->ivhd.length += (current - prev_current);
-+
-+      return current;
-+}
-+
-+unsigned long southbridge_write_acpi_tables(device_t device,
-+                                              unsigned long current,
-+                                              struct acpi_rsdp *rsdp)
-+{
-+      unsigned char iommu;
-+
-+      iommu = 1;
-+      get_option(&iommu, "iommu");
-+
-+      if (iommu) {
-+              acpi_ivrs_t *ivrs;
-+
-+              /* IVRS */
-+              current = ALIGN(current, 8);
-+              printk(BIOS_DEBUG, "ACPI:   * IVRS at %lx\n", current);
-+              ivrs = (acpi_ivrs_t *) current;
-+              acpi_create_ivrs(ivrs, acpi_fill_ivrs);
-+              current += ivrs->header.length;
-+              acpi_add_table(rsdp, ivrs);
-+      }
-+
-+      return current;
-+}
-+
-+static struct pci_operations iommu_ops_pci = {
-+      .set_subsystem = pci_dev_set_subsystem,
-+};
-+
-+static struct device_operations iommu_ops = {
-+      .read_resources = sr5650_iommu_read_resources,
-+      .set_resources = sr5650_iommu_set_resources,
-+      .enable_resources = sr5650_iommu_enable_resources,
-+      .write_acpi_tables = southbridge_write_acpi_tables,
-+      .init = 0,
-+      .scan_bus = 0,
-+      .ops_pci = &iommu_ops_pci,
-+};
-+
-+static const struct pci_driver ht_driver_sr5690 __pci_driver = {
-+      .ops = &iommu_ops,
-+      .vendor = PCI_VENDOR_ID_ATI,
-+      .device = PCI_DEVICE_ID_AMD_SR5650_IOMMU,
-+};
-+
- struct chip_operations southbridge_amd_sr5650_ops = {
-       CHIP_NAME("ATI SR5650")
-       .enable_dev = sr5650_enable,
-diff --git a/src/southbridge/amd/sr5650/sr5650.h 
b/src/southbridge/amd/sr5650/sr5650.h
-index ebbde41..a3518fb 100644
---- a/src/southbridge/amd/sr5650/sr5650.h
-+++ b/src/southbridge/amd/sr5650/sr5650.h
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -21,6 +22,7 @@
- #define __SR5650_H__
- 
- #include <stdint.h>
-+#include <arch/acpi.h>
- #include <device/pci_ids.h>
- #include "chip.h"
- #include "rev.h"
-@@ -95,16 +97,24 @@ u32 nbpcie_p_read_index(device_t dev, u32 index);
- void nbpcie_p_write_index(device_t dev, u32 index, u32 data);
- u32 nbpcie_ind_read_index(device_t nb_dev, u32 index);
- void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 data);
-+uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index);
-+void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data);
-+uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index);
-+void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data);
- u32 pci_ext_read_config32(device_t nb_dev, device_t dev, u32 reg);
- void pci_ext_write_config32(device_t nb_dev, device_t dev, u32 reg, u32 mask, 
u32 val);
- void sr5650_set_tom(device_t nb_dev);
- 
-+unsigned long southbridge_write_acpi_tables(device_t device, unsigned long 
current,
-+                                              struct acpi_rsdp *rsdp);
-+
- void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add);
- void enable_pcie_bar3(device_t nb_dev);
- void disable_pcie_bar3(device_t nb_dev);
- 
- void enable_sr5650_dev8(void);
- void sr5650_htinit(void);
-+void sr5650_htinit_dect_and_enable_isochronous_link(void);
- void sr5650_early_setup(void);
- void sr5650_before_pci_init(void);
- void sr5650_enable(device_t dev);
-@@ -118,6 +128,10 @@ void pcie_config_misc_clk(device_t nb_dev);
- void fam10_optimization(void);
- void sr5650_disable_pcie_bridge(void);
- u32 get_vid_did(device_t dev);
-+void detect_and_enable_iommu(device_t iommu_dev);
-+void sr5650_iommu_read_resources(device_t dev);
-+void sr5650_iommu_set_resources(device_t dev);
-+void sr5650_iommu_enable_resources(device_t dev);
- void sr5650_nb_pci_table(device_t nb_dev);
- void init_gen2(device_t nb_dev, device_t dev, u8 port);
- void sr56x0_lock_hwinitreg(void);
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0112-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
 
b/resources/libreboot/patch/kgpe-d16/0112-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
new file mode 100644
index 0000000..dd83072
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0112-arch-x86-acpi-Add-IVRS-table-generation-routines.patch
@@ -0,0 +1,121 @@
+From 5152908b5fd0983ed36b2a5e35ebcf510cd31727 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 11 Aug 2015 17:48:32 -0500
+Subject: [PATCH 112/143] arch/x86/acpi: Add IVRS table generation routines
+
+Change-Id: Ia5d97d01dc9ddc45f81d998d126d592a915b4a75
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/arch/x86/acpi.c              |   25 +++++++++++++++++++++++++
+ src/arch/x86/include/arch/acpi.h |   31 +++++++++++++++++++++++++++++++
+ 2 files changed, 56 insertions(+)
+
+diff --git a/src/arch/x86/acpi.c b/src/arch/x86/acpi.c
+index 417a322..e73e5f2 100644
+--- a/src/arch/x86/acpi.c
++++ b/src/arch/x86/acpi.c
+@@ -6,6 +6,7 @@
+  *
+  * Copyright (C) 2004 SUSE LINUX AG
+  * Copyright (C) 2005-2009 coresystems GmbH
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * ACPI FADT, FACS, and DSDT table support added by
+  * Nick Barker <address@hidden>, and those portions
+@@ -506,6 +507,30 @@ void acpi_create_hpet(acpi_hpet_t *hpet)
+       header->checksum = acpi_checksum((void *)hpet, sizeof(acpi_hpet_t));
+ }
+ 
++void acpi_create_ivrs(acpi_ivrs_t *ivrs,
++                    unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, 
unsigned long current))
++{
++      acpi_header_t *header = &(ivrs->header);
++      unsigned long current = (unsigned long)ivrs + sizeof(acpi_ivrs_t);
++
++      memset((void *)ivrs, 0, sizeof(acpi_ivrs_t));
++
++      /* Fill out header fields. */
++      memcpy(header->signature, "IVRS", 4);
++      memcpy(header->oem_id, OEM_ID, 6);
++      memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
++      memcpy(header->asl_compiler_id, ASLC, 4);
++
++      header->length = sizeof(acpi_ivrs_t);
++      header->revision = 1; /* ACPI 1.0: N/A, ACPI 2.0/3.0/4.0: 1 */
++
++      current = acpi_fill_ivrs(ivrs, current);
++
++      /* (Re)calculate length and checksum. */
++      header->length = current - (unsigned long)ivrs;
++      header->checksum = acpi_checksum((void *)ivrs, header->length);
++}
++
+ unsigned long acpi_write_hpet(device_t device, unsigned long current, 
acpi_rsdp_t *rsdp)
+ {
+       acpi_hpet_t *hpet;
+diff --git a/src/arch/x86/include/arch/acpi.h 
b/src/arch/x86/include/arch/acpi.h
+index 28f650c..7d583b8 100644
+--- a/src/arch/x86/include/arch/acpi.h
++++ b/src/arch/x86/include/arch/acpi.h
+@@ -4,6 +4,7 @@
+  * Copyright (C) 2004 SUSE LINUX AG
+  * Copyright (C) 2004 Nick Barker
+  * Copyright (C) 2008-2009 coresystems GmbH
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  * (Written by Stefan Reinauer <address@hidden>)
+  *
+  * This program is free software; you can redistribute it and/or modify
+@@ -194,6 +195,32 @@ typedef struct acpi_madt {
+       u32 flags;                      /* Multiple APIC flags */
+ } __attribute__ ((packed)) acpi_madt_t;
+ 
++typedef struct acpi_ivrs_info {
++} __attribute__ ((packed)) acpi_ivrs_info_t;
++
++/* IVRS IVHD (I/O Virtualization Hardware Definition Block) */
++typedef struct acpi_ivrs_ivhd {
++      uint8_t type;
++      uint8_t flags;
++      uint16_t length;
++      uint16_t device_id;
++      uint16_t capability_offset;
++      uint32_t iommu_base_low;
++      uint32_t iommu_base_high;
++      uint16_t pci_segment_group;
++      uint16_t iommu_info;
++      uint32_t efr;
++      uint8_t entry[0];
++} __attribute__ ((packed)) acpi_ivrs_ivhd_t;
++
++/* IVRS (I/O Virtualization Reporting Structure) */
++typedef struct acpi_ivrs {
++      struct acpi_table_header header;
++      uint32_t iv_info;
++      uint32_t reserved[2];
++      struct acpi_ivrs_ivhd ivhd;
++} __attribute__ ((packed)) acpi_ivrs_t;
++
+ enum dev_scope_type {
+       SCOPE_PCI_ENDPOINT = 1,
+       SCOPE_PCI_SUB = 2,
+@@ -497,6 +524,7 @@ unsigned long fw_cfg_acpi_tables(unsigned long start);
+ unsigned long write_acpi_tables(unsigned long addr);
+ unsigned long acpi_fill_madt(unsigned long current);
+ unsigned long acpi_fill_mcfg(unsigned long current);
++unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current);
+ void acpi_create_ssdt_generator(acpi_header_t *ssdt, const char 
*oem_table_id);
+ void acpi_create_fadt(acpi_fadt_t *fadt,acpi_facs_t *facs, void *dsdt);
+ #if IS_ENABLED(CONFIG_COMMON_FADT)
+@@ -535,6 +563,9 @@ void acpi_create_srat(acpi_srat_t *srat,
+ void acpi_create_slit(acpi_slit_t *slit,
+                     unsigned long (*acpi_fill_slit)(unsigned long current));
+ 
++void acpi_create_ivrs(acpi_ivrs_t *ivrs,
++                    unsigned long (*acpi_fill_ivrs)(acpi_ivrs_t* ivrs_struct, 
unsigned long current));
++
+ #if ENV_RAMSTAGE
+ void acpi_create_hpet(acpi_hpet_t *hpet);
+ unsigned long acpi_write_hpet(device_t device, unsigned long start, 
acpi_rsdp_t *rsdp);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0112-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
 
b/resources/libreboot/patch/kgpe-d16/0112-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
deleted file mode 100644
index a20b748..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0112-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
+++ /dev/null
@@ -1,57 +0,0 @@
-From 95976a8660ad2acc7f4aca0665b195e53c53840c Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 13 Aug 2015 17:45:12 -0500
-Subject: [PATCH 112/139] southbridge/amd/sr5650: Hide clock configuration
- device after setup is complete
-
-Change-Id: I043f2eb0993660d0a9351867eca1e73e0b2c37f1
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sr5650/early_setup.c | 16 ++++++++--------
- src/southbridge/amd/sr5650/pcie.c        |  3 +++
- 2 files changed, 11 insertions(+), 8 deletions(-)
-
-diff --git a/src/southbridge/amd/sr5650/early_setup.c 
b/src/southbridge/amd/sr5650/early_setup.c
-index e7cca06..cb666db 100644
---- a/src/southbridge/amd/sr5650/early_setup.c
-+++ b/src/southbridge/amd/sr5650/early_setup.c
-@@ -414,14 +414,14 @@ static void sr5650_por_misc_index_init(device_t nb_dev)
-       set_nbmisc_enable_bits(nb_dev, 0x01, 0xFFFFFFFF, 0x00000310);
- 
-       /* NBCFG (NBMISCIND 0x0): NB_CNTL -
--       *   HIDE_NB_AGP_CAP  ([0], default=1)HIDE
--       *   HIDE_P2P_AGP_CAP ([1], default=1)HIDE
--       *   HIDE_NB_GART_BAR ([2], default=1)HIDE
--       *   HIDE_MMCFG_BAR   ([3], default=1)SHOW
--       *   AGPMODE30        ([4], default=0)DISABLE
--       *   AGP30ENCHANCED   ([5], default=0)DISABLE
--       *   HIDE_AGP_CAP     ([8], default=1)ENABLE */
--      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 3 | 0 << 6);
-+       *   HIDE_NB_AGP_CAP    ([0], default=1)HIDE
-+       *   HIDE_P2P_AGP_CAP   ([1], default=1)HIDE
-+       *   HIDE_NB_GART_BAR   ([2], default=1)HIDE
-+       *   HIDE_MMCFG_BAR     ([3], default=1)SHOW
-+       *   AGPMODE30          ([4], default=0)DISABLE
-+       *   AGP30ENCHANCED     ([5], default=0)DISABLE
-+       *   HIDE_CLKCFG_HEADER ([8], default=0)SHOW */
-+      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 3 | 0 << 6 | 0 << 8);
- 
-       /* IOC_LAT_PERF_CNTR_CNTL */
-       set_nbmisc_enable_bits(nb_dev, 0x30, 0xFF, 0x00);
-diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
-index 09ce217..360e9cb 100644
---- a/src/southbridge/amd/sr5650/pcie.c
-+++ b/src/southbridge/amd/sr5650/pcie.c
-@@ -854,6 +854,9 @@ void sr56x0_lock_hwinitreg(void)
- 
-       /* Lock HWInit Register NBMISCIND:0x0 NBCNTL[7] HWINIT_WR_LOCK */
-       set_nbmisc_enable_bits(nb_dev, 0x00, 1 << 7, 1 << 7);
-+
-+      /* Hide clock configuration PCI device HIDE_CLKCFG_HEADER */
-+      set_nbmisc_enable_bits(nb_dev, 0x00, 0x00000100, 1 << 8);
- }
- 
- /*****************************************
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0113-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
 
b/resources/libreboot/patch/kgpe-d16/0113-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
deleted file mode 100644
index 9e1a042..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0113-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
+++ /dev/null
@@ -1,55 +0,0 @@
-From 6fc24c6bf44b8ea2ad3ca43856500500aa0ffee7 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 11 Aug 2015 17:52:03 -0500
-Subject: [PATCH 113/139] northbridge/amd/amdfam10: Rename mislabeled iommu
- nvram option to gart
-
-Change-Id: Ia24102e164eb5753ade3f9b5ab21eba2fa60836b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/misc_control.c | 12 ++++++------
- 1 file changed, 6 insertions(+), 6 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
-index 703ae51..1df570c 100644
---- a/src/northbridge/amd/amdfam10/misc_control.c
-+++ b/src/northbridge/amd/amdfam10/misc_control.c
-@@ -42,7 +42,7 @@
-  *
-  * @param dev
-  *
-- * There is only one AGP aperture resource needed. The resoruce is added to
-+ * There is only one AGP aperture resource needed. The resource is added to
-  * the northbridge of BSP.
-  *
-  * The same trick can be used to augment legacy VGA resources which can
-@@ -54,7 +54,7 @@
- static void mcf3_read_resources(device_t dev)
- {
-       struct resource *resource;
--      unsigned char iommu;
-+      unsigned char gart;
-       /* Read the generic PCI resources */
-       pci_dev_read_resources(dev);
- 
-@@ -63,13 +63,13 @@ static void mcf3_read_resources(device_t dev)
-               return;
-       }
- 
--      iommu = 1;
--      get_option(&iommu, "iommu");
-+      gart = 1;
-+      get_option(&gart, "gart");
- 
--      if (iommu) {
-+      if (gart) {
-               /* Add a Gart apeture resource */
-               resource = new_resource(dev, 0x94);
--              resource->size = iommu?CONFIG_AGP_APERTURE_SIZE:1;
-+              resource->size = gart?CONFIG_AGP_APERTURE_SIZE:1;
-               resource->align = log2(resource->size);
-               resource->gran  = log2(resource->size);
-               resource->limit = 0xffffffff; /* 4G */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0113-southbridge-amd-sr5650-Add-IOMMU-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0113-southbridge-amd-sr5650-Add-IOMMU-support.patch
new file mode 100644
index 0000000..959e57f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0113-southbridge-amd-sr5650-Add-IOMMU-support.patch
@@ -0,0 +1,804 @@
+From f44168ba86f534ca12566ba7d38ff5f99c6c7e9c Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 11 Aug 2015 17:49:06 -0500
+Subject: [PATCH 113/143] southbridge/amd/sr5650: Add IOMMU support
+
+Change-Id: I2083d0c5653515c27d4626c62a6499b850f7547b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/include/device/pci_ids.h                       |    1 +
+ src/mainboard/asus/kgpe-d16/acpi_tables.c          |   37 ++
+ src/mainboard/supermicro/h8scm_fam10/acpi_tables.c |   37 ++
+ src/southbridge/amd/sr5650/cmn.h                   |    3 +
+ src/southbridge/amd/sr5650/early_setup.c           |   50 +-
+ src/southbridge/amd/sr5650/sr5650.c                |  479 +++++++++++++++++++-
+ src/southbridge/amd/sr5650/sr5650.h                |   14 +
+ 7 files changed, 611 insertions(+), 10 deletions(-)
+
+diff --git a/src/include/device/pci_ids.h b/src/include/device/pci_ids.h
+index 664ac49..72f1ece 100644
+--- a/src/include/device/pci_ids.h
++++ b/src/include/device/pci_ids.h
+@@ -429,6 +429,7 @@
+ #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV12    0x5A20
+ #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV13    0x5A1E
+ #define PCI_DEVICE_ID_AMD_SR5650_PCIE_DEV8     0x5A21
++#define PCI_DEVICE_ID_AMD_SR5650_IOMMU                0x5A23
+ 
+ #define PCI_DEVICE_ID_AMD_CZ_HDA        0x157A
+ #define PCI_DEVICE_ID_AMD_CZ_LPC        0x790E
+diff --git a/src/mainboard/asus/kgpe-d16/acpi_tables.c 
b/src/mainboard/asus/kgpe-d16/acpi_tables.c
+index 4e98dfe..3f8650b 100644
+--- a/src/mainboard/asus/kgpe-d16/acpi_tables.c
++++ b/src/mainboard/asus/kgpe-d16/acpi_tables.c
+@@ -73,3 +73,40 @@ unsigned long acpi_fill_madt(unsigned long current)
+ 
+       return current;
+ }
++
++unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current)
++{
++      uint8_t *p;
++
++      uint32_t apicid_sp5100;
++      uint32_t apicid_sr5650;
++
++      apicid_sp5100 = 0x20;
++      apicid_sr5650 = apicid_sp5100 + 1;
++
++      /* Describe NB IOAPIC */
++      p = (uint8_t *)current;
++      p[0] = 0x48;                    /* Entry type */
++      p[1] = 0;                       /* Device */
++      p[2] = 0;                       /* Bus */
++      p[3] = 0x0;                     /* Data */
++      p[4] = apicid_sr5650;           /* IOAPIC ID */
++      p[5] = 0x1;                     /* Device 0 Function 1 */
++      p[6] = 0x0;                     /* Northbridge bus */
++      p[7] = 0x1;                     /* Variety */
++      current += 8;
++
++      /* Describe SB IOAPIC */
++      p = (uint8_t *)current;
++      p[0] = 0x48;                    /* Entry type */
++      p[1] = 0;                       /* Device */
++      p[2] = 0;                       /* Bus */
++      p[3] = 0xd7;                    /* Data */
++      p[4] = apicid_sp5100;           /* IOAPIC ID */
++      p[5] = 0x14 << 3;               /* Device 0x14 Function 0 */
++      p[6] = 0x0;                     /* Southbridge bus */
++      p[7] = 0x1;                     /* Variety */
++      current += 8;
++
++      return current;
++}
+\ No newline at end of file
+diff --git a/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c 
b/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c
+index 61d16d7..14bd9ed 100644
+--- a/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c
++++ b/src/mainboard/supermicro/h8scm_fam10/acpi_tables.c
+@@ -66,3 +66,40 @@ unsigned long acpi_fill_madt(unsigned long current)
+ 
+       return current;
+ }
++
++unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current)
++{
++      uint8_t *p;
++
++      uint32_t apicid_sp5100;
++      uint32_t apicid_sr5650;
++
++      apicid_sp5100 = 0x20;
++      apicid_sr5650 = apicid_sp5100 + 1;
++
++      /* Describe NB IOAPIC */
++      p = (uint8_t *)current;
++      p[0] = 0x48;                    /* Entry type */
++      p[1] = 0;                       /* Device */
++      p[2] = 0;                       /* Bus */
++      p[3] = 0x0;                     /* Data */
++      p[4] = apicid_sr5650;           /* IOAPIC ID */
++      p[5] = 0x1;                     /* Device 0 Function 1 */
++      p[6] = 0x0;                     /* Northbridge bus */
++      p[7] = 0x1;                     /* Variety */
++      current += 8;
++
++      /* Describe SB IOAPIC */
++      p = (uint8_t *)current;
++      p[0] = 0x48;                    /* Entry type */
++      p[1] = 0;                       /* Device */
++      p[2] = 0;                       /* Bus */
++      p[3] = 0xd7;                    /* Data */
++      p[4] = apicid_sp5100;           /* IOAPIC ID */
++      p[5] = 0x14 << 3;               /* Device 0x14 Function 0 */
++      p[6] = 0x0;                     /* Southbridge bus */
++      p[7] = 0x1;                     /* Variety */
++      current += 8;
++
++      return current;
++}
+diff --git a/src/southbridge/amd/sr5650/cmn.h 
b/src/southbridge/amd/sr5650/cmn.h
+index 23d25d5..a54bdc5 100644
+--- a/src/southbridge/amd/sr5650/cmn.h
++++ b/src/southbridge/amd/sr5650/cmn.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -26,6 +27,8 @@
+ #define NBHTIU_INDEX  0x94 /* Note: It is different with RS690, whose HTIU 
index is 0xA8 */
+ #define NBMC_INDEX    0xE8
+ #define NBPCIE_INDEX          0xE0
++#define L2CFG_INDEX   0xF0
++#define L1CFG_INDEX   0xF8
+ #define EXT_CONF_BASE_ADDRESS CONFIG_MMCONF_BASE_ADDRESS
+ #define       TEMP_MMIO_BASE_ADDRESS  0xC0000000
+ 
+diff --git a/src/southbridge/amd/sr5650/early_setup.c 
b/src/southbridge/amd/sr5650/early_setup.c
+index 62b0dab..e7cca06 100644
+--- a/src/southbridge/amd/sr5650/early_setup.c
++++ b/src/southbridge/amd/sr5650/early_setup.c
+@@ -24,6 +24,8 @@
+ #include <arch/io.h>
+ #include <console/console.h>
+ #include <cpu/x86/msr.h>
++#include <option.h>
++#include <reset.h>
+ #include "sr5650.h"
+ #include "cmn.h"
+ 
+@@ -271,6 +273,34 @@ void sr5650_htinit(void)
+               /* HT Buffer Allocation for Ganged Links!!! */
+ #endif        /* CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || 
CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 */
+       }
++
++}
++
++/* Must be run immediately after HT setup is complete and first warm reset 
has occurred (if applicable)
++ * Attempting to switch the NB into isochronous mode before the CPUs have 
engaged isochronous mode
++ * will cause a system hard lockup...
++ */
++void sr5650_htinit_dect_and_enable_isochronous_link(void)
++{
++      device_t sr5650_f0;
++      unsigned char iommu;
++
++      sr5650_f0 = PCI_DEV(0, 0, 0);
++
++      iommu = 1;
++      get_option(&iommu, "iommu");
++
++      if (iommu) {
++              /* Enable isochronous mode */
++              set_nbcfg_enable_bits(sr5650_f0, 0xc8, 1 << 12, 1 << 12);
++
++              /* Apply pending changes */
++              if (!((pci_read_config32(sr5650_f0, 0xc8) >> 12) & 0x1)) {
++                      printk(BIOS_INFO, "...WARM RESET...\n\n\n");
++                      soft_reset();
++                      die("After soft_reset_x - shouldn't see this 
message!!!\n");
++              }
++      }
+ }
+ 
+ #if CONFIG_NORTHBRIDGE_AMD_AMDFAM10 || CONFIG_NORTHBRIDGE_AMD_AGESA_FAMILY10 
/* save some spaces */
+@@ -335,8 +365,21 @@ static void sr5650_por_pcicfg_init(device_t nb_dev)
+ *****************************************/
+ static void sr5650_por_misc_index_init(device_t nb_dev)
+ {
+-      /* disable IOMMU */
+-      set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0);
++      unsigned char iommu;
++
++      iommu = 1;
++      get_option(&iommu, "iommu");
++
++      if (iommu) {
++              /* enable IOMMU */
++              printk(BIOS_DEBUG, "Enabling IOMMU\n");
++              set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x1);
++      } else {
++              /* disable IOMMU */
++              printk(BIOS_DEBUG, "Disabling IOMMU\n");
++              set_nbmisc_enable_bits(nb_dev, 0x75, 0x1, 0x0);
++      }
++
+       /* NBMISCIND:0x75[29]= 1 Device ID for hotplug and PME message */
+       set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 29, 1 << 29);
+       set_nbmisc_enable_bits(nb_dev, 0x75, 1 << 9, 1 << 9); /* no doc 
reference, comply with BTS */
+@@ -374,10 +417,11 @@ static void sr5650_por_misc_index_init(device_t nb_dev)
+        *   HIDE_NB_AGP_CAP  ([0], default=1)HIDE
+        *   HIDE_P2P_AGP_CAP ([1], default=1)HIDE
+        *   HIDE_NB_GART_BAR ([2], default=1)HIDE
++       *   HIDE_MMCFG_BAR   ([3], default=1)SHOW
+        *   AGPMODE30        ([4], default=0)DISABLE
+        *   AGP30ENCHANCED   ([5], default=0)DISABLE
+        *   HIDE_AGP_CAP     ([8], default=1)ENABLE */
+-      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 6);
++      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 3 | 0 << 6);
+ 
+       /* IOC_LAT_PERF_CNTR_CNTL */
+       set_nbmisc_enable_bits(nb_dev, 0x30, 0xFF, 0x00);
+diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
+index 6db1eb1..b296c47 100644
+--- a/src/southbridge/amd/sr5650/sr5650.c
++++ b/src/southbridge/amd/sr5650/sr5650.c
+@@ -26,7 +26,9 @@
+ #include <device/pci_ops.h>
+ #include <cpu/x86/msr.h>
+ #include <cpu/amd/mtrr.h>
++#include <stdlib.h>
+ #include <delay.h>
++#include <option.h>
+ #include "sr5650.h"
+ #include "cmn.h"
+ 
+@@ -87,6 +89,26 @@ void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 
data)
+       nb_write_index((nb_dev), NBPCIE_INDEX, (index), (data));
+ }
+ 
++uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index)
++{
++      return nb_read_index((nb_dev), L2CFG_INDEX, (index));
++}
++
++void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data)
++{
++      nb_write_index((nb_dev), L2CFG_INDEX | (0x1 << 8), (index), (data));
++}
++
++uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index)
++{
++      return nb_read_index((nb_dev), L1CFG_INDEX, (index));
++}
++
++void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data)
++{
++      nb_write_index((nb_dev), L1CFG_INDEX | (0x1 << 31), (index), (data));
++}
++
+ /***********************************************************
+ * To access bar3 we need to program PCI MMIO 7 in K8.
+ * in_out:
+@@ -286,6 +308,240 @@ u32 get_vid_did(device_t dev)
+       return pci_read_config32(dev, 0);
+ }
+ 
++void detect_and_enable_iommu(device_t iommu_dev) {
++      uint32_t dword;
++      uint8_t l1_target;
++      unsigned char iommu;
++      void * mmio_base;
++
++      iommu = 1;
++      get_option(&iommu, "iommu");
++
++      if (iommu) {
++              printk(BIOS_DEBUG, "Initializing IOMMU\n");
++
++              device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
++
++              if (!nb_dev) {
++                      printk(BIOS_WARNING, "Unable to find SR5690 device!  
IOMMU NOT initialized\n");
++                      return;
++              }
++
++              mmio_base = (void*)(pci_read_config32(iommu_dev, 0x44) & 
0xffffc000);
++
++              // if (get_nb_rev(nb_dev) == REV_SR5650_A11) {
++              //      dword = pci_read_config32(iommu_dev, 0x6c);
++              //      dword &= ~(0x1 << 8);
++              //      pci_write_config32(iommu_dev, 0x6c, dword);
++              // }
++
++              dword = pci_read_config32(iommu_dev, 0x50);
++              dword &= ~(0x1 << 22);
++              pci_write_config32(iommu_dev, 0x50, dword);
++
++              dword = pci_read_config32(iommu_dev, 0x44);
++              dword |= 0x1;
++              pci_write_config32(iommu_dev, 0x44, dword);
++
++              write32((void*)(mmio_base + 0x8), 0x0);
++              write32((void*)(mmio_base + 0xc), 0x08000000);
++              write32((void*)(mmio_base + 0x10), 0x0);
++              write32((void*)(mmio_base + 0x2008), 0x0);
++              write32((void*)(mmio_base + 0x2010), 0x0);
++
++              /* IOMMU L1 initialization */
++              for (l1_target = 0; l1_target < 6; l1_target++) {
++                      dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) 
+ 0xc);
++                      dword |= (0x7 << 28);
++                      l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0xc, 
dword);
++
++                      dword = l1cfg_ind_read_index(nb_dev, (l1_target << 16) 
+ 0x7);
++                      dword |= (0x1 << 5);
++                      l1cfg_ind_write_index(nb_dev, (l1_target << 16) + 0x7, 
dword);
++              }
++
++              /* IOMMU L2 initialization */
++              dword = l2cfg_ind_read_index(nb_dev, 0xc);
++              dword |= (0x7 << 29);
++              l2cfg_ind_write_index(nb_dev, 0xc, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x10);
++              dword &= ~(0x3 << 8);
++              dword |= (0x2 << 8);
++              l2cfg_ind_write_index(nb_dev, 0x10, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x14);
++              dword &= ~(0x3 << 8);
++              dword |= (0x2 << 8);
++              l2cfg_ind_write_index(nb_dev, 0x14, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x18);
++              dword &= ~(0x3 << 8);
++              dword |= (0x2 << 8);
++              l2cfg_ind_write_index(nb_dev, 0x18, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x1c);
++              dword &= ~(0x3 << 8);
++              dword |= (0x2 << 8);
++              l2cfg_ind_write_index(nb_dev, 0x1c, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x50);
++              dword &= ~(0x3 << 8);
++              dword |= (0x2 << 8);
++              l2cfg_ind_write_index(nb_dev, 0x50, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x10);
++              dword |= (0x1 << 4);
++              l2cfg_ind_write_index(nb_dev, 0x10, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x14);
++              dword |= (0x1 << 4);
++              l2cfg_ind_write_index(nb_dev, 0x14, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x18);
++              dword |= (0x1 << 4);
++              l2cfg_ind_write_index(nb_dev, 0x18, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x1c);
++              dword |= (0x1 << 4);
++              l2cfg_ind_write_index(nb_dev, 0x1c, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x50);
++              dword |= (0x1 << 4);
++              l2cfg_ind_write_index(nb_dev, 0x50, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x6);
++              dword |= (0x1 << 7);
++              l2cfg_ind_write_index(nb_dev, 0x6, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x44);
++              dword |= (0x1 << 0);
++              l2cfg_ind_write_index(nb_dev, 0x44, dword);
++
++//            if (get_nb_rev(nb_dev) == REV_SR5650_A21) {
++                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
++                      dword |= (0x1 << 1);
++                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x44);
++                      dword |= (0x1 << 1);
++                      l2cfg_ind_write_index(nb_dev, 0x44, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
++                      dword |= (0x1 << 2);
++                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
++                      dword |= (0x1 << 3);
++                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x44);
++                      dword |= (0x1 << 3);
++                      l2cfg_ind_write_index(nb_dev, 0x44, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
++                      dword |= (0x1 << 4);
++                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x6);
++                      dword |= (0x1 << 5);
++                      l2cfg_ind_write_index(nb_dev, 0x6, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x6);
++                      dword |= (0x1 << 6);
++                      l2cfg_ind_write_index(nb_dev, 0x6, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
++                      dword |= (0x1 << 5);
++                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x44);
++                      dword |= (0x1 << 4);
++                      l2cfg_ind_write_index(nb_dev, 0x44, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
++                      dword |= (0x1 << 6);
++                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x7);
++                      dword |= (0x1 << 7);
++                      l2cfg_ind_write_index(nb_dev, 0x7, dword);
++
++                      dword = l2cfg_ind_read_index(nb_dev, 0x6);
++                      dword |= (0x1 << 8);
++                      l2cfg_ind_write_index(nb_dev, 0x6, dword);
++//            }
++
++              l2cfg_ind_write_index(nb_dev, 0x52, 0xf0000002);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x80);
++              dword |= (0x1 << 0);
++              l2cfg_ind_write_index(nb_dev, 0x80, dword);
++
++              dword = l2cfg_ind_read_index(nb_dev, 0x30);
++              dword |= (0x1 << 0);
++              l2cfg_ind_write_index(nb_dev, 0x30, dword);
++      }
++}
++
++void sr5650_iommu_read_resources(device_t dev)
++{
++      unsigned char iommu;
++      struct resource *res;
++
++      iommu = 1;
++      get_option(&iommu, "iommu");
++
++      /* Get the normal pci resources of this device */
++      pci_dev_read_resources(dev);
++
++      if (iommu) {
++              /* Request MMIO range allocation */
++              res = new_resource(dev, 0x44);          /* IOMMU */
++              res->base = 0x0;
++              res->size = 0x4000;
++              res->limit = 0xFFFFFFFFUL;              /* res->base + 
res->size -1; */
++              res->align = 14;                        /* 16k alignment */
++              res->gran = 14;
++              res->flags = IORESOURCE_MEM | IORESOURCE_RESERVE;
++      }
++
++      compact_resources(dev);
++}
++
++void sr5650_iommu_set_resources(device_t dev)
++{
++      unsigned char iommu;
++      struct resource *res;
++
++      iommu = 1;
++      get_option(&iommu, "iommu");
++
++      /* Get the normal pci resources of this device */
++      pci_dev_read_resources(dev);
++
++      if (iommu) {
++              /* Get the allocated range */
++              res = find_resource(dev, 0x44);
++
++              if (res->base == 0) {
++                      printk(BIOS_WARNING, "Unable to allocate MMIO range to 
IOMMU\n");
++              }
++
++              /* Assign the range to hardware */
++              pci_write_config32(dev, 0x44, res->base & 0xffffc000);
++              pci_write_config32(dev, 0x48, 0x0);
++      }
++
++      /* Run standard resource set routine */
++      pci_dev_set_resources(dev);
++}
++
++void sr5650_iommu_enable_resources(device_t dev)
++{
++      detect_and_enable_iommu(dev);
++}
++
+ void sr5650_nb_pci_table(device_t nb_dev)
+ {     /* NBPOR_InitPOR function. */
+       u8 temp8;
+@@ -365,13 +621,23 @@ void sr5650_enable(device_t dev)
+       dev_ind = dev->path.pci.devfn >> 3;
+       switch (dev_ind) {
+       case 0:         /* bus0, dev0, fun0; */
+-              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n");
+-              enable_pcie_bar3(nb_dev);       /* PCIEMiscInit */
+-
+-              config_gpp_core(nb_dev, sb_dev);
+-              sr5650_gpp_sb_init(nb_dev, sb_dev, 8);
+-
+-              sr5650_nb_pci_table(nb_dev);
++              switch (dev->path.pci.devfn & 0x7) {
++                      case 0:
++                              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-0.\n");
++                              enable_pcie_bar3(nb_dev);       /* PCIEMiscInit 
*/
++
++                              config_gpp_core(nb_dev, sb_dev);
++                              sr5650_gpp_sb_init(nb_dev, sb_dev, 8);
++
++                              sr5650_nb_pci_table(nb_dev);
++                              break;
++                      case 1:
++                              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-1.\n");
++                              break;
++                      case 2:
++                              printk(BIOS_INFO, "Bus-0, Dev-0, Fun-2.\n");
++                              break;
++              }
+               break;
+ 
+       case 2:         /* bus0, dev2,3 GPP1 */
+@@ -438,6 +704,205 @@ void sr5650_enable(device_t dev)
+       }
+ }
+ 
++static void add_ivrs_device_entries(struct device *parent, struct device 
*dev, int depth, int linknum, int8_t *root_level, unsigned long *current, 
uint16_t *length)
++{
++      uint8_t *p;
++      struct device *sibling;
++      struct bus *link;
++
++      if (!root_level) {
++              root_level = malloc(sizeof(int8_t));
++              *root_level = -1;
++      }
++
++      if (dev->path.type == DEVICE_PATH_PCI) {
++              if ((dev->bus->secondary == 0x0) && (dev->path.pci.devfn == 
0x0))
++                      *root_level = depth;
++
++              if (*root_level != -1) {
++                      if (depth >= *root_level) {
++                              if (dev->enabled) {
++                                      if (depth == *root_level) {
++                                              if (dev->path.pci.devfn < (0x1 
<< 3)) {
++                                                      /* SR5690 control 
device */
++                                              } else if ((dev->path.pci.devfn 
>= (0x1 << 3)) && (dev->path.pci.devfn < (0xe << 3))) {
++                                                      /* SR5690 PCIe bridge 
device */
++                                              } else {
++                                                      if (dev->path.pci.devfn 
== (0x14 << 3)) {
++                                                              /* SMBUS 
controller */
++                                                              p = (uint8_t *) 
*current;
++                                                              p[0] = 0x2;     
                /* Entry type */
++                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
++                                                              p[2] = 
dev->bus->secondary;     /* Bus */
++                                                              p[3] = 0x97;    
                /* Data */
++                                                              p[4] = 0x0;     
                /* Padding */
++                                                              p[5] = 0x0;     
                /* Padding */
++                                                              p[6] = 0x0;     
                /* Padding */
++                                                              p[7] = 0x0;     
                /* Padding */
++                                                              *length += 8;
++                                                              *current += 8;
++                                                      } else {
++                                                              /* Other 
southbridge device */
++                                                              p = (uint8_t *) 
*current;
++                                                              p[0] = 0x2;     
                /* Entry type */
++                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
++                                                              p[2] = 
dev->bus->secondary;     /* Bus */
++                                                              p[3] = 0x0;     
                /* Data */
++                                                              p[4] = 0x0;     
                /* Padding */
++                                                              p[5] = 0x0;     
                /* Padding */
++                                                              p[6] = 0x0;     
                /* Padding */
++                                                              p[7] = 0x0;     
                /* Padding */
++                                                              *length += 8;
++                                                              *current += 8;
++                                                      }
++                                              }
++                                      } else {
++                                              if ((dev->hdr_type & 0x7f) == 
PCI_HEADER_TYPE_NORMAL) {
++                                                      /* Device behind bridge 
*/
++                                                      if 
(pci_find_capability(dev, PCI_CAP_ID_PCIE)) {
++                                                              /* Device is 
PCIe */
++                                                              p = (uint8_t *) 
*current;
++                                                              p[0] = 0x2;     
                /* Entry type */
++                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
++                                                              p[2] = 
dev->bus->secondary;     /* Bus */
++                                                              p[3] = 0x0;     
                /* Data */
++                                                              p[4] = 0x0;     
                /* Padding */
++                                                              p[5] = 0x0;     
                /* Padding */
++                                                              p[6] = 0x0;     
                /* Padding */
++                                                              p[7] = 0x0;     
                /* Padding */
++                                                              *length += 8;
++                                                              *current += 8;
++                                                      } else {
++                                                              /* Device is 
legacy PCI or PCI-X */
++                                                              p = (uint8_t *) 
*current;
++                                                              p[0] = 0x42;    
                /* Entry type */
++                                                              p[1] = 
dev->path.pci.devfn;     /* Device */
++                                                              p[2] = 
dev->bus->secondary;     /* Bus */
++                                                              p[3] = 0x0;     
                /* Data */
++                                                              p[4] = 0x0;     
                /* Reserved */
++                                                              p[5] = 
parent->path.pci.devfn;  /* Device */
++                                                              p[6] = 
parent->bus->secondary;  /* Bus */
++                                                              p[7] = 0x0;     
                /* Reserved */
++                                                              *length += 8;
++                                                              *current += 8;
++                                                      }
++                                              }
++                                      }
++                              }
++                      }
++              }
++      }
++
++      for (link = dev->link_list; link; link = link->next)
++              for (sibling = link->children; sibling; sibling = 
sibling->sibling)
++                      add_ivrs_device_entries(dev, sibling, depth + 1, depth, 
root_level, current, length);
++
++      free(root_level);
++}
++
++static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current)
++{
++      uint8_t *p;
++
++      device_t nb_dev = dev_find_slot(0, PCI_DEVFN(0, 0));
++      if (!nb_dev) {
++              printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 
device!  IVRS table not generated...\n");
++              return (unsigned long)ivrs;
++      }
++
++      device_t iommu_dev = dev_find_slot(0, PCI_DEVFN(0, 2));
++      if (!iommu_dev) {
++              printk(BIOS_WARNING, "acpi_fill_ivrs: Unable to locate SR5650 
IOMMU device!  IVRS table not generated...\n");
++              return (unsigned long)ivrs;
++      }
++
++      ivrs->iv_info = 0x0;
++      ivrs->iv_info |= (0x40 << 15);  /* Maximum supported virtual address 
size */
++      ivrs->iv_info |= (0x34 << 8);   /* Maximum supported physical address 
size */
++
++      ivrs->ivhd.type = 0x10;
++      ivrs->ivhd.flags = 0x0e;
++      // if (get_nb_rev(nb_dev) != REV_SR5650_A11) {
++              ivrs->ivhd.flags |= 0x10;                               /* 
Enable ATS support on all revisions except A11 */
++      // }
++      ivrs->ivhd.length = sizeof(struct acpi_ivrs_ivhd);
++      ivrs->ivhd.device_id = 0x2 | (nb_dev->bus->secondary << 8);     /* BDF 
<bus>:00.2 */
++      ivrs->ivhd.capability_offset = 0x40;                            /* 
Capability block 0x40 (type 0xf, "Secure device") */
++      ivrs->ivhd.iommu_base_low = pci_read_config32(iommu_dev, 0x44) & 
0xffffc000;
++      ivrs->ivhd.iommu_base_high = pci_read_config32(iommu_dev, 0x48);
++      ivrs->ivhd.pci_segment_group = 0x0;
++      ivrs->ivhd.iommu_info = 0x0;
++      ivrs->ivhd.iommu_info |= (0x14 << 8);
++      ivrs->ivhd.efr = 0x0;
++
++      /* Describe HPET */
++      p = (uint8_t *)current;
++      p[0] = 0x48;                    /* Entry type */
++      p[1] = 0;                       /* Device */
++      p[2] = 0;                       /* Bus */
++      p[3] = 0xd7;                    /* Data */
++      p[4] = 0x0;                     /* HPET number */
++      p[5] = 0x14 << 3;               /* HPET device */
++      p[6] = nb_dev->bus->secondary;  /* HPET bus */
++      p[7] = 0x2;                     /* Variety */
++      ivrs->ivhd.length += 8;
++      current += 8;
++
++      /* Describe PCI devices */
++      add_ivrs_device_entries(NULL, all_devices, 0, -1, NULL, &current, 
&ivrs->ivhd.length);
++
++      /* Describe IOAPICs */
++      unsigned long prev_current = current;
++      current = acpi_fill_ivrs_ioapic(ivrs, current);
++      ivrs->ivhd.length += (current - prev_current);
++
++      return current;
++}
++
++unsigned long southbridge_write_acpi_tables(device_t device,
++                                              unsigned long current,
++                                              struct acpi_rsdp *rsdp)
++{
++      unsigned char iommu;
++
++      iommu = 1;
++      get_option(&iommu, "iommu");
++
++      if (iommu) {
++              acpi_ivrs_t *ivrs;
++
++              /* IVRS */
++              current = ALIGN(current, 8);
++              printk(BIOS_DEBUG, "ACPI:   * IVRS at %lx\n", current);
++              ivrs = (acpi_ivrs_t *) current;
++              acpi_create_ivrs(ivrs, acpi_fill_ivrs);
++              current += ivrs->header.length;
++              acpi_add_table(rsdp, ivrs);
++      }
++
++      return current;
++}
++
++static struct pci_operations iommu_ops_pci = {
++      .set_subsystem = pci_dev_set_subsystem,
++};
++
++static struct device_operations iommu_ops = {
++      .read_resources = sr5650_iommu_read_resources,
++      .set_resources = sr5650_iommu_set_resources,
++      .enable_resources = sr5650_iommu_enable_resources,
++      .write_acpi_tables = southbridge_write_acpi_tables,
++      .init = 0,
++      .scan_bus = 0,
++      .ops_pci = &iommu_ops_pci,
++};
++
++static const struct pci_driver ht_driver_sr5690 __pci_driver = {
++      .ops = &iommu_ops,
++      .vendor = PCI_VENDOR_ID_ATI,
++      .device = PCI_DEVICE_ID_AMD_SR5650_IOMMU,
++};
++
+ struct chip_operations southbridge_amd_sr5650_ops = {
+       CHIP_NAME("ATI SR5650")
+       .enable_dev = sr5650_enable,
+diff --git a/src/southbridge/amd/sr5650/sr5650.h 
b/src/southbridge/amd/sr5650/sr5650.h
+index ebbde41..a3518fb 100644
+--- a/src/southbridge/amd/sr5650/sr5650.h
++++ b/src/southbridge/amd/sr5650/sr5650.h
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -21,6 +22,7 @@
+ #define __SR5650_H__
+ 
+ #include <stdint.h>
++#include <arch/acpi.h>
+ #include <device/pci_ids.h>
+ #include "chip.h"
+ #include "rev.h"
+@@ -95,16 +97,24 @@ u32 nbpcie_p_read_index(device_t dev, u32 index);
+ void nbpcie_p_write_index(device_t dev, u32 index, u32 data);
+ u32 nbpcie_ind_read_index(device_t nb_dev, u32 index);
+ void nbpcie_ind_write_index(device_t nb_dev, u32 index, u32 data);
++uint32_t l2cfg_ind_read_index(device_t nb_dev, uint32_t index);
++void l2cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data);
++uint32_t l1cfg_ind_read_index(device_t nb_dev, uint32_t index);
++void l1cfg_ind_write_index(device_t nb_dev, uint32_t index, uint32_t data);
+ u32 pci_ext_read_config32(device_t nb_dev, device_t dev, u32 reg);
+ void pci_ext_write_config32(device_t nb_dev, device_t dev, u32 reg, u32 mask, 
u32 val);
+ void sr5650_set_tom(device_t nb_dev);
+ 
++unsigned long southbridge_write_acpi_tables(device_t device, unsigned long 
current,
++                                              struct acpi_rsdp *rsdp);
++
+ void ProgK8TempMmioBase(u8 in_out, u32 pcie_base_add, u32 mmio_base_add);
+ void enable_pcie_bar3(device_t nb_dev);
+ void disable_pcie_bar3(device_t nb_dev);
+ 
+ void enable_sr5650_dev8(void);
+ void sr5650_htinit(void);
++void sr5650_htinit_dect_and_enable_isochronous_link(void);
+ void sr5650_early_setup(void);
+ void sr5650_before_pci_init(void);
+ void sr5650_enable(device_t dev);
+@@ -118,6 +128,10 @@ void pcie_config_misc_clk(device_t nb_dev);
+ void fam10_optimization(void);
+ void sr5650_disable_pcie_bridge(void);
+ u32 get_vid_did(device_t dev);
++void detect_and_enable_iommu(device_t iommu_dev);
++void sr5650_iommu_read_resources(device_t dev);
++void sr5650_iommu_set_resources(device_t dev);
++void sr5650_iommu_enable_resources(device_t dev);
+ void sr5650_nb_pci_table(device_t nb_dev);
+ void init_gen2(device_t nb_dev, device_t dev, u8 port);
+ void sr56x0_lock_hwinitreg(void);
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0114-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
 
b/resources/libreboot/patch/kgpe-d16/0114-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
deleted file mode 100644
index e7f0b9e..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0114-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 215348b2c83c3f1464b0c4d318e5ff6318d82a02 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 11 Aug 2015 17:52:31 -0500
-Subject: [PATCH 114/139] northbridge/amd/amdfam10: Fix gart setup not working
- on Family 15h processors
-
-Change-Id: Ib78620c30502df6add9cc2ea1dbd4fb6dc89203e
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/misc_control.c | 34 ++++++++++++++++++++++-------
- 1 file changed, 26 insertions(+), 8 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
-index 1df570c..4b62c69 100644
---- a/src/northbridge/amd/amdfam10/misc_control.c
-+++ b/src/northbridge/amd/amdfam10/misc_control.c
-@@ -77,7 +77,7 @@ static void mcf3_read_resources(device_t dev)
-       }
- }
- 
--static void set_agp_aperture(device_t dev)
-+static void set_agp_aperture(device_t dev, uint32_t pci_id)
- {
-       struct resource *resource;
- 
-@@ -97,7 +97,7 @@ static void set_agp_aperture(device_t dev)
- 
-               /* Update the other northbriges */
-               pdev = 0;
--              while((pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1203, 
pdev))) {
-+              while ((pdev = dev_find_device(PCI_VENDOR_ID_AMD, pci_id, 
pdev))) {
-                       /* Store the GART size but don't enable it */
-                       pci_write_config32(pdev, 0x90, gart_acr);
- 
-@@ -113,10 +113,19 @@ static void set_agp_aperture(device_t dev)
-       }
- }
- 
--static void mcf3_set_resources(device_t dev)
-+static void mcf3_set_resources_fam10h(device_t dev)
- {
-       /* Set the gart apeture */
--      set_agp_aperture(dev);
-+      set_agp_aperture(dev, 0x1203);
-+
-+      /* Set the generic PCI resources */
-+      pci_dev_set_resources(dev);
-+}
-+
-+static void mcf3_set_resources_fam15h(device_t dev)
-+{
-+      /* Set the gart apeture */
-+      set_agp_aperture(dev, 0x1603);
- 
-       /* Set the generic PCI resources */
-       pci_dev_set_resources(dev);
-@@ -155,9 +164,18 @@ static void misc_control_init(struct device *dev)
- }
- 
- 
--static struct device_operations mcf3_ops  = {
-+static struct device_operations mcf3_ops_fam10h  = {
-+      .read_resources   = mcf3_read_resources,
-+      .set_resources    = mcf3_set_resources_fam10h,
-+      .enable_resources = pci_dev_enable_resources,
-+      .init             = misc_control_init,
-+      .scan_bus         = 0,
-+      .ops_pci          = 0,
-+};
-+
-+static struct device_operations mcf3_ops_fam15h  = {
-       .read_resources   = mcf3_read_resources,
--      .set_resources    = mcf3_set_resources,
-+      .set_resources    = mcf3_set_resources_fam15h,
-       .enable_resources = pci_dev_enable_resources,
-       .init             = misc_control_init,
-       .scan_bus         = 0,
-@@ -165,13 +183,13 @@ static struct device_operations mcf3_ops  = {
- };
- 
- static const struct pci_driver mcf3_driver __pci_driver = {
--      .ops    = &mcf3_ops,
-+      .ops    = &mcf3_ops_fam10h,
-       .vendor = PCI_VENDOR_ID_AMD,
-       .device = 0x1203,
- };
- 
- static const struct pci_driver mcf3_driver_fam15 __pci_driver = {
--      .ops    = &mcf3_ops,
-+      .ops    = &mcf3_ops_fam15h,
-       .vendor = PCI_VENDOR_ID_AMD,
-       .device = 0x1603,
- };
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0114-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
 
b/resources/libreboot/patch/kgpe-d16/0114-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
new file mode 100644
index 0000000..42cebaf
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0114-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch
@@ -0,0 +1,57 @@
+From 2976a30c045a1c525095d8a954f26174fbdc532c Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 13 Aug 2015 17:45:12 -0500
+Subject: [PATCH 114/143] southbridge/amd/sr5650: Hide clock configuration
+ device after setup is complete
+
+Change-Id: I043f2eb0993660d0a9351867eca1e73e0b2c37f1
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sr5650/early_setup.c |   16 ++++++++--------
+ src/southbridge/amd/sr5650/pcie.c        |    3 +++
+ 2 files changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/src/southbridge/amd/sr5650/early_setup.c 
b/src/southbridge/amd/sr5650/early_setup.c
+index e7cca06..cb666db 100644
+--- a/src/southbridge/amd/sr5650/early_setup.c
++++ b/src/southbridge/amd/sr5650/early_setup.c
+@@ -414,14 +414,14 @@ static void sr5650_por_misc_index_init(device_t nb_dev)
+       set_nbmisc_enable_bits(nb_dev, 0x01, 0xFFFFFFFF, 0x00000310);
+ 
+       /* NBCFG (NBMISCIND 0x0): NB_CNTL -
+-       *   HIDE_NB_AGP_CAP  ([0], default=1)HIDE
+-       *   HIDE_P2P_AGP_CAP ([1], default=1)HIDE
+-       *   HIDE_NB_GART_BAR ([2], default=1)HIDE
+-       *   HIDE_MMCFG_BAR   ([3], default=1)SHOW
+-       *   AGPMODE30        ([4], default=0)DISABLE
+-       *   AGP30ENCHANCED   ([5], default=0)DISABLE
+-       *   HIDE_AGP_CAP     ([8], default=1)ENABLE */
+-      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 3 | 0 << 6);
++       *   HIDE_NB_AGP_CAP    ([0], default=1)HIDE
++       *   HIDE_P2P_AGP_CAP   ([1], default=1)HIDE
++       *   HIDE_NB_GART_BAR   ([2], default=1)HIDE
++       *   HIDE_MMCFG_BAR     ([3], default=1)SHOW
++       *   AGPMODE30          ([4], default=0)DISABLE
++       *   AGP30ENCHANCED     ([5], default=0)DISABLE
++       *   HIDE_CLKCFG_HEADER ([8], default=0)SHOW */
++      set_nbmisc_enable_bits(nb_dev, 0x00, 0x0000FFFF, 0 << 0 | 1 << 1 | 1 << 
2 | 0 << 3 | 0 << 6 | 0 << 8);
+ 
+       /* IOC_LAT_PERF_CNTR_CNTL */
+       set_nbmisc_enable_bits(nb_dev, 0x30, 0xFF, 0x00);
+diff --git a/src/southbridge/amd/sr5650/pcie.c 
b/src/southbridge/amd/sr5650/pcie.c
+index 09ce217..360e9cb 100644
+--- a/src/southbridge/amd/sr5650/pcie.c
++++ b/src/southbridge/amd/sr5650/pcie.c
+@@ -854,6 +854,9 @@ void sr56x0_lock_hwinitreg(void)
+ 
+       /* Lock HWInit Register NBMISCIND:0x0 NBCNTL[7] HWINIT_WR_LOCK */
+       set_nbmisc_enable_bits(nb_dev, 0x00, 1 << 7, 1 << 7);
++
++      /* Hide clock configuration PCI device HIDE_CLKCFG_HEADER */
++      set_nbmisc_enable_bits(nb_dev, 0x00, 0x00000100, 1 << 8);
+ }
+ 
+ /*****************************************
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0115-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
 
b/resources/libreboot/patch/kgpe-d16/0115-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
deleted file mode 100644
index ba0f218..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0115-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
+++ /dev/null
@@ -1,129 +0,0 @@
-From 7b3c144695ecc58a7bfc35215fd2933aea0051e1 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 11 Aug 2015 17:53:45 -0500
-Subject: [PATCH 115/139] mainboard/asus/kgpe-d16: Add several nvram
- configuration options
-
-Change-Id: I45b04e8fbdfc65603e1057f7b0e5a13d073fe348
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/acpi_tables.c | 37 +++++++++++++++++++++++++++++++
- src/mainboard/asus/kgpe-d16/cmos.default  |  3 ++-
- src/mainboard/asus/kgpe-d16/cmos.layout   |  7 +++---
- src/mainboard/asus/kgpe-d16/devicetree.cb |  1 +
- src/mainboard/asus/kgpe-d16/romstage.c    |  2 ++
- 5 files changed, 46 insertions(+), 4 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/acpi_tables.c 
b/src/mainboard/asus/kgpe-d16/acpi_tables.c
-index 4e98dfe..3f8650b 100644
---- a/src/mainboard/asus/kgpe-d16/acpi_tables.c
-+++ b/src/mainboard/asus/kgpe-d16/acpi_tables.c
-@@ -73,3 +73,40 @@ unsigned long acpi_fill_madt(unsigned long current)
- 
-       return current;
- }
-+
-+unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t* ivrs, unsigned long current)
-+{
-+      uint8_t *p;
-+
-+      uint32_t apicid_sp5100;
-+      uint32_t apicid_sr5650;
-+
-+      apicid_sp5100 = 0x20;
-+      apicid_sr5650 = apicid_sp5100 + 1;
-+
-+      /* Describe NB IOAPIC */
-+      p = (uint8_t *)current;
-+      p[0] = 0x48;                    /* Entry type */
-+      p[1] = 0;                       /* Device */
-+      p[2] = 0;                       /* Bus */
-+      p[3] = 0x0;                     /* Data */
-+      p[4] = apicid_sr5650;           /* IOAPIC ID */
-+      p[5] = 0x1;                     /* Device 0 Function 1 */
-+      p[6] = 0x0;                     /* Northbridge bus */
-+      p[7] = 0x1;                     /* Variety */
-+      current += 8;
-+
-+      /* Describe SB IOAPIC */
-+      p = (uint8_t *)current;
-+      p[0] = 0x48;                    /* Entry type */
-+      p[1] = 0;                       /* Device */
-+      p[2] = 0;                       /* Bus */
-+      p[3] = 0xd7;                    /* Data */
-+      p[4] = apicid_sp5100;           /* IOAPIC ID */
-+      p[5] = 0x14 << 3;               /* Device 0x14 Function 0 */
-+      p[6] = 0x0;                     /* Southbridge bus */
-+      p[7] = 0x1;                     /* Variety */
-+      current += 8;
-+
-+      return current;
-+}
-\ No newline at end of file
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index 0a898bd..83c1fe8 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -3,7 +3,7 @@ debug_level = Spew
- multi_core = Enable
- slow_cpu = off
- compute_unit_siblings = Enable
--iommu = Disable
-+iommu = Enable
- nmi = Disable
- hypertransport_speed_limit = Auto
- max_mem_clock = DDR3-1600
-@@ -23,6 +23,7 @@ maximum_p_state_limit = 0xf
- probe_filter = Auto
- l3_cache_partitioning = Disable
- ieee1394 = Enable
-+gart = Disable
- experimental_memory_speed_boost = Disable
- power_on_after_fail = On
- boot_option = Fallback
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
-index 010d4db..310b7b1 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.layout
-+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
-@@ -51,9 +51,10 @@ entries
- 473          2       e       13       dimm_spd_checksum
- 475          1       e       14       probe_filter
- 476          1       e       1        l3_cache_partitioning
--477          1       e       1        experimental_memory_speed_boost
--478          1       r       0        allow_spd_nvram_cache_restore
--479          1       e       1        ieee1394
-+477          1       e       1        ieee1394
-+478          1       e       1        gart
-+479          1       e       1        experimental_memory_speed_boost
-+480          1       r       0        allow_spd_nvram_cache_restore
- 728        256       h       0        user_data
- 984         16       h       0        check_sum
- # Reserve the extended AMD configuration registers
-diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
-index ada268b..f87efc6 100644
---- a/src/mainboard/asus/kgpe-d16/devicetree.cb
-+++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
-@@ -15,6 +15,7 @@ chip northbridge/amd/amdfam10/root_complex   # Root complex
-                               chip southbridge/amd/sr5650             # 
Primary southbridge
-                                       device pci 0.0 on end                   
# HT Root Complex 0x9600
-                                       device pci 0.1 on end                   
# CLKCONFIG
-+                                      device pci 0.2 on end                   
# IOMMU
-                                       device pci 2.0 on                       
# PCIE P2P bridge 0x9603 (GPP1 Port0)
-                                               # Slot                          
# PCI E 1 / PCI E 2
-                                       end
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index 2b222f5..fa61f63 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -459,6 +459,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               die("After soft_reset_x - shouldn't see this message!!!\n");
-       }
- 
-+      sr5650_htinit_dect_and_enable_isochronous_link();
-+
-       /* Set default DDR memory voltage
-        * This will be overridden later during RAM initialization
-        */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0115-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
 
b/resources/libreboot/patch/kgpe-d16/0115-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
new file mode 100644
index 0000000..165f6b3
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0115-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch
@@ -0,0 +1,55 @@
+From da60f9b49a5323832cad7cb33d97f29776aaf9e8 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 11 Aug 2015 17:52:03 -0500
+Subject: [PATCH 115/143] northbridge/amd/amdfam10: Rename mislabeled iommu
+ nvram option to gart
+
+Change-Id: Ia24102e164eb5753ade3f9b5ab21eba2fa60836b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/misc_control.c |   12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
+index 703ae51..1df570c 100644
+--- a/src/northbridge/amd/amdfam10/misc_control.c
++++ b/src/northbridge/amd/amdfam10/misc_control.c
+@@ -42,7 +42,7 @@
+  *
+  * @param dev
+  *
+- * There is only one AGP aperture resource needed. The resoruce is added to
++ * There is only one AGP aperture resource needed. The resource is added to
+  * the northbridge of BSP.
+  *
+  * The same trick can be used to augment legacy VGA resources which can
+@@ -54,7 +54,7 @@
+ static void mcf3_read_resources(device_t dev)
+ {
+       struct resource *resource;
+-      unsigned char iommu;
++      unsigned char gart;
+       /* Read the generic PCI resources */
+       pci_dev_read_resources(dev);
+ 
+@@ -63,13 +63,13 @@ static void mcf3_read_resources(device_t dev)
+               return;
+       }
+ 
+-      iommu = 1;
+-      get_option(&iommu, "iommu");
++      gart = 1;
++      get_option(&gart, "gart");
+ 
+-      if (iommu) {
++      if (gart) {
+               /* Add a Gart apeture resource */
+               resource = new_resource(dev, 0x94);
+-              resource->size = iommu?CONFIG_AGP_APERTURE_SIZE:1;
++              resource->size = gart?CONFIG_AGP_APERTURE_SIZE:1;
+               resource->align = log2(resource->size);
+               resource->gran  = log2(resource->size);
+               resource->limit = 0xffffffff; /* 4G */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0116-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
 
b/resources/libreboot/patch/kgpe-d16/0116-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
new file mode 100644
index 0000000..9650d95
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0116-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch
@@ -0,0 +1,96 @@
+From 251ec37bd76462397fbda9d644c665720e5c4a2d Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 11 Aug 2015 17:52:31 -0500
+Subject: [PATCH 116/143] northbridge/amd/amdfam10: Fix gart setup not working
+ on Family 15h processors
+
+Change-Id: Ib78620c30502df6add9cc2ea1dbd4fb6dc89203e
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/misc_control.c |   34 ++++++++++++++++++++-------
+ 1 file changed, 26 insertions(+), 8 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
+index 1df570c..4b62c69 100644
+--- a/src/northbridge/amd/amdfam10/misc_control.c
++++ b/src/northbridge/amd/amdfam10/misc_control.c
+@@ -77,7 +77,7 @@ static void mcf3_read_resources(device_t dev)
+       }
+ }
+ 
+-static void set_agp_aperture(device_t dev)
++static void set_agp_aperture(device_t dev, uint32_t pci_id)
+ {
+       struct resource *resource;
+ 
+@@ -97,7 +97,7 @@ static void set_agp_aperture(device_t dev)
+ 
+               /* Update the other northbriges */
+               pdev = 0;
+-              while((pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1203, 
pdev))) {
++              while ((pdev = dev_find_device(PCI_VENDOR_ID_AMD, pci_id, 
pdev))) {
+                       /* Store the GART size but don't enable it */
+                       pci_write_config32(pdev, 0x90, gart_acr);
+ 
+@@ -113,10 +113,19 @@ static void set_agp_aperture(device_t dev)
+       }
+ }
+ 
+-static void mcf3_set_resources(device_t dev)
++static void mcf3_set_resources_fam10h(device_t dev)
+ {
+       /* Set the gart apeture */
+-      set_agp_aperture(dev);
++      set_agp_aperture(dev, 0x1203);
++
++      /* Set the generic PCI resources */
++      pci_dev_set_resources(dev);
++}
++
++static void mcf3_set_resources_fam15h(device_t dev)
++{
++      /* Set the gart apeture */
++      set_agp_aperture(dev, 0x1603);
+ 
+       /* Set the generic PCI resources */
+       pci_dev_set_resources(dev);
+@@ -155,9 +164,18 @@ static void misc_control_init(struct device *dev)
+ }
+ 
+ 
+-static struct device_operations mcf3_ops  = {
++static struct device_operations mcf3_ops_fam10h  = {
++      .read_resources   = mcf3_read_resources,
++      .set_resources    = mcf3_set_resources_fam10h,
++      .enable_resources = pci_dev_enable_resources,
++      .init             = misc_control_init,
++      .scan_bus         = 0,
++      .ops_pci          = 0,
++};
++
++static struct device_operations mcf3_ops_fam15h  = {
+       .read_resources   = mcf3_read_resources,
+-      .set_resources    = mcf3_set_resources,
++      .set_resources    = mcf3_set_resources_fam15h,
+       .enable_resources = pci_dev_enable_resources,
+       .init             = misc_control_init,
+       .scan_bus         = 0,
+@@ -165,13 +183,13 @@ static struct device_operations mcf3_ops  = {
+ };
+ 
+ static const struct pci_driver mcf3_driver __pci_driver = {
+-      .ops    = &mcf3_ops,
++      .ops    = &mcf3_ops_fam10h,
+       .vendor = PCI_VENDOR_ID_AMD,
+       .device = 0x1203,
+ };
+ 
+ static const struct pci_driver mcf3_driver_fam15 __pci_driver = {
+-      .ops    = &mcf3_ops,
++      .ops    = &mcf3_ops_fam15h,
+       .vendor = PCI_VENDOR_ID_AMD,
+       .device = 0x1603,
+ };
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0116-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
 
b/resources/libreboot/patch/kgpe-d16/0116-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
deleted file mode 100644
index 0e10cc9..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0116-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 5428b15fb1aef85b47fbbb117d943d2525a84692 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 14 Aug 2015 02:50:44 -0500
-Subject: [PATCH 116/139] southbridge/amd/sr5650: Use correct PCI configuration
- block offset
-
-Change-Id: I4277d1788d8f9a501399218544aa6d4d11349ccc
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sr5650/acpi/sr5650.asl | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/southbridge/amd/sr5650/acpi/sr5650.asl 
b/src/southbridge/amd/sr5650/acpi/sr5650.asl
-index a6ab114..1e0d5b0 100644
---- a/src/southbridge/amd/sr5650/acpi/sr5650.asl
-+++ b/src/southbridge/amd/sr5650/acpi/sr5650.asl
-@@ -19,8 +19,8 @@
-  */
- 
- Scope(\) {
--      Name(PCBA, 0xE0000000)  /* Base address of PCIe config space */
--      Name(HPBA, 0xFED00000)  /* Base address of HPET table */
-+      Name(PCBA, CONFIG_MMCONF_BASE_ADDRESS)  /* Base address of PCIe config 
space */
-+      Name(HPBA, 0xFED00000)                  /* Base address of HPET table */
- 
-       /* PIC IRQ mapping registers, C00h-C01h */
-       OperationRegion(PRQM, SystemIO, 0x00000C00, 0x00000002)
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0117-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
 
b/resources/libreboot/patch/kgpe-d16/0117-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
new file mode 100644
index 0000000..e652fbd
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0117-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch
@@ -0,0 +1,82 @@
+From f5f3af0a03970b6d96a0a83985ae20e242379278 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 11 Aug 2015 17:53:45 -0500
+Subject: [PATCH 117/143] mainboard/asus/kgpe-d16: Add several nvram
+ configuration options
+
+Change-Id: I45b04e8fbdfc65603e1057f7b0e5a13d073fe348
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.default  |    3 ++-
+ src/mainboard/asus/kgpe-d16/cmos.layout   |    7 ++++---
+ src/mainboard/asus/kgpe-d16/devicetree.cb |    1 +
+ src/mainboard/asus/kgpe-d16/romstage.c    |    2 ++
+ 4 files changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index 0a898bd..83c1fe8 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -3,7 +3,7 @@ debug_level = Spew
+ multi_core = Enable
+ slow_cpu = off
+ compute_unit_siblings = Enable
+-iommu = Disable
++iommu = Enable
+ nmi = Disable
+ hypertransport_speed_limit = Auto
+ max_mem_clock = DDR3-1600
+@@ -23,6 +23,7 @@ maximum_p_state_limit = 0xf
+ probe_filter = Auto
+ l3_cache_partitioning = Disable
+ ieee1394 = Enable
++gart = Disable
+ experimental_memory_speed_boost = Disable
+ power_on_after_fail = On
+ boot_option = Fallback
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout 
b/src/mainboard/asus/kgpe-d16/cmos.layout
+index 010d4db..310b7b1 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.layout
++++ b/src/mainboard/asus/kgpe-d16/cmos.layout
+@@ -51,9 +51,10 @@ entries
+ 473          2       e       13       dimm_spd_checksum
+ 475          1       e       14       probe_filter
+ 476          1       e       1        l3_cache_partitioning
+-477          1       e       1        experimental_memory_speed_boost
+-478          1       r       0        allow_spd_nvram_cache_restore
+-479          1       e       1        ieee1394
++477          1       e       1        ieee1394
++478          1       e       1        gart
++479          1       e       1        experimental_memory_speed_boost
++480          1       r       0        allow_spd_nvram_cache_restore
+ 728        256       h       0        user_data
+ 984         16       h       0        check_sum
+ # Reserve the extended AMD configuration registers
+diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb 
b/src/mainboard/asus/kgpe-d16/devicetree.cb
+index 8eeb33e..8b35201 100644
+--- a/src/mainboard/asus/kgpe-d16/devicetree.cb
++++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
+@@ -15,6 +15,7 @@ chip northbridge/amd/amdfam10/root_complex   # Root complex
+                               chip southbridge/amd/sr5650             # 
Primary southbridge
+                                       device pci 0.0 on end                   
# HT Root Complex 0x9600
+                                       device pci 0.1 on end                   
# CLKCONFIG
++                                      device pci 0.2 on end                   
# IOMMU
+                                       device pci 2.0 on                       
# PCIE P2P bridge 0x9603 (GPP1 Port0)
+                                               # Slot                          
# PCI E 1 / PCI E 2
+                                       end
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index 5d4005d..cbda9ca 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -459,6 +459,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               die("After soft_reset_x - shouldn't see this message!!!\n");
+       }
+ 
++      sr5650_htinit_dect_and_enable_isochronous_link();
++
+       /* Set default DDR memory voltage
+        * This will be overridden later during RAM initialization
+        */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0117-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0117-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
deleted file mode 100644
index d4a1b9e..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0117-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
+++ /dev/null
@@ -1,119 +0,0 @@
-From 2062da830bac8ed759d18e3b06df0a97fd852ac9 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 14 Aug 2015 15:20:42 -0500
-Subject: [PATCH 117/139] southbridge/amd/sr5650: Add MCFG ACPI table support
-
-Change-Id: I0c4ba74ddcc727cd92b848d5d3240e6f9f392101
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/rs780/rs780.c   |  9 +++++++++
- src/southbridge/amd/rs780/rs780.h   |  1 +
- src/southbridge/amd/sb700/lpc.c     |  6 ------
- src/southbridge/amd/sb800/lpc.c     |  7 +------
- src/southbridge/amd/sr5650/sr5650.c | 16 ++++++++++++++++
- 5 files changed, 27 insertions(+), 12 deletions(-)
-
-diff --git a/src/southbridge/amd/rs780/rs780.c 
b/src/southbridge/amd/rs780/rs780.c
-index c7003c7..6d5e6c7 100644
---- a/src/southbridge/amd/rs780/rs780.c
-+++ b/src/southbridge/amd/rs780/rs780.c
-@@ -353,6 +353,15 @@ void rs780_enable(device_t dev)
-       }
- }
- 
-+unsigned long acpi_fill_mcfg(unsigned long current)
-+{
-+      /* FIXME
-+       * Leave table blank until proper contents
-+       * are determined.
-+       */
-+      return current;
-+}
-+
- struct chip_operations southbridge_amd_rs780_ops = {
-       CHIP_NAME("ATI RS780")
-       .enable_dev = rs780_enable,
-diff --git a/src/southbridge/amd/rs780/rs780.h 
b/src/southbridge/amd/rs780/rs780.h
-index dd2743f..a4ede50 100644
---- a/src/southbridge/amd/rs780/rs780.h
-+++ b/src/southbridge/amd/rs780/rs780.h
-@@ -21,6 +21,7 @@
- #define __RS780_H__
- 
- #include <stdint.h>
-+#include <arch/acpi.h>
- #include <device/pci_ids.h>
- #include "chip.h"
- #include "rev.h"
-diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c
-index 145a01f..fc27bef 100644
---- a/src/southbridge/amd/sb700/lpc.c
-+++ b/src/southbridge/amd/sb700/lpc.c
-@@ -34,12 +34,6 @@
- #include <cpu/amd/powernow.h>
- #include "sb700.h"
- 
--unsigned long acpi_fill_mcfg(unsigned long current)
--{
--       /* Just a dummy */
--       return current;
--}
--
- static void lpc_init(device_t dev)
- {
-       u8 byte;
-diff --git a/src/southbridge/amd/sb800/lpc.c b/src/southbridge/amd/sb800/lpc.c
-index 0cd5b32..af96ea7 100644
---- a/src/southbridge/amd/sb800/lpc.c
-+++ b/src/southbridge/amd/sb800/lpc.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2010 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -29,12 +30,6 @@
- #include <arch/acpi.h>
- #include "sb800.h"
- 
--unsigned long acpi_fill_mcfg(unsigned long current)
--{
--       /* Just a dummy */
--       return current;
--}
--
- static void lpc_init(device_t dev)
- {
-       u8 byte;
-diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
-index b296c47..4622f36 100644
---- a/src/southbridge/amd/sr5650/sr5650.c
-+++ b/src/southbridge/amd/sr5650/sr5650.c
-@@ -800,6 +800,22 @@ static void add_ivrs_device_entries(struct device 
*parent, struct device *dev, i
-       free(root_level);
- }
- 
-+unsigned long acpi_fill_mcfg(unsigned long current)
-+{
-+      struct resource *res;
-+      resource_t mmconf_base = EXT_CONF_BASE_ADDRESS;
-+
-+      device_t dev = dev_find_slot(0, PCI_DEVFN(0, 0));
-+      /* Report MMCONF base */
-+      res = probe_resource(dev, 0x1c);
-+      if (res)
-+              mmconf_base = res->base;
-+
-+      current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current, 
mmconf_base, 0x0, 0x0, 0x1f);
-+
-+      return current;
-+}
-+
- static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current)
- {
-       uint8_t *p;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
 
b/resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
deleted file mode 100644
index a1a2049..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From cd71955dea67d3bea66627c6e40b8a569af60391 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Tue, 18 Aug 2015 17:45:48 -0500
-Subject: [PATCH 118/139] southbridge/amd/sb700: Fix mismatched FADT entries
-
-Change-Id: Ifa0b61678fe362481891fc015cebe08485b66fc1
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/fadt.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/fadt.c 
b/src/southbridge/amd/sb700/fadt.c
-index 6b1924f..209e9aa 100644
---- a/src/southbridge/amd/sb700/fadt.c
-+++ b/src/southbridge/amd/sb700/fadt.c
-@@ -131,7 +131,7 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
-       fadt->x_pm1b_cnt_blk.addrh = 0x0;
- 
-       fadt->x_pm2_cnt_blk.space_id = 1;
--      fadt->x_pm2_cnt_blk.bit_width = 0;
-+      fadt->x_pm2_cnt_blk.bit_width = 8;
-       fadt->x_pm2_cnt_blk.bit_offset = 0;
-       fadt->x_pm2_cnt_blk.resv = 0;
-       fadt->x_pm2_cnt_blk.addrl = ACPI_PMA_CNT_BLK;
-@@ -145,7 +145,7 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
-       fadt->x_pm_tmr_blk.addrh = 0x0;
- 
-       fadt->x_gpe0_blk.space_id = 1;
--      fadt->x_gpe0_blk.bit_width = 32;
-+      fadt->x_gpe0_blk.bit_width = 64;
-       fadt->x_gpe0_blk.bit_offset = 0;
-       fadt->x_gpe0_blk.resv = 0;
-       fadt->x_gpe0_blk.addrl = ACPI_GPE0_BLK;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
 
b/resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
new file mode 100644
index 0000000..27fd1c2
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch
@@ -0,0 +1,30 @@
+From f5d5d25583a6aee7f725a6de8cc0a51753502666 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 14 Aug 2015 02:50:44 -0500
+Subject: [PATCH 118/143] southbridge/amd/sr5650: Use correct PCI
+ configuration block offset
+
+Change-Id: I4277d1788d8f9a501399218544aa6d4d11349ccc
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sr5650/acpi/sr5650.asl |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/southbridge/amd/sr5650/acpi/sr5650.asl 
b/src/southbridge/amd/sr5650/acpi/sr5650.asl
+index a6ab114..1e0d5b0 100644
+--- a/src/southbridge/amd/sr5650/acpi/sr5650.asl
++++ b/src/southbridge/amd/sr5650/acpi/sr5650.asl
+@@ -19,8 +19,8 @@
+  */
+ 
+ Scope(\) {
+-      Name(PCBA, 0xE0000000)  /* Base address of PCIe config space */
+-      Name(HPBA, 0xFED00000)  /* Base address of HPET table */
++      Name(PCBA, CONFIG_MMCONF_BASE_ADDRESS)  /* Base address of PCIe config 
space */
++      Name(HPBA, 0xFED00000)                  /* Base address of HPET table */
+ 
+       /* PIC IRQ mapping registers, C00h-C01h */
+       OperationRegion(PRQM, SystemIO, 0x00000C00, 0x00000002)
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sb700-Fix-drifting-system-clock.patch
 
b/resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sb700-Fix-drifting-system-clock.patch
deleted file mode 100644
index 7a15867..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sb700-Fix-drifting-system-clock.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From d0f4a06a86fbb28d9a6829fec10e7959eb845ab9 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 28 Aug 2015 15:31:31 -0500
-Subject: [PATCH 119/139] southbridge/amd/sb700: Fix drifting system clock
-
-Change-Id: I1698c9b9b1840d254115821f3c0e76b7211e9056
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/southbridge/amd/sb700/early_setup.c | 14 +++++++++++---
- 1 file changed, 11 insertions(+), 3 deletions(-)
-
-diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
-index da03961..fe8824f 100644
---- a/src/southbridge/amd/sb700/early_setup.c
-+++ b/src/southbridge/amd/sb700/early_setup.c
-@@ -431,10 +431,10 @@ static void sb700_devices_por_init(void)
- 
-       /* Configure HPET Counter CLK period */
-       byte = pci_read_config8(dev, 0x43);
--      byte &= 0xF7;   /* unhide HPET regs */
-+      byte &= 0xF7;                           /* Unhide HPET regs */
-       pci_write_config8(dev, 0x43, byte);
--      pci_write_config32(dev, 0x34, 0x0429B17E ); /* Counter CLK period */
--      byte |= 0x08;   /* hide HPET regs */
-+      pci_write_config32(dev, 0x34, 0xb0);    /* HPET_CNTRL = 0xb0 */
-+      byte |= 0x08;                           /* Hide HPET regs */
-       pci_write_config8(dev, 0x43, byte);
- 
-       /* Features Enable */
-@@ -669,6 +669,14 @@ static void sb700_pmio_por_init(void)
-       byte = pmio_read(0xbb);
-       byte |= 0xc0;
-       pmio_write(0xbb, byte);
-+
-+#if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
-+      /* Work around system clock drift issues */
-+      byte = pmio_read(0xd4);
-+      byte |= 0x1 << 6;       /* Enable alternate 14MHz clock source */
-+      byte |= 0x1 << 7;       /* Disable 25MHz oscillator buffer */
-+      pmio_write(0xd4, byte);
-+#endif
- }
- 
- /*
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
 
b/resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
new file mode 100644
index 0000000..9ae30ac
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch
@@ -0,0 +1,121 @@
+From 5bffd9941711ac36bf2828f0df355ff4acc1afd5 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 14 Aug 2015 15:20:42 -0500
+Subject: [PATCH 119/143] southbridge/amd/sr5650: Add MCFG ACPI table support
+
+Change-Id: I0c4ba74ddcc727cd92b848d5d3240e6f9f392101
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/rs780/rs780.c   |   11 +++++++++++
+ src/southbridge/amd/rs780/rs780.h   |    1 +
+ src/southbridge/amd/sb700/lpc.c     |    6 ------
+ src/southbridge/amd/sb800/lpc.c     |    7 +------
+ src/southbridge/amd/sr5650/sr5650.c |   16 ++++++++++++++++
+ 5 files changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/src/southbridge/amd/rs780/rs780.c 
b/src/southbridge/amd/rs780/rs780.c
+index c7003c7..3b2c4f4 100644
+--- a/src/southbridge/amd/rs780/rs780.c
++++ b/src/southbridge/amd/rs780/rs780.c
+@@ -353,6 +353,17 @@ void rs780_enable(device_t dev)
+       }
+ }
+ 
++#if !IS_ENABLED(CONFIG_AMD_SB_CIMX)
++unsigned long acpi_fill_mcfg(unsigned long current)
++{
++      /* FIXME
++       * Leave table blank until proper contents
++       * are determined.
++       */
++      return current;
++}
++#endif
++
+ struct chip_operations southbridge_amd_rs780_ops = {
+       CHIP_NAME("ATI RS780")
+       .enable_dev = rs780_enable,
+diff --git a/src/southbridge/amd/rs780/rs780.h 
b/src/southbridge/amd/rs780/rs780.h
+index dd2743f..a4ede50 100644
+--- a/src/southbridge/amd/rs780/rs780.h
++++ b/src/southbridge/amd/rs780/rs780.h
+@@ -21,6 +21,7 @@
+ #define __RS780_H__
+ 
+ #include <stdint.h>
++#include <arch/acpi.h>
+ #include <device/pci_ids.h>
+ #include "chip.h"
+ #include "rev.h"
+diff --git a/src/southbridge/amd/sb700/lpc.c b/src/southbridge/amd/sb700/lpc.c
+index 145a01f..fc27bef 100644
+--- a/src/southbridge/amd/sb700/lpc.c
++++ b/src/southbridge/amd/sb700/lpc.c
+@@ -34,12 +34,6 @@
+ #include <cpu/amd/powernow.h>
+ #include "sb700.h"
+ 
+-unsigned long acpi_fill_mcfg(unsigned long current)
+-{
+-       /* Just a dummy */
+-       return current;
+-}
+-
+ static void lpc_init(device_t dev)
+ {
+       u8 byte;
+diff --git a/src/southbridge/amd/sb800/lpc.c b/src/southbridge/amd/sb800/lpc.c
+index 0cd5b32..af96ea7 100644
+--- a/src/southbridge/amd/sb800/lpc.c
++++ b/src/southbridge/amd/sb800/lpc.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2010 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -29,12 +30,6 @@
+ #include <arch/acpi.h>
+ #include "sb800.h"
+ 
+-unsigned long acpi_fill_mcfg(unsigned long current)
+-{
+-       /* Just a dummy */
+-       return current;
+-}
+-
+ static void lpc_init(device_t dev)
+ {
+       u8 byte;
+diff --git a/src/southbridge/amd/sr5650/sr5650.c 
b/src/southbridge/amd/sr5650/sr5650.c
+index b296c47..4622f36 100644
+--- a/src/southbridge/amd/sr5650/sr5650.c
++++ b/src/southbridge/amd/sr5650/sr5650.c
+@@ -800,6 +800,22 @@ static void add_ivrs_device_entries(struct device 
*parent, struct device *dev, i
+       free(root_level);
+ }
+ 
++unsigned long acpi_fill_mcfg(unsigned long current)
++{
++      struct resource *res;
++      resource_t mmconf_base = EXT_CONF_BASE_ADDRESS;
++
++      device_t dev = dev_find_slot(0, PCI_DEVFN(0, 0));
++      /* Report MMCONF base */
++      res = probe_resource(dev, 0x1c);
++      if (res)
++              mmconf_base = res->base;
++
++      current += acpi_create_mcfg_mmconfig((acpi_mcfg_mmconfig_t *)current, 
mmconf_base, 0x0, 0x0, 0x1f);
++
++      return current;
++}
++
+ static unsigned long acpi_fill_ivrs(acpi_ivrs_t* ivrs, unsigned long current)
+ {
+       uint8_t *p;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0120-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
 
b/resources/libreboot/patch/kgpe-d16/0120-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
deleted file mode 100644
index 39a7a9f..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0120-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
+++ /dev/null
@@ -1,58 +0,0 @@
-From 473fa0658e73ccdc92d376b8855d3e38e2592d3a Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 20 Aug 2015 12:49:49 -0500
-Subject: [PATCH 120/139] northbridge/amd/amdmct/mct_ddr3: Add cc6 setup
- information messages
-
-Change-Id: I17660ce5429431e08476b7bba15e381636b64c7d
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 42630b9..1c3f5a3 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1496,6 +1496,8 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
-       if (pMCTstat->GStatus & (1 << GSB_NodeIntlv))
-               interleaved = 1;
- 
-+      printk(BIOS_INFO, "%s: Initializing CC6 DRAM storage area for node %d 
(interleaved: %d)\n", __func__, pDCTstat->Node_ID, interleaved);
-+
-       /* Find highest DRAM range (DramLimitAddr) */
-       max_node = 0;
-       max_range = -1;
-@@ -1519,6 +1521,9 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
-       }
- 
-       if (max_range >= 0) {
-+              printk(BIOS_INFO, "%s:\toriginal (node %d) max_range_limit: 
%16llx DRAM limit: %16llx\n", __func__, max_node, max_range_limit,
-+                                              
(((uint64_t)(Get_NB32(pDCTstat->dev_map, 0x124) & 0x1fffff)) << 27) | 
0x7ffffff);
-+
-               if (interleaved)
-                       /* Move upper limit down by 16M * the number of nodes */
-                       max_range_limit -= (0x1000000 * num_nodes);
-@@ -1526,6 +1531,8 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
-                       /* Move upper limit down by 16M */
-                       max_range_limit -= 0x1000000;
- 
-+              printk(BIOS_INFO, "%s:\tnew max_range_limit: %16llx\n", 
__func__, max_range_limit);
-+
-               /* Disable the range */
-               dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
-               byte = dword & 0x3;
-@@ -1560,6 +1567,10 @@ static void set_up_cc6_storage_fam15(struct 
MCTStatStruc *pMCTstat,
-       dword &= ~(0x3f << 12);                         /* 
CoreSaveStateDestNode = destination_node */
-       dword |= (destination_node & 0x3f) << 12;
-       Set_NB32(pDCTstat->dev_link, 0x128, dword);
-+
-+      printk(BIOS_INFO, "%s:\tTarget node: %d\n", __func__, destination_node);
-+
-+      printk(BIOS_INFO, "%s:\tDone\n", __func__);
- }
- 
- static void lock_dram_config(struct MCTStatStruc *pMCTstat,
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0120-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
 
b/resources/libreboot/patch/kgpe-d16/0120-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
new file mode 100644
index 0000000..21743a0
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0120-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch
@@ -0,0 +1,36 @@
+From 26689886278806df6859ca47cc7bb632daf8f3c0 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Tue, 18 Aug 2015 17:45:48 -0500
+Subject: [PATCH 120/143] southbridge/amd/sb700: Fix mismatched FADT entries
+
+Change-Id: Ifa0b61678fe362481891fc015cebe08485b66fc1
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/fadt.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/fadt.c 
b/src/southbridge/amd/sb700/fadt.c
+index e860016..ec5d9bf 100644
+--- a/src/southbridge/amd/sb700/fadt.c
++++ b/src/southbridge/amd/sb700/fadt.c
+@@ -131,7 +131,7 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
+       fadt->x_pm1b_cnt_blk.addrh = 0x0;
+ 
+       fadt->x_pm2_cnt_blk.space_id = 1;
+-      fadt->x_pm2_cnt_blk.bit_width = 0;
++      fadt->x_pm2_cnt_blk.bit_width = 8;
+       fadt->x_pm2_cnt_blk.bit_offset = 0;
+       fadt->x_pm2_cnt_blk.resv = 0;
+       fadt->x_pm2_cnt_blk.addrl = ACPI_PMA_CNT_BLK;
+@@ -145,7 +145,7 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * 
facs, void *dsdt)
+       fadt->x_pm_tmr_blk.addrh = 0x0;
+ 
+       fadt->x_gpe0_blk.space_id = 1;
+-      fadt->x_gpe0_blk.bit_width = 32;
++      fadt->x_gpe0_blk.bit_width = 64;
+       fadt->x_gpe0_blk.bit_offset = 0;
+       fadt->x_gpe0_blk.resv = 0;
+       fadt->x_gpe0_blk.addrl = ACPI_GPE0_BLK;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0121-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
 
b/resources/libreboot/patch/kgpe-d16/0121-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
deleted file mode 100644
index 2d12303..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0121-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From b26909b4b537b7e3b1e5a5b1379ae7745c1e36b3 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 20 Aug 2015 15:53:25 -0500
-Subject: [PATCH 121/139] northbridge/amd/amdfam10: Work around sporadic
- lockups when CC6 enabled
-
-Change-Id: If31140651f25f9c524a824b2da552ce3690eae18
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/northbridge.c | 14 ++++++++++++++
- 1 file changed, 14 insertions(+)
-
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 58b0079..8bd664d 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -814,6 +814,20 @@ static void amdfam10_domain_read_resources(device_t dev)
-                       else
-                               qword = 0x1000000;
- 
-+                      /* FIXME
-+                       * The BKDG appears to be incorrect as to the location 
of the CC6 save region
-+                       * lower boundary on non-interleaved systems, causing 
lockups on attempted write
-+                       * to the CC6 save region.
-+                       *
-+                       * For now, work around by allocating the maximum 
possible CC6 save region size.
-+                       *
-+                       * Determine if this is a BKDG error or a setup problem 
and remove this warning!
-+                       */
-+                      qword = (0x1 << 27);
-+                      max_range_limit = 
(((uint64_t)(pci_read_config32(get_node_pci(max_node, 1), 0x124) & 0x1fffff)) 
<< 27) - 1;
-+
-+                      printk(BIOS_INFO, "Reserving CC6 save segment base: 
%08llx size: %08llx\n", (max_range_limit + 1), qword);
-+
-                       /* Reserve the CC6 save segment */
-                       reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 
10, qword >> 10);
-               }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0121-southbridge-amd-sb700-Fix-drifting-system-clock.patch
 
b/resources/libreboot/patch/kgpe-d16/0121-southbridge-amd-sb700-Fix-drifting-system-clock.patch
new file mode 100644
index 0000000..75a11f6
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0121-southbridge-amd-sb700-Fix-drifting-system-clock.patch
@@ -0,0 +1,47 @@
+From 49e08c434dc1b0a608496f0187c18d2ce83a59e0 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 28 Aug 2015 15:31:31 -0500
+Subject: [PATCH 121/143] southbridge/amd/sb700: Fix drifting system clock
+
+Change-Id: I1698c9b9b1840d254115821f3c0e76b7211e9056
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/southbridge/amd/sb700/early_setup.c |   14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/src/southbridge/amd/sb700/early_setup.c 
b/src/southbridge/amd/sb700/early_setup.c
+index da03961..fe8824f 100644
+--- a/src/southbridge/amd/sb700/early_setup.c
++++ b/src/southbridge/amd/sb700/early_setup.c
+@@ -431,10 +431,10 @@ static void sb700_devices_por_init(void)
+ 
+       /* Configure HPET Counter CLK period */
+       byte = pci_read_config8(dev, 0x43);
+-      byte &= 0xF7;   /* unhide HPET regs */
++      byte &= 0xF7;                           /* Unhide HPET regs */
+       pci_write_config8(dev, 0x43, byte);
+-      pci_write_config32(dev, 0x34, 0x0429B17E ); /* Counter CLK period */
+-      byte |= 0x08;   /* hide HPET regs */
++      pci_write_config32(dev, 0x34, 0xb0);    /* HPET_CNTRL = 0xb0 */
++      byte |= 0x08;                           /* Hide HPET regs */
+       pci_write_config8(dev, 0x43, byte);
+ 
+       /* Features Enable */
+@@ -669,6 +669,14 @@ static void sb700_pmio_por_init(void)
+       byte = pmio_read(0xbb);
+       byte |= 0xc0;
+       pmio_write(0xbb, byte);
++
++#if CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100
++      /* Work around system clock drift issues */
++      byte = pmio_read(0xd4);
++      byte |= 0x1 << 6;       /* Enable alternate 14MHz clock source */
++      byte |= 0x1 << 7;       /* Disable 25MHz oscillator buffer */
++      pmio_write(0xd4, byte);
++#endif
+ }
+ 
+ /*
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
 
b/resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
new file mode 100644
index 0000000..d0a9375
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch
@@ -0,0 +1,58 @@
+From d5949a4d3b9b555b1e2a86d2dcb62b23c71cce6f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 20 Aug 2015 12:49:49 -0500
+Subject: [PATCH 122/143] northbridge/amd/amdmct/mct_ddr3: Add cc6 setup
+ information messages
+
+Change-Id: I17660ce5429431e08476b7bba15e381636b64c7d
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |   11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 42630b9..1c3f5a3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1496,6 +1496,8 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
+       if (pMCTstat->GStatus & (1 << GSB_NodeIntlv))
+               interleaved = 1;
+ 
++      printk(BIOS_INFO, "%s: Initializing CC6 DRAM storage area for node %d 
(interleaved: %d)\n", __func__, pDCTstat->Node_ID, interleaved);
++
+       /* Find highest DRAM range (DramLimitAddr) */
+       max_node = 0;
+       max_range = -1;
+@@ -1519,6 +1521,9 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
+       }
+ 
+       if (max_range >= 0) {
++              printk(BIOS_INFO, "%s:\toriginal (node %d) max_range_limit: 
%16llx DRAM limit: %16llx\n", __func__, max_node, max_range_limit,
++                                              
(((uint64_t)(Get_NB32(pDCTstat->dev_map, 0x124) & 0x1fffff)) << 27) | 
0x7ffffff);
++
+               if (interleaved)
+                       /* Move upper limit down by 16M * the number of nodes */
+                       max_range_limit -= (0x1000000 * num_nodes);
+@@ -1526,6 +1531,8 @@ static void set_up_cc6_storage_fam15(struct MCTStatStruc 
*pMCTstat,
+                       /* Move upper limit down by 16M */
+                       max_range_limit -= 0x1000000;
+ 
++              printk(BIOS_INFO, "%s:\tnew max_range_limit: %16llx\n", 
__func__, max_range_limit);
++
+               /* Disable the range */
+               dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8));
+               byte = dword & 0x3;
+@@ -1560,6 +1567,10 @@ static void set_up_cc6_storage_fam15(struct 
MCTStatStruc *pMCTstat,
+       dword &= ~(0x3f << 12);                         /* 
CoreSaveStateDestNode = destination_node */
+       dword |= (destination_node & 0x3f) << 12;
+       Set_NB32(pDCTstat->dev_link, 0x128, dword);
++
++      printk(BIOS_INFO, "%s:\tTarget node: %d\n", __func__, destination_node);
++
++      printk(BIOS_INFO, "%s:\tDone\n", __func__);
+ }
+ 
+ static void lock_dram_config(struct MCTStatStruc *pMCTstat,
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
 
b/resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
deleted file mode 100644
index 121e37f..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
+++ /dev/null
@@ -1,115 +0,0 @@
-From c16062b7739a77b084d139468f40f43d66ee26e0 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 27 Aug 2015 13:17:14 -0500
-Subject: [PATCH 122/139] northbridge/amd/amdmct/mct_ddr3: Ensure channel clock
- skew is properly set up
-
-Change-Id: Iafc233984ae1d44fe6a1cb5b109d36397cbd991a
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 46 ++++++++++++++++-------------
- 1 file changed, 25 insertions(+), 21 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index 1c3f5a3..a11b227 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -3051,6 +3051,23 @@ static void DCTInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTst
-               printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
-               if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
-                       printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D 
Done\n");
-+
-+                      /* SkewMemClk must be set before MemClkFreqVal is set
-+                       * This relies on DCTInit_D being called for DCT 1 after
-+                       * it has already been called for DCT 0...
-+                       */
-+                      if (is_fam15h()) {
-+                              /* Set memory clock skew if needed */
-+                              if (dct == 1) {
-+                                      if (!pDCTstat->stopDCT[0]) {
-+                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: enabling intra-channel clock skew\n");
-+                                              dword = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe00a);
-+                                              dword |= (0x1 << 4);            
                /* SkewMemClk = 1 */
-+                                              
Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe00a, dword);
-+                                      }
-+                              }
-+                      }
-+
-                       if (AutoConfig_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
-                               printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D 
Done\n");
-                               if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
-@@ -3060,8 +3077,6 @@ static void DCTInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTst
-                       }
-               }
-       }
--
--
- }
- 
- static void DCTFinalInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
-@@ -3069,17 +3084,6 @@ static void DCTFinalInit_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStruc *p
-       uint32_t dword;
- 
-       /* Finalize DRAM init on a single node */
--      if (is_fam15h()) {
--              /* Set memory clock skew if needed */
--              if (dct == 0) {
--                      if (!pDCTstat->stopDCT[0] && !pDCTstat->stopDCT[1]) {
--                              dword = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0d0fe00a);
--                              dword |= (0x1 << 4);                            
/* SkewMemClk = 1 */
--                              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
0x98, 0x0d0fe00a, dword);
--                      }
--              }
--      }
--
-       if (!pDCTstat->stopDCT[dct]) {
-               if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
-                       printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D 
Start\n");
-@@ -3282,28 +3286,28 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-                       if (Twtr < val)
-                               Twtr = val;
- 
--                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xFF;
-+                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xff;
-                       val >>= 4;
-                       val <<= 8;
--                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCmin] & 0xFF;
-+                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCmin] & 0xff;
-                       val *= MTB16x;
-                       if (Trc < val)
-                               Trc = val;
- 
--                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Density] & 0xF;
-+                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Density] & 0xf;
-                       if (Trfc[LDIMM] < byte)
-                               Trfc[LDIMM] = byte;
- 
--                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xF;
-+                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xf;
-                       val <<= 8;
--                      val |= (pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRASmin] & 0xFF);
-+                      val |= (pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRASmin] & 0xff);
-                       val *= MTB16x;
-                       if (Tras < val)
-                               Tras = val;
- 
--                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tFAW] & 0xF;
-+                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tFAW] & 0xf;
-                       val <<= 8;
--                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tFAWmin] & 0xFF;
-+                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tFAWmin] & 0xff;
-                       val *= MTB16x;
-                       if (Tfaw < val)
-                               Tfaw = val;
-@@ -3510,7 +3514,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-               /* Trfc0-Trfc3 */
-               for (i=0; i<4; i++)
-                       if (pDCTstat->Trfc[i] == 0x0)
--                              pDCTstat->Trfc[i] = 0x4;
-+                              pDCTstat->Trfc[i] = 0x1;
-               dword = Get_NB32_DCT(dev, dct, 0x208);                          
/* DRAM Timing 2 */
-               dword &= ~(0x07070707);
-               dword |= (pDCTstat->Trfc[3] & 0x7) << 24;                       
/* Trfc3 */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
 
b/resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
new file mode 100644
index 0000000..44cde38
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch
@@ -0,0 +1,40 @@
+From b398fb43bb4ebc4d8d8c77e07e14b747971c39b4 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 20 Aug 2015 15:53:25 -0500
+Subject: [PATCH 123/143] northbridge/amd/amdfam10: Work around sporadic
+ lockups when CC6 enabled
+
+Change-Id: If31140651f25f9c524a824b2da552ce3690eae18
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/northbridge.c |   14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 740fd79..433a21c 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -814,6 +814,20 @@ static void amdfam10_domain_read_resources(device_t dev)
+                       else
+                               qword = 0x1000000;
+ 
++                      /* FIXME
++                       * The BKDG appears to be incorrect as to the location 
of the CC6 save region
++                       * lower boundary on non-interleaved systems, causing 
lockups on attempted write
++                       * to the CC6 save region.
++                       *
++                       * For now, work around by allocating the maximum 
possible CC6 save region size.
++                       *
++                       * Determine if this is a BKDG error or a setup problem 
and remove this warning!
++                       */
++                      qword = (0x1 << 27);
++                      max_range_limit = 
(((uint64_t)(pci_read_config32(get_node_pci(max_node, 1), 0x124) & 0x1fffff)) 
<< 27) - 1;
++
++                      printk(BIOS_INFO, "Reserving CC6 save segment base: 
%08llx size: %08llx\n", (max_range_limit + 1), qword);
++
+                       /* Reserve the CC6 save segment */
+                       reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 
10, qword >> 10);
+               }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
 
b/resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
deleted file mode 100644
index 8c307a4..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From 0a77e6cc316cd7dd5f68fb3511b6fdc31153872f Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 27 Aug 2015 13:18:06 -0500
-Subject: [PATCH 123/139] northbridge/amd/amdmct/mct_ddr3: Add DDR3 termination
- debug output
-
-Change-Id: Iabd2e3e20b0e9719080f6bd7be2032c1749994dc
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index 09a5f68..7804a38 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -163,6 +163,8 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
-               }
-       }
- 
-+      printk(BIOS_INFO, "DIMM %d RttWr: %01x\n", dimm, term);
-+
-       return term;
- }
- 
-@@ -362,6 +364,7 @@ static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t
-               }
-       }
- 
-+      printk(BIOS_INFO, "DIMM %d RttNom: %01x\n", dimm, term);
-       return term;
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
 
b/resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
new file mode 100644
index 0000000..69cfbc8
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch
@@ -0,0 +1,115 @@
+From 0f7089296606d80dd2b51a8ca9c4178f06aec7d5 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 27 Aug 2015 13:17:14 -0500
+Subject: [PATCH 124/143] northbridge/amd/amdmct/mct_ddr3: Ensure channel
+ clock skew is properly set up
+
+Change-Id: Iafc233984ae1d44fe6a1cb5b109d36397cbd991a
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c |   46 +++++++++++++++------------
+ 1 file changed, 25 insertions(+), 21 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index 1c3f5a3..a11b227 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -3051,6 +3051,23 @@ static void DCTInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTst
+               printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n");
+               if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) {
+                       printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D 
Done\n");
++
++                      /* SkewMemClk must be set before MemClkFreqVal is set
++                       * This relies on DCTInit_D being called for DCT 1 after
++                       * it has already been called for DCT 0...
++                       */
++                      if (is_fam15h()) {
++                              /* Set memory clock skew if needed */
++                              if (dct == 1) {
++                                      if (!pDCTstat->stopDCT[0]) {
++                                              printk(BIOS_DEBUG, 
"\t\tDCTInit_D: enabling intra-channel clock skew\n");
++                                              dword = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe00a);
++                                              dword |= (0x1 << 4);            
                /* SkewMemClk = 1 */
++                                              
Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe00a, dword);
++                                      }
++                              }
++                      }
++
+                       if (AutoConfig_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
+                               printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D 
Done\n");
+                               if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < 
SC_StopError) {
+@@ -3060,8 +3077,6 @@ static void DCTInit_D(struct MCTStatStruc *pMCTstat, 
struct DCTStatStruc *pDCTst
+                       }
+               }
+       }
+-
+-
+ }
+ 
+ static void DCTFinalInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc 
*pDCTstat, u8 dct)
+@@ -3069,17 +3084,6 @@ static void DCTFinalInit_D(struct MCTStatStruc 
*pMCTstat, struct DCTStatStruc *p
+       uint32_t dword;
+ 
+       /* Finalize DRAM init on a single node */
+-      if (is_fam15h()) {
+-              /* Set memory clock skew if needed */
+-              if (dct == 0) {
+-                      if (!pDCTstat->stopDCT[0] && !pDCTstat->stopDCT[1]) {
+-                              dword = 
Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0d0fe00a);
+-                              dword |= (0x1 << 4);                            
/* SkewMemClk = 1 */
+-                              Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 
0x98, 0x0d0fe00a, dword);
+-                      }
+-              }
+-      }
+-
+       if (!pDCTstat->stopDCT[dct]) {
+               if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) {
+                       printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D 
Start\n");
+@@ -3282,28 +3286,28 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+                       if (Twtr < val)
+                               Twtr = val;
+ 
+-                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xFF;
++                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xff;
+                       val >>= 4;
+                       val <<= 8;
+-                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCmin] & 0xFF;
++                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRCmin] & 0xff;
+                       val *= MTB16x;
+                       if (Trc < val)
+                               Trc = val;
+ 
+-                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Density] & 0xF;
++                      byte = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Density] & 0xf;
+                       if (Trfc[LDIMM] < byte)
+                               Trfc[LDIMM] = byte;
+ 
+-                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xF;
++                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tRAS_tRC] & 0xf;
+                       val <<= 8;
+-                      val |= (pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRASmin] & 0xFF);
++                      val |= (pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tRASmin] & 0xff);
+                       val *= MTB16x;
+                       if (Tras < val)
+                               Tras = val;
+ 
+-                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tFAW] & 0xF;
++                      val = pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_Upper_tFAW] & 0xf;
+                       val <<= 8;
+-                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tFAWmin] & 0xFF;
++                      val |= pDCTstat->spd_data.spd_bytes[dct + 
i][SPD_tFAWmin] & 0xff;
+                       val *= MTB16x;
+                       if (Tfaw < val)
+                               Tfaw = val;
+@@ -3510,7 +3514,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+               /* Trfc0-Trfc3 */
+               for (i=0; i<4; i++)
+                       if (pDCTstat->Trfc[i] == 0x0)
+-                              pDCTstat->Trfc[i] = 0x4;
++                              pDCTstat->Trfc[i] = 0x1;
+               dword = Get_NB32_DCT(dev, dct, 0x208);                          
/* DRAM Timing 2 */
+               dword &= ~(0x07070707);
+               dword |= (pDCTstat->Trfc[3] & 0x7) << 24;                       
/* Trfc3 */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
 
b/resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
deleted file mode 100644
index 7040927..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 352de00766d75d9b88a6021bfe5558a36923cc40 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 27 Aug 2015 13:18:53 -0500
-Subject: [PATCH 124/139] northbridge/amd/amdmct/mct_ddr3: Fix a minor RDIMM CS
- select error
-
-Change-Id: I4cdfeec887813c17edcdee8858222414fb19b72c
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mctrci.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-index 624a543..8fd2523 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-@@ -236,7 +236,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
-       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
-                       val = Get_NB32_DCT(dev, dct, 0xa8);
--                      val &= ~(0xf << 8);
-+                      val &= ~(0xff << 8);
- 
-                       switch (MrsChipSel) {
-                               case 0:
-@@ -283,7 +283,7 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
-                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
-                       val = Get_NB32_DCT(dev, dct, 0xa8);
-                       val &= ~(0xff << 8);
--                      val |= (0x3 << (MrsChipSel & 0xfe)) << 8;
-+                      val |= (0x3 << (MrsChipSel & ~0x1)) << 8;
-                       Set_NB32_DCT(dev, dct, 0xa8, val);
- 
-                       /* Resend control word 10 */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
 
b/resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
new file mode 100644
index 0000000..dcf3115
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch
@@ -0,0 +1,36 @@
+From c3e283e8dca7df7f87d7198267ab421e2be19828 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 27 Aug 2015 13:18:06 -0500
+Subject: [PATCH 125/143] northbridge/amd/amdmct/mct_ddr3: Add DDR3
+ termination debug output
+
+Change-Id: Iabd2e3e20b0e9719080f6bd7be2032c1749994dc
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 09a5f68..7804a38 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -163,6 +163,8 @@ static uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t d
+               }
+       }
+ 
++      printk(BIOS_INFO, "DIMM %d RttWr: %01x\n", dimm, term);
++
+       return term;
+ }
+ 
+@@ -362,6 +364,7 @@ static uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t
+               }
+       }
+ 
++      printk(BIOS_INFO, "DIMM %d RttNom: %01x\n", dimm, term);
+       return term;
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
 
b/resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
deleted file mode 100644
index 39148d3..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
+++ /dev/null
@@ -1,65 +0,0 @@
-From 30d692e573ecf0a315b564895cf44e78d1b6daa9 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 27 Aug 2015 13:19:34 -0500
-Subject: [PATCH 125/139] northbridge/amd/amdmct/mct_ddr3: Fix odd rank data
- corruption due to incorrect DQS training
-
-Change-Id: Ibc51f5052d5189e45b3d9aa98ca8febbfe13f178
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 25 +++++++++++++++++--------
- 1 file changed, 17 insertions(+), 8 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index c520515..739a893 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -1324,9 +1324,9 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-               Receiver = receiver_start;
- 
-       /* There are four receiver pairs, loosely associated with chipselects.
--       * This is essentially looping over each DIMM.
-+       * This is essentially looping over each rank within each DIMM.
-        */
--      for (; Receiver < receiver_end; Receiver += 2) {
-+      for (; Receiver < receiver_end; Receiver++) {
-               dimm = (Receiver >> 1);
-               if ((Receiver & 0x1) == 0) {
-                       /* Even rank of DIMM */
-@@ -1340,18 +1340,27 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                       continue;
-               }
- 
-+#if DQS_TRAIN_DEBUG > 0
-+              printk(BIOS_DEBUG, "TrainDQSRdWrPos: Training DQS read/write 
position for receiver %d (DIMM %d)\n", Receiver, dimm);
-+#endif
-+
-               /* Initialize variables */
-               for (lane = lane_start; lane < lane_end; lane++) {
-                       passing_dqs_delay_found[lane] = 0;
-               }
--              memset(dqs_results_array, 0, sizeof(dqs_results_array));
-+              if ((Receiver & 0x1) == 0) {
-+                      /* Even rank of DIMM */
-+                      memset(dqs_results_array, 0, sizeof(dqs_results_array));
-+
-+                      /* Read initial read / write DQS delays */
-+                      
read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, 
dimm, index_reg);
-+                      
read_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, 
index_reg);
- 
--              /* Read initial read / write DQS delays */
--              
read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, 
dimm, index_reg);
--              read_dqs_read_data_timing_registers(initial_read_dqs_delay, 
dev, dct, dimm, index_reg);
-+                      /* Read current settings of other (previously trained) 
lanes */
-+                      
read_dqs_write_data_timing_registers(initial_write_data_timing, dev, dct, dimm, 
index_reg);
-+              }
- 
--              /* Read current settings of other (previously trained) lanes */
--              read_dqs_write_data_timing_registers(initial_write_data_timing, 
dev, dct, dimm, index_reg);
-+              /* Initialize iterators */
-               memcpy(current_write_data_delay, initial_write_data_timing, 
sizeof(current_write_data_delay));
- 
-               for (lane = lane_start; lane < lane_end; lane++) {
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
 
b/resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
new file mode 100644
index 0000000..85f519d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch
@@ -0,0 +1,37 @@
+From da95ad3fda51ddabb5b5799f459828008f841b4c Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 27 Aug 2015 13:18:53 -0500
+Subject: [PATCH 126/143] northbridge/amd/amdmct/mct_ddr3: Fix a minor RDIMM
+ CS select error
+
+Change-Id: I4cdfeec887813c17edcdee8858222414fb19b72c
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mctrci.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+index 624a543..8fd2523 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+@@ -236,7 +236,7 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       val = Get_NB32_DCT(dev, dct, 0xa8);
+-                      val &= ~(0xf << 8);
++                      val &= ~(0xff << 8);
+ 
+                       switch (MrsChipSel) {
+                               case 0:
+@@ -283,7 +283,7 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+                       /* 2. Program F2x[1, 0]A8[CtrlWordCS]=bit mask for 
target chip selects. */
+                       val = Get_NB32_DCT(dev, dct, 0xa8);
+                       val &= ~(0xff << 8);
+-                      val |= (0x3 << (MrsChipSel & 0xfe)) << 8;
++                      val |= (0x3 << (MrsChipSel & ~0x1)) << 8;
+                       Set_NB32_DCT(dev, dct, 0xa8, val);
+ 
+                       /* Resend control word 10 */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
 
b/resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
deleted file mode 100644
index 6a186e1..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
+++ /dev/null
@@ -1,157 +0,0 @@
-From 602d61a1535b24fbb04105e7e4594319641da3df Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 27 Aug 2015 15:10:19 -0500
-Subject: [PATCH 126/139] northbridge/amd/amdmct/mct_ddr3: Use antiphase to
- better center DQS window
-
-Change-Id: I1d85fddd45197ca82dcaa46fe863e64589712d1f
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 57 ++++++++++++++++++--------
- 1 file changed, 40 insertions(+), 17 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index 739a893..d870f17 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -1304,7 +1304,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-       uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
-       uint16_t current_write_dqs_delay[MAX_BYTE_LANES];
-       uint8_t passing_dqs_delay_found[MAX_BYTE_LANES];
--      uint8_t dqs_results_array[2][(lane_end - lane_start)][32][32];          
/* [rank][lane][write step][read step] */
-+      uint8_t dqs_results_array[2][(lane_end - lane_start)][32][48];          
/* [rank][lane][write step][read step + 16] */
- 
-       uint8_t last_pos = 0;
-       uint8_t cur_count = 0;
-@@ -1404,16 +1404,24 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                                        */
-                                       dword = Get_NB32_DCT(dev, dct, 0x268) & 
0x3ffff;
-                                       if (dword & (0x3 << (lane * 2)))
--                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 0;    /* 
Fail */
-+                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 0;   
  /* Fail */
-                                       else
--                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 1;    /* 
Pass */
-+                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 1;   
  /* Pass */
-+                                      if ((current_read_dqs_delay[lane] >> 1) 
>= (32 - 16)) {
-+                                              /* Check antiphase results */
-+                                              dword = Get_NB32_DCT(dev, dct, 
0x26c) & 0x3ffff;
-+                                              if (dword & (0x3 << (lane * 2)))
-+                                                      
dqs_results_array[Receiver & 0x1][lane - 
lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][16 
- (32 - (current_read_dqs_delay[lane] >> 1))] = 0;      /* Fail */
-+                                              else
-+                                                      
dqs_results_array[Receiver & 0x1][lane - 
lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][16 
- (32 - (current_read_dqs_delay[lane] >> 1))] = 1;      /* Pass */
-+                                      }
-                               }
-                       }
- 
-                       if (dual_rank && (Receiver & 0x1)) {
-                               /* Overlay the previous rank test results with 
the current rank */
-                               for (write_iter = 0; write_iter < 32; 
write_iter++) {
--                                      for (read_iter = 0; read_iter < 32; 
read_iter++) {
-+                                      for (read_iter = 0; read_iter < 48; 
read_iter++) {
-                                               if ((dqs_results_array[0][lane 
- lane_start][write_iter][read_iter])
-                                                       && 
(dqs_results_array[1][lane - lane_start][write_iter][read_iter]))
-                                                       
dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 1;
-@@ -1431,8 +1439,8 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                       best_pos = 0;
-                       best_count = 0;
-                       for (write_iter = 0; write_iter < 32; write_iter++) {
--                              for (read_iter = 0; read_iter < 32; 
read_iter++) {
--                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 31)) {
-+                              for (read_iter = 0; read_iter < 48; 
read_iter++) {
-+                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 47)) {
-                                               /* Pass */
-                                               cur_count++;
-                                       } else {
-@@ -1442,18 +1450,28 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                                                       best_pos = last_pos;
-                                               }
-                                               cur_count = 0;
--                                              last_pos = read_iter;
-+                                              last_pos = read_iter + 1;
-                                       }
-                               }
-                               last_pos = 0;
-                       }
- 
-                       if (best_count > 2) {
-+                              uint16_t region_center = (best_pos + 
(best_count / 2));
-+
-+                              if (region_center < 16) {
-+                                      printk(BIOS_WARNING, "TrainDQSRdWrPos: 
negative DQS recovery delay detected!"
-+                                                      "  Attempting to 
continue but your system may be unstable...\n");
-+                                      region_center = 0;
-+                              } else {
-+                                      region_center -= 16;
-+                              }
-+
-                               /* Restore current settings of other 
(previously trained) lanes to the active array */
-                               memcpy(current_read_dqs_delay, 
initial_read_dqs_delay, sizeof(current_read_dqs_delay));
- 
-                               /* Program the Read DQS Timing Control register 
with the center of the passing window */
--                              current_read_dqs_delay[lane] = ((best_pos << 1) 
+ ((best_count << 1) / 2));
-+                              current_read_dqs_delay[lane] = region_center << 
1;
-                               passing_dqs_delay_found[lane] = 1;
- 
-                               /* Commit the current Read DQS Timing Control 
settings to the hardware registers */
-@@ -1464,6 +1482,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
- 
-                               print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 
largest read passing region ", best_count, 4);
-                               print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 
largest read passing region start ", best_pos, 4);
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 
largest read passing region center (raw hardware value) ", region_center, 4);
-                       } else {
-                               /* Reprogram the Read DQS Timing Control 
register with the original settings */
-                               
write_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, 
index_reg);
-@@ -1476,7 +1495,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                       cur_count = 0;
-                       best_pos = 0;
-                       best_count = 0;
--                      for (read_iter = 0; read_iter < 32; read_iter++) {
-+                      for (read_iter = 0; read_iter < 48; read_iter++) {
-                               for (write_iter = 0; write_iter < 32; 
write_iter++) {
-                                       if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (write_iter < 31)) {
-                                               /* Pass */
-@@ -1488,7 +1507,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                                                       best_pos = last_pos;
-                                               }
-                                               cur_count = 0;
--                                              last_pos = write_iter;
-+                                              last_pos = write_iter + 1;
-                                       }
-                               }
-                               last_pos = 0;
-@@ -1511,8 +1530,8 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                               /* Save the final Write Data Timing settings 
for later use */
-                               pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 
1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane];
- 
--                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 
largest write passing region ", best_count, 4);
--                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 
largest write passing region start ", best_pos, 4);
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 
largest write passing region ", best_count, 4);
-+                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 146 
largest write passing region start ", best_pos, 4);
-                       } else {
-                               /* Reprogram the Write DQS Timing Control 
register with the original settings */
-                               
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, 
index_reg);
-@@ -1521,12 +1540,16 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
- 
- #ifdef PRINT_PASS_FAIL_BITMAPS
-               for (lane = lane_start; lane < lane_end; lane++) {
--                      for (read_iter = 0; read_iter < 32; read_iter++) {
--                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
--                                      if (dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter])
-+                      for (write_iter = 0; write_iter < 32; write_iter++) {
-+                              for (read_iter = 0; read_iter < 48; 
read_iter++) {
-+                                      if (dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) {
-                                               printk(BIOS_DEBUG, "+");
--                                      else
--                                              printk(BIOS_DEBUG, ".");
-+                                      } else {
-+                                              if (read_iter < 16)
-+                                                      printk(BIOS_DEBUG, "°");
-+                                              else
-+                                                      printk(BIOS_DEBUG, ".");
-+                                      }
-                               }
-                               printk(BIOS_DEBUG, "\n");
-                       }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
 
b/resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
deleted file mode 100644
index d7cedd7..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
+++ /dev/null
@@ -1,602 +0,0 @@
-From aabb2b44191d7a2716dd89a0b9f3488b2d657cb9 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 27 Aug 2015 23:37:38 -0500
-Subject: [PATCH 127/139] northbridge/amd/amdmct/mct_ddr3: Fix broken support
- for multiple DIMMs on single channel
-
-Change-Id: I0278656e98461882d0a64519dfde54a6cf28ab0f
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    | 336 ++++++++++++++++++++-----
- src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |   8 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   2 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctrci.c   |  26 +-
- src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |   4 +
- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |   8 +-
- 6 files changed, 310 insertions(+), 74 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-index a11b227..5bc80f4 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
-@@ -1360,6 +1360,224 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
-       return slow_access;
- }
- 
-+static uint8_t fam15h_odt_tristate_enable_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
-+{
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-+
-+      uint8_t package_type;
-+      uint8_t odt_tristate_code = 0;
-+
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+
-+      /* Obtain number of DIMMs on channel */
-+      uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+
-+      if (package_type == PT_GR) {
-+              /* Socket G34 */
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* RDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 
*/
-+                      if (MaxDimmsInstallable == 1) {
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
-+
-+                              if (rank_count_dimm0 == 1)
-+                                      odt_tristate_code = 0xe;
-+                              else
-+                                      odt_tristate_code = 0xa;
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if (rank_count_dimm1 == 1)
-+                                              odt_tristate_code = 0xd;
-+                                      else
-+                                              odt_tristate_code = 0x5;
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-+                                              odt_tristate_code = 0xc;
-+                                      else if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 >= 2))
-+                                              odt_tristate_code = 0x4;
-+                                      else if ((rank_count_dimm0 >= 2) && 
(rank_count_dimm1 == 1))
-+                                              odt_tristate_code = 0x8;
-+                                      else
-+                                              odt_tristate_code = 0x0;
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-+                      }
-+              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* LRDIMM */
-+
-+                      /* TODO
-+                       * Implement LRDIMM support
-+                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 
105
-+                       */
-+              } else {
-+                      /* UDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 
*/
-+                      if (MaxDimmsInstallable == 1) {
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
-+
-+                              if (rank_count_dimm0 == 1)
-+                                      odt_tristate_code = 0xe;
-+                              else
-+                                      odt_tristate_code = 0xa;
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if (rank_count_dimm0 == 1)
-+                                              odt_tristate_code = 0xd;
-+                                      else
-+                                              odt_tristate_code = 0x5;
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-+                                              odt_tristate_code = 0xc;
-+                                      else if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 2))
-+                                              odt_tristate_code = 0x4;
-+                                      else if ((rank_count_dimm0 == 2) && 
(rank_count_dimm1 == 1))
-+                                              odt_tristate_code = 0x8;
-+                                      else
-+                                              odt_tristate_code = 0x0;
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-+                      }
-+              }
-+      } else {
-+              /* TODO
-+               * Other socket support unimplemented
-+               */
-+      }
-+
-+      return odt_tristate_code;
-+}
-+
-+static uint8_t fam15h_cs_tristate_enable_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
-+{
-+      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-+
-+      uint8_t package_type;
-+      uint8_t cs_tristate_code = 0;
-+
-+      package_type = mctGet_NVbits(NV_PACK_TYPE);
-+
-+      /* Obtain number of DIMMs on channel */
-+      uint8_t dimm_count = pDCTstat->MAdimms[dct];
-+      uint8_t rank_count_dimm0;
-+      uint8_t rank_count_dimm1;
-+
-+      if (package_type == PT_GR) {
-+              /* Socket G34 */
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      /* RDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 
*/
-+                      if (MaxDimmsInstallable == 1) {
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
-+
-+                              if (rank_count_dimm0 < 4)
-+                                      cs_tristate_code = 0xfc;
-+                              else
-+                                      cs_tristate_code = 0xcc;
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if (rank_count_dimm1 < 4)
-+                                              cs_tristate_code = 0xf3;
-+                                      else
-+                                              cs_tristate_code = 0x33;
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4))
-+                                              cs_tristate_code = 0xf0;
-+                                      else if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 == 4))
-+                                              cs_tristate_code = 0x30;
-+                                      else if ((rank_count_dimm0 == 4) && 
(rank_count_dimm1 < 4))
-+                                              cs_tristate_code = 0xc0;
-+                                      else
-+                                              cs_tristate_code = 0x0;
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-+                      }
-+              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
-+                      /* LRDIMM */
-+
-+                      /* TODO
-+                       * Implement LRDIMM support
-+                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 
105
-+                       */
-+              } else {
-+                      /* UDIMM */
-+                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 
*/
-+                      if (MaxDimmsInstallable == 1) {
-+                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
-+
-+                              if (rank_count_dimm0 == 1)
-+                                      cs_tristate_code = 0xfe;
-+                              else
-+                                      cs_tristate_code = 0xfc;
-+                      } else if (MaxDimmsInstallable == 2) {
-+                              if (dimm_count == 1) {
-+                                      /* 1 DIMM detected */
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if (rank_count_dimm0 == 1)
-+                                              cs_tristate_code = 0xfb;
-+                                      else
-+                                              cs_tristate_code = 0xf3;
-+                              } else if (dimm_count == 2) {
-+                                      /* 2 DIMMs detected */
-+                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
-+                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
-+
-+                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
-+                                              cs_tristate_code = 0xfa;
-+                                      else if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 2))
-+                                              cs_tristate_code = 0xf2;
-+                                      else if ((rank_count_dimm0 == 2) && 
(rank_count_dimm1 == 1))
-+                                              cs_tristate_code = 0xf8;
-+                                      else
-+                                              cs_tristate_code = 0xf0;
-+                              }
-+                      } else if (MaxDimmsInstallable == 3) {
-+                              /* TODO
-+                               * 3 DIMM/channel support unimplemented
-+                               */
-+                      }
-+              }
-+      } else {
-+              /* TODO
-+               * Other socket support unimplemented
-+               */
-+      }
-+
-+      return cs_tristate_code;
-+}
-+
- static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
-                               struct DCTStatStruc *pDCTstat, u8 dct)
- {
-@@ -2299,20 +2517,16 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
-               if (memclk_index <= 0x6) {
-                       delay = 0x5;
-                       delay2 = 0x3;
--              }
--              else if (memclk_index == 0xa) {
-+              } else if (memclk_index == 0xa) {
-                       delay = 0x6;
-                       delay2 = 0x3;
--              }
--              else if (memclk_index == 0xe) {
-+              } else if (memclk_index == 0xe) {
-                       delay = 0x7;
-                       delay2 = 0x4;
--              }
--              else if (memclk_index == 0x12) {
-+              } else if (memclk_index == 0x12) {
-                       delay = 0x8;
-                       delay2 = 0x4;
--              }
--              else if (memclk_index == 0x16) {
-+              } else if (memclk_index == 0x16) {
-                       delay = 0xa;
-                       delay2 = 0x5;
-               }
-@@ -3329,8 +3543,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
-                       tCK16x = 40;
-               else
-                       tCK16x = 48;
--      }
--      else {
-+      } else {
-               if (byte == 7)
-                       tCK16x = 20;
-               else if (byte == 6)
-@@ -4657,13 +4870,13 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
-                                       else
-                                               pDCTstat->RegMan1Present |= 1 
<< i;
-                               }
--                              /* Get Control word values for RC3. We dont 
need it. */
-+                              /* Get control word value for RC3 */
-                               byte = pDCTstat->spd_data.spd_bytes[i][70];
--                              pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); 
/* C3 = SPD byte 70 [7:4] */
--                              /* Get Control word values for RC4, and RC5 */
-+                              pDCTstat->CtrlWrd3 |= ((byte >> 4) & 0xf) << (i 
<< 2);  /* RC3 = SPD byte 70 [7:4] */
-+                              /* Get control word values for RC4 and RC5 */
-                               byte = pDCTstat->spd_data.spd_bytes[i][71];
--                              pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 
2); /* RC4 = SPD byte 71 [3:0] */
--                              pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); 
/* RC5 = SPD byte 71 [7:4] */
-+                              pDCTstat->CtrlWrd4 |= (byte & 0xf) << (i << 2); 
        /* RC4 = SPD byte 71 [3:0] */
-+                              pDCTstat->CtrlWrd5 |= ((byte >> 4) & 0xf) << (i 
<< 2);  /* RC5 = SPD byte 71 [7:4] */
-                       }
-               }
-       }
-@@ -5849,23 +6062,27 @@ static void SetCSTriState(struct MCTStatStruc 
*pMCTstat,
-       u32 val;
-       u32 dev = pDCTstat->dev_dct;
-       u32 index_reg = 0x98;
--      u32 index;
-       u16 word;
- 
--      /* Tri-state unused chipselects when motherboard
--         termination is available */
-+      if (is_fam15h()) {
-+              word = fam15h_cs_tristate_enable_code(pDCTstat, dct);
-+      } else {
-+              /* Tri-state unused chipselects when motherboard
-+              termination is available */
- 
--      /* FIXME: skip for Ax */
-+              /* FIXME: skip for Ax */
- 
--      word = pDCTstat->CSPresent;
--      if (pDCTstat->Status & (1 << SB_Registered)) {
--              word |= (word & 0x55) << 1;
-+              word = pDCTstat->CSPresent;
-+              if (pDCTstat->Status & (1 << SB_Registered)) {
-+                      word |= (word & 0x55) << 1;
-+              }
-+              word = (~word) & 0xff;
-       }
--      word = (~word) & 0xFF;
--      index  = 0x0c;
--      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-+
-+      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
-+      val &= ~0xff;
-       val |= word;
--      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
- }
- 
- static void SetCKETriState(struct MCTStatStruc *pMCTstat,
-@@ -5874,7 +6091,6 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
-       u32 val;
-       u32 dev;
-       u32 index_reg = 0x98;
--      u32 index;
-       u16 word;
- 
-       /* Tri-state unused CKEs when motherboard termination is available */
-@@ -5884,15 +6100,13 @@ static void SetCKETriState(struct MCTStatStruc 
*pMCTstat,
-       dev = pDCTstat->dev_dct;
-       word = pDCTstat->CSPresent;
- 
--      index  = 0x0c;
--      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-+      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
-+      val &= ~(0x3 << 12);
-       if ((word & 0x55) == 0)
-               val |= 1 << 12;
--
--      if ((word & 0xAA) == 0)
-+      if ((word & 0xaa) == 0)
-               val |= 1 << 13;
--
--      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
- }
- 
- static void SetODTTriState(struct MCTStatStruc *pMCTstat,
-@@ -5902,42 +6116,44 @@ static void SetODTTriState(struct MCTStatStruc 
*pMCTstat,
-       u32 dev;
-       u32 index_reg = 0x98;
-       u8 cs;
--      u32 index;
-       u8 odt;
-       u8 max_dimms;
- 
--      /* FIXME: skip for Ax */
--
-       dev = pDCTstat->dev_dct;
- 
--      /* Tri-state unused ODTs when motherboard termination is available */
--      max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
--      odt = 0x0F;     /* ODT tri-state setting */
--
--      if (pDCTstat->Status & (1 <<SB_Registered)) {
--              for (cs = 0; cs < 8; cs += 2) {
--                      if (pDCTstat->CSPresent & (1 << cs)) {
--                              odt &= ~(1 << (cs / 2));
--                              if (mctGet_NVbits(NV_4RANKType) != 0) { /* 
quad-rank capable platform */
--                                      if (pDCTstat->CSPresent & (1 << (cs + 
1)))
--                                              odt &= ~(4 << (cs / 2));
-+      if (is_fam15h()) {
-+              odt = fam15h_odt_tristate_enable_code(pDCTstat, dct);
-+      } else {
-+              /* FIXME: skip for Ax */
-+
-+              /* Tri-state unused ODTs when motherboard termination is 
available */
-+              max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
-+              odt = 0x0f;     /* ODT tri-state setting */
-+
-+              if (pDCTstat->Status & (1 <<SB_Registered)) {
-+                      for (cs = 0; cs < 8; cs += 2) {
-+                              if (pDCTstat->CSPresent & (1 << cs)) {
-+                                      odt &= ~(1 << (cs / 2));
-+                                      if (mctGet_NVbits(NV_4RANKType) != 0) { 
/* quad-rank capable platform */
-+                                              if (pDCTstat->CSPresent & (1 << 
(cs + 1)))
-+                                                      odt &= ~(4 << (cs / 2));
-+                                      }
-                               }
-                       }
-+              } else {                /* AM3 package */
-+                      val = ~(pDCTstat->CSPresent);
-+                      odt = val & 9;  /* swap bits 1 and 2 */
-+                      if (val & (1 << 1))
-+                              odt |= 1 << 2;
-+                      if (val & (1 << 2))
-+                              odt |= 1 << 1;
-               }
--      } else {                /* AM3 package */
--              val = ~(pDCTstat->CSPresent);
--              odt = val & 9;  /* swap bits 1 and 2 */
--              if (val & (1 << 1))
--                      odt |= 1 << 2;
--              if (val & (1 << 2))
--                      odt |= 1 << 1;
-       }
- 
--      index  = 0x0C;
--      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
--      val |= ((odt & 0xFF) << 8);     /* set bits 11:8 ODTTriState[3:0] */
--      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
--
-+      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
-+      val &= ~(0xf << 8);             /* ODTTri = odt */
-+      val |= (odt & 0xf) << 8;
-+      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
- }
- 
- /* Family 15h */
-@@ -6507,7 +6723,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
-               dword |= (read_odt_delay & 0xf);
-               Set_NB32_DCT(dev, dct, 0x240, dword);
- 
--              printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x 
%08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
-+              printk(BIOS_SPEW, "Programmed DCT %d ODT pattern %08x %08x %08x 
%08x\n", dct, odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
-       } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
-               if (pDCTstat->Speed == 3)
-                       dword = 0x00000800;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-index ec5658e..8bc4ec2 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
-@@ -582,7 +582,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-       uint8_t NbPstateThreshold;
-       uint8_t NbPstateHi;
- 
--/* New for LB Support */
-+      /* New for LB Support */
-       u8 NodePresent;
-       u32 dev_host;
-       u32 dev_map;
-@@ -592,9 +592,9 @@ struct DCTStatStruc {              /* A per Node 
structure*/
-       u32 dev_nbctl;
-       u8 TargetFreq;
-       u8 TargetCASL;
--      u8 CtrlWrd3;
--      u8 CtrlWrd4;
--      u8 CtrlWrd5;
-+      uint32_t CtrlWrd3;
-+      uint32_t CtrlWrd4;
-+      uint32_t CtrlWrd5;
-       u8 DqsRdWrPos_Saved;
-       u8 DqsRcvEnGrossMax;
-       u8 DqsRcvEnGrossMin;
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index d870f17..553a54a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -1021,7 +1021,7 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-               pDCTstat->CH_MaxRdLat[dct] = n - 1;
- 
- #if DQS_TRAIN_DEBUG > 0
--      printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, 
pDCTstat->CH_MaxRdLat[dct]);
-+              printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, 
dct, pDCTstat->CH_MaxRdLat[dct]);
- #endif
-       }
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-index 8fd2523..dec2bf8 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
-@@ -18,7 +18,7 @@
-  * Foundation, Inc.
-  */
- 
--static uint8_t fam15h_rdimm_rc2_control_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
-+static uint8_t fam15h_rdimm_rc2_ibt_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
- {
-       uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
- 
-@@ -161,7 +161,7 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-                       val = 0xc; /* if single rank, set DBA1 and DBA0 */
-       } else if (CtrlWordNum == 2) {
-               if (is_fam15h()) {
--                      val = fam15h_rdimm_rc2_control_code(pDCTstat, dct);
-+                      val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0x1) 
<< 2;
-               } else {
-                       if (package_type == PT_GR) {
-                               /* Socket G34 */
-@@ -178,10 +178,14 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
-       } else if (CtrlWordNum == 5) {
-               val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xff;
-       } else if (CtrlWordNum == 8) {
--              if (package_type == PT_GR) {
--                      /* Socket G34 */
--                      if (MaxDimmsInstallable == 2) {
--                              val = 0x0;
-+              if (is_fam15h()) {
-+                      val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0xe) 
>> 1;
-+              } else {
-+                      if (package_type == PT_GR) {
-+                              /* Socket G34 */
-+                              if (MaxDimmsInstallable == 2) {
-+                                      val = 0x0;
-+                              }
-                       }
-               }
-       } else if (CtrlWordNum == 9) {
-@@ -233,7 +237,11 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
- 
-       mct_Wait(1200);
- 
--      for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
-+      pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
-+      if (pDCTstat->GangedMode & 1)
-+              pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
-+
-+      for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel += 2) {
-               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
-                       val = Get_NB32_DCT(dev, dct, 0xa8);
-                       val &= ~(0xff << 8);
-@@ -276,6 +284,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
-       u32 val;
-       uint16_t mem_freq;
- 
-+      pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
-+      if (pDCTstat->GangedMode & 1)
-+              pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
-+
-       pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
-       mem_freq = memclk_to_freq(pDCTstat->TargetFreq);
-       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-index 7804a38..5019faa 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
-@@ -845,6 +845,10 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
-                        */
-       }
- 
-+      pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
-+      if (pDCTstat->GangedMode & 1)
-+              pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
-+
-       /* The following steps are performed once for unbuffered DIMMs and once 
for each
-        * chip select on registered DIMMs: */
-       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-index 73b231e..5cbadc3 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
-@@ -925,7 +925,7 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat,
-  *       OUT
-  * 
----------------------------------------------------------------------------
-  */
--void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm)
-+void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t dimm)
- {
-       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
-       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-@@ -933,6 +933,10 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-       u8 WrLvOdt1=0;
- 
-       if (is_fam15h()) {
-+              /* On Family15h processors, the value for the specific CS being 
targetted
-+               * is taken from F2x238 / F2x23C as appropriate, then loaded 
into F2x9C_x0000_0008
-+               */
-+
-               /* Convert DIMM number to CS */
-               uint32_t dword;
-               uint8_t cs;
-@@ -967,7 +971,7 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
-       set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
-                       DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
- 
--      printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern 
%08x\n", dct, WrLvOdt1);
-+      printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x 
from DIMM %d data\n", dct, WrLvOdt1, dimm);
- 
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
 
b/resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
new file mode 100644
index 0000000..285d836
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch
@@ -0,0 +1,65 @@
+From e1da6392d60e4735e8b972fd20e009c2686ab638 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 27 Aug 2015 13:19:34 -0500
+Subject: [PATCH 127/143] northbridge/amd/amdmct/mct_ddr3: Fix odd rank data
+ corruption due to incorrect DQS training
+
+Change-Id: Ibc51f5052d5189e45b3d9aa98ca8febbfe13f178
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   25 ++++++++++++++++--------
+ 1 file changed, 17 insertions(+), 8 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index c520515..739a893 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -1324,9 +1324,9 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+               Receiver = receiver_start;
+ 
+       /* There are four receiver pairs, loosely associated with chipselects.
+-       * This is essentially looping over each DIMM.
++       * This is essentially looping over each rank within each DIMM.
+        */
+-      for (; Receiver < receiver_end; Receiver += 2) {
++      for (; Receiver < receiver_end; Receiver++) {
+               dimm = (Receiver >> 1);
+               if ((Receiver & 0x1) == 0) {
+                       /* Even rank of DIMM */
+@@ -1340,18 +1340,27 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                       continue;
+               }
+ 
++#if DQS_TRAIN_DEBUG > 0
++              printk(BIOS_DEBUG, "TrainDQSRdWrPos: Training DQS read/write 
position for receiver %d (DIMM %d)\n", Receiver, dimm);
++#endif
++
+               /* Initialize variables */
+               for (lane = lane_start; lane < lane_end; lane++) {
+                       passing_dqs_delay_found[lane] = 0;
+               }
+-              memset(dqs_results_array, 0, sizeof(dqs_results_array));
++              if ((Receiver & 0x1) == 0) {
++                      /* Even rank of DIMM */
++                      memset(dqs_results_array, 0, sizeof(dqs_results_array));
++
++                      /* Read initial read / write DQS delays */
++                      
read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, 
dimm, index_reg);
++                      
read_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, 
index_reg);
+ 
+-              /* Read initial read / write DQS delays */
+-              
read_dqs_write_timing_control_registers(initial_write_dqs_delay, dev, dct, 
dimm, index_reg);
+-              read_dqs_read_data_timing_registers(initial_read_dqs_delay, 
dev, dct, dimm, index_reg);
++                      /* Read current settings of other (previously trained) 
lanes */
++                      
read_dqs_write_data_timing_registers(initial_write_data_timing, dev, dct, dimm, 
index_reg);
++              }
+ 
+-              /* Read current settings of other (previously trained) lanes */
+-              read_dqs_write_data_timing_registers(initial_write_data_timing, 
dev, dct, dimm, index_reg);
++              /* Initialize iterators */
+               memcpy(current_write_data_delay, initial_write_data_timing, 
sizeof(current_write_data_delay));
+ 
+               for (lane = lane_start; lane < lane_end; lane++) {
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0128-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
 
b/resources/libreboot/patch/kgpe-d16/0128-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
deleted file mode 100644
index 6bcf1d1..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0128-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
+++ /dev/null
@@ -1,175 +0,0 @@
-From f6d958412705c488a29bfad0aaaf7bc70cdb255a Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 28 Aug 2015 19:52:05 -0500
-Subject: [PATCH 128/139] drivers/pc80: Add optional spinlock for nvram CBFS
- access
-
-When enabling the IOMMU on certain systems dmesg is spammed with I/O page 
faults like the following:
-AMD-Vi: Event logged [IO_PAGE_FAULT device=00:14.0 domain=0x000a 
address=0x000000fdf9103300 flags=0x0030]
-
-Decoding the faulting address:
-0x000000fdf9103300
-        fdf91x          Hypertransport system management region
-              33        SysMgtCmd (System Management Command) = 0x33
-              3         Base Command Type = 0x3: STPCLK (Stop Clock request)
-               3        SMAF (System Management Action Field) = [3:1] = 0x1
-               1        Signal State Bit Map = [0] = 0x1
-
-Therefore, the error appears to be triggered by an upstream C1E request.
-
-This was eventually traced to concurrent access to the SP5100's SMBus 
controller by
-multiple APs during startup.  Calls to the nvram read functions get_option and 
read_option
-call CBFS functions, which in turn make near-simultaneous requests to the 
SMBus controller,
-thus placing the SP5100 in an invalid state.  This limitation is not 
documented in any public
-AMD errata, and was only discovered through considerable debugging effort.
-
-Change-Id: I4e61b1ab767b1b7958ac7c1cf20eee41d2261bef
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/Kconfig                              |  4 +++
- src/arch/x86/include/arch/smp/spinlock.h |  4 ++-
- src/cpu/amd/car/post_cache_as_ram.c      |  3 +++
- src/drivers/pc80/mc146818rtc.c           | 43 ++++++++++++++++++++++++++++++--
- 4 files changed, 51 insertions(+), 3 deletions(-)
-
-diff --git a/src/Kconfig b/src/Kconfig
-index 4e46364..b85e381 100644
---- a/src/Kconfig
-+++ b/src/Kconfig
-@@ -451,6 +451,10 @@ config HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-       bool
-       default n
- 
-+config HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
-+      bool
-+      default n
-+
- config HAVE_MONOTONIC_TIMER
-       def_bool n
-       help
-diff --git a/src/arch/x86/include/arch/smp/spinlock.h 
b/src/arch/x86/include/arch/smp/spinlock.h
-index 5000779..cf142a9 100644
---- a/src/arch/x86/include/arch/smp/spinlock.h
-+++ b/src/arch/x86/include/arch/smp/spinlock.h
-@@ -1,7 +1,7 @@
- #ifndef ARCH_SMP_SPINLOCK_H
- #define ARCH_SMP_SPINLOCK_H
- 
--#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
-+#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK) 
|| defined(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
- 
- /*
-  * Your basic SMP spinlocks, allowing only a single CPU anywhere
-@@ -14,6 +14,8 @@ typedef struct {
- #ifdef __PRE_RAM__
- spinlock_t* romstage_console_lock(void);
- void initialize_romstage_console_lock(void);
-+spinlock_t* romstage_nvram_cbfs_lock(void);
-+void initialize_romstage_nvram_cbfs_lock(void);
- #endif
- 
- #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
-diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
-index 2282cee..55bb1be 100644
---- a/src/cpu/amd/car/post_cache_as_ram.c
-+++ b/src/cpu/amd/car/post_cache_as_ram.c
-@@ -87,6 +87,9 @@ static void prepare_ramstage_region(void 
*resume_backup_memory)
- #if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
-       initialize_romstage_console_lock();
- #endif
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+      initialize_romstage_nvram_cbfs_lock();
-+#endif
- 
-       print_car_debug("Done\n");
- }
-diff --git a/src/drivers/pc80/mc146818rtc.c b/src/drivers/pc80/mc146818rtc.c
-index 07fc884..59de0a2 100644
---- a/src/drivers/pc80/mc146818rtc.c
-+++ b/src/drivers/pc80/mc146818rtc.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright 2014 The Chromium OS Authors. All rights reserved.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -37,6 +38,11 @@
- #define LB_CKS_LOC            0
- #endif
- 
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+#include <smp/spinlock.h>
-+#endif
-+#endif
- 
- static void cmos_reset_date(void)
- {
-@@ -208,6 +214,12 @@ enum cb_err get_option(void *dest, const char *name)
-       if (!IS_ENABLED(CONFIG_USE_OPTION_TABLE))
-               return CB_CMOS_OTABLE_DISABLED;
- 
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+      spin_lock(romstage_nvram_cbfs_lock());
-+#endif
-+#endif
-+
-       /* Figure out how long name is */
-       namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
- 
-@@ -217,6 +229,11 @@ enum cb_err get_option(void *dest, const char *name)
-       if (!ct) {
-               printk(BIOS_ERR, "RTC: cmos_layout.bin could not be found. "
-                                               "Options are disabled\n");
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+              spin_unlock(romstage_nvram_cbfs_lock());
-+#endif
-+#endif
-               return CB_CMOS_LAYOUT_NOT_FOUND;
-       }
-       ce = (struct cmos_entries*)((unsigned char *)ct + ct->header_length);
-@@ -229,13 +246,35 @@ enum cb_err get_option(void *dest, const char *name)
-       }
-       if (!found) {
-               printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name);
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+              spin_unlock(romstage_nvram_cbfs_lock());
-+#endif
-+#endif
-               return CB_CMOS_OPTION_NOT_FOUND;
-       }
- 
--      if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS)
-+      if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS) {
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+              spin_unlock(romstage_nvram_cbfs_lock());
-+#endif
-+#endif
-               return CB_CMOS_ACCESS_ERROR;
--      if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, 
LB_CKS_LOC))
-+      }
-+      if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, 
LB_CKS_LOC)) {
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+              spin_unlock(romstage_nvram_cbfs_lock());
-+#endif
-+#endif
-               return CB_CMOS_CHECKSUM_INVALID;
-+      }
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+      spin_unlock(romstage_nvram_cbfs_lock());
-+#endif
-+#endif
-       return CB_SUCCESS;
- }
- 
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0128-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
 
b/resources/libreboot/patch/kgpe-d16/0128-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
new file mode 100644
index 0000000..c27a23d
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0128-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch
@@ -0,0 +1,157 @@
+From 6f45e9f8fbf2fe7c3dcd3ee5db6a1f09505f8c11 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 27 Aug 2015 15:10:19 -0500
+Subject: [PATCH 128/143] northbridge/amd/amdmct/mct_ddr3: Use antiphase to
+ better center DQS window
+
+Change-Id: I1d85fddd45197ca82dcaa46fe863e64589712d1f
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   57 +++++++++++++++++-------
+ 1 file changed, 40 insertions(+), 17 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index 739a893..d870f17 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -1304,7 +1304,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+       uint16_t current_read_dqs_delay[MAX_BYTE_LANES];
+       uint16_t current_write_dqs_delay[MAX_BYTE_LANES];
+       uint8_t passing_dqs_delay_found[MAX_BYTE_LANES];
+-      uint8_t dqs_results_array[2][(lane_end - lane_start)][32][32];          
/* [rank][lane][write step][read step] */
++      uint8_t dqs_results_array[2][(lane_end - lane_start)][32][48];          
/* [rank][lane][write step][read step + 16] */
+ 
+       uint8_t last_pos = 0;
+       uint8_t cur_count = 0;
+@@ -1404,16 +1404,24 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                                        */
+                                       dword = Get_NB32_DCT(dev, dct, 0x268) & 
0x3ffff;
+                                       if (dword & (0x3 << (lane * 2)))
+-                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 0;    /* 
Fail */
++                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 0;   
  /* Fail */
+                                       else
+-                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][current_read_dqs_delay[lane] >> 1] = 1;    /* 
Pass */
++                                              dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 1;   
  /* Pass */
++                                      if ((current_read_dqs_delay[lane] >> 1) 
>= (32 - 16)) {
++                                              /* Check antiphase results */
++                                              dword = Get_NB32_DCT(dev, dct, 
0x26c) & 0x3ffff;
++                                              if (dword & (0x3 << (lane * 2)))
++                                                      
dqs_results_array[Receiver & 0x1][lane - 
lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][16 
- (32 - (current_read_dqs_delay[lane] >> 1))] = 0;      /* Fail */
++                                              else
++                                                      
dqs_results_array[Receiver & 0x1][lane - 
lane_start][current_write_data_delay[lane] - initial_write_dqs_delay[lane]][16 
- (32 - (current_read_dqs_delay[lane] >> 1))] = 1;      /* Pass */
++                                      }
+                               }
+                       }
+ 
+                       if (dual_rank && (Receiver & 0x1)) {
+                               /* Overlay the previous rank test results with 
the current rank */
+                               for (write_iter = 0; write_iter < 32; 
write_iter++) {
+-                                      for (read_iter = 0; read_iter < 32; 
read_iter++) {
++                                      for (read_iter = 0; read_iter < 48; 
read_iter++) {
+                                               if ((dqs_results_array[0][lane 
- lane_start][write_iter][read_iter])
+                                                       && 
(dqs_results_array[1][lane - lane_start][write_iter][read_iter]))
+                                                       
dqs_results_array[1][lane - lane_start][write_iter][read_iter] = 1;
+@@ -1431,8 +1439,8 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                       best_pos = 0;
+                       best_count = 0;
+                       for (write_iter = 0; write_iter < 32; write_iter++) {
+-                              for (read_iter = 0; read_iter < 32; 
read_iter++) {
+-                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 31)) {
++                              for (read_iter = 0; read_iter < 48; 
read_iter++) {
++                                      if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (read_iter < 47)) {
+                                               /* Pass */
+                                               cur_count++;
+                                       } else {
+@@ -1442,18 +1450,28 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                                                       best_pos = last_pos;
+                                               }
+                                               cur_count = 0;
+-                                              last_pos = read_iter;
++                                              last_pos = read_iter + 1;
+                                       }
+                               }
+                               last_pos = 0;
+                       }
+ 
+                       if (best_count > 2) {
++                              uint16_t region_center = (best_pos + 
(best_count / 2));
++
++                              if (region_center < 16) {
++                                      printk(BIOS_WARNING, "TrainDQSRdWrPos: 
negative DQS recovery delay detected!"
++                                                      "  Attempting to 
continue but your system may be unstable...\n");
++                                      region_center = 0;
++                              } else {
++                                      region_center -= 16;
++                              }
++
+                               /* Restore current settings of other 
(previously trained) lanes to the active array */
+                               memcpy(current_read_dqs_delay, 
initial_read_dqs_delay, sizeof(current_read_dqs_delay));
+ 
+                               /* Program the Read DQS Timing Control register 
with the center of the passing window */
+-                              current_read_dqs_delay[lane] = ((best_pos << 1) 
+ ((best_count << 1) / 2));
++                              current_read_dqs_delay[lane] = region_center << 
1;
+                               passing_dqs_delay_found[lane] = 1;
+ 
+                               /* Commit the current Read DQS Timing Control 
settings to the hardware registers */
+@@ -1464,6 +1482,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+ 
+                               print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 
largest read passing region ", best_count, 4);
+                               print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 
largest read passing region start ", best_pos, 4);
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 
largest read passing region center (raw hardware value) ", region_center, 4);
+                       } else {
+                               /* Reprogram the Read DQS Timing Control 
register with the original settings */
+                               
write_dqs_read_data_timing_registers(initial_read_dqs_delay, dev, dct, dimm, 
index_reg);
+@@ -1476,7 +1495,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                       cur_count = 0;
+                       best_pos = 0;
+                       best_count = 0;
+-                      for (read_iter = 0; read_iter < 32; read_iter++) {
++                      for (read_iter = 0; read_iter < 48; read_iter++) {
+                               for (write_iter = 0; write_iter < 32; 
write_iter++) {
+                                       if ((dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) && (write_iter < 31)) {
+                                               /* Pass */
+@@ -1488,7 +1507,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                                                       best_pos = last_pos;
+                                               }
+                                               cur_count = 0;
+-                                              last_pos = write_iter;
++                                              last_pos = write_iter + 1;
+                                       }
+                               }
+                               last_pos = 0;
+@@ -1511,8 +1530,8 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                               /* Save the final Write Data Timing settings 
for later use */
+                               pDCTstat->CH_D_DIR_B_DQS[dct][Receiver >> 
1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane];
+ 
+-                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 
largest write passing region ", best_count, 4);
+-                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 
largest write passing region start ", best_pos, 4);
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 
largest write passing region ", best_count, 4);
++                              print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 146 
largest write passing region start ", best_pos, 4);
+                       } else {
+                               /* Reprogram the Write DQS Timing Control 
register with the original settings */
+                               
write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, dct, dimm, 
index_reg);
+@@ -1521,12 +1540,16 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+ 
+ #ifdef PRINT_PASS_FAIL_BITMAPS
+               for (lane = lane_start; lane < lane_end; lane++) {
+-                      for (read_iter = 0; read_iter < 32; read_iter++) {
+-                              for (write_iter = 0; write_iter < 32; 
write_iter++) {
+-                                      if (dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter])
++                      for (write_iter = 0; write_iter < 32; write_iter++) {
++                              for (read_iter = 0; read_iter < 48; 
read_iter++) {
++                                      if (dqs_results_array[Receiver & 
0x1][lane - lane_start][write_iter][read_iter]) {
+                                               printk(BIOS_DEBUG, "+");
+-                                      else
+-                                              printk(BIOS_DEBUG, ".");
++                                      } else {
++                                              if (read_iter < 16)
++                                                      printk(BIOS_DEBUG, "°");
++                                              else
++                                                      printk(BIOS_DEBUG, ".");
++                                      }
+                               }
+                               printk(BIOS_DEBUG, "\n");
+                       }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0129-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
 
b/resources/libreboot/patch/kgpe-d16/0129-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
deleted file mode 100644
index 494181a..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0129-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From ff495fb11ccedb64b6eab1853a8e50d30b3da80a Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 28 Aug 2015 20:02:45 -0500
-Subject: [PATCH 129/139] mainboard/asus/kgpe-d16: Enable CBFS spinlocks
-
-Change-Id: I8f6226d3e74ac5c7f29f708128a7502ced1287bf
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/Kconfig    |  1 +
- src/mainboard/asus/kgpe-d16/romstage.c | 17 +++++++++++++++--
- 2 files changed, 16 insertions(+), 2 deletions(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-index 084a412..a9261f9 100644
---- a/src/mainboard/asus/kgpe-d16/Kconfig
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -15,6 +15,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
-       select SUPERIO_NUVOTON_NCT5572D
-       select PARALLEL_CPU_INIT
-       select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-+      select HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
-       select HAVE_HARD_RESET
-       select HAVE_OPTION_TABLE
-       select HAVE_CMOS_DEFAULT
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index fa61f63..9998359 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -315,6 +315,18 @@ void initialize_romstage_console_lock(void)
-       car_get_var(printk_spinlock) = SPIN_LOCK_UNLOCKED;
- }
- 
-+static spinlock_t nvram_cbfs_spinlock CAR_GLOBAL;
-+
-+spinlock_t* romstage_nvram_cbfs_lock(void)
-+{
-+      return car_get_var_ptr(&nvram_cbfs_spinlock);
-+}
-+
-+void initialize_romstage_nvram_cbfs_lock(void)
-+{
-+      car_get_var(nvram_cbfs_spinlock) = SPIN_LOCK_UNLOCKED;
-+}
-+
- void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
- {
-       uint32_t esp;
-@@ -336,8 +348,9 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               timestamp_init(timestamp_get());
-               timestamp_add_now(TS_START_ROMSTAGE);
- 
--              /* Initialize the printk spinlock */
-+              /* Initialize the printk and nvram CBFS spinlocks */
-               initialize_romstage_console_lock();
-+              initialize_romstage_nvram_cbfs_lock();
- 
-               /* Nothing special needs to be done to find bus 0 */
-               /* Allow the HT devices to be found */
-@@ -561,4 +574,4 @@ BOOL AMD_CB_ManualBUIDSwapList (u8 node, u8 link, const u8 
**List)
-       }
- 
-       return 0;
--}
-\ No newline at end of file
-+}
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
 
b/resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
new file mode 100644
index 0000000..4dcf7c5
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch
@@ -0,0 +1,602 @@
+From d9d10881a0841481d8df2e357adb870ce52f9387 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 27 Aug 2015 23:37:38 -0500
+Subject: [PATCH 129/143] northbridge/amd/amdmct/mct_ddr3: Fix broken support
+ for multiple DIMMs on single channel
+
+Change-Id: I0278656e98461882d0a64519dfde54a6cf28ab0f
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  336 +++++++++++++++++++-----
+ src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |    8 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |    2 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctrci.c   |   26 +-
+ src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |    4 +
+ src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |    8 +-
+ 6 files changed, 310 insertions(+), 74 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+index a11b227..5bc80f4 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+@@ -1360,6 +1360,224 @@ static uint8_t fam15h_slow_access_mode(struct 
DCTStatStruc *pDCTstat, uint8_t dc
+       return slow_access;
+ }
+ 
++static uint8_t fam15h_odt_tristate_enable_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
++{
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
++
++      uint8_t package_type;
++      uint8_t odt_tristate_code = 0;
++
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++      /* Obtain number of DIMMs on channel */
++      uint8_t dimm_count = pDCTstat->MAdimms[dct];
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++
++      if (package_type == PT_GR) {
++              /* Socket G34 */
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* RDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 
*/
++                      if (MaxDimmsInstallable == 1) {
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
++
++                              if (rank_count_dimm0 == 1)
++                                      odt_tristate_code = 0xe;
++                              else
++                                      odt_tristate_code = 0xa;
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if (rank_count_dimm1 == 1)
++                                              odt_tristate_code = 0xd;
++                                      else
++                                              odt_tristate_code = 0x5;
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
++                                              odt_tristate_code = 0xc;
++                                      else if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 >= 2))
++                                              odt_tristate_code = 0x4;
++                                      else if ((rank_count_dimm0 >= 2) && 
(rank_count_dimm1 == 1))
++                                              odt_tristate_code = 0x8;
++                                      else
++                                              odt_tristate_code = 0x0;
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
++                      }
++              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* LRDIMM */
++
++                      /* TODO
++                       * Implement LRDIMM support
++                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 
105
++                       */
++              } else {
++                      /* UDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 
*/
++                      if (MaxDimmsInstallable == 1) {
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
++
++                              if (rank_count_dimm0 == 1)
++                                      odt_tristate_code = 0xe;
++                              else
++                                      odt_tristate_code = 0xa;
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if (rank_count_dimm0 == 1)
++                                              odt_tristate_code = 0xd;
++                                      else
++                                              odt_tristate_code = 0x5;
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
++                                              odt_tristate_code = 0xc;
++                                      else if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 2))
++                                              odt_tristate_code = 0x4;
++                                      else if ((rank_count_dimm0 == 2) && 
(rank_count_dimm1 == 1))
++                                              odt_tristate_code = 0x8;
++                                      else
++                                              odt_tristate_code = 0x0;
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
++                      }
++              }
++      } else {
++              /* TODO
++               * Other socket support unimplemented
++               */
++      }
++
++      return odt_tristate_code;
++}
++
++static uint8_t fam15h_cs_tristate_enable_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
++{
++      uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
++
++      uint8_t package_type;
++      uint8_t cs_tristate_code = 0;
++
++      package_type = mctGet_NVbits(NV_PACK_TYPE);
++
++      /* Obtain number of DIMMs on channel */
++      uint8_t dimm_count = pDCTstat->MAdimms[dct];
++      uint8_t rank_count_dimm0;
++      uint8_t rank_count_dimm1;
++
++      if (package_type == PT_GR) {
++              /* Socket G34 */
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      /* RDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 
*/
++                      if (MaxDimmsInstallable == 1) {
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
++
++                              if (rank_count_dimm0 < 4)
++                                      cs_tristate_code = 0xfc;
++                              else
++                                      cs_tristate_code = 0xcc;
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if (rank_count_dimm1 < 4)
++                                              cs_tristate_code = 0xf3;
++                                      else
++                                              cs_tristate_code = 0x33;
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 < 4))
++                                              cs_tristate_code = 0xf0;
++                                      else if ((rank_count_dimm0 < 4) && 
(rank_count_dimm1 == 4))
++                                              cs_tristate_code = 0x30;
++                                      else if ((rank_count_dimm0 == 4) && 
(rank_count_dimm1 < 4))
++                                              cs_tristate_code = 0xc0;
++                                      else
++                                              cs_tristate_code = 0x0;
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
++                      }
++              } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
++                      /* LRDIMM */
++
++                      /* TODO
++                       * Implement LRDIMM support
++                       * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 
105
++                       */
++              } else {
++                      /* UDIMM */
++                      /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 
*/
++                      if (MaxDimmsInstallable == 1) {
++                              rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) 
+ dct];
++
++                              if (rank_count_dimm0 == 1)
++                                      cs_tristate_code = 0xfe;
++                              else
++                                      cs_tristate_code = 0xfc;
++                      } else if (MaxDimmsInstallable == 2) {
++                              if (dimm_count == 1) {
++                                      /* 1 DIMM detected */
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if (rank_count_dimm0 == 1)
++                                              cs_tristate_code = 0xfb;
++                                      else
++                                              cs_tristate_code = 0xf3;
++                              } else if (dimm_count == 2) {
++                                      /* 2 DIMMs detected */
++                                      rank_count_dimm0 = 
pDCTstat->DimmRanks[(0 * 2) + dct];
++                                      rank_count_dimm1 = 
pDCTstat->DimmRanks[(1 * 2) + dct];
++
++                                      if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 1))
++                                              cs_tristate_code = 0xfa;
++                                      else if ((rank_count_dimm0 == 1) && 
(rank_count_dimm1 == 2))
++                                              cs_tristate_code = 0xf2;
++                                      else if ((rank_count_dimm0 == 2) && 
(rank_count_dimm1 == 1))
++                                              cs_tristate_code = 0xf8;
++                                      else
++                                              cs_tristate_code = 0xf0;
++                              }
++                      } else if (MaxDimmsInstallable == 3) {
++                              /* TODO
++                               * 3 DIMM/channel support unimplemented
++                               */
++                      }
++              }
++      } else {
++              /* TODO
++               * Other socket support unimplemented
++               */
++      }
++
++      return cs_tristate_code;
++}
++
+ static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
+                               struct DCTStatStruc *pDCTstat, u8 dct)
+ {
+@@ -2299,20 +2517,16 @@ static void fam15EnableTrainingMode(struct 
MCTStatStruc *pMCTstat,
+               if (memclk_index <= 0x6) {
+                       delay = 0x5;
+                       delay2 = 0x3;
+-              }
+-              else if (memclk_index == 0xa) {
++              } else if (memclk_index == 0xa) {
+                       delay = 0x6;
+                       delay2 = 0x3;
+-              }
+-              else if (memclk_index == 0xe) {
++              } else if (memclk_index == 0xe) {
+                       delay = 0x7;
+                       delay2 = 0x4;
+-              }
+-              else if (memclk_index == 0x12) {
++              } else if (memclk_index == 0x12) {
+                       delay = 0x8;
+                       delay2 = 0x4;
+-              }
+-              else if (memclk_index == 0x16) {
++              } else if (memclk_index == 0x16) {
+                       delay = 0xa;
+                       delay2 = 0x5;
+               }
+@@ -3329,8 +3543,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
+                       tCK16x = 40;
+               else
+                       tCK16x = 48;
+-      }
+-      else {
++      } else {
+               if (byte == 7)
+                       tCK16x = 20;
+               else if (byte == 6)
+@@ -4657,13 +4870,13 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
+                                       else
+                                               pDCTstat->RegMan1Present |= 1 
<< i;
+                               }
+-                              /* Get Control word values for RC3. We dont 
need it. */
++                              /* Get control word value for RC3 */
+                               byte = pDCTstat->spd_data.spd_bytes[i][70];
+-                              pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); 
/* C3 = SPD byte 70 [7:4] */
+-                              /* Get Control word values for RC4, and RC5 */
++                              pDCTstat->CtrlWrd3 |= ((byte >> 4) & 0xf) << (i 
<< 2);  /* RC3 = SPD byte 70 [7:4] */
++                              /* Get control word values for RC4 and RC5 */
+                               byte = pDCTstat->spd_data.spd_bytes[i][71];
+-                              pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 
2); /* RC4 = SPD byte 71 [3:0] */
+-                              pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); 
/* RC5 = SPD byte 71 [7:4] */
++                              pDCTstat->CtrlWrd4 |= (byte & 0xf) << (i << 2); 
        /* RC4 = SPD byte 71 [3:0] */
++                              pDCTstat->CtrlWrd5 |= ((byte >> 4) & 0xf) << (i 
<< 2);  /* RC5 = SPD byte 71 [7:4] */
+                       }
+               }
+       }
+@@ -5849,23 +6062,27 @@ static void SetCSTriState(struct MCTStatStruc 
*pMCTstat,
+       u32 val;
+       u32 dev = pDCTstat->dev_dct;
+       u32 index_reg = 0x98;
+-      u32 index;
+       u16 word;
+ 
+-      /* Tri-state unused chipselects when motherboard
+-         termination is available */
++      if (is_fam15h()) {
++              word = fam15h_cs_tristate_enable_code(pDCTstat, dct);
++      } else {
++              /* Tri-state unused chipselects when motherboard
++              termination is available */
+ 
+-      /* FIXME: skip for Ax */
++              /* FIXME: skip for Ax */
+ 
+-      word = pDCTstat->CSPresent;
+-      if (pDCTstat->Status & (1 << SB_Registered)) {
+-              word |= (word & 0x55) << 1;
++              word = pDCTstat->CSPresent;
++              if (pDCTstat->Status & (1 << SB_Registered)) {
++                      word |= (word & 0x55) << 1;
++              }
++              word = (~word) & 0xff;
+       }
+-      word = (~word) & 0xFF;
+-      index  = 0x0c;
+-      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
++
++      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
++      val &= ~0xff;
+       val |= word;
+-      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
+ }
+ 
+ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+@@ -5874,7 +6091,6 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
+       u32 val;
+       u32 dev;
+       u32 index_reg = 0x98;
+-      u32 index;
+       u16 word;
+ 
+       /* Tri-state unused CKEs when motherboard termination is available */
+@@ -5884,15 +6100,13 @@ static void SetCKETriState(struct MCTStatStruc 
*pMCTstat,
+       dev = pDCTstat->dev_dct;
+       word = pDCTstat->CSPresent;
+ 
+-      index  = 0x0c;
+-      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
++      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
++      val &= ~(0x3 << 12);
+       if ((word & 0x55) == 0)
+               val |= 1 << 12;
+-
+-      if ((word & 0xAA) == 0)
++      if ((word & 0xaa) == 0)
+               val |= 1 << 13;
+-
+-      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
+ }
+ 
+ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
+@@ -5902,42 +6116,44 @@ static void SetODTTriState(struct MCTStatStruc 
*pMCTstat,
+       u32 dev;
+       u32 index_reg = 0x98;
+       u8 cs;
+-      u32 index;
+       u8 odt;
+       u8 max_dimms;
+ 
+-      /* FIXME: skip for Ax */
+-
+       dev = pDCTstat->dev_dct;
+ 
+-      /* Tri-state unused ODTs when motherboard termination is available */
+-      max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
+-      odt = 0x0F;     /* ODT tri-state setting */
+-
+-      if (pDCTstat->Status & (1 <<SB_Registered)) {
+-              for (cs = 0; cs < 8; cs += 2) {
+-                      if (pDCTstat->CSPresent & (1 << cs)) {
+-                              odt &= ~(1 << (cs / 2));
+-                              if (mctGet_NVbits(NV_4RANKType) != 0) { /* 
quad-rank capable platform */
+-                                      if (pDCTstat->CSPresent & (1 << (cs + 
1)))
+-                                              odt &= ~(4 << (cs / 2));
++      if (is_fam15h()) {
++              odt = fam15h_odt_tristate_enable_code(pDCTstat, dct);
++      } else {
++              /* FIXME: skip for Ax */
++
++              /* Tri-state unused ODTs when motherboard termination is 
available */
++              max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
++              odt = 0x0f;     /* ODT tri-state setting */
++
++              if (pDCTstat->Status & (1 <<SB_Registered)) {
++                      for (cs = 0; cs < 8; cs += 2) {
++                              if (pDCTstat->CSPresent & (1 << cs)) {
++                                      odt &= ~(1 << (cs / 2));
++                                      if (mctGet_NVbits(NV_4RANKType) != 0) { 
/* quad-rank capable platform */
++                                              if (pDCTstat->CSPresent & (1 << 
(cs + 1)))
++                                                      odt &= ~(4 << (cs / 2));
++                                      }
+                               }
+                       }
++              } else {                /* AM3 package */
++                      val = ~(pDCTstat->CSPresent);
++                      odt = val & 9;  /* swap bits 1 and 2 */
++                      if (val & (1 << 1))
++                              odt |= 1 << 2;
++                      if (val & (1 << 2))
++                              odt |= 1 << 1;
+               }
+-      } else {                /* AM3 package */
+-              val = ~(pDCTstat->CSPresent);
+-              odt = val & 9;  /* swap bits 1 and 2 */
+-              if (val & (1 << 1))
+-                      odt |= 1 << 2;
+-              if (val & (1 << 2))
+-                      odt |= 1 << 1;
+       }
+ 
+-      index  = 0x0C;
+-      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+-      val |= ((odt & 0xFF) << 8);     /* set bits 11:8 ODTTriState[3:0] */
+-      Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+-
++      val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
++      val &= ~(0xf << 8);             /* ODTTri = odt */
++      val |= (odt & 0xf) << 8;
++      Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
+ }
+ 
+ /* Family 15h */
+@@ -6507,7 +6723,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc 
*pMCTstat,
+               dword |= (read_odt_delay & 0xf);
+               Set_NB32_DCT(dev, dct, 0x240, dword);
+ 
+-              printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x 
%08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
++              printk(BIOS_SPEW, "Programmed DCT %d ODT pattern %08x %08x %08x 
%08x\n", dct, odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
+       } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
+               if (pDCTstat->Speed == 3)
+                       dword = 0x00000800;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h 
b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+index ec5658e..8bc4ec2 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+@@ -582,7 +582,7 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+       uint8_t NbPstateThreshold;
+       uint8_t NbPstateHi;
+ 
+-/* New for LB Support */
++      /* New for LB Support */
+       u8 NodePresent;
+       u32 dev_host;
+       u32 dev_map;
+@@ -592,9 +592,9 @@ struct DCTStatStruc {              /* A per Node 
structure*/
+       u32 dev_nbctl;
+       u8 TargetFreq;
+       u8 TargetCASL;
+-      u8 CtrlWrd3;
+-      u8 CtrlWrd4;
+-      u8 CtrlWrd5;
++      uint32_t CtrlWrd3;
++      uint32_t CtrlWrd4;
++      uint32_t CtrlWrd5;
+       u8 DqsRdWrPos_Saved;
+       u8 DqsRcvEnGrossMax;
+       u8 DqsRcvEnGrossMin;
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index d870f17..553a54a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -1021,7 +1021,7 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+               pDCTstat->CH_MaxRdLat[dct] = n - 1;
+ 
+ #if DQS_TRAIN_DEBUG > 0
+-      printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, 
pDCTstat->CH_MaxRdLat[dct]);
++              printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, 
dct, pDCTstat->CH_MaxRdLat[dct]);
+ #endif
+       }
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+index 8fd2523..dec2bf8 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+@@ -18,7 +18,7 @@
+  * Foundation, Inc.
+  */
+ 
+-static uint8_t fam15h_rdimm_rc2_control_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
++static uint8_t fam15h_rdimm_rc2_ibt_code(struct DCTStatStruc *pDCTstat, 
uint8_t dct)
+ {
+       uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+ 
+@@ -161,7 +161,7 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+                       val = 0xc; /* if single rank, set DBA1 and DBA0 */
+       } else if (CtrlWordNum == 2) {
+               if (is_fam15h()) {
+-                      val = fam15h_rdimm_rc2_control_code(pDCTstat, dct);
++                      val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0x1) 
<< 2;
+               } else {
+                       if (package_type == PT_GR) {
+                               /* Socket G34 */
+@@ -178,10 +178,14 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
+       } else if (CtrlWordNum == 5) {
+               val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xff;
+       } else if (CtrlWordNum == 8) {
+-              if (package_type == PT_GR) {
+-                      /* Socket G34 */
+-                      if (MaxDimmsInstallable == 2) {
+-                              val = 0x0;
++              if (is_fam15h()) {
++                      val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0xe) 
>> 1;
++              } else {
++                      if (package_type == PT_GR) {
++                              /* Socket G34 */
++                              if (MaxDimmsInstallable == 2) {
++                                      val = 0x0;
++                              }
+                       }
+               }
+       } else if (CtrlWordNum == 9) {
+@@ -233,7 +237,11 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc 
*pMCTstat,
+ 
+       mct_Wait(1200);
+ 
+-      for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
++      pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
++      if (pDCTstat->GangedMode & 1)
++              pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
++
++      for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel += 2) {
+               if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
+                       val = Get_NB32_DCT(dev, dct, 0xa8);
+                       val &= ~(0xff << 8);
+@@ -276,6 +284,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
+       u32 val;
+       uint16_t mem_freq;
+ 
++      pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
++      if (pDCTstat->GangedMode & 1)
++              pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
++
+       pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
+       mem_freq = memclk_to_freq(pDCTstat->TargetFreq);
+       for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+index 7804a38..5019faa 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+@@ -845,6 +845,10 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+                        */
+       }
+ 
++      pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
++      if (pDCTstat->GangedMode & 1)
++              pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
++
+       /* The following steps are performed once for unbuffered DIMMs and once 
for each
+        * chip select on registered DIMMs: */
+       for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+index 73b231e..5cbadc3 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+@@ -925,7 +925,7 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat,
+  *       OUT
+  * 
----------------------------------------------------------------------------
+  */
+-void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, u8 dimm)
++void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, 
uint8_t dct, uint8_t dimm)
+ {
+       sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
+       sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
+@@ -933,6 +933,10 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+       u8 WrLvOdt1=0;
+ 
+       if (is_fam15h()) {
++              /* On Family15h processors, the value for the specific CS being 
targetted
++               * is taken from F2x238 / F2x23C as appropriate, then loaded 
into F2x9C_x0000_0008
++               */
++
+               /* Convert DIMM number to CS */
+               uint32_t dword;
+               uint8_t cs;
+@@ -967,7 +971,7 @@ void programODT(struct MCTStatStruc *pMCTstat, struct 
DCTStatStruc *pDCTstat, ui
+       set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
+                       DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
+ 
+-      printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern 
%08x\n", dct, WrLvOdt1);
++      printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x 
from DIMM %d data\n", dct, WrLvOdt1, dimm);
+ 
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0130-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
 
b/resources/libreboot/patch/kgpe-d16/0130-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
deleted file mode 100644
index b530570..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0130-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
+++ /dev/null
@@ -1,155 +0,0 @@
-From 66525594fa1976aae7d7f97e4b7455fc66e900df Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Fri, 28 Aug 2015 20:48:17 -0500
-Subject: [PATCH 130/139] cpu/amd/microcode: Introduce CBFS access spinlock to
- avoid IOMMU failure
-
-Change-Id: Ib7e8cb171f44833167053ca98a85cca23021dfba
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/Kconfig                              |  4 ++++
- src/arch/x86/include/arch/smp/spinlock.h |  7 ++++++-
- src/cpu/amd/microcode/microcode.c        | 24 +++++++++++++++++++++++-
- src/mainboard/asus/kgpe-d16/Kconfig      |  1 +
- src/mainboard/asus/kgpe-d16/romstage.c   | 15 ++++++++++++++-
- 5 files changed, 48 insertions(+), 3 deletions(-)
-
-diff --git a/src/Kconfig b/src/Kconfig
-index b85e381..5d5da98 100644
---- a/src/Kconfig
-+++ b/src/Kconfig
-@@ -455,6 +455,10 @@ config HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
-       bool
-       default n
- 
-+config HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK
-+      bool
-+      default n
-+
- config HAVE_MONOTONIC_TIMER
-       def_bool n
-       help
-diff --git a/src/arch/x86/include/arch/smp/spinlock.h 
b/src/arch/x86/include/arch/smp/spinlock.h
-index cf142a9..291c943 100644
---- a/src/arch/x86/include/arch/smp/spinlock.h
-+++ b/src/arch/x86/include/arch/smp/spinlock.h
-@@ -1,7 +1,10 @@
- #ifndef ARCH_SMP_SPINLOCK_H
- #define ARCH_SMP_SPINLOCK_H
- 
--#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK) 
|| defined(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
-+#if !defined(__PRE_RAM__) \
-+      || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)       \
-+      || defined(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)    \
-+      || defined(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
- 
- /*
-  * Your basic SMP spinlocks, allowing only a single CPU anywhere
-@@ -16,6 +19,8 @@ spinlock_t* romstage_console_lock(void);
- void initialize_romstage_console_lock(void);
- spinlock_t* romstage_nvram_cbfs_lock(void);
- void initialize_romstage_nvram_cbfs_lock(void);
-+spinlock_t* romstage_microcode_cbfs_lock(void);
-+void initialize_romstage_microcode_cbfs_lock(void);
- #endif
- 
- #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
-diff --git a/src/cpu/amd/microcode/microcode.c 
b/src/cpu/amd/microcode/microcode.c
-index badd3b7..bf644ab 100644
---- a/src/cpu/amd/microcode/microcode.c
-+++ b/src/cpu/amd/microcode/microcode.c
-@@ -25,6 +25,12 @@
- #include <cbfs.h>
- #include <arch/io.h>
- 
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
-+#include <smp/spinlock.h>
-+#endif
-+#endif
-+
- #define UCODE_DEBUG(fmt, args...)     \
-       do { printk(BIOS_DEBUG, "[microcode] "fmt, ##args); } while(0)
- 
-@@ -201,14 +207,30 @@ void amd_update_microcode_from_cbfs(uint32_t 
equivalent_processor_rev_id)
-                       return;
-               }
- 
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
-+              spin_lock(romstage_microcode_cbfs_lock());
-+#endif
-+#endif
-+
-               ucode = cbfs_boot_map_with_leak(microcode_cbfs_file[i],
-                                               CBFS_TYPE_MICROCODE, 
&ucode_len);
-               if (!ucode) {
-                       UCODE_DEBUG("microcode file not found. Skipping 
updates.\n");
--
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
-+                      spin_unlock(romstage_microcode_cbfs_lock());
-+#endif
-+#endif
-                       return;
-               }
- 
-               amd_update_microcode(ucode, ucode_len, 
equivalent_processor_rev_id);
-+
-+#ifdef __PRE_RAM__
-+#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
-+              spin_unlock(romstage_microcode_cbfs_lock());
-+#endif
-+#endif
-       }
- }
-diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
-index a9261f9..ff9afd3 100644
---- a/src/mainboard/asus/kgpe-d16/Kconfig
-+++ b/src/mainboard/asus/kgpe-d16/Kconfig
-@@ -16,6 +16,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
-       select PARALLEL_CPU_INIT
-       select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
-       select HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
-+      select HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK
-       select HAVE_HARD_RESET
-       select HAVE_OPTION_TABLE
-       select HAVE_CMOS_DEFAULT
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index 9998359..d1b75b6 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -327,6 +327,18 @@ void initialize_romstage_nvram_cbfs_lock(void)
-       car_get_var(nvram_cbfs_spinlock) = SPIN_LOCK_UNLOCKED;
- }
- 
-+static spinlock_t microcode_cbfs_spinlock CAR_GLOBAL;
-+
-+spinlock_t* romstage_microcode_cbfs_lock(void)
-+{
-+      return car_get_var_ptr(&microcode_cbfs_spinlock);
-+}
-+
-+void initialize_romstage_microcode_cbfs_lock(void)
-+{
-+      car_get_var(microcode_cbfs_spinlock) = SPIN_LOCK_UNLOCKED;
-+}
-+
- void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
- {
-       uint32_t esp;
-@@ -348,9 +360,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
-               timestamp_init(timestamp_get());
-               timestamp_add_now(TS_START_ROMSTAGE);
- 
--              /* Initialize the printk and nvram CBFS spinlocks */
-+              /* Initialize the printk, nvram CBFS, and microcode CBFS 
spinlocks */
-               initialize_romstage_console_lock();
-               initialize_romstage_nvram_cbfs_lock();
-+              initialize_romstage_microcode_cbfs_lock();
- 
-               /* Nothing special needs to be done to find bus 0 */
-               /* Allow the HT devices to be found */
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0130-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
 
b/resources/libreboot/patch/kgpe-d16/0130-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
new file mode 100644
index 0000000..b85f17f
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0130-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch
@@ -0,0 +1,175 @@
+From 73800f43dd3190d18488720410c73f2a4769d82d Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 28 Aug 2015 19:52:05 -0500
+Subject: [PATCH 130/143] drivers/pc80: Add optional spinlock for nvram CBFS
+ access
+
+When enabling the IOMMU on certain systems dmesg is spammed with I/O page 
faults like the following:
+AMD-Vi: Event logged [IO_PAGE_FAULT device=00:14.0 domain=0x000a 
address=0x000000fdf9103300 flags=0x0030]
+
+Decoding the faulting address:
+0x000000fdf9103300
+        fdf91x          Hypertransport system management region
+              33        SysMgtCmd (System Management Command) = 0x33
+              3         Base Command Type = 0x3: STPCLK (Stop Clock request)
+               3        SMAF (System Management Action Field) = [3:1] = 0x1
+               1        Signal State Bit Map = [0] = 0x1
+
+Therefore, the error appears to be triggered by an upstream C1E request.
+
+This was eventually traced to concurrent access to the SP5100's SPI Flash 
controller by
+multiple APs during startup.  Calls to the nvram read functions get_option and 
read_option
+call CBFS functions, which in turn make near-simultaneous requests to the SPI 
Flash
+controller, thus placing the SP5100 in an invalid state.  This limitation is 
not documented
+in any public AMD errata, and was only discovered through considerable 
debugging effort.
+
+Change-Id: I4e61b1ab767b1b7958ac7c1cf20eee41d2261bef
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/Kconfig                              |    4 +++
+ src/arch/x86/include/arch/smp/spinlock.h |    4 ++-
+ src/cpu/amd/car/post_cache_as_ram.c      |    3 +++
+ src/drivers/pc80/mc146818rtc.c           |   43 ++++++++++++++++++++++++++++--
+ 4 files changed, 51 insertions(+), 3 deletions(-)
+
+diff --git a/src/Kconfig b/src/Kconfig
+index 5aa33d00..70f3cf2 100644
+--- a/src/Kconfig
++++ b/src/Kconfig
+@@ -450,6 +450,10 @@ config HAVE_ROMSTAGE_CONSOLE_SPINLOCK
+       bool
+       default n
+ 
++config HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
++      bool
++      default n
++
+ config HAVE_MONOTONIC_TIMER
+       def_bool n
+       help
+diff --git a/src/arch/x86/include/arch/smp/spinlock.h 
b/src/arch/x86/include/arch/smp/spinlock.h
+index 3283540..74f8ece 100644
+--- a/src/arch/x86/include/arch/smp/spinlock.h
++++ b/src/arch/x86/include/arch/smp/spinlock.h
+@@ -1,7 +1,7 @@
+ #ifndef ARCH_SMP_SPINLOCK_H
+ #define ARCH_SMP_SPINLOCK_H
+ 
+-#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
++#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK) 
|| defined(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
+ 
+ /*
+  * Your basic SMP spinlocks, allowing only a single CPU anywhere
+@@ -14,6 +14,8 @@ typedef struct {
+ #ifdef __PRE_RAM__
+ spinlock_t *romstage_console_lock(void);
+ void initialize_romstage_console_lock(void);
++spinlock_t* romstage_nvram_cbfs_lock(void);
++void initialize_romstage_nvram_cbfs_lock(void);
+ #endif
+ 
+ #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+diff --git a/src/cpu/amd/car/post_cache_as_ram.c 
b/src/cpu/amd/car/post_cache_as_ram.c
+index 2282cee..55bb1be 100644
+--- a/src/cpu/amd/car/post_cache_as_ram.c
++++ b/src/cpu/amd/car/post_cache_as_ram.c
+@@ -87,6 +87,9 @@ static void prepare_ramstage_region(void 
*resume_backup_memory)
+ #if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)
+       initialize_romstage_console_lock();
+ #endif
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++      initialize_romstage_nvram_cbfs_lock();
++#endif
+ 
+       print_car_debug("Done\n");
+ }
+diff --git a/src/drivers/pc80/mc146818rtc.c b/src/drivers/pc80/mc146818rtc.c
+index 07fc884..59de0a2 100644
+--- a/src/drivers/pc80/mc146818rtc.c
++++ b/src/drivers/pc80/mc146818rtc.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright 2014 The Chromium OS Authors. All rights reserved.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -37,6 +38,11 @@
+ #define LB_CKS_LOC            0
+ #endif
+ 
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++#include <smp/spinlock.h>
++#endif
++#endif
+ 
+ static void cmos_reset_date(void)
+ {
+@@ -208,6 +214,12 @@ enum cb_err get_option(void *dest, const char *name)
+       if (!IS_ENABLED(CONFIG_USE_OPTION_TABLE))
+               return CB_CMOS_OTABLE_DISABLED;
+ 
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++      spin_lock(romstage_nvram_cbfs_lock());
++#endif
++#endif
++
+       /* Figure out how long name is */
+       namelen = strnlen(name, CMOS_MAX_NAME_LENGTH);
+ 
+@@ -217,6 +229,11 @@ enum cb_err get_option(void *dest, const char *name)
+       if (!ct) {
+               printk(BIOS_ERR, "RTC: cmos_layout.bin could not be found. "
+                                               "Options are disabled\n");
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++              spin_unlock(romstage_nvram_cbfs_lock());
++#endif
++#endif
+               return CB_CMOS_LAYOUT_NOT_FOUND;
+       }
+       ce = (struct cmos_entries*)((unsigned char *)ct + ct->header_length);
+@@ -229,13 +246,35 @@ enum cb_err get_option(void *dest, const char *name)
+       }
+       if (!found) {
+               printk(BIOS_DEBUG, "WARNING: No CMOS option '%s'.\n", name);
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++              spin_unlock(romstage_nvram_cbfs_lock());
++#endif
++#endif
+               return CB_CMOS_OPTION_NOT_FOUND;
+       }
+ 
+-      if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS)
++      if (get_cmos_value(ce->bit, ce->length, dest) != CB_SUCCESS) {
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++              spin_unlock(romstage_nvram_cbfs_lock());
++#endif
++#endif
+               return CB_CMOS_ACCESS_ERROR;
+-      if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, 
LB_CKS_LOC))
++      }
++      if (!cmos_checksum_valid(LB_CKS_RANGE_START, LB_CKS_RANGE_END, 
LB_CKS_LOC)) {
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++              spin_unlock(romstage_nvram_cbfs_lock());
++#endif
++#endif
+               return CB_CMOS_CHECKSUM_INVALID;
++      }
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++      spin_unlock(romstage_nvram_cbfs_lock());
++#endif
++#endif
+       return CB_SUCCESS;
+ }
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
 
b/resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
new file mode 100644
index 0000000..48fcb00
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch
@@ -0,0 +1,61 @@
+From 3bae76eb132ce6b35542e7727397556b457d6d77 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 28 Aug 2015 20:02:45 -0500
+Subject: [PATCH 131/143] mainboard/asus/kgpe-d16: Enable CBFS spinlocks
+
+Change-Id: I8f6226d3e74ac5c7f29f708128a7502ced1287bf
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/Kconfig    |    1 +
+ src/mainboard/asus/kgpe-d16/romstage.c |   15 ++++++++++++++-
+ 2 files changed, 15 insertions(+), 1 deletion(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+index 084a412..a9261f9 100644
+--- a/src/mainboard/asus/kgpe-d16/Kconfig
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -15,6 +15,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+       select SUPERIO_NUVOTON_NCT5572D
+       select PARALLEL_CPU_INIT
+       select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
++      select HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
+       select HAVE_HARD_RESET
+       select HAVE_OPTION_TABLE
+       select HAVE_CMOS_DEFAULT
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index cbda9ca..9998359 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -315,6 +315,18 @@ void initialize_romstage_console_lock(void)
+       car_get_var(printk_spinlock) = SPIN_LOCK_UNLOCKED;
+ }
+ 
++static spinlock_t nvram_cbfs_spinlock CAR_GLOBAL;
++
++spinlock_t* romstage_nvram_cbfs_lock(void)
++{
++      return car_get_var_ptr(&nvram_cbfs_spinlock);
++}
++
++void initialize_romstage_nvram_cbfs_lock(void)
++{
++      car_get_var(nvram_cbfs_spinlock) = SPIN_LOCK_UNLOCKED;
++}
++
+ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
+ {
+       uint32_t esp;
+@@ -336,8 +348,9 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               timestamp_init(timestamp_get());
+               timestamp_add_now(TS_START_ROMSTAGE);
+ 
+-              /* Initialize the printk spinlock */
++              /* Initialize the printk and nvram CBFS spinlocks */
+               initialize_romstage_console_lock();
++              initialize_romstage_nvram_cbfs_lock();
+ 
+               /* Nothing special needs to be done to find bus 0 */
+               /* Allow the HT devices to be found */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
 
b/resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
deleted file mode 100644
index 72d834c..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
+++ /dev/null
@@ -1,41 +0,0 @@
-From a3c83c34f3871be5624259a8a5d76bbae0386720 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 3 Sep 2015 17:39:51 -0500
-Subject: [PATCH 131/139] mainboard/asus/kgpe-d16: Limit HT speed to 2.6GHz
-
-The CPU <--> CPU HT wiring on this board has only been validated
-to 2.6GHz.  While higher frequencies appear to function initially,
-and in fact function when only one CPU package is installed, dual
-CPU package systems will lock up after around 6 - 12 hours of uptime
-due to presumed HT link errors at the higher (>= 2.8GHz) HT clocks.
-
-If applications are not being used that stress the coherent fabric,
-then the uptime before hang may be much longer.  Users attempting
-to overclock the HT links are advised to "burn in test" the HT links
-by running memtester locked to a node with no local memory installed.
-
-Change-Id: I8fae90c67aa0e8b103e9b8906dea50d1e92ea5a9
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/romstage.c | 5 +++++
- 1 file changed, 5 insertions(+)
-
-diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
-index d1b75b6..8f1ec35 100644
---- a/src/mainboard/asus/kgpe-d16/romstage.c
-+++ b/src/mainboard/asus/kgpe-d16/romstage.c
-@@ -349,6 +349,11 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
- 
-       struct sys_info *sysinfo = &sysinfo_car;
- 
-+      /* Limit the maximum HT speed to 2.6GHz to prevent lockups
-+       * due to HT CPU <--> CPU wiring not being validated to 3.2GHz
-+       */
-+      sysinfo->ht_link_cfg.ht_speed_limit = 2600;
-+
-       uint32_t bsp_apicid = 0, val;
-       uint8_t byte;
-       msr_t msr;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0132-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0132-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
deleted file mode 100644
index 126e45a..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0132-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
+++ /dev/null
@@ -1,70 +0,0 @@
-From 4dede601a2017d8a9696f8f2013a9b2b97d5169e Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 3 Sep 2015 17:43:52 -0500
-Subject: [PATCH 132/139] cpu/amd/family_10h-family_15h: Apply missing Family
- 15h errata fixes
-
-Change-Id: I132874fe5b5a8b9a87422e2f07bff03bc5863ca4
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h | 12 ++++++++++++
- src/northbridge/amd/amdfam10/misc_control.c  |  6 ++++++
- 2 files changed, 18 insertions(+)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index af59120..7a84fcb 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -166,6 +166,14 @@ static const struct {
-         0x0000000C, 0x00000000,
-         0x0000000C, 0x00000000},      /* Cx and Dx multiple-link processor */
- 
-+      { OSVW_ID_Length, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000005, 0x00000000,
-+        0x00000005, 0x00000000},      /* OSVW_ID_Length = 0x5 */
-+
-+      { OSVW_Status, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00000010, 0x00000000,
-+        0x00000010, 0x00000000},      /* OsvwId4 = 0x1 */
-+
-       { BU_CFG2, AMD_DR_Dx, AMD_PTYPE_ALL,
-         0x00000000, 1 << (50-32),
-         0x00000000, 1 << (50-32)},    /* D0 or Above, RdMmExtCfgQwEn*/
-@@ -638,6 +646,10 @@ static const struct {
-       { 3, 0x1b8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00001000, 0x00001000 },     /* [12] = L3PrivReplEn */
- 
-+      /* Errata 504 workaround */
-+      { 3, 0x1b8, AMD_FAM15_ALL, AMD_PTYPE_ALL,
-+        0x00040000, 0x00040000 },     /* [18] = 1b */
-+
-       /* IBS Control Register */
-       { 3, 0x1cc, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
-         0x00000100, 0x00000100 },     /* [8] = LvtOffsetVal */
-diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
-index 4b62c69..a3d6b19 100644
---- a/src/northbridge/amd/amdfam10/misc_control.c
-+++ b/src/northbridge/amd/amdfam10/misc_control.c
-@@ -79,6 +79,7 @@ static void mcf3_read_resources(device_t dev)
- 
- static void set_agp_aperture(device_t dev, uint32_t pci_id)
- {
-+      uint32_t dword;
-       struct resource *resource;
- 
-       resource = probe_resource(dev, 0x94);
-@@ -109,6 +110,11 @@ static void set_agp_aperture(device_t dev, uint32_t 
pci_id)
- 
-                       /* Report the resource has been stored... */
-                       report_resource_stored(pdev, resource, " <gart>");
-+
-+                      /* Errata 540 workaround */
-+                      dword = pci_read_config32(pdev, 0x90);
-+                      dword |= 0x1 << 6;                      /* 
DisGartTblWlkPrb = 0x1 */
-+                      pci_write_config32(pdev, 0x90, dword);
-               }
-       }
- }
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0132-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
 
b/resources/libreboot/patch/kgpe-d16/0132-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
new file mode 100644
index 0000000..2660565
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0132-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch
@@ -0,0 +1,155 @@
+From 150c1d37f6b42233ae47a9289563164b8685825a Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Fri, 28 Aug 2015 20:48:17 -0500
+Subject: [PATCH 132/143] cpu/amd/microcode: Introduce CBFS access spinlock to
+ avoid IOMMU failure
+
+Change-Id: Ib7e8cb171f44833167053ca98a85cca23021dfba
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/Kconfig                              |    4 ++++
+ src/arch/x86/include/arch/smp/spinlock.h |    7 ++++++-
+ src/cpu/amd/microcode/microcode.c        |   24 +++++++++++++++++++++++-
+ src/mainboard/asus/kgpe-d16/Kconfig      |    1 +
+ src/mainboard/asus/kgpe-d16/romstage.c   |   15 ++++++++++++++-
+ 5 files changed, 48 insertions(+), 3 deletions(-)
+
+diff --git a/src/Kconfig b/src/Kconfig
+index 70f3cf2..353eede 100644
+--- a/src/Kconfig
++++ b/src/Kconfig
+@@ -454,6 +454,10 @@ config HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
+       bool
+       default n
+ 
++config HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK
++      bool
++      default n
++
+ config HAVE_MONOTONIC_TIMER
+       def_bool n
+       help
+diff --git a/src/arch/x86/include/arch/smp/spinlock.h 
b/src/arch/x86/include/arch/smp/spinlock.h
+index 74f8ece..a9dcfcd 100644
+--- a/src/arch/x86/include/arch/smp/spinlock.h
++++ b/src/arch/x86/include/arch/smp/spinlock.h
+@@ -1,7 +1,10 @@
+ #ifndef ARCH_SMP_SPINLOCK_H
+ #define ARCH_SMP_SPINLOCK_H
+ 
+-#if !defined(__PRE_RAM__) || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK) 
|| defined(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)
++#if !defined(__PRE_RAM__) \
++      || defined(CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK)       \
++      || defined(CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK)    \
++      || defined(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
+ 
+ /*
+  * Your basic SMP spinlocks, allowing only a single CPU anywhere
+@@ -16,6 +19,8 @@ spinlock_t *romstage_console_lock(void);
+ void initialize_romstage_console_lock(void);
+ spinlock_t* romstage_nvram_cbfs_lock(void);
+ void initialize_romstage_nvram_cbfs_lock(void);
++spinlock_t* romstage_microcode_cbfs_lock(void);
++void initialize_romstage_microcode_cbfs_lock(void);
+ #endif
+ 
+ #define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+diff --git a/src/cpu/amd/microcode/microcode.c 
b/src/cpu/amd/microcode/microcode.c
+index badd3b7..bf644ab 100644
+--- a/src/cpu/amd/microcode/microcode.c
++++ b/src/cpu/amd/microcode/microcode.c
+@@ -25,6 +25,12 @@
+ #include <cbfs.h>
+ #include <arch/io.h>
+ 
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
++#include <smp/spinlock.h>
++#endif
++#endif
++
+ #define UCODE_DEBUG(fmt, args...)     \
+       do { printk(BIOS_DEBUG, "[microcode] "fmt, ##args); } while(0)
+ 
+@@ -201,14 +207,30 @@ void amd_update_microcode_from_cbfs(uint32_t 
equivalent_processor_rev_id)
+                       return;
+               }
+ 
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
++              spin_lock(romstage_microcode_cbfs_lock());
++#endif
++#endif
++
+               ucode = cbfs_boot_map_with_leak(microcode_cbfs_file[i],
+                                               CBFS_TYPE_MICROCODE, 
&ucode_len);
+               if (!ucode) {
+                       UCODE_DEBUG("microcode file not found. Skipping 
updates.\n");
+-
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
++                      spin_unlock(romstage_microcode_cbfs_lock());
++#endif
++#endif
+                       return;
+               }
+ 
+               amd_update_microcode(ucode, ucode_len, 
equivalent_processor_rev_id);
++
++#ifdef __PRE_RAM__
++#if IS_ENABLED(CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK)
++              spin_unlock(romstage_microcode_cbfs_lock());
++#endif
++#endif
+       }
+ }
+diff --git a/src/mainboard/asus/kgpe-d16/Kconfig 
b/src/mainboard/asus/kgpe-d16/Kconfig
+index a9261f9..ff9afd3 100644
+--- a/src/mainboard/asus/kgpe-d16/Kconfig
++++ b/src/mainboard/asus/kgpe-d16/Kconfig
+@@ -16,6 +16,7 @@ config BOARD_SPECIFIC_OPTIONS # dummy
+       select PARALLEL_CPU_INIT
+       select HAVE_ROMSTAGE_CONSOLE_SPINLOCK
+       select HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK
++      select HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK
+       select HAVE_HARD_RESET
+       select HAVE_OPTION_TABLE
+       select HAVE_CMOS_DEFAULT
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index 9998359..d1b75b6 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -327,6 +327,18 @@ void initialize_romstage_nvram_cbfs_lock(void)
+       car_get_var(nvram_cbfs_spinlock) = SPIN_LOCK_UNLOCKED;
+ }
+ 
++static spinlock_t microcode_cbfs_spinlock CAR_GLOBAL;
++
++spinlock_t* romstage_microcode_cbfs_lock(void)
++{
++      return car_get_var_ptr(&microcode_cbfs_spinlock);
++}
++
++void initialize_romstage_microcode_cbfs_lock(void)
++{
++      car_get_var(microcode_cbfs_spinlock) = SPIN_LOCK_UNLOCKED;
++}
++
+ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
+ {
+       uint32_t esp;
+@@ -348,9 +360,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+               timestamp_init(timestamp_get());
+               timestamp_add_now(TS_START_ROMSTAGE);
+ 
+-              /* Initialize the printk and nvram CBFS spinlocks */
++              /* Initialize the printk, nvram CBFS, and microcode CBFS 
spinlocks */
+               initialize_romstage_console_lock();
+               initialize_romstage_nvram_cbfs_lock();
++              initialize_romstage_microcode_cbfs_lock();
+ 
+               /* Nothing special needs to be done to find bus 0 */
+               /* Allow the HT devices to be found */
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0133-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
 
b/resources/libreboot/patch/kgpe-d16/0133-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
new file mode 100644
index 0000000..77982af
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0133-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch
@@ -0,0 +1,41 @@
+From b508ee385b1d1ce53d40d4ff46f3b642382906b8 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 3 Sep 2015 17:39:51 -0500
+Subject: [PATCH 133/143] mainboard/asus/kgpe-d16: Limit HT speed to 2.6GHz
+
+The CPU <--> CPU HT wiring on this board has only been validated
+to 2.6GHz.  While higher frequencies appear to function initially,
+and in fact function when only one CPU package is installed, dual
+CPU package systems will lock up after around 6 - 12 hours of uptime
+due to presumed HT link errors at the higher (>= 2.8GHz) HT clocks.
+
+If applications are not being used that stress the coherent fabric,
+then the uptime before hang may be much longer.  Users attempting
+to overclock the HT links are advised to "burn in test" the HT links
+by running memtester locked to a node with no local memory installed.
+
+Change-Id: I8fae90c67aa0e8b103e9b8906dea50d1e92ea5a9
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/romstage.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/mainboard/asus/kgpe-d16/romstage.c 
b/src/mainboard/asus/kgpe-d16/romstage.c
+index d1b75b6..8f1ec35 100644
+--- a/src/mainboard/asus/kgpe-d16/romstage.c
++++ b/src/mainboard/asus/kgpe-d16/romstage.c
+@@ -349,6 +349,11 @@ void cache_as_ram_main(unsigned long bist, unsigned long 
cpu_init_detectedx)
+ 
+       struct sys_info *sysinfo = &sysinfo_car;
+ 
++      /* Limit the maximum HT speed to 2.6GHz to prevent lockups
++       * due to HT CPU <--> CPU wiring not being validated to 3.2GHz
++       */
++      sysinfo->ht_link_cfg.ht_speed_limit = 2600;
++
+       uint32_t bsp_apicid = 0, val;
+       uint8_t byte;
+       msr_t msr;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0133-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
 
b/resources/libreboot/patch/kgpe-d16/0133-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
deleted file mode 100644
index 1993cab..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0133-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
+++ /dev/null
@@ -1,231 +0,0 @@
-From d73cea7b450c1da2d4cd4af9d28f3ea97fb40f9d Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 3 Sep 2015 18:59:53 -0500
-Subject: [PATCH 133/139] northbridge/amd/amdmct/mct_ddr3: Use StopOnError to
- decrease training time
-
-Change-Id: I979e27c32a3e0b101590fba0de3d7a25d6fc44d2
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 84 +++++++++++++++++++-------
- src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |  4 +-
- 2 files changed, 64 insertions(+), 24 deletions(-)
-
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-index 553a54a..f2a7681 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
-@@ -1121,7 +1121,7 @@ static void stop_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
- }
- 
- static void read_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
--                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane, uint8_t stop_on_error)
- {
-       uint32_t dword;
-       uint32_t dev = pDCTstat->dev_dct;
-@@ -1133,24 +1133,35 @@ static void 
read_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
-       if (lane < 4) {
-               Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
-               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       } else if (lane < 8) {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-+      } else if (lane == 8) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-+              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword &= ~(0xff);                       /* EccMask = 0x0 */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       } else if (lane == 0xff) {
-               Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
-               Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword &= ~(0xff);                       /* EccMask = 0x0 */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       } else {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       }
- 
--      dword = Get_NB32_DCT(dev, dct, 0x27c);
--      dword &= ~(0xff);                               /* EccMask = 0 */
--      if (lane != 0xff)
--              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
--                      dword |= 0xff;                  /* EccMask = 0xff */
--      Set_NB32_DCT(dev, dct, 0x27c, dword);
--
-       dword = Get_NB32_DCT(dev, dct, 0x270);
-       dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
- //    dword |= (0x55555);
-@@ -1182,7 +1193,8 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
- 
-       dword = Get_NB32_DCT(dev, dct, 0x250);
-       dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
--      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
-+      dword &= ~(0x1 << 4);                           /* StopOnErr = 
stop_on_error */
-+      dword |= (stop_on_error & 0x1) << 4;
-       dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
-       dword |= (0x1 << 8);
-       dword &= ~(0x7 << 5);                           /* CmdType = 0 (Read) */
-@@ -1202,7 +1214,7 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
- }
- 
- static void write_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
--                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
-+                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane, uint8_t stop_on_error)
- {
-       uint32_t dword;
-       uint32_t dev = pDCTstat->dev_dct;
-@@ -1214,24 +1226,35 @@ static void 
write_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
-       if (lane < 4) {
-               Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
-               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       } else if (lane < 8) {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-+      } else if (lane == 8) {
-+              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-+              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword &= ~(0xff);                       /* EccMask = 0x0 */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       } else if (lane == 0xff) {
-               Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
-               Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword &= ~(0xff);                       /* EccMask = 0x0 */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       } else {
-               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
-               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
-+              dword = Get_NB32_DCT(dev, dct, 0x27c);
-+              dword |= 0xff;                          /* EccMask = 0xff */
-+              Set_NB32_DCT(dev, dct, 0x27c, dword);
-       }
- 
--      dword = Get_NB32_DCT(dev, dct, 0x27c);
--      dword &= ~(0xff);                               /* EccMask = 0 */
--      if (lane != 0xff)
--              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
--                      dword |= 0xff;                  /* EccMask = 0xff */
--      Set_NB32_DCT(dev, dct, 0x27c, dword);
--
-       dword = Get_NB32_DCT(dev, dct, 0x270);
-       dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
- //    dword |= (0x55555);
-@@ -1263,7 +1286,8 @@ static void write_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
- 
-       dword = Get_NB32_DCT(dev, dct, 0x250);
-       dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
--      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
-+      dword &= ~(0x1 << 4);                           /* StopOnErr = 
stop_on_error */
-+      dword |= (stop_on_error & 0x1) << 4;
-       dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
-       dword |= (0x1 << 8);
-       dword &= ~(0x7 << 5);                           /* CmdType = 1 (Write) 
*/
-@@ -1297,6 +1321,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-       uint8_t dual_rank;
-       uint8_t write_iter;
-       uint8_t read_iter;
-+      uint8_t check_antiphase;
-       uint16_t initial_write_dqs_delay[MAX_BYTE_LANES];
-       uint16_t initial_read_dqs_delay[MAX_BYTE_LANES];
-       uint16_t initial_write_data_timing[MAX_BYTE_LANES];
-@@ -1378,7 +1403,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                               /* 2.10.5.8.4 (2 B)
-                                * Write the DRAM training pattern to the test 
address
-                                */
--                              write_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, dct, Receiver, lane);
-+                              write_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, dct, Receiver, lane, 0);
- 
-                               /* Read current settings of other (previously 
trained) lanes */
-                               
read_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
-@@ -1389,6 +1414,12 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                               for (current_read_dqs_delay[lane] = 0; 
current_read_dqs_delay[lane] < 0x40; current_read_dqs_delay[lane] += 2) {
-                                       
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 current_read_dqs_delay[lane] ", 
current_read_dqs_delay[lane], 6);
- 
-+                                      if ((current_read_dqs_delay[lane] >> 1) 
>= (32 - 16)) {
-+                                              check_antiphase = 1;
-+                                      } else {
-+                                              check_antiphase = 0;
-+                                      }
-+
-                                       /* 2.10.5.8.4 (2 A i)
-                                        * Commit the current Read DQS Timing 
Control settings to the hardware registers
-                                        */
-@@ -1397,7 +1428,16 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                                       /* 2.10.5.8.4 (2 A ii)
-                                        * Read the DRAM training pattern from 
the test address
-                                        */
--                                      
read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane);
-+                                      
read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane, 
((check_antiphase == 0)?1:0));
-+
-+                                      if (check_antiphase == 0) {
-+                                              /* Check for early abort before 
analyzing per-nibble status */
-+                                              dword = Get_NB32_DCT(dev, dct, 
0x264) & 0x1ffffff;
-+                                              if (dword != 0) {
-+                                                      
dqs_results_array[Receiver & 0x1][lane - 
lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 0;   
  /* Fail */
-+                                                      continue;
-+                                              }
-+                                      }
- 
-                                       /* 2.10.5.8.4 (2 A iii)
-                                        * Record pass / fail status
-@@ -1407,7 +1447,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-                                               dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 0;   
  /* Fail */
-                                       else
-                                               dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 1;   
  /* Pass */
--                                      if ((current_read_dqs_delay[lane] >> 1) 
>= (32 - 16)) {
-+                                      if (check_antiphase == 1) {
-                                               /* Check antiphase results */
-                                               dword = Get_NB32_DCT(dev, dct, 
0x26c) & 0x3ffff;
-                                               if (dword & (0x3 << (lane * 2)))
-@@ -1630,7 +1670,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
-       uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
-       uint8_t dqs_results_array[1024];
- 
--      uint16_t ren_step = 0x40;
-+      uint16_t ren_step = 0x40;
-       uint32_t index_reg = 0x98;
-       uint32_t dev = pDCTstat->dev_dct;
- 
-diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-index 3ede104..667854a 100644
---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
-@@ -1617,14 +1617,14 @@ static void dqsTrainMaxRdLatency_SW_Fam15(struct 
MCTStatStruc *pMCTstat,
-               /* 2.10.5.8.5.1.[2,3]
-                * Write the DRAM training pattern to the test address
-                */
--              write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, current_worst_case_total_delay_dimm << 1, 0xff);
-+              write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, current_worst_case_total_delay_dimm << 1, 0xff, 0);
- 
-               /* 2.10.5.8.5.1.4
-                * Incrementally test each MaxRdLatency candidate
-                */
-               for (; pDCTstat->CH_MaxRdLat[Channel] < 0x3ff; 
pDCTstat->CH_MaxRdLat[Channel]++) {
-                       write_max_read_latency_to_registers(pMCTstat, pDCTstat, 
Channel, pDCTstat->CH_MaxRdLat[Channel]);
--                      read_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff);
-+                      read_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff, 0);
-                       dword = Get_NB32_DCT(dev, Channel, 0x268) & 0x3ffff;
-                       if (!dword)
-                               break;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0134-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0134-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
new file mode 100644
index 0000000..c52d584
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0134-cpu-amd-family_10h-family_15h-Apply-missing-Family-1.patch
@@ -0,0 +1,70 @@
+From 448990c014328f7e6951e3ba1c4dfab25e35e9dd Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 3 Sep 2015 17:43:52 -0500
+Subject: [PATCH 134/143] cpu/amd/family_10h-family_15h: Apply missing Family
+ 15h errata fixes
+
+Change-Id: I132874fe5b5a8b9a87422e2f07bff03bc5863ca4
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h |   12 ++++++++++++
+ src/northbridge/amd/amdfam10/misc_control.c  |    6 ++++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index af59120..7a84fcb 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -166,6 +166,14 @@ static const struct {
+         0x0000000C, 0x00000000,
+         0x0000000C, 0x00000000},      /* Cx and Dx multiple-link processor */
+ 
++      { OSVW_ID_Length, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000005, 0x00000000,
++        0x00000005, 0x00000000},      /* OSVW_ID_Length = 0x5 */
++
++      { OSVW_Status, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00000010, 0x00000000,
++        0x00000010, 0x00000000},      /* OsvwId4 = 0x1 */
++
+       { BU_CFG2, AMD_DR_Dx, AMD_PTYPE_ALL,
+         0x00000000, 1 << (50-32),
+         0x00000000, 1 << (50-32)},    /* D0 or Above, RdMmExtCfgQwEn*/
+@@ -638,6 +646,10 @@ static const struct {
+       { 3, 0x1b8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00001000, 0x00001000 },     /* [12] = L3PrivReplEn */
+ 
++      /* Errata 504 workaround */
++      { 3, 0x1b8, AMD_FAM15_ALL, AMD_PTYPE_ALL,
++        0x00040000, 0x00040000 },     /* [18] = 1b */
++
+       /* IBS Control Register */
+       { 3, 0x1cc, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL,
+         0x00000100, 0x00000100 },     /* [8] = LvtOffsetVal */
+diff --git a/src/northbridge/amd/amdfam10/misc_control.c 
b/src/northbridge/amd/amdfam10/misc_control.c
+index 4b62c69..a3d6b19 100644
+--- a/src/northbridge/amd/amdfam10/misc_control.c
++++ b/src/northbridge/amd/amdfam10/misc_control.c
+@@ -79,6 +79,7 @@ static void mcf3_read_resources(device_t dev)
+ 
+ static void set_agp_aperture(device_t dev, uint32_t pci_id)
+ {
++      uint32_t dword;
+       struct resource *resource;
+ 
+       resource = probe_resource(dev, 0x94);
+@@ -109,6 +110,11 @@ static void set_agp_aperture(device_t dev, uint32_t 
pci_id)
+ 
+                       /* Report the resource has been stored... */
+                       report_resource_stored(pdev, resource, " <gart>");
++
++                      /* Errata 540 workaround */
++                      dword = pci_read_config32(pdev, 0x90);
++                      dword |= 0x1 << 6;                      /* 
DisGartTblWlkPrb = 0x1 */
++                      pci_write_config32(pdev, 0x90, dword);
+               }
+       }
+ }
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0134-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
 
b/resources/libreboot/patch/kgpe-d16/0134-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
deleted file mode 100644
index 22a0833..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0134-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From b83b06df45933d9b0ab3f8848bf940bbfd00be67 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Thu, 3 Sep 2015 19:27:40 -0500
-Subject: [PATCH 134/139] mainboard/asus/kgpe-d16: Enable GART by default
-
-Change-Id: I73eb2425bbdb7e329a544d55461877d1dee0d05b
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/mainboard/asus/kgpe-d16/cmos.default | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
-index 83c1fe8..bc4c332 100644
---- a/src/mainboard/asus/kgpe-d16/cmos.default
-+++ b/src/mainboard/asus/kgpe-d16/cmos.default
-@@ -23,7 +23,7 @@ maximum_p_state_limit = 0xf
- probe_filter = Auto
- l3_cache_partitioning = Disable
- ieee1394 = Enable
--gart = Disable
-+gart = Enable
- experimental_memory_speed_boost = Disable
- power_on_after_fail = On
- boot_option = Fallback
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
 
b/resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
deleted file mode 100644
index 5d18509..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 057d4bcc43dfb1eec7fcf53b955592fa30d47fec Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 7 Sep 2015 03:39:15 -0500
-Subject: [PATCH 135/139] northbridge/amd/amdfam10: Fix incorrect channel
- buffer count configuration
-
-Change-Id: If70825449f298aa66f7f8b76dbd7367455a6deb1
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdfam10/northbridge.c | 13 +++++--------
- 1 file changed, 5 insertions(+), 8 deletions(-)
-
-diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
-index 8bd664d..f039a5c 100644
---- a/src/northbridge/amd/amdfam10/northbridge.c
-+++ b/src/northbridge/amd/amdfam10/northbridge.c
-@@ -188,17 +188,14 @@ static void ht_route_link(struct bus *link, scan_state 
mode)
-        * not correctly configured
-        */
-       busses = pci_read_config32(link->dev, link->cap + 0x14);
--      busses &= 0xff000000;
-+      busses &= ~(0xff << 8);
-       busses |= parent->secondary & 0xff;
--      if (mode == HT_ROUTE_CLOSE) {
--              busses |= 0xfeff << 8;
--      } else if (mode == HT_ROUTE_SCAN) {
-+      if (mode == HT_ROUTE_CLOSE)
-+              busses |= 0xff << 8;
-+      else if (mode == HT_ROUTE_SCAN)
-               busses |= ((u32) link->secondary & 0xff) << 8;
--              busses |= 0xfc << 16;
--      } else if (mode == HT_ROUTE_FINAL) {
-+      else if (mode == HT_ROUTE_FINAL)
-               busses |= ((u32) link->secondary & 0xff) << 8;
--              busses |= ((u32) link->subordinate & 0xff) << 16;
--      }
-       pci_write_config32(link->dev, link->cap + 0x14, busses);
- 
-       if (mode == HT_ROUTE_FINAL) {
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
 
b/resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
new file mode 100644
index 0000000..b946b42
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch
@@ -0,0 +1,231 @@
+From be23a938df377710e927fa920a656a70409139b4 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 3 Sep 2015 18:59:53 -0500
+Subject: [PATCH 135/143] northbridge/amd/amdmct/mct_ddr3: Use StopOnError to
+ decrease training time
+
+Change-Id: I979e27c32a3e0b101590fba0de3d7a25d6fc44d2
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |   84 +++++++++++++++++-------
+ src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c   |    4 +-
+ 2 files changed, 64 insertions(+), 24 deletions(-)
+
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+index 553a54a..f2a7681 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+@@ -1121,7 +1121,7 @@ static void stop_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+ }
+ 
+ static void read_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
+-                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane, uint8_t stop_on_error)
+ {
+       uint32_t dword;
+       uint32_t dev = pDCTstat->dev_dct;
+@@ -1133,24 +1133,35 @@ static void 
read_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
+       if (lane < 4) {
+               Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
+               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword |= 0xff;                          /* EccMask = 0xff */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       } else if (lane < 8) {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword |= 0xff;                          /* EccMask = 0xff */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
++      } else if (lane == 8) {
++              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
++              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword &= ~(0xff);                       /* EccMask = 0x0 */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       } else if (lane == 0xff) {
+               Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
+               Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword &= ~(0xff);                       /* EccMask = 0x0 */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       } else {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword |= 0xff;                          /* EccMask = 0xff */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       }
+ 
+-      dword = Get_NB32_DCT(dev, dct, 0x27c);
+-      dword &= ~(0xff);                               /* EccMask = 0 */
+-      if (lane != 0xff)
+-              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
+-                      dword |= 0xff;                  /* EccMask = 0xff */
+-      Set_NB32_DCT(dev, dct, 0x27c, dword);
+-
+       dword = Get_NB32_DCT(dev, dct, 0x270);
+       dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
+ //    dword |= (0x55555);
+@@ -1182,7 +1193,8 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+ 
+       dword = Get_NB32_DCT(dev, dct, 0x250);
+       dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
+-      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
++      dword &= ~(0x1 << 4);                           /* StopOnErr = 
stop_on_error */
++      dword |= (stop_on_error & 0x1) << 4;
+       dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
+       dword |= (0x1 << 8);
+       dword &= ~(0x7 << 5);                           /* CmdType = 0 (Read) */
+@@ -1202,7 +1214,7 @@ static void read_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+ }
+ 
+ static void write_dram_dqs_training_pattern_fam15(struct MCTStatStruc 
*pMCTstat,
+-                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane)
++                              struct DCTStatStruc *pDCTstat, uint8_t dct, 
uint8_t Receiver, uint8_t lane, uint8_t stop_on_error)
+ {
+       uint32_t dword;
+       uint32_t dev = pDCTstat->dev_dct;
+@@ -1214,24 +1226,35 @@ static void 
write_dram_dqs_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
+       if (lane < 4) {
+               Set_NB32_DCT(dev, dct, 0x274, ~(0xff << (lane * 8)));
+               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword |= 0xff;                          /* EccMask = 0xff */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       } else if (lane < 8) {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~(0xff << (lane * 8)));
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword |= 0xff;                          /* EccMask = 0xff */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
++      } else if (lane == 8) {
++              Set_NB32_DCT(dev, dct, 0x274, ~0x0);
++              Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword &= ~(0xff);                       /* EccMask = 0x0 */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       } else if (lane == 0xff) {
+               Set_NB32_DCT(dev, dct, 0x274, ~0xffffffff);
+               Set_NB32_DCT(dev, dct, 0x278, ~0xffffffff);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword &= ~(0xff);                       /* EccMask = 0x0 */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       } else {
+               Set_NB32_DCT(dev, dct, 0x274, ~0x0);
+               Set_NB32_DCT(dev, dct, 0x278, ~0x0);
++              dword = Get_NB32_DCT(dev, dct, 0x27c);
++              dword |= 0xff;                          /* EccMask = 0xff */
++              Set_NB32_DCT(dev, dct, 0x27c, dword);
+       }
+ 
+-      dword = Get_NB32_DCT(dev, dct, 0x27c);
+-      dword &= ~(0xff);                               /* EccMask = 0 */
+-      if (lane != 0xff)
+-              if ((lane != 8) || (pDCTstat->DimmECCPresent == 0))
+-                      dword |= 0xff;                  /* EccMask = 0xff */
+-      Set_NB32_DCT(dev, dct, 0x27c, dword);
+-
+       dword = Get_NB32_DCT(dev, dct, 0x270);
+       dword &= ~(0x7ffff);                            /* DataPrbsSeed = 55555 
*/
+ //    dword |= (0x55555);
+@@ -1263,7 +1286,8 @@ static void write_dram_dqs_training_pattern_fam15(struct 
MCTStatStruc *pMCTstat,
+ 
+       dword = Get_NB32_DCT(dev, dct, 0x250);
+       dword |= (0x1 << 3);                            /* ResetAllErr = 1 */
+-      dword &= ~(0x1 << 4);                           /* StopOnErr = 0 */
++      dword &= ~(0x1 << 4);                           /* StopOnErr = 
stop_on_error */
++      dword |= (stop_on_error & 0x1) << 4;
+       dword &= ~(0x3 << 8);                           /* CmdTgt = 1 
(Alternate between Target A and Target B) */
+       dword |= (0x1 << 8);
+       dword &= ~(0x7 << 5);                           /* CmdType = 1 (Write) 
*/
+@@ -1297,6 +1321,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+       uint8_t dual_rank;
+       uint8_t write_iter;
+       uint8_t read_iter;
++      uint8_t check_antiphase;
+       uint16_t initial_write_dqs_delay[MAX_BYTE_LANES];
+       uint16_t initial_read_dqs_delay[MAX_BYTE_LANES];
+       uint16_t initial_write_data_timing[MAX_BYTE_LANES];
+@@ -1378,7 +1403,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                               /* 2.10.5.8.4 (2 B)
+                                * Write the DRAM training pattern to the test 
address
+                                */
+-                              write_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, dct, Receiver, lane);
++                              write_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, dct, Receiver, lane, 0);
+ 
+                               /* Read current settings of other (previously 
trained) lanes */
+                               
read_dqs_read_data_timing_registers(current_read_dqs_delay, dev, dct, dimm, 
index_reg);
+@@ -1389,6 +1414,12 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                               for (current_read_dqs_delay[lane] = 0; 
current_read_dqs_delay[lane] < 0x40; current_read_dqs_delay[lane] += 2) {
+                                       
print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 current_read_dqs_delay[lane] ", 
current_read_dqs_delay[lane], 6);
+ 
++                                      if ((current_read_dqs_delay[lane] >> 1) 
>= (32 - 16)) {
++                                              check_antiphase = 1;
++                                      } else {
++                                              check_antiphase = 0;
++                                      }
++
+                                       /* 2.10.5.8.4 (2 A i)
+                                        * Commit the current Read DQS Timing 
Control settings to the hardware registers
+                                        */
+@@ -1397,7 +1428,16 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                                       /* 2.10.5.8.4 (2 A ii)
+                                        * Read the DRAM training pattern from 
the test address
+                                        */
+-                                      
read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane);
++                                      
read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, dct, Receiver, lane, 
((check_antiphase == 0)?1:0));
++
++                                      if (check_antiphase == 0) {
++                                              /* Check for early abort before 
analyzing per-nibble status */
++                                              dword = Get_NB32_DCT(dev, dct, 
0x264) & 0x1ffffff;
++                                              if (dword != 0) {
++                                                      
dqs_results_array[Receiver & 0x1][lane - 
lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 0;   
  /* Fail */
++                                                      continue;
++                                              }
++                                      }
+ 
+                                       /* 2.10.5.8.4 (2 A iii)
+                                        * Record pass / fail status
+@@ -1407,7 +1447,7 @@ static uint8_t TrainDQSRdWrPos_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+                                               dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 0;   
  /* Fail */
+                                       else
+                                               dqs_results_array[Receiver & 
0x1][lane - lane_start][current_write_data_delay[lane] - 
initial_write_dqs_delay[lane]][(current_read_dqs_delay[lane] >> 1) + 16] = 1;   
  /* Pass */
+-                                      if ((current_read_dqs_delay[lane] >> 1) 
>= (32 - 16)) {
++                                      if (check_antiphase == 1) {
+                                               /* Check antiphase results */
+                                               dword = Get_NB32_DCT(dev, dct, 
0x26c) & 0x3ffff;
+                                               if (dword & (0x3 << (lane * 2)))
+@@ -1630,7 +1670,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct 
MCTStatStruc *pMCTstat,
+       uint16_t current_phy_phase_delay[MAX_BYTE_LANES];
+       uint8_t dqs_results_array[1024];
+ 
+-      uint16_t ren_step = 0x40;
++      uint16_t ren_step = 0x40;
+       uint32_t index_reg = 0x98;
+       uint32_t dev = pDCTstat->dev_dct;
+ 
+diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c 
b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+index 3ede104..667854a 100644
+--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
++++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+@@ -1617,14 +1617,14 @@ static void dqsTrainMaxRdLatency_SW_Fam15(struct 
MCTStatStruc *pMCTstat,
+               /* 2.10.5.8.5.1.[2,3]
+                * Write the DRAM training pattern to the test address
+                */
+-              write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, current_worst_case_total_delay_dimm << 1, 0xff);
++              write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, 
Channel, current_worst_case_total_delay_dimm << 1, 0xff, 0);
+ 
+               /* 2.10.5.8.5.1.4
+                * Incrementally test each MaxRdLatency candidate
+                */
+               for (; pDCTstat->CH_MaxRdLat[Channel] < 0x3ff; 
pDCTstat->CH_MaxRdLat[Channel]++) {
+                       write_max_read_latency_to_registers(pMCTstat, pDCTstat, 
Channel, pDCTstat->CH_MaxRdLat[Channel]);
+-                      read_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff);
++                      read_dram_dqs_training_pattern_fam15(pMCTstat, 
pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff, 0);
+                       dword = Get_NB32_DCT(dev, Channel, 0x268) & 0x3ffff;
+                       if (!dword)
+                               break;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0136-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
 
b/resources/libreboot/patch/kgpe-d16/0136-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
deleted file mode 100644
index 0f4e5ed..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0136-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-From 587ece004106252847b7d08bf3c21c86c8b2e360 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 7 Sep 2015 18:07:03 -0500
-Subject: [PATCH 136/139] cpu/amd/family_10h-family_15h: Force iolink detect to
- either 1 or 0
-
-Change-Id: Ifd8f5f1ab28588d100e9e4b1fb0ec2525ad2f552
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index 7a0701c..ff9a033 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -1239,7 +1239,7 @@ static void cpuSetAMDPCI(u8 node)
-               for (link = 0; link < 4; link++) {
-                       if (AMD_CpuFindCapability(node, link, &offset)) {
-                               ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
--                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
-+                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
- 
-                               if (!iolink && ganged) {
-                                       if (probe_filter_enabled) {
-@@ -1391,7 +1391,7 @@ static void cpuSetAMDPCI(u8 node)
-               for (link = 0; link < 4; link++) {
-                       if (AMD_CpuFindCapability(node, link, &offset)) {
-                               ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
--                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
-+                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
- 
-                               /* Set defaults */
-                               isoc_rsp_tok_1 = 0;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0136-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
 
b/resources/libreboot/patch/kgpe-d16/0136-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
new file mode 100644
index 0000000..59ce417
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0136-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch
@@ -0,0 +1,27 @@
+From 2170a443bd2ca52ffcc4fa596e0a9c81400b112b Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 3 Sep 2015 19:27:40 -0500
+Subject: [PATCH 136/143] mainboard/asus/kgpe-d16: Enable GART by default
+
+Change-Id: I73eb2425bbdb7e329a544d55461877d1dee0d05b
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/mainboard/asus/kgpe-d16/cmos.default |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/mainboard/asus/kgpe-d16/cmos.default 
b/src/mainboard/asus/kgpe-d16/cmos.default
+index 83c1fe8..bc4c332 100644
+--- a/src/mainboard/asus/kgpe-d16/cmos.default
++++ b/src/mainboard/asus/kgpe-d16/cmos.default
+@@ -23,7 +23,7 @@ maximum_p_state_limit = 0xf
+ probe_filter = Auto
+ l3_cache_partitioning = Disable
+ ieee1394 = Enable
+-gart = Disable
++gart = Enable
+ experimental_memory_speed_boost = Disable
+ power_on_after_fail = On
+ boot_option = Fallback
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
 
b/resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
new file mode 100644
index 0000000..7f99cf9
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch
@@ -0,0 +1,42 @@
+From 442e3d1282adc8b6fa274e880578f8bb0bfd1464 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 7 Sep 2015 03:39:15 -0500
+Subject: [PATCH 137/143] northbridge/amd/amdfam10: Fix incorrect channel
+ buffer count configuration
+
+Change-Id: If70825449f298aa66f7f8b76dbd7367455a6deb1
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdfam10/northbridge.c |   13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/src/northbridge/amd/amdfam10/northbridge.c 
b/src/northbridge/amd/amdfam10/northbridge.c
+index 433a21c..b4bbf23 100644
+--- a/src/northbridge/amd/amdfam10/northbridge.c
++++ b/src/northbridge/amd/amdfam10/northbridge.c
+@@ -188,17 +188,14 @@ static void ht_route_link(struct bus *link, scan_state 
mode)
+        * not correctly configured
+        */
+       busses = pci_read_config32(link->dev, link->cap + 0x14);
+-      busses &= 0xff000000;
++      busses &= ~(0xff << 8);
+       busses |= parent->secondary & 0xff;
+-      if (mode == HT_ROUTE_CLOSE) {
+-              busses |= 0xfeff << 8;
+-      } else if (mode == HT_ROUTE_SCAN) {
++      if (mode == HT_ROUTE_CLOSE)
++              busses |= 0xff << 8;
++      else if (mode == HT_ROUTE_SCAN)
+               busses |= ((u32) link->secondary & 0xff) << 8;
+-              busses |= 0xfc << 16;
+-      } else if (mode == HT_ROUTE_FINAL) {
++      else if (mode == HT_ROUTE_FINAL)
+               busses |= ((u32) link->secondary & 0xff) << 8;
+-              busses |= ((u32) link->subordinate & 0xff) << 16;
+-      }
+       pci_write_config32(link->dev, link->cap + 0x14, busses);
+ 
+       if (mode == HT_ROUTE_FINAL) {
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
 
b/resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
deleted file mode 100644
index bb4ff3b..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
+++ /dev/null
@@ -1,144 +0,0 @@
-From 21df09828beb3385b1fe1eaa763578780e444b77 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 7 Sep 2015 18:07:43 -0500
-Subject: [PATCH 137/139] northbridge/amd/amdht: Fix XCS buffer count setup on
- AMD Family 15h CPUs
-
-Change-Id: Ie4bc8b3ea6b110bc507beda025de53d828118f55
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/northbridge/amd/amdht/h3ncmn.c | 94 +++++++++++++++++++++++++++++++++++++-
- 1 file changed, 92 insertions(+), 2 deletions(-)
-
-diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
-index 841fc0c..80fe7ce 100644
---- a/src/northbridge/amd/amdht/h3ncmn.c
-+++ b/src/northbridge/amd/amdht/h3ncmn.c
-@@ -2,6 +2,7 @@
-  * This file is part of the coreboot project.
-  *
-  * Copyright (C) 2007 Advanced Micro Devices, Inc.
-+ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
-  *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License as published by
-@@ -1393,6 +1394,75 @@ static uint32_t fam10NorthBridgeFreqMask(u8 node, 
cNorthBridge *nb)
- 
- 
/***************************************************************************//**
-  *
-+ * static u16
-+ * fam15NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
-+ *
-+ *  Description:
-+ *    Return a mask that eliminates HT frequencies that cannot be used due to 
a slow
-+ *    northbridge frequency.
-+ *
-+ *  Parameters:
-+ *    @param[in]  node     = Result could (later) be for a specific node
-+ *    @param[in]  *nb      = this northbridge
-+ *    @return  = Frequency mask
-+ *
-+ 
******************************************************************************/
-+static uint32_t fam15NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
-+{
-+      u8 nbCOF;
-+      uint32_t supported;
-+
-+      nbCOF = getMinNbCOF();
-+      /*
-+       * nbCOF is minimum northbridge speed in hundreds of MHz.
-+       * HT can not go faster than the minimum speed of the northbridge.
-+       */
-+      if ((nbCOF >= 6) && (nbCOF < 10))
-+      {
-+              /* Generation 1 HT link frequency */
-+              /* Convert frequency to bit and all less significant bits,
-+               * by setting next power of 2 and subtracting 1.
-+               */
-+              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
-+      }
-+      else if ((nbCOF >= 10) && (nbCOF <= 32))
-+      {
-+              /* Generation 3 HT link frequency
-+               * Assume error retry is enabled on all Gen 3 links
-+               */
-+              nbCOF *= 2;
-+              if (nbCOF > 32)
-+                      nbCOF = 32;
-+
-+              /* Convert frequency to bit and all less significant bits,
-+               * by setting next power of 2 and subtracting 1.
-+               */
-+              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
-+      }
-+      else if (nbCOF > 32)
-+      {
-+              supported = HT_FREQUENCY_LIMIT_3200M;
-+      }
-+      /* unlikely cases, but include as a defensive measure, also avoid trick 
above */
-+      else if (nbCOF == 4)
-+      {
-+              supported = HT_FREQUENCY_LIMIT_400M;
-+      }
-+      else if (nbCOF == 2)
-+      {
-+              supported = HT_FREQUENCY_LIMIT_200M;
-+      }
-+      else
-+      {
-+              STOP_HERE;
-+              supported = HT_FREQUENCY_LIMIT_200M;
-+      }
-+
-+      return (fixEarlySampleFreqCapability(supported));
-+}
-+
-+/***************************************************************************//**
-+ *
-  * static void
-  * gatherLinkData(sMainData *pDat, cNorthBridge *nb)
-  *
-@@ -2266,6 +2336,26 @@ static void fam10BufferOptimizations(u8 node, sMainData 
*pDat, cNorthBridge *nb)
-       }
- }
- 
-+/***************************************************************************//**
-+ *
-+ * static void
-+ * fam15BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
-+ *
-+ *  Description:
-+ *     Buffer tunings are inherently northbridge specific. Check for specific 
configs
-+ *     which require adjustments and apply any standard workarounds to this 
node.
-+ *
-+ *  Parameters:
-+ *    @param[in] node       = the node to tune
-+ *    @param[in] *pDat  = global state
-+ *    @param[in] nb = this northbridge
-+ *
-+ 
******************************************************************************/
-+static void fam15BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge 
*nb)
-+{
-+      /* Buffer count setup on Family 15h is currently handled in 
cpuSetAMDPCI */
-+}
-+
- /*
-  * North Bridge 'constructor'.
-  *
-@@ -2324,11 +2414,11 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
-               ht3SetCFGAddrMap,
-               convertBitsToWidth,
-               convertWidthToBits,
--              fam10NorthBridgeFreqMask,
-+              fam15NorthBridgeFreqMask,
-               gatherLinkData,
-               setLinkData,
-               ht3WriteTrafficDistribution,
--              fam10BufferOptimizations,
-+              fam15BufferOptimizations,
-               0x00000001,
-               0x00000200,
-               18,
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
 
b/resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
deleted file mode 100644
index 18c1420..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
+++ /dev/null
@@ -1,158 +0,0 @@
-From d08d31fc7f2299fc6c12be09061c62170615d160 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Mon, 7 Sep 2015 22:26:55 -0500
-Subject: [PATCH 138/139] cpu/amd/family_10h-family_15h: Fix link type
- detection and XCS buffer count setup
-
-Change-Id: If63dd97f070df4aab25a1e1a34df4b1112fff4b1
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/fidvid.c    |  2 +-
- src/cpu/amd/family_10h-family_15h/init_cpus.c | 33 +++++++++++++++------------
- 2 files changed, 20 insertions(+), 15 deletions(-)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
-index ed8cafa..84315b4 100644
---- a/src/cpu/amd/family_10h-family_15h/fidvid.c
-+++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
-@@ -379,7 +379,7 @@ static u32 nb_clk_did(int node, uint64_t cpuRev, uint8_t 
procPkg) {
-         u8 link0isGen3 = 0;
-         u8 offset;
-         if (AMD_CpuFindCapability(node, 0, &offset)) {
--        link0isGen3 = (AMD_checkLinkType(node, 0, offset) & 
HTPHY_LINKTYPE_HT3 );
-+        link0isGen3 = (AMD_checkLinkType(node, offset) & HTPHY_LINKTYPE_HT3 );
-       }
-         /* FIXME: NB_CLKDID should be 101b for AMD_DA_C2 in package
-            S1g3 in link Gen3 mode, but I don't know how to tell
-diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-index ff9a033..f86cc75 100644
---- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
-+++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
-@@ -845,7 +845,7 @@ static BOOL AMD_CpuFindCapability(u8 node, u8 cap_count, 
u8 * offset)
-  *
-  * Returns the link characteristic mask.
-  */
--static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
-+static u32 AMD_checkLinkType(u8 node, u8 regoff)
- {
-       uint32_t val;
-       uint32_t val2;
-@@ -876,7 +876,7 @@ static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
-                       linktype |= HTPHY_LINKTYPE_HT1;
- 
-               /* Check ganged */
--              val = pci_read_config32(NODE_PCI(node, 0), (link << 2) + 0x170);
-+              val = pci_read_config32(NODE_PCI(node, 0), (((regoff - 0x80) / 
0x20) << 2) + 0x170);
- 
-               if (val & 1)
-                       linktype |= HTPHY_LINKTYPE_GANGED;
-@@ -1119,7 +1119,7 @@ static void cpuSetAMDPCI(u8 node)
-                        */
-                       for (j = 0; j < 4; j++) {
-                               if (AMD_CpuFindCapability(node, j, &offset)) {
--                                      if (AMD_checkLinkType(node, j, offset)
-+                                      if (AMD_checkLinkType(node, offset)
-                                           & fam10_htphy_default[i].linktype) {
-                                               AMD_SetHtPhyRegister(node, j,
-                                                                    i);
-@@ -1217,6 +1217,7 @@ static void cpuSetAMDPCI(u8 node)
-               pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
- 
-               uint8_t link;
-+              uint8_t link_real;
-               uint8_t ganged;
-               uint8_t iolink;
-               uint8_t probe_filter_enabled = !!dual_node;
-@@ -1238,8 +1239,9 @@ static void cpuSetAMDPCI(u8 node)
- 
-               for (link = 0; link < 4; link++) {
-                       if (AMD_CpuFindCapability(node, link, &offset)) {
--                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
--                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
-+                              link_real = (offset - 0x80) / 0x20;
-+                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link_real << 2) + 0x170) & 0x1);
-+                              iolink = !!(AMD_checkLinkType(node, offset) & 
HTPHY_LINKTYPE_NONCOHERENT);
- 
-                               if (!iolink && ganged) {
-                                       if (probe_filter_enabled) {
-@@ -1335,7 +1337,7 @@ static void cpuSetAMDPCI(u8 node)
-                                       np_req_cmd = 12;
-                               }
- 
--                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x94);
-+                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x94);
-                               dword &= ~(0x3 << 27);                  /* 
IsocRspData = isoc_rsp_data */
-                               dword |= ((isoc_rsp_data & 0x3) << 27);
-                               dword &= ~(0x3 << 25);                  /* 
IsocNpReqData = isoc_np_req_data */
-@@ -1346,9 +1348,9 @@ static void cpuSetAMDPCI(u8 node)
-                               dword |= ((isoc_preq & 0x7) << 19);
-                               dword &= ~(0x7 << 16);                  /* 
IsocNpReqCmd = isoc_np_req_cmd */
-                               dword |= ((isoc_np_req_cmd & 0x7) << 16);
--                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x94, dword);
-+                              pci_write_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x94, dword);
- 
--                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x90);
-+                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x90);
-                               dword &= ~(0x1 << 31);                  /* 
LockBc = 0x1 */
-                               dword |= ((0x1 & 0x1) << 31);
-                               dword &= ~(0x7 << 25);                  /* 
FreeData = free_data */
-@@ -1367,7 +1369,7 @@ static void cpuSetAMDPCI(u8 node)
-                               dword |= ((preq & 0x7) << 5);
-                               dword &= ~(0x1f << 0);                  /* 
NpReqCmd = np_req_cmd */
-                               dword |= ((np_req_cmd & 0x1f) << 0);
--                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x90, dword);
-+                              pci_write_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x90, dword);
-                       }
-               }
- 
-@@ -1390,8 +1392,9 @@ static void cpuSetAMDPCI(u8 node)
- 
-               for (link = 0; link < 4; link++) {
-                       if (AMD_CpuFindCapability(node, link, &offset)) {
--                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
--                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
-+                              link_real = (offset - 0x80) / 0x20;
-+                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link_real << 2) + 0x170) & 0x1);
-+                              iolink = !!(AMD_checkLinkType(node, offset) & 
HTPHY_LINKTYPE_NONCOHERENT);
- 
-                               /* Set defaults */
-                               isoc_rsp_tok_1 = 0;
-@@ -1619,7 +1622,7 @@ static void cpuSetAMDPCI(u8 node)
-                                       }
-                               }
- 
--                              dword = pci_read_config32(NODE_PCI(node, 3), 
(link << 2) + 0x148);
-+                              dword = pci_read_config32(NODE_PCI(node, 3), 
(link_real << 2) + 0x148);
-                               dword &= ~(0x3 << 30);                  /* 
FreeTok[3:2] = free_tokens[3:2] */
-                               dword |= (((free_tokens >> 2) & 0x3) << 30);
-                               dword &= ~(0x1 << 28);                  /* 
IsocRspTok1 = isoc_rsp_tok_1 */
-@@ -1652,7 +1655,7 @@ static void cpuSetAMDPCI(u8 node)
-                               dword |= (((preq_tok_0) & 0x3) << 2);
-                               dword &= ~(0x3 << 0);                   /* 
ReqTok0 = req_tok_0 */
-                               dword |= (((req_tok_0) & 0x3) << 0);
--                              pci_write_config32(NODE_PCI(node, 3), (link << 
2) + 0x148, dword);
-+                              pci_write_config32(NODE_PCI(node, 3), 
(link_real << 2) + 0x148, dword);
-                       }
-               }
- 
-@@ -1698,6 +1701,7 @@ static void cpuSetAMDPCI(u8 node)
-       }
- 
-       uint8_t link;
-+      uint8_t link_real;
-       uint8_t isochronous;
-       uint8_t isochronous_link_present;
- 
-@@ -1705,7 +1709,8 @@ static void cpuSetAMDPCI(u8 node)
-       isochronous_link_present = 0;
-       for (link = 0; link < 4; link++) {
-               if (AMD_CpuFindCapability(node, link, &offset)) {
--                      isochronous = (pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x84) >> 12) & 0x1;
-+                      link_real = (offset - 0x80) / 0x20;
-+                      isochronous = (pci_read_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x84) >> 12) & 0x1;
- 
-                       if (isochronous)
-                               isochronous_link_present = 1;
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
 
b/resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
new file mode 100644
index 0000000..06c9be3
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0138-cpu-amd-family_10h-family_15h-Force-iolink-detect-to.patch
@@ -0,0 +1,37 @@
+From 56dd3cc28dd39ea689234513c8baeb568d8b40ea Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 7 Sep 2015 18:07:03 -0500
+Subject: [PATCH 138/143] cpu/amd/family_10h-family_15h: Force iolink detect
+ to either 1 or 0
+
+Change-Id: Ifd8f5f1ab28588d100e9e4b1fb0ec2525ad2f552
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index da6424f..a0c5f93 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -1239,7 +1239,7 @@ static void cpuSetAMDPCI(u8 node)
+               for (link = 0; link < 4; link++) {
+                       if (AMD_CpuFindCapability(node, link, &offset)) {
+                               ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
+-                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
++                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
+ 
+                               if (!iolink && ganged) {
+                                       if (probe_filter_enabled) {
+@@ -1391,7 +1391,7 @@ static void cpuSetAMDPCI(u8 node)
+               for (link = 0; link < 4; link++) {
+                       if (AMD_CpuFindCapability(node, link, &offset)) {
+                               ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
+-                              iolink = (AMD_checkLinkType(node, link, offset) 
& HTPHY_LINKTYPE_NONCOHERENT);
++                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
+ 
+                               /* Set defaults */
+                               isoc_rsp_tok_1 = 0;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0139-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0139-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
deleted file mode 100644
index da36ce8..0000000
--- 
a/resources/libreboot/patch/kgpe-d16/0139-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 43dd7e42cfd9e3af706dd28fc482921b54029496 Mon Sep 17 00:00:00 2001
-From: Timothy Pearson <address@hidden>
-Date: Sun, 13 Sep 2015 15:54:32 -0500
-Subject: [PATCH 139/139] cpu/amd/family_10h-family_15h: Enable DFE on Family
- 15h HT3 links
-
-Change-Id: I5e719984ddd723f9e375ff1a9d4fa1ef042cf3eb
-Signed-off-by: Timothy Pearson <address@hidden>
----
- src/cpu/amd/family_10h-family_15h/defaults.h | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
-index 7a84fcb..b906866 100644
---- a/src/cpu/amd/family_10h-family_15h/defaults.h
-+++ b/src/cpu/amd/family_10h-family_15h/defaults.h
-@@ -857,4 +857,12 @@ static const struct {
-       { 0xC0, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
-         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
-                                          [20:16] RttIndex = 04h */
-+
-+      { 0xc4, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+        0x00013480, 0x0003fc80 },     /* [17:10] DCV = 0x4d,
-+                                             [7] DfeEn = 0x1 */
-+
-+      { 0xd4, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
-+        0x00013480, 0x0003fc80 },     /* [17:10] DCV = 0x4d,
-+                                             [7] DfeEn = 0x1 */
- };
--- 
-1.9.1
-
diff --git 
a/resources/libreboot/patch/kgpe-d16/0139-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
 
b/resources/libreboot/patch/kgpe-d16/0139-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
new file mode 100644
index 0000000..aa57af9
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0139-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch
@@ -0,0 +1,144 @@
+From 01739baefdad1263adacb59442577941e037422f Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 7 Sep 2015 18:07:43 -0500
+Subject: [PATCH 139/143] northbridge/amd/amdht: Fix XCS buffer count setup on
+ AMD Family 15h CPUs
+
+Change-Id: Ie4bc8b3ea6b110bc507beda025de53d828118f55
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/northbridge/amd/amdht/h3ncmn.c |   94 +++++++++++++++++++++++++++++++++++-
+ 1 file changed, 92 insertions(+), 2 deletions(-)
+
+diff --git a/src/northbridge/amd/amdht/h3ncmn.c 
b/src/northbridge/amd/amdht/h3ncmn.c
+index 369ce3e..6c111c6 100644
+--- a/src/northbridge/amd/amdht/h3ncmn.c
++++ b/src/northbridge/amd/amdht/h3ncmn.c
+@@ -2,6 +2,7 @@
+  * This file is part of the coreboot project.
+  *
+  * Copyright (C) 2007 Advanced Micro Devices, Inc.
++ * Copyright (C) 2015 Timothy Pearson <address@hidden>, Raptor Engineering
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -1393,6 +1394,75 @@ static uint32_t fam10NorthBridgeFreqMask(u8 node, 
cNorthBridge *nb)
+ 
+ 
/***************************************************************************//**
+  *
++ * static u16
++ * fam15NorthBridgeFreqMask(u8 NodeID, cNorthBridge *nb)
++ *
++ *  Description:
++ *    Return a mask that eliminates HT frequencies that cannot be used due to 
a slow
++ *    northbridge frequency.
++ *
++ *  Parameters:
++ *    @param[in]  node     = Result could (later) be for a specific node
++ *    @param[in]  *nb      = this northbridge
++ *    @return  = Frequency mask
++ *
++ 
******************************************************************************/
++static uint32_t fam15NorthBridgeFreqMask(u8 node, cNorthBridge *nb)
++{
++      u8 nbCOF;
++      uint32_t supported;
++
++      nbCOF = getMinNbCOF();
++      /*
++       * nbCOF is minimum northbridge speed in hundreds of MHz.
++       * HT can not go faster than the minimum speed of the northbridge.
++       */
++      if ((nbCOF >= 6) && (nbCOF < 10))
++      {
++              /* Generation 1 HT link frequency */
++              /* Convert frequency to bit and all less significant bits,
++               * by setting next power of 2 and subtracting 1.
++               */
++              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
++      }
++      else if ((nbCOF >= 10) && (nbCOF <= 32))
++      {
++              /* Generation 3 HT link frequency
++               * Assume error retry is enabled on all Gen 3 links
++               */
++              nbCOF *= 2;
++              if (nbCOF > 32)
++                      nbCOF = 32;
++
++              /* Convert frequency to bit and all less significant bits,
++               * by setting next power of 2 and subtracting 1.
++               */
++              supported = ((uint32_t)1 << ((nbCOF >> 1) + 2)) - 1;
++      }
++      else if (nbCOF > 32)
++      {
++              supported = HT_FREQUENCY_LIMIT_3200M;
++      }
++      /* unlikely cases, but include as a defensive measure, also avoid trick 
above */
++      else if (nbCOF == 4)
++      {
++              supported = HT_FREQUENCY_LIMIT_400M;
++      }
++      else if (nbCOF == 2)
++      {
++              supported = HT_FREQUENCY_LIMIT_200M;
++      }
++      else
++      {
++              STOP_HERE;
++              supported = HT_FREQUENCY_LIMIT_200M;
++      }
++
++      return (fixEarlySampleFreqCapability(supported));
++}
++
++/***************************************************************************//**
++ *
+  * static void
+  * gatherLinkData(sMainData *pDat, cNorthBridge *nb)
+  *
+@@ -2270,6 +2340,26 @@ static void fam10BufferOptimizations(u8 node, sMainData 
*pDat, cNorthBridge *nb)
+       }
+ }
+ 
++/***************************************************************************//**
++ *
++ * static void
++ * fam15BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge *nb)
++ *
++ *  Description:
++ *     Buffer tunings are inherently northbridge specific. Check for specific 
configs
++ *     which require adjustments and apply any standard workarounds to this 
node.
++ *
++ *  Parameters:
++ *    @param[in] node       = the node to tune
++ *    @param[in] *pDat  = global state
++ *    @param[in] nb = this northbridge
++ *
++ 
******************************************************************************/
++static void fam15BufferOptimizations(u8 node, sMainData *pDat, cNorthBridge 
*nb)
++{
++      /* Buffer count setup on Family 15h is currently handled in 
cpuSetAMDPCI */
++}
++
+ /*
+  * North Bridge 'constructor'.
+  *
+@@ -2328,11 +2418,11 @@ void newNorthBridge(u8 node, cNorthBridge *nb)
+               ht3SetCFGAddrMap,
+               convertBitsToWidth,
+               convertWidthToBits,
+-              fam10NorthBridgeFreqMask,
++              fam15NorthBridgeFreqMask,
+               gatherLinkData,
+               setLinkData,
+               ht3WriteTrafficDistribution,
+-              fam10BufferOptimizations,
++              fam15BufferOptimizations,
+               0x00000001,
+               0x00000200,
+               18,
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0140-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
 
b/resources/libreboot/patch/kgpe-d16/0140-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
new file mode 100644
index 0000000..3cd24a1
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0140-cpu-amd-family_10h-family_15h-Fix-link-type-detectio.patch
@@ -0,0 +1,158 @@
+From 3e7456a5999ae840e95b054908057e19b40aaf40 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 7 Sep 2015 22:26:55 -0500
+Subject: [PATCH 140/143] cpu/amd/family_10h-family_15h: Fix link type
+ detection and XCS buffer count setup
+
+Change-Id: If63dd97f070df4aab25a1e1a34df4b1112fff4b1
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/fidvid.c    |    2 +-
+ src/cpu/amd/family_10h-family_15h/init_cpus.c |   33 ++++++++++++++-----------
+ 2 files changed, 20 insertions(+), 15 deletions(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c 
b/src/cpu/amd/family_10h-family_15h/fidvid.c
+index 7453ad4..f4ca888 100644
+--- a/src/cpu/amd/family_10h-family_15h/fidvid.c
++++ b/src/cpu/amd/family_10h-family_15h/fidvid.c
+@@ -379,7 +379,7 @@ static u32 nb_clk_did(int node, uint64_t cpuRev, uint8_t 
procPkg) {
+         u8 link0isGen3 = 0;
+         u8 offset;
+         if (AMD_CpuFindCapability(node, 0, &offset)) {
+-        link0isGen3 = (AMD_checkLinkType(node, 0, offset) & 
HTPHY_LINKTYPE_HT3 );
++        link0isGen3 = (AMD_checkLinkType(node, offset) & HTPHY_LINKTYPE_HT3 );
+       }
+         /* FIXME: NB_CLKDID should be 101b for AMD_DA_C2 in package
+            S1g3 in link Gen3 mode, but I don't know how to tell
+diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c 
b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+index a0c5f93..344dab0 100644
+--- a/src/cpu/amd/family_10h-family_15h/init_cpus.c
++++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c
+@@ -845,7 +845,7 @@ static BOOL AMD_CpuFindCapability(u8 node, u8 cap_count, 
u8 * offset)
+  *
+  * Returns the link characteristic mask.
+  */
+-static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
++static u32 AMD_checkLinkType(u8 node, u8 regoff)
+ {
+       uint32_t val;
+       uint32_t val2;
+@@ -876,7 +876,7 @@ static u32 AMD_checkLinkType(u8 node, u8 link, u8 regoff)
+                       linktype |= HTPHY_LINKTYPE_HT1;
+ 
+               /* Check ganged */
+-              val = pci_read_config32(NODE_PCI(node, 0), (link << 2) + 0x170);
++              val = pci_read_config32(NODE_PCI(node, 0), (((regoff - 0x80) / 
0x20) << 2) + 0x170);
+ 
+               if (val & 1)
+                       linktype |= HTPHY_LINKTYPE_GANGED;
+@@ -1119,7 +1119,7 @@ static void cpuSetAMDPCI(u8 node)
+                        */
+                       for (j = 0; j < 4; j++) {
+                               if (AMD_CpuFindCapability(node, j, &offset)) {
+-                                      if (AMD_checkLinkType(node, j, offset)
++                                      if (AMD_checkLinkType(node, offset)
+                                           & fam10_htphy_default[i].linktype) {
+                                               AMD_SetHtPhyRegister(node, j,
+                                                                    i);
+@@ -1217,6 +1217,7 @@ static void cpuSetAMDPCI(u8 node)
+               pci_write_config32(NODE_PCI(node, 3), 0x1a0, dword);
+ 
+               uint8_t link;
++              uint8_t link_real;
+               uint8_t ganged;
+               uint8_t iolink;
+               uint8_t probe_filter_enabled = !!dual_node;
+@@ -1238,8 +1239,9 @@ static void cpuSetAMDPCI(u8 node)
+ 
+               for (link = 0; link < 4; link++) {
+                       if (AMD_CpuFindCapability(node, link, &offset)) {
+-                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
+-                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
++                              link_real = (offset - 0x80) / 0x20;
++                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link_real << 2) + 0x170) & 0x1);
++                              iolink = !!(AMD_checkLinkType(node, offset) & 
HTPHY_LINKTYPE_NONCOHERENT);
+ 
+                               if (!iolink && ganged) {
+                                       if (probe_filter_enabled) {
+@@ -1335,7 +1337,7 @@ static void cpuSetAMDPCI(u8 node)
+                                       np_req_cmd = 12;
+                               }
+ 
+-                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x94);
++                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x94);
+                               dword &= ~(0x3 << 27);                  /* 
IsocRspData = isoc_rsp_data */
+                               dword |= ((isoc_rsp_data & 0x3) << 27);
+                               dword &= ~(0x3 << 25);                  /* 
IsocNpReqData = isoc_np_req_data */
+@@ -1346,9 +1348,9 @@ static void cpuSetAMDPCI(u8 node)
+                               dword |= ((isoc_preq & 0x7) << 19);
+                               dword &= ~(0x7 << 16);                  /* 
IsocNpReqCmd = isoc_np_req_cmd */
+                               dword |= ((isoc_np_req_cmd & 0x7) << 16);
+-                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x94, dword);
++                              pci_write_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x94, dword);
+ 
+-                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link * 0x20) + 0x90);
++                              dword = pci_read_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x90);
+                               dword &= ~(0x1 << 31);                  /* 
LockBc = 0x1 */
+                               dword |= ((0x1 & 0x1) << 31);
+                               dword &= ~(0x7 << 25);                  /* 
FreeData = free_data */
+@@ -1367,7 +1369,7 @@ static void cpuSetAMDPCI(u8 node)
+                               dword |= ((preq & 0x7) << 5);
+                               dword &= ~(0x1f << 0);                  /* 
NpReqCmd = np_req_cmd */
+                               dword |= ((np_req_cmd & 0x1f) << 0);
+-                              pci_write_config32(NODE_PCI(node, 0), (link * 
0x20) + 0x90, dword);
++                              pci_write_config32(NODE_PCI(node, 0), 
(link_real * 0x20) + 0x90, dword);
+                       }
+               }
+ 
+@@ -1390,8 +1392,9 @@ static void cpuSetAMDPCI(u8 node)
+ 
+               for (link = 0; link < 4; link++) {
+                       if (AMD_CpuFindCapability(node, link, &offset)) {
+-                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link << 2) + 0x170) & 0x1);
+-                              iolink = !!(AMD_checkLinkType(node, link, 
offset) & HTPHY_LINKTYPE_NONCOHERENT);
++                              link_real = (offset - 0x80) / 0x20;
++                              ganged = !!(pci_read_config32(NODE_PCI(node, 
0), (link_real << 2) + 0x170) & 0x1);
++                              iolink = !!(AMD_checkLinkType(node, offset) & 
HTPHY_LINKTYPE_NONCOHERENT);
+ 
+                               /* Set defaults */
+                               isoc_rsp_tok_1 = 0;
+@@ -1619,7 +1622,7 @@ static void cpuSetAMDPCI(u8 node)
+                                       }
+                               }
+ 
+-                              dword = pci_read_config32(NODE_PCI(node, 3), 
(link << 2) + 0x148);
++                              dword = pci_read_config32(NODE_PCI(node, 3), 
(link_real << 2) + 0x148);
+                               dword &= ~(0x3 << 30);                  /* 
FreeTok[3:2] = free_tokens[3:2] */
+                               dword |= (((free_tokens >> 2) & 0x3) << 30);
+                               dword &= ~(0x1 << 28);                  /* 
IsocRspTok1 = isoc_rsp_tok_1 */
+@@ -1652,7 +1655,7 @@ static void cpuSetAMDPCI(u8 node)
+                               dword |= (((preq_tok_0) & 0x3) << 2);
+                               dword &= ~(0x3 << 0);                   /* 
ReqTok0 = req_tok_0 */
+                               dword |= (((req_tok_0) & 0x3) << 0);
+-                              pci_write_config32(NODE_PCI(node, 3), (link << 
2) + 0x148, dword);
++                              pci_write_config32(NODE_PCI(node, 3), 
(link_real << 2) + 0x148, dword);
+                       }
+               }
+ 
+@@ -1698,6 +1701,7 @@ static void cpuSetAMDPCI(u8 node)
+       }
+ 
+       uint8_t link;
++      uint8_t link_real;
+       uint8_t isochronous;
+       uint8_t isochronous_link_present;
+ 
+@@ -1706,7 +1710,8 @@ static void cpuSetAMDPCI(u8 node)
+       if (revision & AMD_FAM15_ALL) {
+               for (link = 0; link < 4; link++) {
+                       if (AMD_CpuFindCapability(node, link, &offset)) {
+-                              isochronous = (pci_read_config32(NODE_PCI(node, 
0), (link * 0x20) + 0x84) >> 12) & 0x1;
++                              link_real = (offset - 0x80) / 0x20;
++                              isochronous = (pci_read_config32(NODE_PCI(node, 
0), (link_real * 0x20) + 0x84) >> 12) & 0x1;
+ 
+                               if (isochronous)
+                                       isochronous_link_present = 1;
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0141-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
 
b/resources/libreboot/patch/kgpe-d16/0141-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
new file mode 100644
index 0000000..5dfd35a
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0141-cpu-amd-family_10h-family_15h-Enable-DFE-on-Family-1.patch
@@ -0,0 +1,32 @@
+From a48cdc6abd37ccd7e41bcac11a97475a464b8a2e Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Sun, 13 Sep 2015 15:54:32 -0500
+Subject: [PATCH 141/143] cpu/amd/family_10h-family_15h: Enable DFE on Family
+ 15h HT3 links
+
+Change-Id: I5e719984ddd723f9e375ff1a9d4fa1ef042cf3eb
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/defaults.h |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h 
b/src/cpu/amd/family_10h-family_15h/defaults.h
+index 7a84fcb..b906866 100644
+--- a/src/cpu/amd/family_10h-family_15h/defaults.h
++++ b/src/cpu/amd/family_10h-family_15h/defaults.h
+@@ -857,4 +857,12 @@ static const struct {
+       { 0xC0, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL,
+         0x40040000, 0xe01F0000 },     /* [31:29] RttCtl = 02h,
+                                          [20:16] RttIndex = 04h */
++
++      { 0xc4, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++        0x00013480, 0x0003fc80 },     /* [17:10] DCV = 0x4d,
++                                             [7] DfeEn = 0x1 */
++
++      { 0xd4, AMD_FAM15_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3,
++        0x00013480, 0x0003fc80 },     /* [17:10] DCV = 0x4d,
++                                             [7] DfeEn = 0x1 */
+ };
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0142-cpu-amd-family_10h-family_15h-Fix-build-when-microco.patch
 
b/resources/libreboot/patch/kgpe-d16/0142-cpu-amd-family_10h-family_15h-Fix-build-when-microco.patch
new file mode 100644
index 0000000..2c37b13
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0142-cpu-amd-family_10h-family_15h-Fix-build-when-microco.patch
@@ -0,0 +1,28 @@
+From eb8c3bae85caf446f38e820e9569268731ef4cab Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Mon, 19 Oct 2015 03:14:04 -0500
+Subject: [PATCH 142/143] cpu/amd/family_10h-family_15h: Fix build when
+ microcode not included
+
+Change-Id: I9bd7ea57b0e307d871215754aa490eb15fafcce2
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/cpu/amd/family_10h-family_15h/Kconfig |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/cpu/amd/family_10h-family_15h/Kconfig 
b/src/cpu/amd/family_10h-family_15h/Kconfig
+index bfb6751..be9203d 100644
+--- a/src/cpu/amd/family_10h-family_15h/Kconfig
++++ b/src/cpu/amd/family_10h-family_15h/Kconfig
+@@ -11,7 +11,7 @@ config CPU_AMD_MODEL_10XXX
+       select UDELAY_LAPIC
+       select HAVE_MONOTONIC_TIMER
+       select SUPPORT_CPU_UCODE_IN_CBFS
+-      select CPU_MICROCODE_MULTIPLE_FILES
++      select CPU_MICROCODE_MULTIPLE_FILES if CPU_MICROCODE_CBFS_GENERATE
+ 
+ if CPU_AMD_MODEL_10XXX
+ 
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/kgpe-d16/0143-device-smbus-Avoid-infinite-loop-if-i2c-device-has-w.patch
 
b/resources/libreboot/patch/kgpe-d16/0143-device-smbus-Avoid-infinite-loop-if-i2c-device-has-w.patch
new file mode 100644
index 0000000..bf9c829
--- /dev/null
+++ 
b/resources/libreboot/patch/kgpe-d16/0143-device-smbus-Avoid-infinite-loop-if-i2c-device-has-w.patch
@@ -0,0 +1,39 @@
+From 54ef1e4efe549e310b29258fe9c2efcc367ae942 Mon Sep 17 00:00:00 2001
+From: Timothy Pearson <address@hidden>
+Date: Thu, 22 Oct 2015 17:19:19 -0500
+Subject: [PATCH 143/143] device/smbus: Avoid infinite loop if i2c device has
+ wrong parent
+
+Change-Id: I4c615f3c5b3908178b8223cb6620c393bbfb4e7f
+Signed-off-by: Timothy Pearson <address@hidden>
+---
+ src/device/smbus_ops.c |   13 +++++++++++--
+ 1 file changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/src/device/smbus_ops.c b/src/device/smbus_ops.c
+index 184a06a..f4b1355 100644
+--- a/src/device/smbus_ops.c
++++ b/src/device/smbus_ops.c
+@@ -29,8 +29,17 @@ struct bus *get_pbus_smbus(device_t dev)
+ {
+       struct bus *pbus = dev->bus;
+ 
+-      while (pbus && pbus->dev && !ops_smbus_bus(pbus))
+-              pbus = pbus->dev->bus;
++      while (pbus && pbus->dev && !ops_smbus_bus(pbus)) {
++              if (pbus->dev->bus != pbus) {
++                      pbus = pbus->dev->bus;
++              }
++              else {
++                      printk(BIOS_WARNING,
++                              "%s Find SMBus bus operations: unable to 
proceed\n",
++                              dev_path(dev));
++                      break;
++              }
++      }
+ 
+       if (!pbus || !pbus->dev || !pbus->dev->ops
+           || !pbus->dev->ops->ops_smbus_bus) {
+-- 
+1.7.9.5
+
diff --git 
a/resources/libreboot/patch/misc/0009-chromeos-Allow-disabling-vboot-firmware-verification.patch
 
b/resources/libreboot/patch/misc/0009-chromeos-Allow-disabling-vboot-firmware-verification.patch
deleted file mode 100644
index 6df7636..0000000
--- 
a/resources/libreboot/patch/misc/0009-chromeos-Allow-disabling-vboot-firmware-verification.patch
+++ /dev/null
@@ -1,68 +0,0 @@
-From a5dba25113e8bd989b74763baabd7a07931fa314 Mon Sep 17 00:00:00 2001
-From: Paul Kocialkowski <address@hidden>
-Date: Sun, 9 Aug 2015 10:23:38 +0200
-Subject: [PATCH 9/9] chromeos: Allow disabling vboot firmware verification
- when ChromeOS is enabled
-
-Some ChromeOS bindings might be wanted without using vboot verification, for
-instance to boot up depthcharge from the version of Coreboot installed in the
-write-protected part of the SPI flash (without jumping to a RW firmware).
-
-Vboot firmware verification is still selected by default when ChromeOS is
-enabled, but this allows more flexibility since vboot firmware verification is
-no longer a hard requirement for ChromeOS (that this particular use case still
-allows booting ChromeOS).
-
-In the future, it would make sense to have all the separate components that
-CONFIG_CHROMEOS enables have their own config options, so that they can be
-enabled separately.
-
-Change-Id: Ia4057a56838aa05dcf3cb250ae1a27fd91402ddb
-Signed-off-by: Paul Kocialkowski <address@hidden>
----
- src/vendorcode/google/chromeos/Kconfig        | 2 +-
- src/vendorcode/google/chromeos/vboot2/Kconfig | 4 ++++
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/src/vendorcode/google/chromeos/Kconfig 
b/src/vendorcode/google/chromeos/Kconfig
-index 8309d19..694e0d7 100644
---- a/src/vendorcode/google/chromeos/Kconfig
-+++ b/src/vendorcode/google/chromeos/Kconfig
-@@ -31,7 +31,6 @@ config CHROMEOS
-       select BOOTMODE_STRAPS
-       select ELOG
-       select COLLECT_TIMESTAMPS
--      select VBOOT_VERIFY_FIRMWARE
-       help
-         Enable ChromeOS specific features like the GPIO sub table in
-         the coreboot table. NOTE: Enabling this option on an unsupported
-@@ -129,6 +128,7 @@ config VIRTUAL_DEV_SWITCH
- 
- config VBOOT_VERIFY_FIRMWARE
-       bool "Verify firmware with vboot."
-+      default y if CHROMEOS
-       default n
-       depends on HAVE_HARD_RESET
-       help
-diff --git a/src/vendorcode/google/chromeos/vboot2/Kconfig 
b/src/vendorcode/google/chromeos/vboot2/Kconfig
-index 930b009..610a847 100644
---- a/src/vendorcode/google/chromeos/vboot2/Kconfig
-+++ b/src/vendorcode/google/chromeos/vboot2/Kconfig
-@@ -16,6 +16,8 @@
- ## Foundation, Inc.
- ##
- 
-+if VBOOT_VERIFY_FIRMWARE
-+
- config VBOOT_STARTS_IN_BOOTBLOCK
-       bool "Vboot starts verifying in bootblock"
-       default n
-@@ -133,3 +135,5 @@ config VBOOT_DYNAMIC_WORK_BUFFER
-         ram to allocate the vboot work buffer. That means vboot verification
-         is after memory init and requires main memory to back the work
-         buffer.
-+
-+endif # VBOOT_VERIFY_FIRMWARE
--- 
-1.9.1
-
diff --git a/resources/scripts/helpers/download/coreboot 
b/resources/scripts/helpers/download/coreboot
index 9b96695..8fdf2a8 100755
--- a/resources/scripts/helpers/download/coreboot
+++ b/resources/scripts/helpers/download/coreboot
@@ -44,7 +44,7 @@ git clone http://review.coreboot.org/coreboot
 cd "coreboot/"
 
 # reset to previously tested revision
-git reset --hard d98471ccb412f61d7da2c5eb5ca8eeb8fece384a
+git reset --hard 33fb4cf0ffb01be8bcb6b488872c87eb50e7d77f
 
 # vboot submodule is needed
 git submodule update --init --checkout -- 3rdparty/vboot/
@@ -130,8 +130,7 @@ git am 
"../resources/libreboot/patch/misc/0008-lenovo-t500-Add-clone-of-Lenovo-T
 # Chromebook:
 
 printf "chromeos: Allow disabling vboot firmware verification when ChromeOS is 
enabled\n"
-git am 
"../resources/libreboot/patch/misc/0009-chromeos-Allow-disabling-vboot-firmware-verification.patch"
-# git fetch http://review.coreboot.org/coreboot refs/changes/43/11143/2 && git 
cherry-pick FETCH_HEAD
+git am 
"../resources/libreboot/patch/chromebook/0001-chromeos-Allow-disabling-vboot-firmware-verification.patch"
 
 # KGPE-D16 patches
 # note: current top patch is http://review.coreboot.org/#/c/12072/6
-- 
1.9.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]