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.c1237
1 files changed, 0 insertions, 1237 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
deleted file mode 100644
index 52032e9362..0000000000
--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+++ /dev/null
@@ -1,1237 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <string.h>
-#include <arch/cpu.h>
-#include <arch/acpi.h>
-#include <cpu/x86/msr.h>
-#include <cpu/amd/msr.h>
-#include <cpu/x86/mtrr.h>
-#include <cpu/amd/mtrr.h>
-#include <device/device.h>
-#include <device/pci_def.h>
-#include <device/pci_ops.h>
-#include <console/console.h>
-#include <cbfs.h>
-#include <cbmem.h>
-#include <spi-generic.h>
-#include <spi_flash.h>
-#include <pc80/mc146818rtc.h>
-#include <stdint.h>
-#include <types.h>
-
-#include "mct_d.h"
-#include "mct_d_gcc.h"
-
-#include "s3utils.h"
-
-#define S3NV_FILE_NAME "s3nv"
-
-static uint8_t is_fam15h(void)
-{
- uint8_t fam15h = 0;
- uint32_t family;
-
- family = cpuid_eax(0x80000001);
- family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-
- if (family >= 0x6f)
- /* Family 15h or later */
- fam15h = 1;
-
- return fam15h;
-}
-
-static ssize_t get_s3nv_file_offset(void);
-
-ssize_t get_s3nv_file_offset(void)
-{
- struct region_device s3nv_region;
- struct cbfsf s3nv_cbfs_file;
- if (cbfs_boot_locate(&s3nv_cbfs_file, S3NV_FILE_NAME, NULL)) {
- printk(BIOS_DEBUG, "S3 state file not found in CBFS: %s\n", S3NV_FILE_NAME);
- return -1;
- }
- cbfs_file_data(&s3nv_region, &s3nv_cbfs_file);
-
- return s3nv_region.region.offset;
-}
-
-#if ENV_PCI_SIMPLE_DEVICE
-static uint32_t read_config32_dct(pci_devfn_t dev, uint8_t node, uint8_t dct,
- uint32_t reg)
-#else
-static uint32_t read_config32_dct(struct device *dev, uint8_t node, uint8_t dct,
- uint32_t reg)
-#endif
-{
- if (is_fam15h()) {
- uint32_t dword;
-#if ENV_PCI_SIMPLE_DEVICE
- pci_devfn_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-#else
- struct device *dev_fn1 = pcidev_on_root(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);
-}
-
-#if ENV_PCI_SIMPLE_DEVICE
-static void write_config32_dct(pci_devfn_t dev, uint8_t node, uint8_t dct,
- uint32_t reg, uint32_t value)
-#else
-static void write_config32_dct(struct device *dev, uint8_t node, uint8_t dct,
- uint32_t reg, uint32_t value)
-#endif
-{
- if (is_fam15h()) {
- uint32_t dword;
-#if ENV_PCI_SIMPLE_DEVICE
- pci_devfn_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-#else
- struct device *dev_fn1 = pcidev_on_root(0x18 + node, 1);
-#endif
-
- /* Select DCT */
- dword = pci_read_config32(dev_fn1, 0x10c);
- dword &= ~0x1;
- dword |= (dct & 0x1);
- pci_write_config32(dev_fn1, 0x10c, dword);
- } else {
- /* Apply offset */
- reg += dct * 0x100;
- }
-
- pci_write_config32(dev, reg, value);
-}
-
-#if ENV_PCI_SIMPLE_DEVICE
-static uint32_t read_amd_dct_index_register(pci_devfn_t dev,
- uint32_t index_ctl_reg, uint32_t index)
-#else
-static uint32_t read_amd_dct_index_register(struct device *dev,
- uint32_t index_ctl_reg, uint32_t index)
-#endif
-{
- uint32_t dword;
-
- index &= ~(1 << 30);
- pci_write_config32(dev, index_ctl_reg, index);
- do {
- dword = pci_read_config32(dev, index_ctl_reg);
- } while (!(dword & (1 << 31)));
- dword = pci_read_config32(dev, index_ctl_reg + 0x04);
-
- return dword;
-}
-
-#if ENV_PCI_SIMPLE_DEVICE
-static uint32_t read_amd_dct_index_register_dct(pci_devfn_t dev, uint8_t node,
- uint8_t dct, uint32_t index_ctl_reg, uint32_t index)
-#else
-static uint32_t read_amd_dct_index_register_dct(struct device *dev,
- uint8_t node, uint8_t dct, uint32_t index_ctl_reg,
- uint32_t index)
-#endif
-{
- if (is_fam15h()) {
- uint32_t dword;
-#if ENV_PCI_SIMPLE_DEVICE
- pci_devfn_t dev_fn1 = PCI_DEV(0, 0x18 + node, 1);
-#else
- struct device *dev_fn1 = pcidev_on_root(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);
-}
-
-/* Non-cryptographic 64-bit hash function taken from Stack Overflow:
- * http://stackoverflow.com/a/13326345
- * Any 64-bit hash with sufficiently low collision potential
- * could be used instead.
- */
-void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash)
-{
- const unsigned long long prime = 2654435789ULL;
- uint16_t byte;
- *spd_hash = 104395301;
-
- for (byte = 0; byte < 256; byte++)
- *spd_hash += (spd_data[byte] * prime) ^ (*spd_hash >> 23);
-
- *spd_hash = *spd_hash ^ (*spd_hash << 37);
-}
-
-uint16_t calculate_nvram_mct_hash(void)
-{
- uint32_t nvram;
- uint16_t ret;
-
- ret = 0;
- if (get_option(&nvram, "max_mem_clock") == CB_SUCCESS)
- ret |= nvram & 0xf;
- if (get_option(&nvram, "minimum_memory_voltage") == CB_SUCCESS)
- ret |= (nvram & 0x3) << 4;
- if (get_option(&nvram, "ECC_memory") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 6;
- if (get_option(&nvram, "ECC_redirection") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 7;
- if (get_option(&nvram, "ecc_scrub_rate") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 8;
- if (get_option(&nvram, "interleave_chip_selects") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 9;
- if (get_option(&nvram, "interleave_nodes") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 10;
- if (get_option(&nvram, "interleave_memory_channels") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 11;
- if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 12;
- if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
- ret |= (nvram & 0x1) << 13;
-
- return ret;
-}
-
-static struct amd_s3_persistent_data *map_s3nv_in_nvram(void)
-{
- ssize_t s3nv_offset;
- ssize_t s3nv_file_offset;
- void *s3nv_cbfs_file_ptr;
- struct amd_s3_persistent_data *persistent_data;
-
- /* Obtain CBFS file offset */
- s3nv_offset = get_s3nv_file_offset();
- if (s3nv_offset == -1)
- return NULL;
-
- /* Align flash pointer to nearest boundary */
- s3nv_file_offset = s3nv_offset;
- s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
- s3nv_offset += CONFIG_S3_DATA_SIZE;
- s3nv_file_offset = s3nv_offset - s3nv_file_offset;
-
- /* Map data structure in CBFS and restore settings */
- s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, CBFS_TYPE_RAW, NULL);
- if (!s3nv_cbfs_file_ptr) {
- printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", S3NV_FILE_NAME);
- return NULL;
- }
- persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
-
- return persistent_data;
-}
-
-int8_t load_spd_hashes_from_nvram(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
-{
- struct amd_s3_persistent_data *persistent_data;
-
- persistent_data = map_s3nv_in_nvram();
- if (!persistent_data)
- return -1;
-
- memcpy(pDCTstat->spd_data.nvram_spd_hash, persistent_data->node[pDCTstat->Node_ID].spd_hash, sizeof(pDCTstat->spd_data.nvram_spd_hash));
- memcpy(pDCTstat->spd_data.nvram_memclk, persistent_data->node[pDCTstat->Node_ID].memclk, sizeof(pDCTstat->spd_data.nvram_memclk));
-
- pMCTstat->nvram_checksum = persistent_data->nvram_checksum;
-
- return 0;
-}
-
-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 void wrmsr_uint64_t(unsigned long index, uint64_t value)
-{
- msr_t msr;
- msr.hi = (value & 0xffffffff00000000ULL) >> 32;
- msr.lo = (value & 0xffffffff);
- wrmsr(index, msr);
-}
-
-static uint32_t read_config32_dct_nbpstate(struct device *dev, uint8_t node,
- uint8_t dct, uint8_t nb_pstate,
- uint32_t reg)
-{
- uint32_t dword;
- struct device *dev_fn1 = pcidev_on_root(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);
-}
-
-static void copy_cbmem_spd_data_to_save_variable(struct amd_s3_persistent_data *persistent_data, uint8_t *restored)
-{
- uint8_t node;
- uint8_t dimm;
- uint8_t channel;
- struct amdmct_memory_info *mem_info;
- mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
- if (mem_info == NULL) {
- /* can't find amdmct information in cbmem */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++)
- for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
- persistent_data->node[node].spd_hash[dimm] = 0xffffffffffffffffULL;
-
- return;
- }
-
- for (node = 0; node < MAX_NODES_SUPPORTED; node++)
- for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
- calculate_spd_hash(mem_info->dct_stat[node].spd_data.spd_bytes[dimm], &persistent_data->node[node].spd_hash[dimm]);
-
- for (node = 0; node < MAX_NODES_SUPPORTED; node++)
- for (channel = 0; channel < 2; channel++)
- persistent_data->node[node].memclk[channel] = mem_info->dct_stat[node].Speed;
-
- persistent_data->nvram_checksum = calculate_nvram_mct_hash();
-
- if (restored) {
- if (mem_info->mct_stat.GStatus & (1 << GSB_ConfigRestored))
- *restored = 1;
- else
- *restored = 0;
- }
-}
-
-void copy_mct_data_to_save_variable(struct amd_s3_persistent_data *persistent_data)
-{
- uint8_t i;
- uint8_t j;
- uint8_t node;
- uint8_t channel;
-
- /* Zero out data structure */
- memset(persistent_data, 0, sizeof(struct amd_s3_persistent_data));
-
- /* Load data from DCTs into data structure */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- struct device *dev_fn1 = pcidev_on_root(0x18 + node, 1);
- struct device *dev_fn2 = pcidev_on_root(0x18 + node, 2);
- struct device *dev_fn3 = pcidev_on_root(0x18 + node, 3);
- /* Test for node presence */
- if ((!dev_fn1) || (pci_read_config32(dev_fn1, PCI_VENDOR_ID) == 0xffffffff)) {
- persistent_data->node[node].node_present = 0;
- continue;
- }
- persistent_data->node[node].node_present = 1;
-
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
-
- /* Stage 1 */
- data->f2x110 = pci_read_config32(dev_fn2, 0x110);
-
- /* Stage 2 */
- data->f1x40 = 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);
- data->f2x10c = pci_read_config32(dev_fn2, 0x10c);
- data->f2x114 = pci_read_config32(dev_fn2, 0x114);
- data->f2x118 = pci_read_config32(dev_fn2, 0x118);
- data->f2x11c = pci_read_config32(dev_fn2, 0x11c);
- data->f2x1b0 = pci_read_config32(dev_fn2, 0x1b0);
- data->f3x44 = pci_read_config32(dev_fn3, 0x44);
- for (i = 0; i < 16; i++) {
- data->msr0000020[i] =
- rdmsr_uint64_t(MTRR_PHYS_BASE(0) | i);
- }
- data->msr00000250 = rdmsr_uint64_t(MTRR_FIX_64K_00000);
- data->msr00000258 = rdmsr_uint64_t(MTRR_FIX_16K_80000);
- for (i = 0; i < 8; i++)
- data->msr0000026[i] = rdmsr_uint64_t(0x00000260 | (i + 8));
- data->msr000002ff = rdmsr_uint64_t(MTRR_DEF_TYPE_MSR);
- data->msrc0010010 = rdmsr_uint64_t(SYSCFG_MSR);
- data->msrc001001a = rdmsr_uint64_t(TOP_MEM);
- data->msrc001001d = rdmsr_uint64_t(TOP_MEM2);
- data->msrc001001f = rdmsr_uint64_t(NB_CFG_MSR);
-
- /* Stage 3 */
- 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);
-
- if (channel == 1)
- data->f2x9cx0d0fe00a = read_amd_dct_index_register_dct(dev_fn2, node, channel, 0x98, 0x0d0fe00a);
- }
-
- /* Stage 4 */
- 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_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_dct(dev_fn2, node, channel, 0x98, 0x04);
-
- /* Stage 9 */
- 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_dct(dev_fn2, node, channel, 0x98, 0x10 + i);
- for (i = 0; i < 12; 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_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_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_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_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_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_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 (CONFIG(DIMM_DDR3)) {
- for (i = 0; i < 12; 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_dct(dev_fn2, node, channel, 0x98, 0x40 + i);
- }
-
- /* Other */
- /* ECC scrub rate control */
- data->f3x58 = read_config32_dct(dev_fn3, node, 0, 0x58);
-
- /* ECC scrub location */
- write_config32_dct(dev_fn3, node, 0, 0x58, 0x0); /* Disable sequential scrub to work around non-atomic location read */
- data->f3x5c = read_config32_dct(dev_fn3, node, 0, 0x5c);
- data->f3x60 = read_config32_dct(dev_fn3, node, 0, 0x60);
- write_config32_dct(dev_fn3, node, 0, 0x58, data->f3x58); /* Re-enable sequential scrub */
- }
- }
-}
-
-static void write_config32_dct_nbpstate(pci_devfn_t dev, uint8_t node,
- uint8_t dct, uint8_t nb_pstate,
- uint32_t reg, uint32_t value)
-{
- uint32_t dword;
- pci_devfn_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(pci_devfn_t dev,
- uint32_t index_ctl_reg, uint32_t index,
- uint32_t value)
-{
- uint32_t dword;
-
- pci_write_config32(dev, index_ctl_reg + 0x04, value);
- index |= (1 << 30);
- pci_write_config32(dev, index_ctl_reg, index);
- do {
- dword = pci_read_config32(dev, index_ctl_reg);
- } while (!(dword & (1 << 31)));
-}
-
-static void write_amd_dct_index_register_dct(pci_devfn_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;
- pci_devfn_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);
-}
-
-void restore_mct_data_from_save_variable(struct amd_s3_persistent_data *persistent_data, uint8_t training_only)
-{
- uint8_t i;
- uint8_t j;
- uint8_t node;
- uint8_t channel;
- uint8_t ganged;
- uint8_t dct_enabled;
- uint32_t dword;
-
- if (training_only) {
- /* Only restore the Receiver Enable and DQS training registers */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- /* Restore training parameters */
- for (i = 0; i < 4; i++)
- for (j = 0; j < 3; j++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
- for (i = 0; i < 4; i++)
- for (j = 0; j < 3; j++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
-
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x10 + i, data->f2x9cx10[i]);
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x20 + i, data->f2x9cx20[i]);
-
- if (CONFIG(DIMM_DDR3)) {
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x30 + i, data->f2x9cx30[i]);
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x40 + i, data->f2x9cx40[i]);
- }
-
- /* Restore MaxRdLatency */
- if (is_fam15h()) {
- for (i = 0; i < 4; i++)
- write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 0x210, data->f2x210[i]);
- } else {
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x78, data->f2x78);
- }
-
- /* Other timing control registers */
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x8c, data->f2x8c);
- }
- }
-
- return;
- }
-
- /* Load data from data structure into DCTs */
- /* Stage 1 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- pci_write_config32(PCI_DEV(0, 0x18 + node, 2), 0x110, data->f2x110);
- }
- }
-
- /* Stage 2 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- 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);
- if (is_fam15h())
- /* Do not set LockDramCfg or CC6SaveEn at this time */
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x118, data->f2x118 & ~(0x3 << 18));
- else
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x118, data->f2x118);
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x11c, data->f2x11c);
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x1b0, data->f2x1b0);
- write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, channel, 0x44, data->f3x44);
- for (i = 0; i < 16; i++) {
- wrmsr_uint64_t(MTRR_PHYS_BASE(0) | i,
- data->msr0000020[i]);
- }
- wrmsr_uint64_t(MTRR_FIX_64K_00000, data->msr00000250);
- wrmsr_uint64_t(MTRR_FIX_16K_80000, data->msr00000258);
- /* FIXME
- * Restoring these MSRs causes a hang on resume due to
- * destroying CAR while still executing from CAR!
- * For now, skip restoration...
- */
- // for (i = 0; i < 8; i++)
- // wrmsr_uint64_t(0x00000260 | (i + 8), data->msr0000026[i]);
- wrmsr_uint64_t(MTRR_DEF_TYPE_MSR, data->msr000002ff);
- wrmsr_uint64_t(SYSCFG_MSR, data->msrc0010010);
- wrmsr_uint64_t(TOP_MEM, data->msrc001001a);
- wrmsr_uint64_t(TOP_MEM2, data->msrc001001d);
- wrmsr_uint64_t(NB_CFG_MSR, data->msrc001001f);
- }
- }
-
- /* Stage 3 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- if (is_fam15h())
- ganged = 0;
- else
- ganged = !!(data->f2x110 & 0x10);
- if ((ganged == 1) && (channel > 0))
- continue;
-
- 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);
-
- if (channel == 1)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x0d0fe00a, data->f2x9cx0d0fe00a);
- }
- }
- }
-
- /* Stage 4 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- if (is_fam15h())
- ganged = 0;
- else
- ganged = !!(data->f2x110 & 0x10);
- if ((ganged == 1) && (channel > 0))
- continue;
-
- 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 Address/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 */
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x94, data->f2x94);
- }
- }
-
- /* Stage 5 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- 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_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++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- for (i = 0; i < 9; i++)
- for (j = 0; j < 3; j++)
- write_amd_dct_index_register_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);
- }
- }
- }
-
- /* Stage 7 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- if (is_fam15h())
- ganged = 0;
- else
- ganged = !!(data->f2x110 & 0x10);
- if ((ganged == 1) && (channel > 0))
- continue;
-
- if (!is_fam15h())
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x04, data->f2x9cx04);
- }
- }
-
- /* Stage 8 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- dct_enabled = !(data->f2x94 & (1 << 14));
- if (!dct_enabled)
- continue;
-
- 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 = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90);
- dword |= (1 << 1);
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90, dword);
- }
- }
-
- /* Stage 9 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- dct_enabled = !(data->f2x94 & (1 << 14));
- if (!dct_enabled)
- continue;
-
- printk(BIOS_SPEW, "Waiting for DIMMs to exit self refresh node: %d channel: %d\n", node, channel);
-
- /* Wait for transition from self refresh mode to complete */
- do {
- dword = read_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x90);
- } while (dword & (1 << 1));
-
- /* Restore registers */
- 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);
- }
- }
-
- /* Stage 10 */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x10 + i, data->f2x9cx10[i]);
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x20 + i, data->f2x9cx20[i]);
- for (i = 0; i < 4; i++)
- for (j = 0; j < 3; j++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
- for (i = 0; i < 4; i++)
- for (j = 0; j < 3; j++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
- 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_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_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_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_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);
- }
- }
-
- /* Stage 11 */
- if (CONFIG(DIMM_DDR3)) {
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x30 + i, data->f2x9cx30[i]);
- for (i = 0; i < 12; i++)
- write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x40 + i, data->f2x9cx40[i]);
- }
- }
- }
-
- /* Other */
- for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
- for (channel = 0; channel < 2; channel++) {
- struct amd_s3_persistent_mct_channel_data *data = &persistent_data->node[node].channel[channel];
- if (!persistent_data->node[node].node_present)
- continue;
-
- /* ECC scrub location */
- write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 0x5c, data->f3x5c);
- write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 0x60, data->f3x60);
-
- /* ECC scrub rate control */
- write_config32_dct(PCI_DEV(0, 0x18 + node, 3), node, 0, 0x58, data->f3x58);
-
- if (is_fam15h())
- /* Set LockDramCfg and CC6SaveEn */
- write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x118, data->f2x118);
- }
- }
-}
-
-int8_t save_mct_information_to_nvram(void)
-{
- uint8_t nvram;
- uint8_t restored = 0;
-
- if (acpi_is_wakeup_s3())
- return 0;
-
- printk(BIOS_DEBUG, "Writing AMD DCT configuration to Flash\n");
-
- struct spi_flash flash;
- ssize_t s3nv_offset;
- struct amd_s3_persistent_data *persistent_data;
-
- /* Allocate temporary data structures */
- persistent_data = malloc(sizeof(struct amd_s3_persistent_data));
- if (!persistent_data) {
- printk(BIOS_DEBUG, "Could not allocate S3 data structure in RAM\n");
- return -1;
- }
-
- /* Obtain MCT configuration data */
- copy_mct_data_to_save_variable(persistent_data);
-
- /* Save RAM SPD data at the same time */
- copy_cbmem_spd_data_to_save_variable(persistent_data, &restored);
-
- if (restored) {
- /* Allow training bypass if DIMM configuration is unchanged on next boot */
- nvram = 1;
- set_option("allow_spd_nvram_cache_restore", &nvram);
-
- printk(BIOS_DEBUG, "Hardware configuration unchanged since last boot; skipping write\n");
- free(persistent_data);
- return 0;
- }
-
- /* Obtain CBFS file offset */
- s3nv_offset = get_s3nv_file_offset();
- if (s3nv_offset == -1) {
- free(persistent_data);
- return -1;
- }
-
- /* Align flash pointer to nearest boundary */
- s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
- s3nv_offset += CONFIG_S3_DATA_SIZE;
-
- /* Initialize SPI and detect devices */
- spi_init();
- if (spi_flash_probe(0, 0, &flash)) {
- printk(BIOS_DEBUG, "Could not find SPI device\n");
- return -1;
- }
-
- spi_flash_volatile_group_begin(&flash);
-
- /* Erase and write data structure */
- spi_flash_erase(&flash, s3nv_offset, CONFIG_S3_DATA_SIZE);
- spi_flash_write(&flash, s3nv_offset,
- sizeof(struct amd_s3_persistent_data), persistent_data);
-
- /* Deallocate temporary data structures */
- free(persistent_data);
-
- spi_flash_volatile_group_end(&flash);
-
- /* Allow training bypass if DIMM configuration is unchanged on next boot */
- nvram = 1;
- set_option("allow_spd_nvram_cache_restore", &nvram);
-
- return 0;
-}
-
-int8_t restore_mct_information_from_nvram(uint8_t training_only)
-{
- struct amd_s3_persistent_data *persistent_data;
-
- persistent_data = map_s3nv_in_nvram();
- if (!persistent_data)
- return -1;
-
- restore_mct_data_from_save_variable(persistent_data, training_only);
-
- return 0;
-}
-
-void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat)
-{
- uint8_t dimm;
-
- for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
- calculate_spd_hash(pDCTstat->spd_data.spd_bytes[dimm], &pDCTstat->spd_data.spd_hash[dimm]);
- }
-}
-
-void compare_nvram_spd_hashes(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat)
-{
- uint8_t dimm;
-
- pDCTstat->spd_data.nvram_spd_match = 1;
- for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
- if (pDCTstat->spd_data.spd_hash[dimm] != pDCTstat->spd_data.nvram_spd_hash[dimm])
- pDCTstat->spd_data.nvram_spd_match = 0;
- }
-}