aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/s3utils.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/s3utils.c652
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]);
}
}
}