northbridge/amd/amdfam10: Enable CC6 DRAM save area setup

Change-Id: Ibeb35da3395dc77a21a2f92f0e1d0845be53d175
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
Reviewed-on: http://review.coreboot.org/11977
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Timothy Pearson 2015-06-05 21:13:30 -05:00 committed by Ronald G. Minnich
parent df1fb9c05f
commit cfb93e70bf
2 changed files with 202 additions and 0 deletions

View File

@ -702,6 +702,8 @@ struct chip_operations northbridge_amd_amdfam10_ops = {
static void amdfam10_domain_read_resources(device_t dev)
{
unsigned reg;
uint8_t nvram;
uint8_t enable_cc6;
/* Find the already assigned resource pairs */
get_fx_devs();
@ -745,6 +747,74 @@ static void amdfam10_domain_read_resources(device_t dev)
/* Reserve lower DRAM region to force PCI MMIO region to correct location above 0xefffffff */
ram_resource(dev, 7, 0, rdmsr(TOP_MEM).lo >> 10);
#endif
if (is_fam15h()) {
enable_cc6 = 0;
if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
enable_cc6 = !!nvram;
if (enable_cc6) {
uint8_t node;
uint8_t interleaved;
int8_t range;
int8_t max_range;
uint8_t max_node;
uint64_t max_range_limit;
uint32_t dword;
uint32_t dword2;
uint64_t qword;
uint8_t num_nodes;
/* Find highest DRAM range (DramLimitAddr) */
max_node = 0;
max_range = -1;
interleaved = 0;
max_range_limit = 0;
for (range = 0; range < 8; range++) {
dword = f1_read_config32(0x40 + (range * 0x8));
if (!(dword & 0x3))
continue;
if ((dword >> 8) & 0x7)
interleaved = 1;
dword = f1_read_config32(0x44 + (range * 0x8));
dword2 = f1_read_config32(0x144 + (range * 0x8));
qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
qword |= (((uint64_t)dword2) & 0xff) << 40;
if (qword > max_range_limit) {
max_range = range;
max_range_limit = qword;
max_node = dword & 0x7;
}
}
num_nodes = 0;
device_t node_dev;
for (node = 0; node < FX_DEVS; node++) {
node_dev = get_node_pci(node, 0);
/* Test for node presence */
if ((node_dev) && (pci_read_config32(node_dev, PCI_VENDOR_ID) != 0xffffffff))
num_nodes++;
}
/* Calculate CC6 sotrage area size */
if (interleaved)
qword = (0x1000000 * num_nodes);
else
qword = 0x1000000;
/* Reserve the CC6 save segment */
reserved_ram_resource(dev, 8, max_range_limit >> 10, qword >> 10);
/* Set up the C-state base address */
msr_t c_state_addr_msr;
c_state_addr_msr = rdmsr(0xc0010073);
c_state_addr_msr.lo = 0xe0e0; /* CstateAddr = 0xe0e0 */
wrmsr(0xc0010073, c_state_addr_msr);
}
}
}
static u32 my_find_pci_tolm(struct bus *bus, u32 tolm)

View File

@ -1194,6 +1194,100 @@ static void compare_nvram_spd_hashes(struct MCTStatStruc *pMCTstat,
}
#endif
static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, uint8_t num_nodes)
{
uint8_t interleaved;
uint8_t destination_node;
int8_t range;
int8_t max_range;
uint8_t max_node;
uint64_t max_range_limit;
uint32_t dword;
uint32_t dword2;
uint64_t qword;
interleaved = 0;
if (pMCTstat->GStatus & (1 << GSB_NodeIntlv))
interleaved = 1;
/* Find highest DRAM range (DramLimitAddr) */
max_node = 0;
max_range = -1;
max_range_limit = 0;
for (range = 0; range < 8; range++) {
dword = Get_NB32(pDCTstat->dev_map, 0x40 + (range * 0x8));
if (!(dword & 0x3))
continue;
dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
qword = ((((uint64_t)dword) >> 16) & 0xffff) << 24;
qword |= (((uint64_t)dword2) & 0xff) << 40;
if (qword > max_range_limit) {
max_range = range;
max_range_limit = qword;
max_node = dword & 0x7;
}
}
if (pDCTstat->Node_ID == max_node) {
if (max_range >= 0) {
if (interleaved)
/* Move upper limit down by 16M * the number of nodes */
max_range_limit -= (0x1000000 * num_nodes);
else
/* Move upper limit down by 16M */
max_range_limit -= 0x1000000;
/* Store modified range */
dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8));
dword &= ~(0xffff << 16); /* DramLimit[39:24] = max_range_limit[39:24] */
dword |= (max_range_limit >> 24) & 0xffff;
Set_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8), dword);
dword = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8));
dword &= ~(0xffff << 16); /* DramLimit[47:40] = max_range_limit[47:40] */
dword |= (max_range_limit >> 40) & 0xff;
Set_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8), dword);
}
}
/* Determine save state destination node */
if (interleaved)
destination_node = Get_NB32(pDCTstat->dev_host, 0x60) & 0x7;
else
destination_node = max_node;
/* Set save state destination node */
dword = Get_NB32(pDCTstat->dev_link, 0x128);
dword &= ~(0x3f << 12); /* CoreSaveStateDestNode = destination_node */
dword |= (destination_node & 0x3f) << 12;
Set_NB32(pDCTstat->dev_link, 0x128, dword);
}
static void lock_dram_config(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat)
{
uint32_t dword;
dword = Get_NB32(pDCTstat->dev_dct, 0x118);
dword |= 0x1 << 19; /* LockDramCfg = 1 */
Set_NB32(pDCTstat->dev_dct, 0x118, dword);
}
static void set_cc6_save_enable(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat, uint8_t enable)
{
uint32_t dword;
dword = Get_NB32(pDCTstat->dev_dct, 0x118);
dword &= ~(0x1 << 18); /* CC6SaveEn = enable */
dword |= (enable & 0x1) << 18;
Set_NB32(pDCTstat->dev_dct, 0x118, dword);
}
static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA)
{
@ -1243,6 +1337,7 @@ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
u8 Node, NodesWmem;
u32 node_sys_base;
uint8_t nvram;
uint8_t enable_cc6;
uint8_t allow_config_restore;
uint8_t s3resume = acpi_is_wakeup_s3();
@ -1413,6 +1508,43 @@ restartinit:
mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat);
}
if (is_fam15h()) {
enable_cc6 = 0;
if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
enable_cc6 = !!nvram;
if (enable_cc6) {
uint8_t num_nodes;
num_nodes = 0;
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
struct DCTStatStruc *pDCTstat;
pDCTstat = pDCTstatA + Node;
if (pDCTstat->NodePresent)
num_nodes++;
}
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
struct DCTStatStruc *pDCTstat;
pDCTstat = pDCTstatA + Node;
if (pDCTstat->NodePresent)
set_up_cc6_storage_fam15(pMCTstat, pDCTstat, num_nodes);
}
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
struct DCTStatStruc *pDCTstat;
pDCTstat = pDCTstatA + Node;
if (pDCTstat->NodePresent) {
lock_dram_config(pMCTstat, pDCTstat);
set_cc6_save_enable(pMCTstat, pDCTstat, 1);
}
}
}
}
mct_FinalMCT_D(pMCTstat, pDCTstatA);
printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", pMCTstat->GStatus);
}