diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-10-16 13:51:51 -0500 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2015-11-02 23:45:19 +0100 |
commit | 730a043fb6cb4dd3cb5af8f8640365727b598648 (patch) | |
tree | 59afe45caca1a8e1682939c7e44e95344104533e /src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | |
parent | d150006c4a4584bc9933c2d8ff580a54c4f0cc2a (diff) | |
download | coreboot-730a043fb6cb4dd3cb5af8f8640365727b598648.tar.xz |
cpu/amd: Add initial AMD Family 15h support
TEST: Booted ASUS KGPE-D16 with single Opteron 6380
* Unbuffered DDR3 DIMMs tested and working
* Suspend to RAM (S3) tested and working
Change-Id: Idffd2ce36ce183fbfa087e5ba69a9148f084b45e
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
Reviewed-on: http://review.coreboot.org/11966
Tested-by: build bot (Jenkins)
Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/s3utils.c')
-rw-r--r-- | src/northbridge/amd/amdmct/mct_ddr3/s3utils.c | 652 |
1 files changed, 503 insertions, 149 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c index 4b745d2846..3c2043be54 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c @@ -14,6 +14,7 @@ */ #include <string.h> +#include <arch/cpu.h> #include <arch/acpi.h> #include <cpu/x86/msr.h> #include <device/device.h> @@ -28,6 +29,23 @@ #define S3NV_FILE_NAME "s3nv" +#ifdef __RAMSTAGE__ +static inline uint8_t is_fam15h(void) +{ + uint8_t fam15h = 0; + uint32_t family; + + family = cpuid_eax(0x80000001); + family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8); + + if (family >= 0x6f) + /* Family 15h or later */ + fam15h = 1; + + return fam15h; +} +#endif + static ssize_t get_s3nv_file_offset(void); ssize_t get_s3nv_file_offset(void) @@ -43,6 +61,28 @@ ssize_t get_s3nv_file_offset(void) return s3nv_region.region.offset; } +static uint32_t read_config32_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t reg) { + if (is_fam15h()) { + uint32_t dword; +#ifdef __PRE_RAM__ + device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1); +#else + device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1)); +#endif + + /* Select DCT */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~0x1; + dword |= (dct & 0x1); + pci_write_config32(dev_fn1, 0x10c, dword); + } else { + /* Apply offset */ + reg += dct * 0x100; + } + + return pci_read_config32(dev, reg); +} + static uint32_t read_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg, uint32_t index) { uint32_t dword; @@ -57,12 +97,54 @@ static uint32_t read_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg return dword; } +static uint32_t read_amd_dct_index_register_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t index_ctl_reg, uint32_t index) +{ + if (is_fam15h()) { + uint32_t dword; +#ifdef __PRE_RAM__ + device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1); +#else + device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1)); +#endif + + /* Select DCT */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~0x1; + dword |= (dct & 0x1); + pci_write_config32(dev_fn1, 0x10c, dword); + } else { + /* Apply offset */ + index_ctl_reg += dct * 0x100; + } + + return read_amd_dct_index_register(dev, index_ctl_reg, index); +} + #ifdef __RAMSTAGE__ static uint64_t rdmsr_uint64_t(unsigned long index) { msr_t msr = rdmsr(index); return (((uint64_t)msr.hi) << 32) | ((uint64_t)msr.lo); } +static uint32_t read_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t dct, uint8_t nb_pstate, uint32_t reg) { + uint32_t dword; + device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1)); + + /* Select DCT */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~0x1; + dword |= (dct & 0x1); + pci_write_config32(dev_fn1, 0x10c, dword); + + /* Select NB Pstate index */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~(0x3 << 4); + dword |= (nb_pstate & 0x3) << 4; + pci_write_config32(dev_fn1, 0x10c, dword); + + return pci_read_config32(dev, reg); +} + void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_data) { uint8_t i; @@ -78,7 +160,8 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da device_t dev_fn1 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 1)); device_t dev_fn2 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 2)); device_t dev_fn3 = dev_find_slot(0, PCI_DEVFN(0x18 + node, 3)); - if ((!dev_fn1) || (!dev_fn2) || (!dev_fn3)) { + /* Test for node presence */ + if ((!dev_fn1) || (pci_read_config32(dev_fn1, PCI_VENDOR_ID) == 0xffffffff)) { persistent_data->node[node].node_present = 0; continue; } @@ -91,22 +174,22 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da data->f2x110 = pci_read_config32(dev_fn2, 0x110); /* Stage 2 */ - data->f1x40 = pci_read_config32(dev_fn1, 0x40 + (0x100 * channel)); - data->f1x44 = pci_read_config32(dev_fn1, 0x44 + (0x100 * channel)); - data->f1x48 = pci_read_config32(dev_fn1, 0x48 + (0x100 * channel)); - data->f1x4c = pci_read_config32(dev_fn1, 0x4c + (0x100 * channel)); - data->f1x50 = pci_read_config32(dev_fn1, 0x50 + (0x100 * channel)); - data->f1x54 = pci_read_config32(dev_fn1, 0x54 + (0x100 * channel)); - data->f1x58 = pci_read_config32(dev_fn1, 0x58 + (0x100 * channel)); - data->f1x5c = pci_read_config32(dev_fn1, 0x5c + (0x100 * channel)); - data->f1x60 = pci_read_config32(dev_fn1, 0x60 + (0x100 * channel)); - data->f1x64 = pci_read_config32(dev_fn1, 0x64 + (0x100 * channel)); - data->f1x68 = pci_read_config32(dev_fn1, 0x68 + (0x100 * channel)); - data->f1x6c = pci_read_config32(dev_fn1, 0x6c + (0x100 * channel)); - data->f1x70 = pci_read_config32(dev_fn1, 0x70 + (0x100 * channel)); - data->f1x74 = pci_read_config32(dev_fn1, 0x74 + (0x100 * channel)); - data->f1x78 = pci_read_config32(dev_fn1, 0x78 + (0x100 * channel)); - data->f1x7c = pci_read_config32(dev_fn1, 0x7c + (0x100 * channel)); + data->f1x40 = read_config32_dct(dev_fn1, node, channel, 0x40); + data->f1x44 = read_config32_dct(dev_fn1, node, channel, 0x44); + data->f1x48 = read_config32_dct(dev_fn1, node, channel, 0x48); + data->f1x4c = read_config32_dct(dev_fn1, node, channel, 0x4c); + data->f1x50 = read_config32_dct(dev_fn1, node, channel, 0x50); + data->f1x54 = read_config32_dct(dev_fn1, node, channel, 0x54); + data->f1x58 = read_config32_dct(dev_fn1, node, channel, 0x58); + data->f1x5c = read_config32_dct(dev_fn1, node, channel, 0x5c); + data->f1x60 = read_config32_dct(dev_fn1, node, channel, 0x60); + data->f1x64 = read_config32_dct(dev_fn1, node, channel, 0x64); + data->f1x68 = read_config32_dct(dev_fn1, node, channel, 0x68); + data->f1x6c = read_config32_dct(dev_fn1, node, channel, 0x6c); + data->f1x70 = read_config32_dct(dev_fn1, node, channel, 0x70); + data->f1x74 = read_config32_dct(dev_fn1, node, channel, 0x74); + data->f1x78 = read_config32_dct(dev_fn1, node, channel, 0x78); + data->f1x7c = read_config32_dct(dev_fn1, node, channel, 0x7c); data->f1xf0 = pci_read_config32(dev_fn1, 0xf0); data->f1x120 = pci_read_config32(dev_fn1, 0x120); data->f1x124 = pci_read_config32(dev_fn1, 0x124); @@ -130,75 +213,144 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da data->msrc001001f = rdmsr_uint64_t(0xc001001f); /* Stage 3 */ - data->f2x40 = pci_read_config32(dev_fn2, 0x40 + (0x100 * channel)); - data->f2x44 = pci_read_config32(dev_fn2, 0x44 + (0x100 * channel)); - data->f2x48 = pci_read_config32(dev_fn2, 0x48 + (0x100 * channel)); - data->f2x4c = pci_read_config32(dev_fn2, 0x4c + (0x100 * channel)); - data->f2x50 = pci_read_config32(dev_fn2, 0x50 + (0x100 * channel)); - data->f2x54 = pci_read_config32(dev_fn2, 0x54 + (0x100 * channel)); - data->f2x58 = pci_read_config32(dev_fn2, 0x58 + (0x100 * channel)); - data->f2x5c = pci_read_config32(dev_fn2, 0x5c + (0x100 * channel)); - data->f2x60 = pci_read_config32(dev_fn2, 0x60 + (0x100 * channel)); - data->f2x64 = pci_read_config32(dev_fn2, 0x64 + (0x100 * channel)); - data->f2x68 = pci_read_config32(dev_fn2, 0x68 + (0x100 * channel)); - data->f2x6c = pci_read_config32(dev_fn2, 0x6c + (0x100 * channel)); - data->f2x78 = pci_read_config32(dev_fn2, 0x78 + (0x100 * channel)); - data->f2x7c = pci_read_config32(dev_fn2, 0x7c + (0x100 * channel)); - data->f2x80 = pci_read_config32(dev_fn2, 0x80 + (0x100 * channel)); - data->f2x84 = pci_read_config32(dev_fn2, 0x84 + (0x100 * channel)); - data->f2x88 = pci_read_config32(dev_fn2, 0x88 + (0x100 * channel)); - data->f2x8c = pci_read_config32(dev_fn2, 0x8c + (0x100 * channel)); - data->f2x90 = pci_read_config32(dev_fn2, 0x90 + (0x100 * channel)); - data->f2xa4 = pci_read_config32(dev_fn2, 0xa4 + (0x100 * channel)); - data->f2xa8 = pci_read_config32(dev_fn2, 0xa8 + (0x100 * channel)); + data->f2x40 = read_config32_dct(dev_fn2, node, channel, 0x40); + data->f2x44 = read_config32_dct(dev_fn2, node, channel, 0x44); + data->f2x48 = read_config32_dct(dev_fn2, node, channel, 0x48); + data->f2x4c = read_config32_dct(dev_fn2, node, channel, 0x4c); + data->f2x50 = read_config32_dct(dev_fn2, node, channel, 0x50); + data->f2x54 = read_config32_dct(dev_fn2, node, channel, 0x54); + data->f2x58 = read_config32_dct(dev_fn2, node, channel, 0x58); + data->f2x5c = read_config32_dct(dev_fn2, node, channel, 0x5c); + data->f2x60 = read_config32_dct(dev_fn2, node, channel, 0x60); + data->f2x64 = read_config32_dct(dev_fn2, node, channel, 0x64); + data->f2x68 = read_config32_dct(dev_fn2, node, channel, 0x68); + data->f2x6c = read_config32_dct(dev_fn2, node, channel, 0x6c); + data->f2x78 = read_config32_dct(dev_fn2, node, channel, 0x78); + data->f2x7c = read_config32_dct(dev_fn2, node, channel, 0x7c); + data->f2x80 = read_config32_dct(dev_fn2, node, channel, 0x80); + data->f2x84 = read_config32_dct(dev_fn2, node, channel, 0x84); + data->f2x88 = read_config32_dct(dev_fn2, node, channel, 0x88); + data->f2x8c = read_config32_dct(dev_fn2, node, channel, 0x8c); + data->f2x90 = read_config32_dct(dev_fn2, node, channel, 0x90); + data->f2xa4 = read_config32_dct(dev_fn2, node, channel, 0xa4); + data->f2xa8 = read_config32_dct(dev_fn2, node, channel, 0xa8); + + /* Family 15h-specific configuration */ + if (is_fam15h()) { + data->f2x200 = read_config32_dct(dev_fn2, node, channel, 0x200); + data->f2x204 = read_config32_dct(dev_fn2, node, channel, 0x204); + data->f2x208 = read_config32_dct(dev_fn2, node, channel, 0x208); + data->f2x20c = read_config32_dct(dev_fn2, node, channel, 0x20c); + for (i=0; i<4; i++) + data->f2x210[i] = read_config32_dct_nbpstate(dev_fn2, node, channel, i, 0x210); + data->f2x214 = read_config32_dct(dev_fn2, node, channel, 0x214); + data->f2x218 = read_config32_dct(dev_fn2, node, channel, 0x218); + data->f2x21c = read_config32_dct(dev_fn2, node, channel, 0x21c); + data->f2x22c = read_config32_dct(dev_fn2, node, channel, 0x22c); + data->f2x230 = read_config32_dct(dev_fn2, node, channel, 0x230); + data->f2x234 = read_config32_dct(dev_fn2, node, channel, 0x234); + data->f2x238 = read_config32_dct(dev_fn2, node, channel, 0x238); + data->f2x23c = read_config32_dct(dev_fn2, node, channel, 0x23c); + data->f2x240 = read_config32_dct(dev_fn2, node, channel, 0x240); + + data->f2x9cx0d0fe003 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe003); + data->f2x9cx0d0fe013 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe013); + for (i=0; i<9; i++) + data->f2x9cx0d0f0_8_0_1f[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f001f | (i << 8)); + data->f2x9cx0d0f201f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f201f); + data->f2x9cx0d0f211f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f211f); + data->f2x9cx0d0f221f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f221f); + data->f2x9cx0d0f801f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f801f); + data->f2x9cx0d0f811f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f811f); + data->f2x9cx0d0f821f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f821f); + data->f2x9cx0d0fc01f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc01f); + data->f2x9cx0d0fc11f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc11f); + data->f2x9cx0d0fc21f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc21f); + data->f2x9cx0d0f4009 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f4009); + for (i=0; i<9; i++) + data->f2x9cx0d0f0_8_0_02[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0002 | (i << 8)); + for (i=0; i<9; i++) + data->f2x9cx0d0f0_8_0_06[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0006 | (i << 8)); + for (i=0; i<9; i++) + data->f2x9cx0d0f0_8_0_0a[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f000a | (i << 8)); + + data->f2x9cx0d0f2002 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2002); + data->f2x9cx0d0f2102 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2102); + data->f2x9cx0d0f2202 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2202); + data->f2x9cx0d0f8002 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8002); + data->f2x9cx0d0f8006 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8006); + data->f2x9cx0d0f800a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f800a); + data->f2x9cx0d0f8102 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8102); + data->f2x9cx0d0f8106 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8106); + data->f2x9cx0d0f810a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f810a); + data->f2x9cx0d0fc002 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc002); + data->f2x9cx0d0fc006 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc006); + data->f2x9cx0d0fc00a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00a); + data->f2x9cx0d0fc00e = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc00e); + data->f2x9cx0d0fc012 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc012); + + data->f2x9cx0d0f2031 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2031); + data->f2x9cx0d0f2131 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2131); + data->f2x9cx0d0f2231 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2231); + data->f2x9cx0d0f8031 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8031); + data->f2x9cx0d0f8131 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8131); + data->f2x9cx0d0f8231 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8231); + data->f2x9cx0d0fc031 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc031); + data->f2x9cx0d0fc131 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc131); + data->f2x9cx0d0fc231 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fc231); + for (i=0; i<9; i++) + data->f2x9cx0d0f0_0_f_31[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0031 | (i << 8)); + + data->f2x9cx0d0f8021 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f8021); + } /* Stage 4 */ - data->f2x94 = pci_read_config32(dev_fn2, 0x94 + (0x100 * channel)); + data->f2x94 = read_config32_dct(dev_fn2, node, channel, 0x94); /* Stage 6 */ for (i=0; i<9; i++) for (j=0; j<3; j++) - data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4)); - data->f2x9cx00 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x00); - data->f2x9cx0a = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0a); - data->f2x9cx0c = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0c); + data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4)); + data->f2x9cx00 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x00); + data->f2x9cx0a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0a); + data->f2x9cx0c = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0c); /* Stage 7 */ - data->f2x9cx04 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x04); + data->f2x9cx04 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x04); /* Stage 9 */ - data->f2x9cx0d0fe006 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe006); - data->f2x9cx0d0fe007 = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0fe007); + data->f2x9cx0d0fe006 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe006); + data->f2x9cx0d0fe007 = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe007); /* Stage 10 */ for (i=0; i<12; i++) - data->f2x9cx10[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x10 + i); + data->f2x9cx10[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x10 + i); for (i=0; i<12; i++) - data->f2x9cx20[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x20 + i); + data->f2x9cx20[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x20 + i); for (i=0; i<4; i++) for (j=0; j<3; j++) - data->f2x9cx3_0_0_3_1[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j)); + data->f2x9cx3_0_0_3_1[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x01 + i) + (0x100 * j)); for (i=0; i<4; i++) for (j=0; j<3; j++) - data->f2x9cx3_0_0_7_5[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j)); - data->f2x9cx0d = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d); + data->f2x9cx3_0_0_7_5[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, (0x05 + i) + (0x100 * j)); + data->f2x9cx0d = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d); for (i=0; i<9; i++) - data->f2x9cx0d0f0_f_0_13[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8)); + data->f2x9cx0d0f0_f_0_13[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0013 | (i << 8)); for (i=0; i<9; i++) - data->f2x9cx0d0f0_f_0_30[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8)); + data->f2x9cx0d0f0_f_0_30[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0030 | (i << 8)); for (i=0; i<4; i++) - data->f2x9cx0d0f2_f_0_30[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8)); + data->f2x9cx0d0f2_f_0_30[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f2030 | (i << 8)); for (i=0; i<2; i++) for (j=0; j<3; j++) - data->f2x9cx0d0f8_8_4_0[i][j] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4)); - data->f2x9cx0d0f812f = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x0d0f812f); + data->f2x9cx0d0f8_8_4_0[i][j] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4)); + data->f2x9cx0d0f812f = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0f812f); /* Stage 11 */ if (IS_ENABLED(CONFIG_DIMM_DDR3)) { for (i=0; i<12; i++) - data->f2x9cx30[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x30 + i); + data->f2x9cx30[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x30 + i); for (i=0; i<12; i++) - data->f2x9cx40[i] = read_amd_dct_index_register(dev_fn2, 0x98 + (0x100 * channel), 0x40 + i); + data->f2x9cx40[i] = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x40 + i); } /* Other */ @@ -208,6 +360,43 @@ void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_da } } #else +static void write_config32_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t reg, uint32_t value) { + if (is_fam15h()) { + uint32_t dword; + device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1); + + /* Select DCT */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~0x1; + dword |= (dct & 0x1); + pci_write_config32(dev_fn1, 0x10c, dword); + } else { + /* Apply offset */ + reg += dct * 0x100; + } + + pci_write_config32(dev, reg, value); +} + +static void write_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t dct, uint8_t nb_pstate, uint32_t reg, uint32_t value) { + uint32_t dword; + device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1); + + /* Select DCT */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~0x1; + dword |= (dct & 0x1); + pci_write_config32(dev_fn1, 0x10c, dword); + + /* Select NB Pstate index */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~(0x3 << 4); + dword |= (nb_pstate & 0x3) << 4; + pci_write_config32(dev_fn1, 0x10c, dword); + + pci_write_config32(dev, reg, value); +} + static void write_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg, uint32_t index, uint32_t value) { uint32_t dword; @@ -219,6 +408,25 @@ static void write_amd_dct_index_register(device_t dev, uint32_t index_ctl_reg, u dword = pci_read_config32(dev, index_ctl_reg); } while (!(dword & (1 << 31))); } + +static void write_amd_dct_index_register_dct(device_t dev, uint8_t node, uint8_t dct, uint32_t index_ctl_reg, uint32_t index, uint32_t value) +{ + if (is_fam15h()) { + uint32_t dword; + device_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1); + + /* Select DCT */ + dword = pci_read_config32(dev_fn1, 0x10c); + dword &= ~0x1; + dword |= (dct & 0x1); + pci_write_config32(dev_fn1, 0x10c, dword); + } else { + /* Apply offset */ + index_ctl_reg += dct * 0x100; + } + + return write_amd_dct_index_register(dev, index_ctl_reg, index, value); +} #endif #ifdef __PRE_RAM__ @@ -258,31 +466,31 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste if (!persistent_data->node[node].node_present) continue; - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x40 + (0x100 * channel), data->f1x40); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x44 + (0x100 * channel), data->f1x44); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x48 + (0x100 * channel), data->f1x48); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x4c + (0x100 * channel), data->f1x4c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x50 + (0x100 * channel), data->f1x50); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x54 + (0x100 * channel), data->f1x54); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x58 + (0x100 * channel), data->f1x58); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x5c + (0x100 * channel), data->f1x5c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x60 + (0x100 * channel), data->f1x60); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x64 + (0x100 * channel), data->f1x64); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x68 + (0x100 * channel), data->f1x68); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x6c + (0x100 * channel), data->f1x6c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x70 + (0x100 * channel), data->f1x70); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x74 + (0x100 * channel), data->f1x74); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x78 + (0x100 * channel), data->f1x78); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x7c + (0x100 * channel), data->f1x7c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0xf0 + (0x100 * channel), data->f1xf0); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x120 + (0x100 * channel), data->f1x120); - pci_write_config32(PCI_DEV(0, 0x18 + node, 1), 0x124 + (0x100 * channel), data->f1x124); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x10c + (0x100 * channel), data->f2x10c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x114 + (0x100 * channel), data->f2x114); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x118 + (0x100 * channel), data->f2x118); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x11c + (0x100 * channel), data->f2x11c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x1b0 + (0x100 * channel), data->f2x1b0); - pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x44 + (0x100 * channel), data->f3x44); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x40, data->f1x40); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x44, data->f1x44); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x48, data->f1x48); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x4c, data->f1x4c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x50, data->f1x50); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x54, data->f1x54); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x58, data->f1x58); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x5c, data->f1x5c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x60, data->f1x60); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x64, data->f1x64); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x68, data->f1x68); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x6c, data->f1x6c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x70, data->f1x70); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x74, data->f1x74); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x78, data->f1x78); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x7c, data->f1x7c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0xf0, data->f1xf0); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x120, data->f1x120); + write_config32_dct(PCI_DEV(0, 0x18 + node, 1), node, channel, 0x124, data->f1x124); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x10c, data->f2x10c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x114, data->f2x114); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x118, data->f2x118); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x11c, data->f2x11c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x1b0, data->f2x1b0); + write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, channel, 0x44, data->f3x44); for (i=0; i<16; i++) { wrmsr_uint64_t(0x00000200 | i, data->msr0000020[i]); } @@ -309,31 +517,97 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste if (!persistent_data->node[node].node_present) continue; - ganged = !!(data->f2x110 & 0x10); + if (is_fam15h()) + ganged = 0; + else + ganged = !!(data->f2x110 & 0x10); if ((ganged == 1) && (channel > 0)) continue; - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x40 + (0x100 * channel), data->f2x40); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x44 + (0x100 * channel), data->f2x44); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x48 + (0x100 * channel), data->f2x48); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x4c + (0x100 * channel), data->f2x4c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x50 + (0x100 * channel), data->f2x50); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x54 + (0x100 * channel), data->f2x54); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x58 + (0x100 * channel), data->f2x58); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x5c + (0x100 * channel), data->f2x5c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x60 + (0x100 * channel), data->f2x60); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x64 + (0x100 * channel), data->f2x64); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x68 + (0x100 * channel), data->f2x68); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x6c + (0x100 * channel), data->f2x6c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x78 + (0x100 * channel), data->f2x78); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x7c + (0x100 * channel), data->f2x7c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x80 + (0x100 * channel), data->f2x80); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x84 + (0x100 * channel), data->f2x84); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x88 + (0x100 * channel), data->f2x88); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x8c + (0x100 * channel), data->f2x8c); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel), data->f2x90); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa4 + (0x100 * channel), data->f2xa4); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0xa8 + (0x100 * channel), data->f2xa8); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x40, data->f2x40); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x44, data->f2x44); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x48, data->f2x48); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x4c, data->f2x4c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x50, data->f2x50); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x54, data->f2x54); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x58, data->f2x58); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x5c, data->f2x5c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x60, data->f2x60); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x64, data->f2x64); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x68, data->f2x68); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x6c, data->f2x6c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x78, data->f2x78); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x7c, data->f2x7c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x80, data->f2x80); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x84, data->f2x84); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x88, data->f2x88); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x8c, data->f2x8c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90, data->f2x90); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0xa4, data->f2xa4); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0xa8, data->f2xa8); + } + } + + /* Family 15h-specific configuration */ + if (is_fam15h()) { + for (node = 0; node < MAX_NODES_SUPPORTED; node++) { + for (channel = 0; channel < 2; channel++) { + struct amd_s3_persistent_mct_channel_data* data = &persistent_data->node[node].channel[channel]; + if (!persistent_data->node[node].node_present) + continue; + + /* Initialize DCT */ + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0000000b, 0x80000000); + dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe013); + dword &= ~0xffff; + dword |= 0x118; + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, dword); + + /* Restore values */ + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x200, data->f2x200); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x204, data->f2x204); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x208, data->f2x208); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x20c, data->f2x20c); + for (i=0; i<4; i++) + write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 0x210, data->f2x210[i]); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x214, data->f2x214); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x218, data->f2x218); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x21c, data->f2x21c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x22c, data->f2x22c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x230, data->f2x230); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x234, data->f2x234); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x238, data->f2x238); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x23c, data->f2x23c); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x240, data->f2x240); + + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe013, data->f2x9cx0d0fe013); + for (i=0; i<9; i++) + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f001f | (i << 8), data->f2x9cx0d0f0_8_0_1f[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f201f, data->f2x9cx0d0f201f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f211f, data->f2x9cx0d0f211f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f221f, data->f2x9cx0d0f221f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f801f, data->f2x9cx0d0f801f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f811f, data->f2x9cx0d0f811f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f821f, data->f2x9cx0d0f821f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc01f, data->f2x9cx0d0fc01f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc11f, data->f2x9cx0d0fc11f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc21f, data->f2x9cx0d0fc21f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f4009, data->f2x9cx0d0f4009); + + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2031, data->f2x9cx0d0f2031); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2131, data->f2x9cx0d0f2131); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2231, data->f2x9cx0d0f2231); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8031, data->f2x9cx0d0f8031); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8131, data->f2x9cx0d0f8131); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8231, data->f2x9cx0d0f8231); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc031, data->f2x9cx0d0fc031); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc131, data->f2x9cx0d0fc131); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc231, data->f2x9cx0d0fc231); + for (i=0; i<9; i++) + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0031 | (i << 8), data->f2x9cx0d0f0_0_f_31[i]); + + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8021, data->f2x9cx0d0f8021); + } } } @@ -344,33 +618,44 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste if (!persistent_data->node[node].node_present) continue; - ganged = !!(data->f2x110 & 0x10); + if (is_fam15h()) + ganged = 0; + else + ganged = !!(data->f2x110 & 0x10); if ((ganged == 1) && (channel > 0)) continue; - /* Disable PHY auto-compensation engine */ - dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08); - if (!(dword & (1 << 30))) { - dword |= (1 << 30); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08, dword); - - /* Wait for 5us */ - mct_Wait(100); + if (is_fam15h()) { + /* Program PllLockTime = 0x190 */ + dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006); + dword &= ~0xffff; + dword |= 0x190; + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword); + + /* Program MemClkFreqVal = 0 */ + dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94); + dword &= (0x1 << 7); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94, dword); + + /* Restore DRAM Adddress/Timing Control Register */ + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04); + } else { + /* Disable PHY auto-compensation engine */ + dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08); + if (!(dword & (1 << 30))) { + dword |= (1 << 30); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08, dword); + + /* Wait for 5us */ + mct_Wait(100); + } } /* Restore DRAM Configuration High Register */ - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x94 + (0x100 * channel), data->f2x94); - - /* Enable PHY auto-compensation engine */ - dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08); - dword &= ~(1 << 30); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08, dword); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94, data->f2x94); } } - /* Wait for 750us */ - mct_Wait(15000); - /* Stage 5 */ for (node = 0; node < MAX_NODES_SUPPORTED; node++) { for (channel = 0; channel < 2; channel++) { @@ -378,17 +663,40 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste if (!persistent_data->node[node].node_present) continue; - ganged = !!(data->f2x110 & 0x10); + if (is_fam15h()) + ganged = 0; + else + ganged = !!(data->f2x110 & 0x10); if ((ganged == 1) && (channel > 0)) continue; + dct_enabled = !(data->f2x94 & (1 << 14)); + if (!dct_enabled) + continue; + /* Wait for any pending PHY frequency changes to complete */ do { - dword = read_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x08); + dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94); } while (dword & (1 << 21)); + + if (is_fam15h()) { + /* Program PllLockTime = 0xf */ + dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006); + dword &= ~0xffff; + dword |= 0xf; + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, dword); + } else { + /* Enable PHY auto-compensation engine */ + dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08); + dword &= ~(1 << 30); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x08, dword); + } } } + /* Wait for 750us */ + mct_Wait(15000); + /* Stage 6 */ for (node = 0; node < MAX_NODES_SUPPORTED; node++) { for (channel = 0; channel < 2; channel++) { @@ -398,10 +706,49 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste for (i=0; i<9; i++) for (j=0; j<3; j++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x00, data->f2x9cx00); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0a, data->f2x9cx0a); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0c, data->f2x9cx0c); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f0_f_8_0_0_8_4_0[i][j]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x00, data->f2x9cx00); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0a, data->f2x9cx0a); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0c, data->f2x9cx0c); + } + } + + /* Family 15h-specific configuration */ + if (is_fam15h()) { + for (node = 0; node < MAX_NODES_SUPPORTED; node++) { + for (channel = 0; channel < 2; channel++) { + struct amd_s3_persistent_mct_channel_data* data = &persistent_data->node[node].channel[channel]; + if (!persistent_data->node[node].node_present) + continue; + + dword = read_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe003); + dword |= (0x3 << 13); /* DisAutoComp, DisablePredriverCal = 1 */ + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, dword); + + for (i=0; i<9; i++) + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0006 | (i << 8), data->f2x9cx0d0f0_8_0_06[i]); + for (i=0; i<9; i++) + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f000a | (i << 8), data->f2x9cx0d0f0_8_0_0a[i]); + for (i=0; i<9; i++) + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0002 | (i << 8), (0x8000 | data->f2x9cx0d0f0_8_0_02[i])); + + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8006, data->f2x9cx0d0f8006); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f800a, data->f2x9cx0d0f800a); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8106, data->f2x9cx0d0f8106); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f810a, data->f2x9cx0d0f810a); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc006, data->f2x9cx0d0fc006); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc00a, data->f2x9cx0d0fc00a); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc00e, data->f2x9cx0d0fc00e); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc012, data->f2x9cx0d0fc012); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8002, (0x8000 | data->f2x9cx0d0f8002)); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f8102, (0x8000 | data->f2x9cx0d0f8102)); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fc002, (0x8000 | data->f2x9cx0d0fc002)); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2002, (0x8000 | data->f2x9cx0d0f2002)); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2102, (0x8000 | data->f2x9cx0d0f2102)); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2202, (0x8000 | data->f2x9cx0d0f2202)); + + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe003, data->f2x9cx0d0fe003); + } } } @@ -412,11 +759,15 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste if (!persistent_data->node[node].node_present) continue; - ganged = !!(data->f2x110 & 0x10); + if (is_fam15h()) + ganged = 0; + else + ganged = !!(data->f2x110 & 0x10); if ((ganged == 1) && (channel > 0)) continue; - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x04, data->f2x9cx04); + if (!is_fam15h()) + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04); } } @@ -431,16 +782,19 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste if (!dct_enabled) continue; - ganged = !!(data->f2x110 & 0x10); + if (is_fam15h()) + ganged = 0; + else + ganged = !!(data->f2x110 & 0x10); if ((ganged == 1) && (channel > 0)) continue; printk(BIOS_SPEW, "Taking DIMMs out of self refresh node: %d channel: %d\n", node, channel); /* Exit self refresh mode */ - dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel)); + dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90); dword |= (1 << 1); - pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel), dword); + write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90, dword); } } @@ -459,12 +813,12 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste /* Wait for transition from self refresh mode to complete */ do { - dword = pci_read_config32(PCI_DEV(0, 0x18 + node, 2), 0x90 + (0x100 * channel)); + dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90); } while (dword & (1 << 1)); /* Restore registers */ - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0fe006, data->f2x9cx0d0fe006); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0fe007, data->f2x9cx0d0fe007); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe006, data->f2x9cx0d0fe006); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe007, data->f2x9cx0d0fe007); } } @@ -476,26 +830,26 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste continue; for (i=0; i<12; i++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x10 + i, data->f2x9cx10[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x10 + i, data->f2x9cx10[i]); for (i=0; i<12; i++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x20 + i, data->f2x9cx20[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x20 + i, data->f2x9cx20[i]); for (i=0; i<4; i++) for (j=0; j<3; j++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]); for (i=0; i<4; i++) for (j=0; j<3; j++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d, data->f2x9cx0d); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d, data->f2x9cx0d); for (i=0; i<9; i++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0013 | (i << 8), data->f2x9cx0d0f0_f_0_13[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0013 | (i << 8), data->f2x9cx0d0f0_f_0_13[i]); for (i=0; i<9; i++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0030 | (i << 8), data->f2x9cx0d0f0_f_0_30[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0030 | (i << 8), data->f2x9cx0d0f0_f_0_30[i]); for (i=0; i<4; i++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f2030 | (i << 8), data->f2x9cx0d0f2_f_0_30[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f2030 | (i << 8), data->f2x9cx0d0f2_f_0_30[i]); for (i=0; i<2; i++) for (j=0; j<3; j++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f8_8_4_0[i][j]); - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x0d0f812f, data->f2x9cx0d0f812f); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f0000 | (i << 8) | (j * 4), data->f2x9cx0d0f8_8_4_0[i][j]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0f812f, data->f2x9cx0d0f812f); } } @@ -508,9 +862,9 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste continue; for (i=0; i<12; i++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x30 + i, data->f2x9cx30[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x30 + i, data->f2x9cx30[i]); for (i=0; i<12; i++) - write_amd_dct_index_register(PCI_DEV(0, 0x18 + node, 2), 0x98 + (0x100 * channel), 0x40 + i, data->f2x9cx40[i]); + write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x40 + i, data->f2x9cx40[i]); } } } |