libreboot

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 5999dba5f71f1c05040a551d2420ab8c7f3a9da4
parent 4d909153e79661e54999e51693668f6d1ecc1cca
Author: Francis Rowe <info@gluglug.org.uk>
Date:   Sat, 17 Oct 2015 16:10:53 +0100

New board: ASUS KGPE-D16

coreboot build errors:

In file included from src/northbridge/amd/amdfam10/misc_control.c:35:0:
src/include/option.h:13:27: error: static declaration of 'get_option' follows non-static declaration
 static inline enum cb_err get_option(void *dest, const char *name)
                           ^
In file included from src/northbridge/amd/amdfam10/misc_control.c:34:0:
src/include/pc80/mc146818rtc.h:176:13: note: previous declaration of 'get_option' was here
 enum cb_err get_option(void *dest, const char *name);

Ping tpearson about this.

Also ping him about the fact that there isn't actually an option to
enable or disable native graphics initialization, but that the option
MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG is in fact available and set to Y in the
Kconfig file. I think this is probably since there isn't even an option
ROM available for the machine, so it's pointless to offer the setting.

Diffstat:
resources/libreboot/config/depthcharge/veyron_speedy/config | 3+++
resources/libreboot/config/grub/kfsn4-dre/config | 10+++++++---
resources/libreboot/config/grub/kfsn4-dre_2mb/config | 10+++++++---
resources/libreboot/config/grub/kgpe-d16/config | 580+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/config/grub/macbook21/config | 3+++
resources/libreboot/config/grub/qemu_i440fx_piix4/config | 3+++
resources/libreboot/config/grub/qemu_q35_ich9/config | 3+++
resources/libreboot/config/grub/r400_4mb/config | 3+++
resources/libreboot/config/grub/r400_8mb/config | 3+++
resources/libreboot/config/grub/t400_4mb/config | 3+++
resources/libreboot/config/grub/t400_8mb/config | 3+++
resources/libreboot/config/grub/t500_4mb/config | 3+++
resources/libreboot/config/grub/t500_8mb/config | 3+++
resources/libreboot/config/grub/t60/config | 3+++
resources/libreboot/config/grub/x200_4mb/config | 3+++
resources/libreboot/config/grub/x200_8mb/config | 3+++
resources/libreboot/config/grub/x60/config | 3+++
resources/libreboot/patch/kgpe-d16/0001-util-cbmem-Fix-failure-with-certain-cbmem-base-align.patch | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0002-cpu-amd-microcode-Update-microcode-parser-to-handle-.patch | 41+++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0003-arch-x86-boot-smbios-Add-SPD-IDs-for-Kingston-and-Co.patch | 36++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0004-arch-x86-smbios-Add-Crucial-DIMM-manufacturer-ID.patch | 27+++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0005-southbridge-amd-sr5650-Remove-unnecessary-register-c.patch | 33+++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0006-drivers-i2c-w83795-Add-full-support-for-fan-control-.patch | 661+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0007-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch | 3673+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0008-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch | 641+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0009-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch | 619+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0010-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch | 788+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch | 3451+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0012-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0013-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0014-northbridge-amd-amdfam10-Fix-typo-in-comment.patch | 33+++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0015-device-hypertransport-Add-additional-debug-output.patch | 33+++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0016-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch | 3218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0017-mainboard-asus-kgpe-d16-Add-nvram-option-to-enable-d.patch | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0018-cpu-amd-model_10xxx-Clean-up-debugging-statements.patch | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0019-southbridge-amd-sb700-Add-Suspend-to-RAM-S3-support.patch | 365+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0020-superio-nuvoton-nct5572d-Enable-power-state-after-po.patch | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0021-northbridge-amd-amdfam10-Add-Suspend-to-RAM-S3-Flash.patch | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0022-northbridge-amd-amdmct-mct_ddr3-Add-initial-Suspend-.patch | 986+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0023-cpu-amd-car-Add-initial-Suspend-to-RAM-S3-support.patch | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0024-mainboard-asus-kgpe-d16-Add-initial-Suspend-to-RAM-S.patch | 830+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0025-include-smbios-Update-SMBIOS-memory-structures-to-ve.patch | 31+++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0026-mainboard-asus-kgpe-d16-Set-DDR3-memory-voltage-base.patch | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0027-northbridge-amd-amdfam10-Set-DIMM-voltage-based-on-S.patch | 176+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0028-src-console-Add-x86-romstage-spinlock-option.patch | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0029-northbridge-amd-amdmct-mct_ddr3-Fix-S3-suspend-overr.patch | 49+++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0030-northbridge-amd-amdmct-mct_ddr3-Fix-failing-S3-resum.patch | 46++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0031-northbridge-amd-amdmct-Fix-S3-suspend-resume-with-la.patch | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0032-src-console-Add-x86-printk-spinlock-support.patch | 126+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0033-lib-stack-Add-stack-overrun-detection.patch | 36++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0034-cpu-x86-lapic-Add-stack-overrun-detection.patch | 32++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0035-southbridge-amd-sr5650-Add-AMD-Family-15h-CPU-suppor.patch | 26++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0036-cpu-amd-Add-initial-AMD-Family-15h-support.patch | 15930+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0037-mainboard-asus-kgpe-d16-Add-initial-Family-15h-CPU-s.patch | 563+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0038-amdmct-mct_ddr3-Disable-Fam10h-specific-MTRR-setup-o.patch | 36++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0039-cpu-amd-car-Add-romstage-BSP-stack-overrun-detection.patch | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0040-cpu-amd-car-Increase-Family-10h-CAR-size-limit-to-12.patch | 28++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0041-cpu-amd-car-Move-AP-stacks-below-the-BSP-stack-to-fr.patch | 30++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0042-northbridge-amd-amdmct-Read-SPD-data-into-cache-to-d.patch | 459+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0043-cpu-amd-car-Initialize-entire-CAR-space-instead-of-o.patch | 32++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0044-amd-amdmct-mct_ddr3-Improve-SPD-DIMM-detect-reliabil.patch | 47+++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0045-amd-amdmct-mct_ddr3-Use-training-values-from-previou.patch | 769+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0046-northbridge-amd-amdfam10-Enable-CC6-DRAM-save-area-s.patch | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0047-mainboard-asus-kgpe-d16-Enable-CC6.patch | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0048-cpu-amd-Add-CC6-support.patch | 1302+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0049-northbridge-amd-amdmct-Skip-DCT-config-write-to-Flas.patch | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0050-southbridge-amd-sb700-Add-AHCI-support.patch | 658+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0051-mainboard-asus-kgpe-d16-Properly-initialize-SB700-SA.patch | 47+++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0052-southbridge-amd-sb700-Disable-broken-SATA-MSI-functi.patch | 39+++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0053-southbridge-amd-sb700-Indicate-iSATA-eSATA-port-type.patch | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0054-northbridge-amd-amdfam10-Add-ability-to-set-maximum-.patch | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0055-northbridge-amd-amdmct-Verify-MCT-NVRAM-options-befo.patch | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0056-src-northbridge-amd-amdmct-Add-option-to-override-ba.patch | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0057-mainboard-asus-kgpe-d16-Add-missing-IRQ-routing-for-.patch | 207+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0058-northbridge-amd-amdmct-Fix-hang-on-boot-due-to-inval.patch | 35+++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0059-southbridge-amd-sr5650-Fix-GPP3a-link-training-in-hi.patch | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0060-southbridge-amd-sr5650-Add-optional-delay-after-link.patch | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0061-mainboard-asus-kgpe-d16-Properly-configure-SR5690-so.patch | 30++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0062-southbridge-amd-sb700-Add-option-to-disable-SATA-ALP.patch | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0063-mainboard-asus-kgpe-d16-Set-SP5100-subtype.patch | 24++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0064-northbridge-amd-amdmct-Fix-crash-on-startup-due-to-N.patch | 31+++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0065-northbridge-amd-amdmct-Clear-memory-before-enabling-.patch | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0066-southbridge-amd-sb700-Do-drive-detection-even-in-AHC.patch | 140+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0067-src-southbridge-amd-sb700-Reset-SATA-controller-in-A.patch | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0068-southbridge-amd-sb700-Recover-if-AHCI-disk-detection.patch | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0069-southbridge-amd-sb700-Fix-SATA-port-4-5-drive-detect.patch | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0070-southbridge-amd-sb700-Fix-random-persistent-SATA-AHC.patch | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0071-northbridge-amd-amdmct-mct_ddr3-Fix-lockups-and-wast.patch | 423+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0072-cpu-amd-Fix-AMD-Family-15h-ECC-initialization-reliab.patch | 479+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0073-northbridge-amd-amdfam10-Properly-indicate-node-and-.patch | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0074-amd-amdmct-mct_ddr3-Add-Family-15h-RDIMM-timing-and-.patch | 513+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0075-northbridge-amd-amdmct-mct_ddr3-Attempt-to-recover-f.patch | 254+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0076-northbridge-amd-amdmct-mct_ddr3-Work-around-strange-.patch | 40++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0077-northbridge-amd-amdmct-mct_ddr3-Add-additional-debug.patch | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0078-northbridge-amd-amdmct-mct_ddr3-Fix-null-pointer-acc.patch | 238+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0079-northbridge-amd-amdmct-mct_ddr3-Add-missing-Family-1.patch | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0080-northbridge-amd-amdmct-mct_ddr3-Set-SkewMemClk-when-.patch | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0081-northbridge-amd-amdmct-mct_ddr3-Properly-indicate-cl.patch | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0082-northbridge-amd-amdmct-mct_ddr3-Fix-Family-10h-boot-.patch | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0083-src-southbridge-amd-sr5650-Always-configure-lane-dir.patch | 48++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0084-cpu-amd-model_10xxx-Fix-BSP-stack-corruption-on-32-c.patch | 26++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0085-northbridge-amd-amdmct-mct_ddr3-Fix-RDIMM-errors-due.patch | 411+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0086-amd-amdmct-mct_ddr3-Partially-fix-up-registered-DIMM.patch | 957+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0087-northbridge-amd-amdmct-Fix-Family-15h-detection.patch | 47+++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0088-northbridge-amd-amdmct-mct_ddr3-Add-registered-and-x.patch | 1893+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0089-cpu-amd-model_10xxx-Fix-Family-15h-multiple-package-.patch | 948+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0090-northbridge-amd-amdfam10-Add-probe-filter-support.patch | 212+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0091-cpu-amd-model_10xxx-Bring-initial-HT-register-config.patch | 246+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0092-northbridge-amd-amdmct-mct_ddr3-Move-K10D-configurat.patch | 334+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0093-mainboard-asus-kgpe-d16-Fix-I-O-link-detection.patch | 26++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0094-cpu-amd-model_10xxx-Set-northbridge-throttle-values.patch | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0095-cpu-amd-model_10xxx-Fix-incorrect-revision-detection.patch | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0096-northbridge-amd-amdht-Add-support-for-HT3-2.8GHz-and.patch | 559+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0097-amd-model_10xxx-Fix-poor-performance-on-Family-15h-C.patch | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0098-amd-amdmct-mct_ddr3-Fix-poor-performance-on-Family-1.patch | 1087+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0099-northbridge-amd-amdht-Fix-poor-performance-on-Family.patch | 28++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0100-northbridge-amd-amdfam10-Fix-poor-performance-on-Fam.patch | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0101-cpu-amd-model_10xxx-Configure-NB-register-2.patch | 31+++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0102-cpu-amd-model_10xxx-Set-up-link-XCS-token-counts-on-.patch | 342+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0103-northbridge-amd-amdmct-mct_ddr3-Force-retraining-on-.patch | 34++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0104-northbridge-amd-amdfam10-Fix-invalid-NUMA-table.patch | 26++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0105-northbridge-amd-amdfam10-Add-Family-15h-cache-partit.patch | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0106-amd-amdmct-mct_ddr3-Set-prefetch-double-stride-to-im.patch | 25+++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0107-cpu-amd-model_10xxx-Set-up-Family-15h-Link-Base-Chan.patch | 190+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0108-cpu-amd-model_10xxx-Set-up-cache-controls-on-Family-.patch | 41+++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0109-cpu-amd-model_10xxx-Set-up-SRI-to-XCS-Token-Count-re.patch | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0110-amd-amdfam10-Control-Family-15h-cache-partitioning-a.patch | 175+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0111-northbridge-amd-amdht-Add-isochronous-setup-support-.patch | 270+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0112-arch-x86-acpi-Add-IVRS-table-generation-routines.patch | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0113-southbridge-amd-sr5650-Add-IOMMU-support.patch | 709+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0114-southbridge-amd-sr5650-Hide-clock-configuration-devi.patch | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0115-northbridge-amd-amdfam10-Rename-mislabeled-iommu-nvr.patch | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0116-northbridge-amd-amdfam10-Fix-gart-setup-not-working-.patch | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0117-mainboard-asus-kgpe-d16-Add-several-nvram-configurat.patch | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0118-southbridge-amd-sr5650-Use-correct-PCI-configuration.patch | 28++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0119-southbridge-amd-sr5650-Add-MCFG-ACPI-table-support.patch | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0120-southbridge-amd-sb700-Fix-mismatched-FADT-entries.patch | 34++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0121-southbridge-amd-sb700-Fix-drifting-system-clock.patch | 45+++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0122-northbridge-amd-amdmct-mct_ddr3-Add-cc6-setup-inform.patch | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0123-northbridge-amd-amdfam10-Work-around-sporadic-lockup.patch | 38++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0124-northbridge-amd-amdmct-mct_ddr3-Ensure-channel-clock.patch | 113+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0125-northbridge-amd-amdmct-mct_ddr3-Add-DDR3-termination.patch | 34++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0126-northbridge-amd-amdmct-mct_ddr3-Fix-a-minor-RDIMM-CS.patch | 35+++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0127-northbridge-amd-amdmct-mct_ddr3-Fix-odd-rank-data-co.patch | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0128-northbridge-amd-amdmct-mct_ddr3-Use-antiphase-to-bet.patch | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0129-northbridge-amd-amdmct-mct_ddr3-Fix-broken-support-f.patch | 602+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0130-drivers-pc80-Add-optional-spinlock-for-nvram-CBFS-ac.patch | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0131-mainboard-asus-kgpe-d16-Enable-CBFS-spinlocks.patch | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0132-cpu-amd-microcode-Introduce-CBFS-access-spinlock-to-.patch | 151++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0133-mainboard-asus-kgpe-d16-Limit-HT-speed-to-2.6GHz.patch | 38++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0134-cpu-amd-model_10xxx-Apply-missing-Family-15h-errata-.patch | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0135-northbridge-amd-amdmct-mct_ddr3-Use-StopOnError-to-d.patch | 229+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0136-mainboard-asus-kgpe-d16-Enable-GART-by-default.patch | 25+++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0137-northbridge-amd-amdfam10-Fix-incorrect-channel-buffe.patch | 40++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0138-cpu-amd-model_10xxx-Force-iolink-detect-to-either-1-.patch | 35+++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0139-northbridge-amd-amdht-Fix-XCS-buffer-count-setup-on-.patch | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0140-cpu-amd-model_10xxx-Fix-link-type-detection-and-XCS-.patch | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
resources/libreboot/patch/kgpe-d16/0141-cpu-amd-model_10xxx-Enable-DFE-on-Family-15h-HT3-lin.patch | 44++++++++++++++++++++++++++++++++++++++++++++
resources/scripts/helpers/download/coreboot | 6++++++
159 files changed, 54884 insertions(+), 6 deletions(-)

diff --git a/resources/libreboot/config/depthcharge/veyron_speedy/config b/resources/libreboot/config/depthcharge/veyron_speedy/config @@ -456,6 +456,9 @@ 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/config/grub/kfsn4-dre/config b/resources/libreboot/config/grub/kfsn4-dre/config @@ -135,6 +135,7 @@ CONFIG_MAINBOARD_SMBIOS_MANUFACTURER="ASUS" # CONFIG_BOARD_ASUS_F2A85_M_LE is not set # CONFIG_BOARD_ASUS_K8V_X is not set CONFIG_BOARD_ASUS_KFSN4_DRE=y +# CONFIG_BOARD_ASUS_KGPE_D16 is not set # CONFIG_BOARD_ASUS_M2N_E is not set # CONFIG_BOARD_ASUS_M2V_MX_SE is not set # CONFIG_BOARD_ASUS_M2V is not set @@ -213,8 +214,8 @@ CONFIG_HEAP_SIZE=0xc0000 # CPU # # CONFIG_CPU_ALLWINNER_A10 is not set -CONFIG_DCACHE_BSP_STACK_SIZE=0x2000 -CONFIG_DCACHE_BSP_STACK_SLUSH=0x1000 +CONFIG_DCACHE_BSP_STACK_SIZE=0x4000 +CONFIG_DCACHE_BSP_STACK_SLUSH=0x4000 CONFIG_DCACHE_AP_STACK_SIZE=0x400 CONFIG_CPU_SOCKET_TYPE=0x10 # CONFIG_EXT_RT_TBL_SUPPORT is not set @@ -409,6 +410,7 @@ CONFIG_SUBSYSTEM_DEVICE_ID=0x0000 # Generic Drivers # # CONFIG_DRIVERS_AS3722_RTC is not set +CONFIG_DEVICE_SPECIFIC_OPTIONS=y # CONFIG_GIC is not set # CONFIG_SMBIOS_PROVIDED_BY_MOBO is not set # CONFIG_DRIVERS_I2C_RTD2132 is not set @@ -450,7 +452,6 @@ CONFIG_USBDEBUG_DONGLE_STD=y # CONFIG_USBDEBUG_DONGLE_FTDI_FT232H is not set CONFIG_USBDEBUG_OPTIONAL_HUB_PORT=0 CONFIG_DRIVERS_XGI_Z79_COMMON=y -CONFIG_DEVICE_SPECIFIC_OPTIONS=y CONFIG_DRIVERS_XGI_Z9S=y # CONFIG_DRIVER_XPOWERS_AXP209 is not set CONFIG_RTC=y @@ -499,6 +500,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 # 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 is not set # CONFIG_TIMER_QUEUE is not set diff --git a/resources/libreboot/config/grub/kfsn4-dre_2mb/config b/resources/libreboot/config/grub/kfsn4-dre_2mb/config @@ -135,6 +135,7 @@ CONFIG_MAINBOARD_SMBIOS_MANUFACTURER="ASUS" # CONFIG_BOARD_ASUS_F2A85_M_LE is not set # CONFIG_BOARD_ASUS_K8V_X is not set CONFIG_BOARD_ASUS_KFSN4_DRE=y +# CONFIG_BOARD_ASUS_KGPE_D16 is not set # CONFIG_BOARD_ASUS_M2N_E is not set # CONFIG_BOARD_ASUS_M2V_MX_SE is not set # CONFIG_BOARD_ASUS_M2V is not set @@ -213,8 +214,8 @@ CONFIG_HEAP_SIZE=0xc0000 # CPU # # CONFIG_CPU_ALLWINNER_A10 is not set -CONFIG_DCACHE_BSP_STACK_SIZE=0x2000 -CONFIG_DCACHE_BSP_STACK_SLUSH=0x1000 +CONFIG_DCACHE_BSP_STACK_SIZE=0x4000 +CONFIG_DCACHE_BSP_STACK_SLUSH=0x4000 CONFIG_DCACHE_AP_STACK_SIZE=0x400 CONFIG_CPU_SOCKET_TYPE=0x10 # CONFIG_EXT_RT_TBL_SUPPORT is not set @@ -409,6 +410,7 @@ CONFIG_SUBSYSTEM_DEVICE_ID=0x0000 # Generic Drivers # # CONFIG_DRIVERS_AS3722_RTC is not set +CONFIG_DEVICE_SPECIFIC_OPTIONS=y # CONFIG_GIC is not set # CONFIG_SMBIOS_PROVIDED_BY_MOBO is not set # CONFIG_DRIVERS_I2C_RTD2132 is not set @@ -450,7 +452,6 @@ CONFIG_USBDEBUG_DONGLE_STD=y # CONFIG_USBDEBUG_DONGLE_FTDI_FT232H is not set CONFIG_USBDEBUG_OPTIONAL_HUB_PORT=0 CONFIG_DRIVERS_XGI_Z79_COMMON=y -CONFIG_DEVICE_SPECIFIC_OPTIONS=y CONFIG_DRIVERS_XGI_Z9S=y # CONFIG_DRIVER_XPOWERS_AXP209 is not set CONFIG_RTC=y @@ -499,6 +500,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 # 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 is not set # CONFIG_TIMER_QUEUE is not set diff --git a/resources/libreboot/config/grub/kgpe-d16/config b/resources/libreboot/config/grub/kgpe-d16/config @@ -0,0 +1,580 @@ +# +# Automatically generated file; DO NOT EDIT. +# coreboot configuration +# + +# +# General setup +# +CONFIG_LOCALVERSION="" +CONFIG_CBFS_PREFIX="fallback" +CONFIG_COMPILER_GCC=y +# CONFIG_COMPILER_LLVM_CLANG is not set +# CONFIG_ANY_TOOLCHAIN is not set +# CONFIG_CCACHE is not set +# CONFIG_FMD_GENPARSER is not set +# CONFIG_SCONFIG_GENPARSER is not set +# CONFIG_USE_OPTION_TABLE is not set +# CONFIG_UNCOMPRESSED_RAMSTAGE is not set +CONFIG_COMPRESS_RAMSTAGE=y +CONFIG_INCLUDE_CONFIG_FILE=y +CONFIG_EARLY_CBMEM_INIT=y +# CONFIG_COLLECT_TIMESTAMPS is not set +# CONFIG_USE_BLOBS is not set +# CONFIG_COVERAGE is not set +# CONFIG_RELOCATABLE_MODULES is not set +# CONFIG_RELOCATABLE_RAMSTAGE is not set +CONFIG_FLASHMAP_OFFSET=0 +CONFIG_BOOTBLOCK_SIMPLE=y +# CONFIG_BOOTBLOCK_NORMAL is not set +CONFIG_BOOTBLOCK_SOURCE="bootblock_simple.c" +# CONFIG_SKIP_MAX_REBOOT_CNT_CLEAR is not set +# CONFIG_UPDATE_IMAGE is not set +# CONFIG_GENERIC_GPIO_LIB is not set +# CONFIG_BOARD_ID_AUTO is not set +# CONFIG_BOARD_ID_MANUAL is not set +# CONFIG_RAM_CODE_SUPPORT is not set +# CONFIG_ACPI_SATA_GENERATOR is not set + +# +# Mainboard +# +# CONFIG_VENDOR_A_TREND is not set +# CONFIG_VENDOR_AAEON is not set +# CONFIG_VENDOR_ABIT is not set +# CONFIG_VENDOR_ADLINK is not set +# CONFIG_VENDOR_ADVANSUS is not set +# CONFIG_VENDOR_AMD is not set +# CONFIG_VENDOR_AOPEN is not set +# CONFIG_VENDOR_APPLE is not set +# CONFIG_VENDOR_ARIMA is not set +# CONFIG_VENDOR_ARTECGROUP is not set +# CONFIG_VENDOR_ASROCK is not set +CONFIG_VENDOR_ASUS=y +# CONFIG_VENDOR_AVALUE is not set +# CONFIG_VENDOR_AZZA is not set +# CONFIG_VENDOR_BACHMANN is not set +# CONFIG_VENDOR_BAP is not set +# CONFIG_VENDOR_BCOM is not set +# CONFIG_VENDOR_BIFFEROS is not set +# CONFIG_VENDOR_BIOSTAR is not set +# CONFIG_VENDOR_BROADCOM is not set +# CONFIG_VENDOR_COMPAQ is not set +# CONFIG_VENDOR_CUBIETECH is not set +# CONFIG_VENDOR_DIGITALLOGIC is not set +# CONFIG_VENDOR_DMP is not set +# CONFIG_VENDOR_ECS is not set +# CONFIG_VENDOR_EMULATION is not set +# CONFIG_VENDOR_GETAC is not set +# CONFIG_VENDOR_GIGABYTE is not set +# CONFIG_VENDOR_GIZMOSPHERE is not set +# CONFIG_VENDOR_GOOGLE is not set +# CONFIG_VENDOR_HP is not set +# CONFIG_VENDOR_IBASE is not set +# CONFIG_VENDOR_IBM is not set +# CONFIG_VENDOR_IEI is not set +# CONFIG_VENDOR_INTEL is not set +# CONFIG_VENDOR_IWAVE is not set +# CONFIG_VENDOR_IWILL is not set +# CONFIG_VENDOR_JETWAY is not set +# CONFIG_VENDOR_KONTRON is not set +# CONFIG_VENDOR_LANNER is not set +# CONFIG_VENDOR_LENOVO is not set +# CONFIG_VENDOR_LINUTOP is not set +# CONFIG_VENDOR_LIPPERT is not set +# CONFIG_VENDOR_MITAC is not set +# CONFIG_VENDOR_MSI is not set +# CONFIG_VENDOR_NEC is not set +# CONFIG_VENDOR_NEWISYS is not set +# CONFIG_VENDOR_NOKIA is not set +# CONFIG_VENDOR_NVIDIA is not set +# CONFIG_VENDOR_PACKARDBELL is not set +# CONFIG_VENDOR_PCENGINES is not set +# CONFIG_VENDOR_RCA is not set +# CONFIG_VENDOR_RODA is not set +# CONFIG_VENDOR_SAMSUNG is not set +# CONFIG_VENDOR_SIEMENS is not set +# CONFIG_VENDOR_SOYO is not set +# CONFIG_VENDOR_SUNW is not set +# CONFIG_VENDOR_SUPERMICRO is not set +# CONFIG_VENDOR_TECHNEXION is not set +# CONFIG_VENDOR_THOMSON is not set +# CONFIG_VENDOR_TI is not set +# CONFIG_VENDOR_TRAVERSE is not set +# CONFIG_VENDOR_TYAN is not set +# CONFIG_VENDOR_VIA is not set +# CONFIG_VENDOR_WINENT is not set +# CONFIG_VENDOR_WYSE is not set +CONFIG_BOARD_SPECIFIC_OPTIONS=y +CONFIG_MAINBOARD_DIR="asus/kgpe-d16" +CONFIG_MAINBOARD_PART_NUMBER="KGPE-D16" +CONFIG_IRQ_SLOT_COUNT=13 +CONFIG_MAINBOARD_VENDOR="ASUS" +CONFIG_APIC_ID_OFFSET=0 +CONFIG_HW_MEM_HOLE_SIZEK=0x100000 +CONFIG_MAX_CPUS=32 +CONFIG_MAX_PHYSICAL_CPUS=4 +# CONFIG_HW_MEM_HOLE_SIZE_AUTO_INC is not set +CONFIG_HT_CHAIN_END_UNITID_BASE=0x20 +CONFIG_HT_CHAIN_UNITID_BASE=0x0 +CONFIG_ONBOARD_VGA_IS_PRIMARY=y +# CONFIG_VGA_BIOS is not set +# CONFIG_UDELAY_IO is not set +CONFIG_MAINBOARD_SERIAL_NUMBER="123456789" +CONFIG_DCACHE_RAM_BASE=0xc2000 +CONFIG_DCACHE_RAM_SIZE=0x1e000 +CONFIG_MMCONF_BASE_ADDRESS=0xc0000000 +CONFIG_MAINBOARD_SMBIOS_MANUFACTURER="ASUS" +# CONFIG_BOARD_ASUS_A8N_E is not set +# CONFIG_BOARD_ASUS_A8N_SLI is not set +# CONFIG_BOARD_ASUS_A8V_E_DELUXE is not set +# CONFIG_BOARD_ASUS_A8V_E_SE is not set +# CONFIG_BOARD_ASUS_DSBF is not set +# CONFIG_BOARD_ASUS_F2A85_M is not set +# CONFIG_BOARD_ASUS_F2A85_M_LE is not set +# CONFIG_BOARD_ASUS_K8V_X is not set +# CONFIG_BOARD_ASUS_KFSN4_DRE is not set +CONFIG_BOARD_ASUS_KGPE_D16=y +# CONFIG_BOARD_ASUS_M2N_E is not set +# CONFIG_BOARD_ASUS_M2V_MX_SE is not set +# CONFIG_BOARD_ASUS_M2V is not set +# CONFIG_BOARD_ASUS_M4A78_EM is not set +# CONFIG_BOARD_ASUS_M4A785M is not set +# CONFIG_BOARD_ASUS_M4A785TM is not set +# CONFIG_BOARD_ASUS_M5A88_V is not set +# CONFIG_BOARD_ASUS_MEW_AM is not set +# CONFIG_BOARD_ASUS_MEW_VM is not set +# CONFIG_BOARD_ASUS_P2B_D is not set +# CONFIG_BOARD_ASUS_P2B_DS is not set +# CONFIG_BOARD_ASUS_P2B_F is not set +# CONFIG_BOARD_ASUS_P2B_LS is not set +# CONFIG_BOARD_ASUS_P2B is not set +# CONFIG_BOARD_ASUS_P3B_F is not set +CONFIG_AGP_APERTURE_SIZE=0x4000000 +CONFIG_BOOTBLOCK_MAINBOARD_INIT="mainboard/asus/kgpe-d16/bootblock.c" +CONFIG_MAINBOARD_POWER_ON_AFTER_POWER_FAIL=y +# CONFIG_PCI_64BIT_PREF_MEM is not set +CONFIG_SB_HT_CHAIN_ON_BUS0=1 +CONFIG_SOUTHBRIDGE_AMD_SB700_SATA_PORT_COUNT_BITFIELD=0x3f +CONFIG_UART_FOR_CONSOLE=0 +CONFIG_ID_SECTION_OFFSET=0x80 +CONFIG_RAMTOP=0x400000 +CONFIG_USBDEBUG_HCD_INDEX=0 +CONFIG_BOOT_MEDIA_SPI_BUS=0 +CONFIG_TTYS0_LCS=3 +CONFIG_CBFS_SIZE=0x800000 +CONFIG_CACHE_ROM_SIZE_OVERRIDE=0 +CONFIG_POST_DEVICE=y +CONFIG_CPU_ADDR_BITS=48 +CONFIG_DEFAULT_CONSOLE_LOGLEVEL=8 +CONFIG_USBDEBUG=y +CONFIG_MAINBOARD_VERSION="1.0" +# CONFIG_DRIVERS_PS2_KEYBOARD is not set +CONFIG_BOARD_ROMSIZE_KB_2048=y +# CONFIG_COREBOOT_ROMSIZE_KB_64 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_128 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_256 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_512 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_1024 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_2048 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_4096 is not set +CONFIG_COREBOOT_ROMSIZE_KB_8192=y +# CONFIG_COREBOOT_ROMSIZE_KB_12288 is not set +# CONFIG_COREBOOT_ROMSIZE_KB_16384 is not set +CONFIG_COREBOOT_ROMSIZE_KB=8192 +CONFIG_ROM_SIZE=0x800000 +# CONFIG_SYSTEM_TYPE_LAPTOP is not set + +# +# Chipset +# + +# +# SoC +# +# CONFIG_SOC_BROADCOM_CYGNUS is not set +CONFIG_BOOTBLOCK_NORTHBRIDGE_INIT="northbridge/amd/amdfam10/bootblock.c" +CONFIG_BOOTBLOCK_SOUTHBRIDGE_INIT="southbridge/amd/sb700/bootblock.c" +CONFIG_TTYS0_BASE=0x3f8 +CONFIG_EHCI_BAR=0xfef00000 +CONFIG_HEAP_SIZE=0xc0000 +# CONFIG_SOC_MARVELL_BG4CD is not set +# CONFIG_SOC_NVIDIA_TEGRA124 is not set +# CONFIG_SOC_NVIDIA_TEGRA132 is not set +# CONFIG_SOC_NVIDIA_TEGRA210 is not set +# CONFIG_SOC_QC_IPQ806X is not set +# CONFIG_SOC_ROCKCHIP_RK3288 is not set +# CONFIG_CPU_SAMSUNG_EXYNOS5250 is not set +# CONFIG_CPU_SAMSUNG_EXYNOS5420 is not set +# CONFIG_SOC_UCB_RISCV is not set + +# +# CPU +# +# CONFIG_CPU_ALLWINNER_A10 is not set +CONFIG_DCACHE_BSP_STACK_SIZE=0x4000 +CONFIG_DCACHE_BSP_STACK_SLUSH=0x4000 +CONFIG_DCACHE_AP_STACK_SIZE=0x400 +CONFIG_CPU_SOCKET_TYPE=0x15 +# CONFIG_EXT_RT_TBL_SUPPORT is not set +CONFIG_CBB=0x0 +CONFIG_CDB=0x18 +CONFIG_XIP_ROM_SIZE=0x80000 +CONFIG_CPU_AMD_SOCKET_G34_NON_AGESA=y +CONFIG_DIMM_SUPPORT=0x0005 +CONFIG_LIFT_BSP_APIC_ID=y +CONFIG_SET_FIDVID=y +CONFIG_UDELAY_LAPIC_FIXED_FSB=200 +CONFIG_SET_FIDVID_DEBUG=y +# CONFIG_SET_FIDVID_CORE0_ONLY is not set +CONFIG_SET_FIDVID_STORE_AP_APICID_AT_FIRST=y +CONFIG_CPU_AMD_MODEL_10XXX=y +CONFIG_NUM_IPI_STARTS=1 +CONFIG_SET_FIDVID_CORE_RANGE=0 +# CONFIG_CPU_AMD_AGESA is not set +CONFIG_S3_DATA_SIZE=32768 +# CONFIG_CPU_AMD_PI is not set +# CONFIG_CPU_ARMLTD_CORTEX_A9 is not set +CONFIG_SSE2=y +# CONFIG_CPU_INTEL_FIRMWARE_INTERFACE_TABLE is not set +# CONFIG_CPU_INTEL_TURBO_NOT_PACKAGE_SCOPED is not set +# CONFIG_CPU_TI_AM335X is not set +CONFIG_PARALLEL_CPU_INIT=y +CONFIG_UDELAY_LAPIC=y +# CONFIG_LAPIC_MONOTONIC_TIMER is not set +# CONFIG_UDELAY_TSC is not set +# CONFIG_UDELAY_TIMER2 is not set +# CONFIG_TSC_CALIBRATE_WITH_IO is not set +CONFIG_TSC_SYNC_LFENCE=y +# CONFIG_TSC_SYNC_MFENCE is not set +CONFIG_LOGICAL_CPUS=y +# CONFIG_SMM_TSEG is not set +CONFIG_X86_AMD_FIXED_MTRRS=y +# CONFIG_PLATFORM_USES_FSP1_0 is not set +# CONFIG_PARALLEL_MP is not set +# CONFIG_BACKUP_DEFAULT_SMM_REGION is not set +# CONFIG_MIRROR_PAYLOAD_TO_RAM_BEFORE_LOADING is not set +CONFIG_CACHE_AS_RAM=y +CONFIG_SMP=y +CONFIG_AP_SIPI_VECTOR=0xfffff000 +CONFIG_SSE=y +CONFIG_SUPPORT_CPU_UCODE_IN_CBFS=y +# CONFIG_CPU_MICROCODE_CBFS_GENERATE is not set +# CONFIG_CPU_MICROCODE_CBFS_EXTERNAL is not set +CONFIG_CPU_MICROCODE_CBFS_NONE=y + +# +# Northbridge +# +# CONFIG_NORTHBRIDGE_AMD_AGESA is not set +CONFIG_MMCONF_BUS_NUMBER=256 +CONFIG_NORTHBRIDGE_AMD_AMDFAM10=y +CONFIG_SB_HT_CHAIN_UNITID_OFFSET_ONLY=y +# CONFIG_HT_CHAIN_DISTRIBUTE is not set +# CONFIG_DIMM_FBDIMM is not set +# CONFIG_DIMM_DDR2 is not set +CONFIG_DIMM_DDR3=y +CONFIG_DIMM_REGISTERED=y +# CONFIG_SVI_HIGH_FREQ is not set + +# +# HyperTransport setup +# +# CONFIG_LIMIT_HT_DOWN_WIDTH_8 is not set +CONFIG_LIMIT_HT_DOWN_WIDTH_16=y +# CONFIG_LIMIT_HT_UP_WIDTH_8 is not set +CONFIG_LIMIT_HT_UP_WIDTH_16=y +# CONFIG_AMD_NB_CIMX is not set +# CONFIG_NORTHBRIDGE_AMD_CIMX_RD890 is not set +CONFIG_VIDEO_MB=0 +# CONFIG_NORTHBRIDGE_AMD_PI is not set +CONFIG_RAMBASE=0x100000 +CONFIG_HPET_ADDRESS=0xfed00000 +CONFIG_MAX_PIRQ_LINKS=4 + +# +# Southbridge +# +# CONFIG_AMD_SB_CIMX is not set +# CONFIG_SOUTHBRIDGE_AMD_CIMX_SB800 is not set +# CONFIG_SOUTHBRIDGE_AMD_CIMX_SB900 is not set +CONFIG_SOUTHBRIDGE_AMD_SB700=y +CONFIG_SOUTHBRIDGE_SPECIFIC_OPTIONS=y +CONFIG_SOUTHBRIDGE_AMD_SUBTYPE_SP5100=y +# CONFIG_SOUTHBRIDGE_AMD_SB700_SKIP_ISA_DMA_INIT is not set +CONFIG_SOUTHBRIDGE_AMD_SB700_DISABLE_ISA_DMA=y +CONFIG_SOUTHBRIDGE_AMD_SR5650=y +# CONFIG_SOUTHBRIDGE_INTEL_COMMON is not set + +# +# Super I/O +# +CONFIG_SUPERIO_NUVOTON_COMMON_ROMSTAGE=y +CONFIG_SUPERIO_NUVOTON_NCT5572D=y + +# +# Embedded Controllers +# +# CONFIG_MAINBOARD_HAS_CHROMEOS is not set +# CONFIG_UEFI_2_4_BINDING is not set +# CONFIG_ARCH_ARM is not set +# CONFIG_ARCH_BOOTBLOCK_ARM is not set +# CONFIG_ARCH_VERSTAGE_ARM is not set +# CONFIG_ARCH_ROMSTAGE_ARM is not set +# CONFIG_ARCH_RAMSTAGE_ARM is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV4 is not set +# CONFIG_ARCH_VERSTAGE_ARMV4 is not set +# CONFIG_ARCH_ROMSTAGE_ARMV4 is not set +# CONFIG_ARCH_RAMSTAGE_ARMV4 is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV7 is not set +# CONFIG_ARCH_VERSTAGE_ARMV7 is not set +# CONFIG_ARCH_ROMSTAGE_ARMV7 is not set +# CONFIG_ARCH_RAMSTAGE_ARMV7 is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV7_M is not set +# CONFIG_ARCH_VERSTAGE_ARMV7_M is not set +# CONFIG_ARM_BOOTBLOCK_CUSTOM is not set +# CONFIG_ARM_LPAE is not set +# CONFIG_ARCH_ARM64 is not set +# CONFIG_ARCH_BOOTBLOCK_ARM64 is not set +# CONFIG_ARCH_VERSTAGE_ARM64 is not set +# CONFIG_ARCH_ROMSTAGE_ARM64 is not set +# CONFIG_ARCH_RAMSTAGE_ARM64 is not set +# CONFIG_ARCH_BOOTBLOCK_ARMV8_64 is not set +# CONFIG_ARCH_VERSTAGE_ARMV8_64 is not set +# CONFIG_ARCH_ROMSTAGE_ARMV8_64 is not set +# CONFIG_ARCH_RAMSTAGE_ARMV8_64 is not set +# CONFIG_ARM64_BOOTBLOCK_CUSTOM is not set +# CONFIG_ARM64_A53_ERRATUM_843419 is not set +# CONFIG_ARCH_MIPS is not set +# CONFIG_ARCH_BOOTBLOCK_MIPS is not set +# CONFIG_ARCH_VERSTAGE_MIPS is not set +# CONFIG_ARCH_ROMSTAGE_MIPS is not set +# CONFIG_ARCH_RAMSTAGE_MIPS is not set +# CONFIG_ARCH_RISCV is not set +# CONFIG_ARCH_BOOTBLOCK_RISCV is not set +# CONFIG_ARCH_VERSTAGE_RISCV is not set +# CONFIG_ARCH_ROMSTAGE_RISCV is not set +# CONFIG_ARCH_RAMSTAGE_RISCV is not set +# CONFIG_RISCV_BOOTBLOCK_CUSTOM is not set +CONFIG_ARCH_X86=y +CONFIG_ARCH_BOOTBLOCK_X86_32=y +CONFIG_ARCH_VERSTAGE_X86_32=y +CONFIG_ARCH_ROMSTAGE_X86_32=y +CONFIG_ARCH_RAMSTAGE_X86_32=y +# CONFIG_ARCH_BOOTBLOCK_X86_64 is not set +# CONFIG_ARCH_VERSTAGE_X86_64 is not set +# CONFIG_ARCH_ROMSTAGE_X86_64 is not set +# CONFIG_ARCH_RAMSTAGE_X86_64 is not set +# CONFIG_AP_IN_SIPI_WAIT is not set +# CONFIG_SIPI_VECTOR_IN_ROM is not set +# CONFIG_ROMCC is not set +# CONFIG_LATE_CBMEM_INIT is not set +CONFIG_PC80_SYSTEM=y +CONFIG_HAVE_CMOS_DEFAULT=y +CONFIG_CMOS_DEFAULT_FILE="src/mainboard/$(MAINBOARDDIR)/cmos.default" +CONFIG_IOAPIC_INTERRUPTS_ON_FSB=y +# CONFIG_IOAPIC_INTERRUPTS_ON_APIC_SERIAL_BUS is not set +# CONFIG_COMPILE_IN_DSDT is not set + +# +# Devices +# +# CONFIG_MAINBOARD_HAS_NATIVE_VGA_INIT is not set +CONFIG_NATIVE_VGA_INIT_USE_EDID=y +CONFIG_MAINBOARD_HAS_NATIVE_VGA_INIT_TEXTMODECFG=y +# CONFIG_VGA_ROM_RUN is not set +# CONFIG_ON_DEVICE_ROM_RUN is not set +# CONFIG_MULTIPLE_VGA_ADAPTERS is not set +# CONFIG_SPD_CACHE is not set +CONFIG_PCI=y +CONFIG_HYPERTRANSPORT_PLUGIN_SUPPORT=y +CONFIG_PCIX_PLUGIN_SUPPORT=y +CONFIG_PCIEXP_PLUGIN_SUPPORT=y +CONFIG_CARDBUS_PLUGIN_SUPPORT=y +# CONFIG_AZALIA_PLUGIN_SUPPORT is not set +# CONFIG_PCIEXP_COMMON_CLOCK is not set +# CONFIG_PCIEXP_ASPM is not set +# CONFIG_PCIEXP_CLK_PM is not set +# CONFIG_EARLY_PCI_BRIDGE is not set +# CONFIG_PCIEXP_L1_SUB_STATE is not set +CONFIG_SUBSYSTEM_VENDOR_ID=0x0000 +CONFIG_SUBSYSTEM_DEVICE_ID=0x0000 +# CONFIG_PXE_ROM is not set +# CONFIG_SOFTWARE_I2C is not set + +# +# Generic Drivers +# +# CONFIG_DRIVERS_AS3722_RTC is not set +CONFIG_DRIVERS_ASPEED_AST_COMMON=y +CONFIG_DEVICE_SPECIFIC_OPTIONS=y +CONFIG_DRIVERS_ASPEED_AST2050=y +# CONFIG_ELOG is not set +# CONFIG_GIC is not set +# CONFIG_SMBIOS_PROVIDED_BY_MOBO is not set +# CONFIG_DRIVERS_I2C_RTD2132 is not set +CONFIG_DRIVERS_I2C_W83795=y +# CONFIG_INTEL_DP is not set +# CONFIG_INTEL_DDI is not set +# CONFIG_INTEL_EDID is not set +# CONFIG_INTEL_INT15 is not set +# CONFIG_INTEL_GMA_ACPI is not set +# CONFIG_DRIVER_INTEL_I210 is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_DRIVERS_LENOVO_WACOM is not set +# CONFIG_DRIVER_MAXIM_MAX77686 is not set +# CONFIG_DRIVER_PARADE_PS8625 is not set +CONFIG_DRIVERS_MC146818=y +# CONFIG_MAINBOARD_HAS_LPC_TPM is not set +# CONFIG_DRIVERS_RICOH_RCE822 is not set +# CONFIG_DRIVERS_SIL_3114 is not set +CONFIG_SPI_FLASH=y +CONFIG_SPI_ATOMIC_SEQUENCING=y +CONFIG_SPI_FLASH_MEMORY_MAPPED=y +# CONFIG_SPI_FLASH_NO_FAST_READ is not set +CONFIG_SPI_FLASH_ADESTO=y +CONFIG_SPI_FLASH_AMIC=y +CONFIG_SPI_FLASH_ATMEL=y +CONFIG_SPI_FLASH_EON=y +CONFIG_SPI_FLASH_GIGADEVICE=y +CONFIG_SPI_FLASH_MACRONIX=y +CONFIG_SPI_FLASH_SPANSION=y +CONFIG_SPI_FLASH_SST=y +CONFIG_SPI_FLASH_STMICRO=y +CONFIG_SPI_FLASH_WINBOND=y +# CONFIG_SPI_FLASH_FAST_READ_DUAL_OUTPUT_3B is not set +# CONFIG_HAVE_SPI_CONSOLE_SUPPORT is not set +# CONFIG_DRIVER_TI_TPS65090 is not set +# CONFIG_DRIVERS_TI_TPS65913 is not set +# CONFIG_DRIVERS_TI_TPS65913_RTC is not set +CONFIG_DRIVERS_UART=y +CONFIG_DRIVERS_UART_8250IO=y +# CONFIG_NO_UART_ON_SUPERIO is not set +# CONFIG_DRIVERS_UART_8250MEM is not set +# CONFIG_DRIVERS_UART_8250MEM_32 is not set +# CONFIG_HAVE_UART_SPECIAL is not set +# CONFIG_DRIVERS_UART_OXPCIE is not set +# CONFIG_DRIVERS_UART_PL011 is not set +CONFIG_HAVE_USBDEBUG=y +CONFIG_HAVE_USBDEBUG_OPTIONS=y +CONFIG_USBDEBUG_IN_ROMSTAGE=y +CONFIG_USBDEBUG_DEFAULT_PORT=0 +CONFIG_USBDEBUG_DONGLE_STD=y +# CONFIG_USBDEBUG_DONGLE_BEAGLEBONE is not set +# CONFIG_USBDEBUG_DONGLE_BEAGLEBONE_BLACK is not set +# CONFIG_USBDEBUG_DONGLE_FTDI_FT232H is not set +CONFIG_USBDEBUG_OPTIONAL_HUB_PORT=0 +# CONFIG_DRIVER_XPOWERS_AXP209 is not set +CONFIG_RTC=y +# CONFIG_TPM is not set +CONFIG_STACK_SIZE=0x1000 +CONFIG_MMCONF_SUPPORT_DEFAULT=y +CONFIG_MMCONF_SUPPORT=y +# CONFIG_BOOTMODE_STRAPS is not set + +# +# Console +# +CONFIG_SQUELCH_EARLY_SMP=y +CONFIG_CONSOLE_SERIAL=y + +# +# I/O mapped, 8250-compatible +# +CONFIG_CONSOLE_SERIAL_115200=y +# CONFIG_CONSOLE_SERIAL_57600 is not set +# CONFIG_CONSOLE_SERIAL_38400 is not set +# CONFIG_CONSOLE_SERIAL_19200 is not set +# CONFIG_CONSOLE_SERIAL_9600 is not set +CONFIG_TTYS0_BAUD=115200 +# CONFIG_SPKMODEM is not set +CONFIG_CONSOLE_USB=y +# CONFIG_CONSOLE_NE2K is not set +CONFIG_CONSOLE_CBMEM=y +CONFIG_CONSOLE_CBMEM_BUFFER_SIZE=0x20000 +CONFIG_DEFAULT_CONSOLE_LOGLEVEL_8=y +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_7 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_6 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_5 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_4 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_3 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_2 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_1 is not set +# CONFIG_DEFAULT_CONSOLE_LOGLEVEL_0 is not set +# CONFIG_NO_POST is not set +# CONFIG_CMOS_POST is not set +# CONFIG_CONSOLE_POST is not set +CONFIG_POST_DEVICE_NONE=y +# CONFIG_POST_DEVICE_LPC is not set +# CONFIG_POST_DEVICE_PCI_PCIE is not set +CONFIG_POST_IO=y +CONFIG_POST_IO_PORT=0x80 +CONFIG_HAVE_ACPI_RESUME=y +CONFIG_HAVE_HARD_RESET=y +CONFIG_HAVE_ROMSTAGE_CONSOLE_SPINLOCK=y +CONFIG_HAVE_ROMSTAGE_NVRAM_CBFS_SPINLOCK=y +CONFIG_HAVE_ROMSTAGE_MICROCODE_CBFS_SPINLOCK=y +CONFIG_HAVE_MONOTONIC_TIMER=y +# CONFIG_GENERIC_UDELAY is not set +# CONFIG_TIMER_QUEUE is not set +CONFIG_HAVE_OPTION_TABLE=y +# CONFIG_PIRQ_ROUTE is not set +# CONFIG_HAVE_SMI_HANDLER is not set +CONFIG_PCI_IO_CFG_EXT=y +CONFIG_IOAPIC=y +# CONFIG_USE_WATCHDOG_ON_BOOT is not set +CONFIG_VGA=y +# CONFIG_GFXUMA is not set +CONFIG_HAVE_ACPI_TABLES=y +CONFIG_HAVE_MP_TABLE=y +CONFIG_HAVE_PIRQ_TABLE=y +# CONFIG_COMMON_FADT is not set + +# +# System tables +# +CONFIG_GENERATE_MP_TABLE=y +CONFIG_GENERATE_PIRQ_TABLE=y +CONFIG_GENERATE_SMBIOS_TABLES=y +CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME="KGPE-D16" + +# +# Payload +# +# CONFIG_PAYLOAD_NONE is not set +CONFIG_PAYLOAD_ELF=y +# CONFIG_PAYLOAD_FILO is not set +# CONFIG_PAYLOAD_GRUB2 is not set +# CONFIG_PAYLOAD_SEABIOS is not set +# CONFIG_PAYLOAD_LINUX is not set +# CONFIG_PAYLOAD_TIANOCORE is not set +CONFIG_PAYLOAD_FILE="grub.elf" +CONFIG_COMPRESSED_PAYLOAD_LZMA=y + +# +# Debugging +# +# CONFIG_GDB_STUB is not set +# CONFIG_FATAL_ASSERTS is not set +# CONFIG_DEBUG_CBFS is not set +CONFIG_HAVE_DEBUG_RAM_SETUP=y +# CONFIG_DEBUG_RAM_SETUP is not set +CONFIG_HAVE_DEBUG_CAR=y +# CONFIG_DEBUG_CAR is not set +# CONFIG_DEBUG_PIRQ is not set +CONFIG_HAVE_DEBUG_SMBUS=y +# CONFIG_DEBUG_SMBUS is not set +# CONFIG_DEBUG_MALLOC is not set +# CONFIG_DEBUG_ACPI is not set +# CONFIG_DEBUG_SPI_FLASH is not set +# CONFIG_DEBUG_USBDEBUG is not set +# CONFIG_TRACE is not set +CONFIG_ENABLE_APIC_EXT_ID=y +CONFIG_WARNINGS_ARE_ERRORS=y +# CONFIG_POWER_BUTTON_DEFAULT_ENABLE is not set +# CONFIG_POWER_BUTTON_DEFAULT_DISABLE is not set +# CONFIG_POWER_BUTTON_FORCE_ENABLE is not set +# CONFIG_POWER_BUTTON_FORCE_DISABLE is not set +# CONFIG_POWER_BUTTON_IS_OPTIONAL is not set +# CONFIG_REG_SCRIPT is not set +CONFIG_MAX_REBOOT_CNT=3 diff --git a/resources/libreboot/config/grub/macbook21/config b/resources/libreboot/config/grub/macbook21/config @@ -435,6 +435,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set # CONFIG_TIMER_QUEUE is not set diff --git a/resources/libreboot/config/grub/qemu_i440fx_piix4/config b/resources/libreboot/config/grub/qemu_i440fx_piix4/config @@ -411,6 +411,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 # CONFIG_HAVE_ACPI_RESUME is not set # CONFIG_HAVE_HARD_RESET is not set +# 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/qemu_q35_ich9/config b/resources/libreboot/config/grub/qemu_q35_ich9/config @@ -414,6 +414,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 # 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 is not set # CONFIG_HAVE_OPTION_TABLE is not set # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/r400_4mb/config b/resources/libreboot/config/grub/r400_4mb/config @@ -440,6 +440,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/r400_8mb/config b/resources/libreboot/config/grub/r400_8mb/config @@ -440,6 +440,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/t400_4mb/config b/resources/libreboot/config/grub/t400_4mb/config @@ -440,6 +440,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/t400_8mb/config b/resources/libreboot/config/grub/t400_8mb/config @@ -440,6 +440,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/t500_4mb/config b/resources/libreboot/config/grub/t500_4mb/config @@ -440,6 +440,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/t500_8mb/config b/resources/libreboot/config/grub/t500_8mb/config @@ -440,6 +440,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/t60/config b/resources/libreboot/config/grub/t60/config @@ -452,6 +452,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set # CONFIG_TIMER_QUEUE is not set diff --git a/resources/libreboot/config/grub/x200_4mb/config b/resources/libreboot/config/grub/x200_4mb/config @@ -430,6 +430,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/x200_8mb/config b/resources/libreboot/config/grub/x200_8mb/config @@ -430,6 +430,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set CONFIG_HAVE_OPTION_TABLE=y # CONFIG_PIRQ_ROUTE is not set diff --git a/resources/libreboot/config/grub/x60/config b/resources/libreboot/config/grub/x60/config @@ -456,6 +456,9 @@ CONFIG_POST_IO=y CONFIG_POST_IO_PORT=0x80 CONFIG_HAVE_ACPI_RESUME=y 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 is not set # CONFIG_TIMER_QUEUE is not set diff --git a/resources/libreboot/patch/kgpe-d16/0001-util-cbmem-Fix-failure-with-certain-cbmem-base-align.patch b/resources/libreboot/patch/kgpe-d16/0001-util-cbmem-Fix-failure-with-certain-cbmem-base-align.patch @@ -0,0 +1,205 @@ +From 4e0a69562a189e9abe06979a993f50e3f0b2069b Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 18:07:17 -0500 +Subject: [PATCH 001/146] util/cbmem: Fix failure with certain cbmem base + alignments + +--- + util/cbmem/cbmem.c | 61 ++++++++++++++++++++++++++++++++-------------------- + 1 file changed, 38 insertions(+), 23 deletions(-) + +diff --git a/util/cbmem/cbmem.c b/util/cbmem/cbmem.c +index 74cb52d..69ffbaf 100644 +--- a/util/cbmem/cbmem.c ++++ b/util/cbmem/cbmem.c +@@ -2,6 +2,7 @@ + * This file is part of the coreboot project. + * + * Copyright 2012 Google Inc. ++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, 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,8 +104,7 @@ static void unmap_memory(void) + if (size_to_mib(mapped_size) == 0) { + debug("Unmapping %zuMB of virtual memory at %p.\n", + size_to_mib(mapped_size), mapped_virtual); +- } +- else { ++ } else { + debug("Unmapping %zuMB of virtual memory at %p.\n", + size_to_mib(mapped_size), mapped_virtual); + } +@@ -113,7 +113,7 @@ static void unmap_memory(void) + mapped_size = 0; + } + +-static void *map_memory_size(u64 physical, size_t size) ++static void *map_memory_size(u64 physical, size_t size, uint8_t abort_on_failure) + { + void *v; + off_t p; +@@ -131,8 +131,7 @@ static void *map_memory_size(u64 physical, size_t size) + if (size_to_mib(size) == 0) { + debug("Mapping %zuB of physical memory at 0x%jx (requested 0x%jx).\n", + size, (intmax_t)p, (intmax_t)physical); +- } +- else { ++ } else { + debug("Mapping %zuMB of physical memory at 0x%jx (requested 0x%jx).\n", + size_to_mib(size), (intmax_t)p, (intmax_t)physical); + } +@@ -153,9 +152,13 @@ static void *map_memory_size(u64 physical, size_t size) + } + + if (v == MAP_FAILED) { +- fprintf(stderr, "Failed to mmap /dev/mem: %s\n", +- strerror(errno)); +- exit(1); ++ if (abort_on_failure) { ++ fprintf(stderr, "Failed to mmap /dev/mem: %s\n", ++ strerror(errno)); ++ exit(1); ++ } else { ++ return 0; ++ } + } + + /* Remember what we actually mapped ... */ +@@ -173,7 +176,7 @@ static void *map_memory_size(u64 physical, size_t size) + + static void *map_memory(u64 physical) + { +- return map_memory_size(physical, MAP_BYTES); ++ return map_memory_size(physical, MAP_BYTES, 1); + } + + /* +@@ -210,14 +213,16 @@ static struct lb_cbmem_ref parse_cbmem_ref(struct lb_cbmem_ref *cbmem_ref) + return ret; + } + +-static int parse_cbtable(u64 address, size_t table_size) ++static int parse_cbtable(u64 address, size_t table_size, uint8_t abort_on_failure) + { +- int i, found = 0; ++ int i, found, ret = 0; + void *buf; + + debug("Looking for coreboot table at %" PRIx64 " %zd bytes.\n", + address, table_size); +- buf = map_memory_size(address, table_size); ++ buf = map_memory_size(address, table_size, abort_on_failure); ++ if (!buf) ++ return -2; + + /* look at every 16 bytes within 4K of the base */ + +@@ -283,7 +288,17 @@ static int parse_cbtable(u64 address, size_t table_size) + *(struct lb_forward *) lbr_p; + debug(" Found forwarding entry.\n"); + unmap_memory(); +- return parse_cbtable(lbf_p.forward, table_size); ++ ret = parse_cbtable(lbf_p.forward, table_size, 0); ++ if (ret == -2) { ++ /* try again with a smaller memory mapping request */ ++ ret = parse_cbtable(lbf_p.forward, table_size / 2, 1); ++ if (ret == -2) ++ exit(1); ++ else ++ return ret; ++ } else { ++ return ret; ++ } + } + default: + break; +@@ -544,7 +559,7 @@ static void dump_timestamps(int mach_readable) + } + + size = sizeof(*tst_p); +- tst_p = map_memory_size((unsigned long)timestamps.cbmem_addr, size); ++ tst_p = map_memory_size((unsigned long)timestamps.cbmem_addr, size, 1); + + timestamp_set_tick_freq(tst_p->tick_freq_mhz); + +@@ -553,7 +568,7 @@ static void dump_timestamps(int mach_readable) + size += tst_p->num_entries * sizeof(tst_p->entries[0]); + + unmap_memory(); +- tst_p = map_memory_size((unsigned long)timestamps.cbmem_addr, size); ++ tst_p = map_memory_size((unsigned long)timestamps.cbmem_addr, size, 1); + + /* Report the base time within the table. */ + prev_stamp = 0; +@@ -604,7 +619,7 @@ static void dump_console(void) + } + + console_p = map_memory_size((unsigned long)console.cbmem_addr, +- 2 * sizeof(uint32_t)); ++ 2 * sizeof(uint32_t), 1); + /* The in-memory format of the console area is: + * u32 size + * u32 cursor +@@ -626,7 +641,7 @@ static void dump_console(void) + } + + console_p = map_memory_size((unsigned long)console.cbmem_addr, +- size + sizeof(size) + sizeof(cursor)); ++ size + sizeof(size) + sizeof(cursor), 1); + memcpy(console_c, console_p + 8, size); + console_c[size] = 0; + console_c[cursor] = 0; +@@ -647,7 +662,7 @@ static void hexdump(unsigned long memory, int length) + uint8_t *m; + int all_zero = 0; + +- m = map_memory_size((intptr_t)memory, length); ++ m = map_memory_size((intptr_t)memory, length, 1); + + if (length > MAP_BYTES) { + printf("Truncating hex dump from %d to %d bytes\n\n", +@@ -803,7 +818,7 @@ static void dump_cbmem_toc(void) + + start = unpack_lb64(cbmem.start); + +- cbmem_area = map_memory_size(start, unpack_lb64(cbmem.size)); ++ cbmem_area = map_memory_size(start, unpack_lb64(cbmem.size), 1); + entries = (struct cbmem_entry *)cbmem_area; + + if (entries[0].magic == CBMEM_MAGIC) { +@@ -814,12 +829,12 @@ static void dump_cbmem_toc(void) + rootptr -= sizeof(struct cbmem_root_pointer); + unmap_memory(); + struct cbmem_root_pointer *r = +- map_memory_size(rootptr, sizeof(*r)); ++ map_memory_size(rootptr, sizeof(*r), 1); + if (r->magic == CBMEM_POINTER_MAGIC) { + struct cbmem_root *root; + uint64_t rootaddr = rootptr + r->root_offset; + unmap_memory(); +- root = map_memory_size(rootaddr, ROOT_MIN_SIZE); ++ root = map_memory_size(rootaddr, ROOT_MIN_SIZE, 1); + dump_dynamic_cbmem_toc(root); + } else + fprintf(stderr, "No valid coreboot CBMEM root pointer found.\n"); +@@ -1205,14 +1220,14 @@ int main(int argc, char** argv) + dtbuffer++; + } + +- parse_cbtable(baseaddr, cb_table_size); ++ parse_cbtable(baseaddr, cb_table_size, 1); + #else + int j; + static const int possible_base_addresses[] = { 0, 0xf0000 }; + + /* Find and parse coreboot table */ + for (j = 0; j < ARRAY_SIZE(possible_base_addresses); j++) { +- if (parse_cbtable(possible_base_addresses[j], MAP_BYTES)) ++ if (parse_cbtable(possible_base_addresses[j], MAP_BYTES, 1)) + break; + } + #endif +-- +1.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0002-cpu-amd-microcode-Update-microcode-parser-to-handle-.patch b/resources/libreboot/patch/kgpe-d16/0002-cpu-amd-microcode-Update-microcode-parser-to-handle-.patch @@ -0,0 +1,41 @@ +From f65e4abec63a8ec3bfb5a784cecb7405c463c038 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Tue, 11 Aug 2015 19:14:34 -0500 +Subject: [PATCH 002/146] cpu/amd/microcode: Update microcode parser to handle + expanded blob files + +--- + src/cpu/amd/microcode/microcode.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/cpu/amd/microcode/microcode.c b/src/cpu/amd/microcode/microcode.c +index 45e4bf0..ce5b08f 100644 +--- a/src/cpu/amd/microcode/microcode.c ++++ b/src/cpu/amd/microcode/microcode.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 <tpearson@raptorengineeringinc.com>, 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 +@@ -83,13 +84,13 @@ static void amd_update_microcode(const void *ucode, size_t ucode_len, + const uint8_t *c = ucode; + const uint8_t *ucode_end = (uint8_t*)ucode + ucode_len; + +- while (c <= (ucode_end - 2048)) { ++ while (c <= (ucode_end - 4096)) { + m = (struct microcode *)c; + if (m->processor_rev_id == equivalent_processor_rev_id) { + apply_microcode_patch(m); + break; + } +- c += 2048; ++ c += 4096; + } + } + +-- +1.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0003-arch-x86-boot-smbios-Add-SPD-IDs-for-Kingston-and-Co.patch b/resources/libreboot/patch/kgpe-d16/0003-arch-x86-boot-smbios-Add-SPD-IDs-for-Kingston-and-Co.patch @@ -0,0 +1,36 @@ +From f612a5cc0afba6e1af60652283dd47f3f34dcca7 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Thu, 25 Jun 2015 18:37:58 -0500 +Subject: [PATCH 003/146] arch/x86/boot/smbios: Add SPD IDs for Kingston and + Corsair + +--- + src/arch/x86/smbios.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c +index a1f05da..74288f9 100644 +--- a/src/arch/x86/smbios.c ++++ b/src/arch/x86/smbios.c +@@ -124,10 +124,18 @@ static int smbios_processor_name(char *start) + void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t) + { + switch (mod_id) { ++ case 0x9801: ++ t->manufacturer = smbios_add_string(t->eos, ++ "Kingston"); ++ break; + case 0x987f: + t->manufacturer = smbios_add_string(t->eos, + "Hynix"); + break; ++ case 0x9e02: ++ t->manufacturer = smbios_add_string(t->eos, ++ "Corsair"); ++ break; + case 0xad80: + t->manufacturer = smbios_add_string(t->eos, + "Hynix/Hyundai"); +-- +1.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0004-arch-x86-smbios-Add-Crucial-DIMM-manufacturer-ID.patch b/resources/libreboot/patch/kgpe-d16/0004-arch-x86-smbios-Add-Crucial-DIMM-manufacturer-ID.patch @@ -0,0 +1,27 @@ +From 4daf71b080abe86e2fe61af3adbc57a710b7ea02 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Tue, 28 Jul 2015 09:22:59 -0500 +Subject: [PATCH 004/146] arch/x86/smbios: Add Crucial DIMM manufacturer ID + +--- + src/arch/x86/smbios.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/arch/x86/smbios.c b/src/arch/x86/smbios.c +index 74288f9..6d645a3 100644 +--- a/src/arch/x86/smbios.c ++++ b/src/arch/x86/smbios.c +@@ -124,6 +124,10 @@ static int smbios_processor_name(char *start) + void smbios_fill_dimm_manufacturer_from_id(uint16_t mod_id, struct smbios_type17 *t) + { + switch (mod_id) { ++ case 0x2c80: ++ t->manufacturer = smbios_add_string(t->eos, ++ "Crucial"); ++ break; + case 0x9801: + t->manufacturer = smbios_add_string(t->eos, + "Kingston"); +-- +1.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0005-southbridge-amd-sr5650-Remove-unnecessary-register-c.patch b/resources/libreboot/patch/kgpe-d16/0005-southbridge-amd-sr5650-Remove-unnecessary-register-c.patch @@ -0,0 +1,33 @@ +From 0d0290e3866dd24c77de9114937b692bba0e9db9 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sun, 2 Aug 2015 21:29:20 -0500 +Subject: [PATCH 005/146] southbridge/amd/sr5650: Remove unnecessary register + configuration + +--- + src/southbridge/amd/sr5650/early_setup.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/southbridge/amd/sr5650/early_setup.c b/src/southbridge/amd/sr5650/early_setup.c +index d91f3bd..ec555f8 100644 +--- a/src/southbridge/amd/sr5650/early_setup.c ++++ b/src/southbridge/amd/sr5650/early_setup.c +@@ -1,6 +1,7 @@ + /* + * This file is part of the coreboot project. + * ++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering + * Copyright (C) 2010 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify +@@ -437,7 +438,6 @@ static void sr5650_por_htiu_index_init(device_t nb_dev) + set_htiu_enable_bits(nb_dev, 0x1D, 0x1<<2, 0x1<<2); + set_htiu_enable_bits(nb_dev, 0x1D, 0x1<<4, 0x1<<4); + +- set_nbcfg_enable_bits(cpu_f0, 0x68, 3 << 21, 0 << 21); + axindxc_reg(0x10, 1 << 9, 1 << 9); + set_pcie_enable_bits(nb_dev, 0x10 | 5 << 16, 1 << 9, 1 << 9); + set_htiu_enable_bits(nb_dev, 0x06, 0x1<<26, 0x1<<26); +-- +1.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0006-drivers-i2c-w83795-Add-full-support-for-fan-control-.patch b/resources/libreboot/patch/kgpe-d16/0006-drivers-i2c-w83795-Add-full-support-for-fan-control-.patch @@ -0,0 +1,661 @@ +From 12a58e8598d572ee4997f0a6670796b5e82d318b Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 17:53:20 -0500 +Subject: [PATCH 006/146] drivers/i2c/w83795: Add full support for fan + control, fan monitoring, and voltage monitoring + +--- + src/drivers/i2c/w83795/chip.h | 146 +++++++++++++++++++ + src/drivers/i2c/w83795/w83795.c | 301 +++++++++++++++++++++++++++------------ + src/drivers/i2c/w83795/w83795.h | 50 +++++-- + 3 files changed, 392 insertions(+), 105 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..413ea87 +--- /dev/null ++++ b/src/drivers/i2c/w83795/chip.h +@@ -0,0 +1,146 @@ ++/* ++ * This file is part of the coreboot project. ++ * ++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, 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) */ ++ ++ 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 2bbe0be..0e40710 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 <tpearson@raptorengineeringinc.com>, 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,12 +22,19 @@ + #include <arch/cpu.h> + #include <console/console.h> + #include <device/device.h> +-#include "southbridge/amd/cimx/sb700/smbus.h" /*SMBUS_IO_BASE*/ ++#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_SB700) ++# include "southbridge/amd/sb700/smbus.h" /*SMBUS_IO_BASE*/ ++#else ++# include "southbridge/amd/cimx/sb700/smbus.h" /*SMBUS_IO_BASE*/ ++#endif + #include "w83795.h" ++#include "chip.h" ++ ++static uint32_t smbus_io_base; + + static int w83795_set_bank(u8 bank) + { +- return do_smbus_write_byte(SMBUS_IO_BASE, W83795_DEV, W83795_REG_BANKSEL, bank); ++ return do_smbus_write_byte(smbus_io_base, W83795_DEV, W83795_REG_BANKSEL, bank); + } + + static u8 w83795_read(u16 reg) +@@ -35,11 +43,11 @@ static u8 w83795_read(u16 reg) + + ret = w83795_set_bank(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 = do_smbus_read_byte(smbus_io_base, W83795_DEV, reg & 0xff); + return ret; + } + +@@ -49,18 +57,18 @@ static u8 w83795_write(u16 reg, u8 value) + + err = w83795_set_bank(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 = do_smbus_write_byte(smbus_io_base, W83795_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(u8 dts_src) + { + u8 val; + +@@ -68,45 +76,6 @@ static void w83795_dts_enable(u8 dts_src) + val = w83795_read(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); +-} +- +-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) +@@ -131,40 +100,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) + { +- 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); + +- /* 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,12 +114,45 @@ 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 (config->smbus_aux) ++ smbus_io_base = SMBUS_AUX_IO_BASE; ++ else ++ smbus_io_base = SMBUS_IO_BASE; + +- if (do_smbus_read_byte(SMBUS_IO_BASE, W83795_DEV, 0x00) < 0) { ++ if (do_smbus_read_byte(smbus_io_base, W83795_DEV, 0x00) < 0) { + printk(BIOS_ERR, "W83795G/ADG Nuvoton H/W Monitor not found\n"); + return; + } +@@ -192,18 +166,156 @@ static void w83795_init(w83795_fan_mode_t mode, u8 dts_src) + 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); ++ /* Fan monitor settings */ ++ w83795_write(W83795_REG_FANIN_CTRL1, config->fanin_ctl1); ++ w83795_write(W83795_REG_FANIN_CTRL2, config->fanin_ctl2); ++ ++ /* Temperature thresholds */ ++ w83795_write(W83795_REG_TEMP_CRIT(0), config->tr1_critical_temperature); ++ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(0), config->tr1_critical_hysteresis); ++ w83795_write(W83795_REG_TEMP_WARN(0), config->tr1_warning_temperature); ++ w83795_write(W83795_REG_TEMP_WARN_HYSTER(0), config->tr1_warning_hysteresis); ++ w83795_write(W83795_REG_TEMP_CRIT(1), config->tr2_critical_temperature); ++ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(1), config->tr2_critical_hysteresis); ++ w83795_write(W83795_REG_TEMP_WARN(1), config->tr2_warning_temperature); ++ w83795_write(W83795_REG_TEMP_WARN_HYSTER(1), config->tr2_warning_hysteresis); ++ w83795_write(W83795_REG_TEMP_CRIT(2), config->tr3_critical_temperature); ++ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(2), config->tr3_critical_hysteresis); ++ w83795_write(W83795_REG_TEMP_WARN(2), config->tr3_warning_temperature); ++ w83795_write(W83795_REG_TEMP_WARN_HYSTER(2), config->tr3_warning_hysteresis); ++ w83795_write(W83795_REG_TEMP_CRIT(3), config->tr4_critical_temperature); ++ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(3), config->tr4_critical_hysteresis); ++ w83795_write(W83795_REG_TEMP_WARN(3), config->tr4_warning_temperature); ++ w83795_write(W83795_REG_TEMP_WARN_HYSTER(3), config->tr4_warning_hysteresis); ++ w83795_write(W83795_REG_TEMP_CRIT(4), config->tr5_critical_temperature); ++ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(4), config->tr5_critical_hysteresis); ++ w83795_write(W83795_REG_TEMP_WARN(4), config->tr5_warning_temperature); ++ w83795_write(W83795_REG_TEMP_WARN_HYSTER(4), config->tr5_warning_hysteresis); ++ w83795_write(W83795_REG_TEMP_CRIT(5), config->tr6_critical_temperature); ++ w83795_write(W83795_REG_TEMP_CRIT_HYSTER(5), config->tr6_critical_hysteresis); ++ w83795_write(W83795_REG_TEMP_WARN(5), config->tr6_warning_temperature); ++ w83795_write(W83795_REG_TEMP_WARN_HYSTER(5), config->tr6_warning_hysteresis); ++ ++ /* DTS enable */ ++ w83795_write(W83795_REG_DTSE, config->temp_dtse); ++ ++ /* DTS temperature thresholds */ ++ w83795_write(W83795_REG_DTS_CRIT, config->dts_critical_temperature); ++ w83795_write(W83795_REG_DTS_CRIT_HYSTER, config->dts_critical_hysteresis); ++ w83795_write(W83795_REG_DTS_WARN, config->dts_warning_temperature); ++ w83795_write(W83795_REG_DTS_WARN_HYSTER, config->dts_warning_hysteresis); ++ ++ /* Configure DTS registers in bank3 before enabling DTS */ ++ w83795_dts_configure(dts_src); ++ ++ /* Temperature monitor settings */ ++ w83795_write(W83795_REG_TEMP_CTRL1, config->temp_ctl1); ++ w83795_write(W83795_REG_TEMP_CTRL2, config->temp_ctl2); ++ ++ /* Temperature to fan mappings */ ++ w83795_write(W83795_REG_TFMR(0), config->temp1_fan_select); ++ w83795_write(W83795_REG_TFMR(1), config->temp2_fan_select); ++ w83795_write(W83795_REG_TFMR(2), config->temp3_fan_select); ++ w83795_write(W83795_REG_TFMR(3), config->temp4_fan_select); ++ w83795_write(W83795_REG_TFMR(4), config->temp5_fan_select); ++ w83795_write(W83795_REG_TFMR(5), config->temp6_fan_select); ++ ++ /* Temperature data source to temperature mappings */ ++ w83795_write(W83795_REG_T12TSS, ((config->temp2_source_select & 0xff) << 8) | (config->temp1_source_select & 0xff)); ++ w83795_write(W83795_REG_T34TSS, ((config->temp4_source_select & 0xff) << 8) | (config->temp3_source_select & 0xff)); ++ w83795_write(W83795_REG_T56TSS, ((config->temp6_source_select & 0xff) << 8) | (config->temp5_source_select & 0xff)); + +- /* enable monitoring operations */ +- val = w83795_read(W83795_REG_CONFIG); +- val |= W83795_REG_CONFIG_START; +- w83795_write(W83795_REG_CONFIG, val); ++ /* Set Critical Temperature to Full Speed all fan (CTFS) */ ++ w83795_write(W83795_REG_CTFS(0), config->temp1_critical_temperature); ++ w83795_write(W83795_REG_CTFS(1), config->temp2_critical_temperature); ++ w83795_write(W83795_REG_CTFS(2), config->temp3_critical_temperature); ++ w83795_write(W83795_REG_CTFS(3), config->temp4_critical_temperature); ++ w83795_write(W83795_REG_CTFS(4), config->temp5_critical_temperature); ++ w83795_write(W83795_REG_CTFS(5), config->temp6_critical_temperature); ++ ++ /* Set fan control target temperatures */ ++ w83795_write(W83795_REG_TTTI(0), config->temp1_target_temperature); ++ w83795_write(W83795_REG_TTTI(1), config->temp2_target_temperature); ++ w83795_write(W83795_REG_TTTI(2), config->temp3_target_temperature); ++ w83795_write(W83795_REG_TTTI(3), config->temp4_target_temperature); ++ w83795_write(W83795_REG_TTTI(4), config->temp5_target_temperature); ++ w83795_write(W83795_REG_TTTI(5), config->temp6_target_temperature); ++ ++ /* Set fan stall prevention parameters */ ++ w83795_write(W83795_REG_FAN_NONSTOP(0), config->fan1_nonstop); ++ w83795_write(W83795_REG_FAN_NONSTOP(1), config->fan2_nonstop); ++ w83795_write(W83795_REG_FAN_NONSTOP(2), config->fan3_nonstop); ++ w83795_write(W83795_REG_FAN_NONSTOP(3), config->fan4_nonstop); ++ w83795_write(W83795_REG_FAN_NONSTOP(4), config->fan5_nonstop); ++ w83795_write(W83795_REG_FAN_NONSTOP(5), config->fan6_nonstop); ++ w83795_write(W83795_REG_FAN_NONSTOP(6), config->fan7_nonstop); ++ w83795_write(W83795_REG_FAN_NONSTOP(7), config->fan8_nonstop); ++ ++ /* Set fan default speed */ ++ w83795_write(W83795_REG_DFSP, fan_pct_to_cfg_val(config->default_speed)); ++ ++ /* Set initial fan speeds */ ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(0), fan_pct_to_cfg_val(config->fan1_duty)); ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(1), fan_pct_to_cfg_val(config->fan2_duty)); ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(2), fan_pct_to_cfg_val(config->fan3_duty)); ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(3), fan_pct_to_cfg_val(config->fan4_duty)); ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(4), fan_pct_to_cfg_val(config->fan5_duty)); ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(5), fan_pct_to_cfg_val(config->fan6_duty)); ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(6), fan_pct_to_cfg_val(config->fan7_duty)); ++ w83795_write(W83795_REG_FAN_MANUAL_SPEED(7), fan_pct_to_cfg_val(config->fan8_duty)); ++ ++ /* Voltage monitor settings */ ++ w83795_write(W83795_REG_VOLT_CTRL1, config->volt_ctl1); ++ w83795_write(W83795_REG_VOLT_CTRL2, config->volt_ctl2); ++ ++ /* Voltage high/low limits */ ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(0), millivolts_to_limit_value_type1(config->vcore1_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(0), millivolts_to_limit_value_type1(config->vcore1_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(1), millivolts_to_limit_value_type1(config->vcore2_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(1), millivolts_to_limit_value_type1(config->vcore2_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(2), millivolts_to_limit_value_type1(config->vsen3_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(2), millivolts_to_limit_value_type1(config->vsen3_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(3), millivolts_to_limit_value_type1(config->vsen4_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(3), millivolts_to_limit_value_type1(config->vsen4_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(4), millivolts_to_limit_value_type1(config->vsen5_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(4), millivolts_to_limit_value_type1(config->vsen5_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(5), millivolts_to_limit_value_type1(config->vsen6_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(5), millivolts_to_limit_value_type1(config->vsen6_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(6), millivolts_to_limit_value_type1(config->vsen7_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(6), millivolts_to_limit_value_type1(config->vsen7_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(7), millivolts_to_limit_value_type1(config->vsen8_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(7), millivolts_to_limit_value_type1(config->vsen8_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(8), millivolts_to_limit_value_type1(config->vsen9_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(8), millivolts_to_limit_value_type1(config->vsen9_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(9), millivolts_to_limit_value_type1(config->vsen10_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(9), millivolts_to_limit_value_type1(config->vsen10_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(10), millivolts_to_limit_value_type1(config->vsen11_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(10), millivolts_to_limit_value_type1(config->vsen11_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(11), millivolts_to_limit_value_type1(config->vtt_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(11), millivolts_to_limit_value_type1(config->vtt_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(12), millivolts_to_limit_value_type2(config->vdd_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(12), millivolts_to_limit_value_type2(config->vdd_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(13), millivolts_to_limit_value_type2(config->vsb_high_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_LOW(13), millivolts_to_limit_value_type2(config->vsb_low_limit_mv)); ++ w83795_write(W83795_REG_VOLT_LIM_HIGH(14), millivolts_to_limit_value_type2(config->vbat_high_limit_mv)); ++ w83795_write(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(W83795_REG_VOLT_LIM_HIGH_2_M(4), limit_value >> 2); ++ w83795_write(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(W83795_REG_VOLT_LIM_LOW_2_M(4), limit_value >> 2); ++ w83795_write(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(W83795_REG_VOLT_LIM_HIGH_2_M(5), limit_value >> 2); ++ w83795_write(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(W83795_REG_VOLT_LIM_LOW_2_M(5), limit_value >> 2); ++ w83795_write(W83795_REG_VOLT_LIM_LOW_2_L(5), limit_value & 0x3); + +- w83795_dts_enable(dts_src); + w83795_set_fan(mode); + + printk(BIOS_INFO, "Fan CTFS(celsius) TTTI(celsius)\n"); +@@ -219,6 +331,11 @@ static void w83795_init(w83795_fan_mode_t mode, u8 dts_src) + val = w83795_read(W83795_REG_DTS(i)); + printk(BIOS_DEBUG, "DTS%x ReadOut=%x\n", i, val); + } ++ ++ /* start monitoring operation */ ++ val = w83795_read(W83795_REG_CONFIG); ++ val |= W83795_REG_CONFIG_START; ++ w83795_write(W83795_REG_CONFIG, val); + } + + static void w83795_hwm_init(struct device *dev) +@@ -232,9 +349,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..59fa273 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 <tpearson@raptorengineeringinc.com>, 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,6 +30,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 +40,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/0007-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch b/resources/libreboot/patch/kgpe-d16/0007-drivers-aspeed-Add-native-text-mode-VGA-support-for-.patch @@ -0,0 +1,3673 @@ +From 27f2cdc381f7bac82f868acef86bcc95467fe24c Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 17:38:09 -0500 +Subject: [PATCH 007/146] drivers/aspeed: Add native text mode VGA support for + the AST2050 + +--- + 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..cc090bb +--- /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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <airlied@redhat.com> ++ */ ++#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 <tpearson@raptorengineeringinc.com>, 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 <airlied@redhat.com> ++ */ ++#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 <tpearson@raptorengineeringinc.com>, 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 <airlied@redhat.com> ++ */ ++ ++#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/0008-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch b/resources/libreboot/patch/kgpe-d16/0008-southbridge-amd-sb700-Fix-boot-hang-on-ASUS-KGPE-D16.patch @@ -0,0 +1,641 @@ +From bdcf5ce540eb621d31655a172eb43ddf86d4cea0 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 17:46:15 -0500 +Subject: [PATCH 008/146] southbridge/amd/sb700: Fix boot hang on ASUS + KGPE-D16 + +--- + 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 42ca2bb..064f32e 100644 +--- a/src/southbridge/amd/sb700/Kconfig ++++ b/src/southbridge/amd/sb700/Kconfig +@@ -41,6 +41,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..fa89d18 +--- /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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 f544c88..3e6ddf1 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 <tpearson@raptorengineeringinc.com>, 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,11 +58,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); +@@ -127,9 +125,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"); +@@ -293,6 +292,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 */ +@@ -371,7 +374,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 <tpearson@raptorengineeringinc.com>, 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.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0009-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch b/resources/libreboot/patch/kgpe-d16/0009-southbridge-amd-sr5650-Fix-boot-failure-on-ASUS-KGPE.patch @@ -0,0 +1,619 @@ +From dd732a07e6aec5386eea9a00845f62c5b8b6ae68 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 17:46:38 -0500 +Subject: [PATCH 009/146] southbridge/amd/sr5650: Fix boot failure on ASUS + KGPE-D16 + +--- + 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, Raptor Engineering + * Copyright (C) 2010 Advanced Micro Devices, Inc. ++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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/0010-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch b/resources/libreboot/patch/kgpe-d16/0010-cpu-amd-Add-initial-support-for-AMD-Socket-G34-proce.patch @@ -0,0 +1,788 @@ +From a7e9e5b7d4f3699e043574b2ad5d13ff65125fce Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 17:50:29 -0500 +Subject: [PATCH 010/146] cpu/amd: Add initial support for AMD Socket G34 + processors + +--- + 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 | 105 +++++++++++++++++++++++++++- + 13 files changed, 390 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 + +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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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..778e96f 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 <tpearson@raptorengineeringinc.com>, 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) { ++ /* 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 <tpearson@raptorengineeringinc.com>, 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..7bd8675 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..bafda10 100644 +--- a/src/northbridge/amd/amdht/ht_wrapper.c ++++ b/src/northbridge/amd/amdht/ht_wrapper.c +@@ -113,6 +113,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 +142,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 +160,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 ++ * ++ */ ++static 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); ++ } ++ } ++ } ++ } ++ } ++ } + } +-- +1.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch b/resources/libreboot/patch/kgpe-d16/0011-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch @@ -0,0 +1,3451 @@ +From 791a6ea672f16f971422f10514bb0c4225930489 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 17:55:58 -0500 +Subject: [PATCH 011/146] northbridge/amd/amdmct: Fix broken AMD K10 DDR3 + memory initalization + +--- + 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 | 803 +++++++++++----------- + 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 | 114 +--- + 18 files changed, 1254 insertions(+), 1142 deletions(-) + +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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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..8572243 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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..587c414 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 <tpearson@raptorengineeringinc.com>, 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,215 @@ 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); +- +- mct_SetFinalRcvrEnDly_D(pDCTstat, RcvrEnDly, Final_Value, Channel, Receiver, dev, index_reg, Addl_Index, 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 + +- if(pDCTstat->ErrStatus & (1 << SB_SmallRCVR)) { +- Errors |= 1 << SB_SmallRCVR; +- } ++ /* 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]; + +- RcvrEnDly += Pass1MemClkDly; +- if(RcvrEnDly > CTLRMaxDelay) { +- CTLRMaxDelay = RcvrEnDly; ++ /* 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); ++ } + } + +- } /* while Receiver */ ++ /* 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 ++ */ ++ ++ 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 +613,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 +660,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 +690,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 +722,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 +807,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 +851,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 +909,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 +939,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 +975,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 +1076,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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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 <tpearson@raptorengineeringinc.com>, 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..47260f2 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,13 +310,19 @@ 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); + } + + /* 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 +@@ -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/0012-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch b/resources/libreboot/patch/kgpe-d16/0012-northbridge-amd-amdmct-mct_ddr3-Fix-curly-brace-styl.patch @@ -0,0 +1,93 @@ +From 7192af06922df114da15077d51e8882d3d10f101 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Tue, 8 Sep 2015 16:08:45 -0500 +Subject: [PATCH 012/146] northbridge/amd/amdmct/mct_ddr3: Fix curly brace + style violations + +--- + 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.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0013-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch b/resources/libreboot/patch/kgpe-d16/0013-northbridge-amd-amdfam10-Limit-maximum-RAM-clock-to-.patch @@ -0,0 +1,120 @@ +From 818a658a290203625a65df4dde4901ea66fd72c8 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 18:00:27 -0500 +Subject: [PATCH 013/146] northbridge/amd/amdfam10: Limit maximum RAM clock to + BKDG recommendations + +--- + src/northbridge/amd/amdfam10/raminit_amdmct.c | 53 +++++++++++++++++++------ + 1 file changed, 40 insertions(+), 13 deletions(-) + +diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c b/src/northbridge/amd/amdfam10/raminit_amdmct.c +index a0d47f4..fa14e4f 100644 +--- a/src/northbridge/amd/amdfam10/raminit_amdmct.c ++++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c +@@ -28,13 +28,6 @@ static void print_tx(const char *strval, u32 val) + } + #endif + +-static void print_t(const char *strval) +-{ +-#if CONFIG_DEBUG_RAM_SETUP +- printk(BIOS_DEBUG, "%s", strval); +-#endif +-} +- + static void print_tf(const char *func, const char *strval) + { + #if CONFIG_DEBUG_RAM_SETUP +@@ -42,30 +35,59 @@ 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"); ++ } ++ } + } + + return freq; +@@ -118,6 +140,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 */ +@@ -205,6 +230,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) +@@ -243,3 +269,4 @@ static void amdmct_cbmem_store_info(struct sys_info *sysinfo) + } + #endif + } ++#endif +-- +1.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0014-northbridge-amd-amdfam10-Fix-typo-in-comment.patch b/resources/libreboot/patch/kgpe-d16/0014-northbridge-amd-amdfam10-Fix-typo-in-comment.patch @@ -0,0 +1,33 @@ +From d5701700c4c905866a58c600b7a9f1a7f534e5f6 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 18:01:31 -0500 +Subject: [PATCH 014/146] northbridge/amd/amdfam10: Fix typo in comment + +--- + src/northbridge/amd/amdfam10/misc_control.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/northbridge/amd/amdfam10/misc_control.c b/src/northbridge/amd/amdfam10/misc_control.c +index e242e34..85c8838 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 <tpearson@raptorengineeringinc.com>, 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 +@@ -47,7 +48,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.7.9.5 + diff --git a/resources/libreboot/patch/kgpe-d16/0015-device-hypertransport-Add-additional-debug-output.patch b/resources/libreboot/patch/kgpe-d16/0015-device-hypertransport-Add-additional-debug-output.patch @@ -0,0 +1,33 @@ +From c8c17707af0850b4e520a2616e217e9fae2cf0e3 Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Sat, 5 Sep 2015 18:06:52 -0500 +Subject: [PATCH 015/146] device/hypertransport: Add additional debug output + +--- + 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 <yhlu@tyan.com> for Tyan) + * Copyright (C) 2005-2006 Stefan Reinauer <stepan@openbios.org> ++ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, 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/0016-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch b/resources/libreboot/patch/kgpe-d16/0016-mainboard-asus-kgpe-d16-Add-initial-support-for-the-.patch @@ -0,0 +1,3218 @@ +From ef853baaaec3bf5aee31f443a7930f9882e3a01c Mon Sep 17 00:00:00 2001 +From: Timothy Pearson <kb9vqf@pearsoncomputing.net> +Date: Thu, 30 Apr 2015 01:47:31 -0500 +Subject: [PATCH 016/146] 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. +--- + 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 <tpearson@raptorengineeringinc.com>, 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 */