aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mct_d.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.c132
1 files changed, 132 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index ad0e6e807b..27fa7ae018 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -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);
}