summaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdfam10
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineeringinc.com>2015-06-08 19:35:06 -0500
committerRonald G. Minnich <rminnich@gmail.com>2015-11-11 18:45:14 +0100
commit83abd81c8acb3a53dfc125e248d9e5fd58f3e0f7 (patch)
treeca0652a1421652f4eb8b4af358f66e2fc256e1db /src/northbridge/amd/amdfam10
parentdd4390b6e055ef862084a5fc45b756d6fe09151d (diff)
cpu/amd: Add CC6 support
This patch adds CC6 power save support to the AMD Family 15h support code. As CC6 is a complex power saving state that relies heavily on CPU, northbridge, and southbridge cooperation, this patch alters significant amounts of code throughout the tree simultaneously. Allowing the CPU to enter CC6 allows the second level of turbo boost to be reached, and also provides significant power savings when the system is idle due to the complete core shutdown. Change-Id: I44ce157cda97fb85f3e8f3d7262d4712b5410670 Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/11979 Tested-by: build bot (Jenkins) Tested-by: Raptor Engineering Automated Test Stand <noreply@raptorengineeringinc.com> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org> Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/northbridge/amd/amdfam10')
-rw-r--r--src/northbridge/amd/amdfam10/link_control.c81
-rw-r--r--src/northbridge/amd/amdfam10/northbridge.c58
2 files changed, 107 insertions, 32 deletions
diff --git a/src/northbridge/amd/amdfam10/link_control.c b/src/northbridge/amd/amdfam10/link_control.c
index 1091ef4f2e..7fa9f12b05 100644
--- a/src/northbridge/amd/amdfam10/link_control.c
+++ b/src/northbridge/amd/amdfam10/link_control.c
@@ -49,15 +49,94 @@ static inline uint8_t is_fam15h(void)
static void nb_control_init(struct device *dev)
{
+ uint8_t enable_c_states;
+ uint8_t enable_cc6;
uint32_t dword;
printk(BIOS_DEBUG, "NB: Function 4 Link Control.. ");
+ /* Configure L3 Power Control */
+ dword = pci_read_config32(dev, 0x1c4);
+ dword |= (0x1 << 8); /* L3PwrSavEn = 1 */
+ pci_write_config32(dev, 0x1c4, dword);
+
if (is_fam15h()) {
+ /* Configure L3 Control 2 */
+ dword = pci_read_config32(dev, 0x1cc);
+ dword &= ~(0x7 << 6); /* ImplRdProjDelayThresh = 0x2 */
+ dword |= (0x2 << 6);
+ pci_write_config32(dev, 0x1cc, dword);
+
+ /* Configure TDP Accumulator Divisor Control */
+ dword = pci_read_config32(dev, 0x104);
+ dword &= ~(0xfff << 2); /* TdpAccDivRate = 0xc8 */
+ dword |= (0xc8 << 2);
+ dword &= ~0x3; /* TdpAccDivVal = 0x1 */
+ dword |= 0x1;
+ pci_write_config32(dev, 0x104, dword);
+
+ /* Configure Sample and Residency Timers */
+ dword = pci_read_config32(dev, 0x110);
+ dword &= ~0xfff; /* CSampleTimer = 0x1 */
+ dword |= 0x1;
+ pci_write_config32(dev, 0x110, dword);
+
+ /* Configure APM TDP Control */
+ dword = pci_read_config32(dev, 0x16c);
+ dword |= (0x1 << 4); /* ApmTdpLimitIntEn = 1 */
+ pci_write_config32(dev, 0x16c, dword);
+
/* Enable APM */
dword = pci_read_config32(dev, 0x15c);
dword |= (0x1 << 7); /* ApmMasterEn = 1 */
pci_write_config32(dev, 0x15c, dword);
+
+ enable_c_states = 0;
+ enable_cc6 = 0;
+#if IS_ENABLED(CONFIG_HAVE_ACPI_TABLES)
+ uint8_t nvram;
+
+ if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
+ enable_c_states = !!nvram;
+
+ if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
+ enable_cc6 = !!nvram;
+#endif
+
+ if (enable_c_states) {
+ /* Configure C-state Control 1 */
+ dword = pci_read_config32(dev, 0x118);
+ dword |= (0x1 << 24); /* PwrGateEnCstAct1 = 1 */
+ dword &= ~(0x7 << 21); /* ClkDivisorCstAct1 = 0x0 */
+ dword &= ~(0x3 << 18); /* CacheFlushTmrSelCstAct1 = 0x1 */
+ dword |= (0x1 << 18);
+ dword |= (0x1 << 17); /* CacheFlushEnCstAct1 = 1 */
+ dword |= (0x1 << 16); /* CpuPrbEnCstAct1 = 1 */
+ dword &= ~(0x1 << 8); /* PwrGateEnCstAct0 = 0 */
+ dword &= ~(0x7 << 5); /* ClkDivisorCstAct0 = 0x0 */
+ dword &= ~(0x3 << 2); /* CacheFlushTmrSelCstAct0 = 0x2 */
+ dword |= (0x2 << 2);
+ dword |= (0x1 << 1); /* CacheFlushEnCstAct0 = 1 */
+ dword |= 0x1; /* CpuPrbEnCstAct0 = 1 */
+ pci_write_config32(dev, 0x118, dword);
+
+ /* Configure C-state Control 2 */
+ dword = pci_read_config32(dev, 0x11c);
+ dword &= ~(0x1 << 8); /* PwrGateEnCstAct2 = 0 */
+ dword &= ~(0x7 << 5); /* ClkDivisorCstAct2 = 0x0 */
+ dword &= ~(0x3 << 2); /* CacheFlushTmrSelCstAct0 = 0x0 */
+ dword &= ~(0x1 << 1); /* CacheFlushEnCstAct0 = 0 */
+ dword &= ~(0x1); /* CpuPrbEnCstAct0 = 0 */
+ pci_write_config32(dev, 0x11c, dword);
+
+ /* Configure C-state Policy Control 1 */
+ dword = pci_read_config32(dev, 0x128);
+ dword &= ~(0x7f << 5); /* CacheFlushTmr = 0x28 */
+ dword |= (0x28 << 5);
+ dword &= ~0x1; /* CoreCstateMode = !enable_cc6 */
+ dword |= ((enable_cc6)?0:1);
+ pci_write_config32(dev, 0x128, dword);
+ }
}
printk(BIOS_DEBUG, "done.\n");
@@ -83,4 +162,4 @@ static const struct pci_driver mcf4_driver_fam15 __pci_driver = {
.ops = &mcf4_ops,
.vendor = PCI_VENDOR_ID_AMD,
.device = 0x1604,
-}; \ No newline at end of file
+};
diff --git a/src/northbridge/amd/amdfam10/northbridge.c b/src/northbridge/amd/amdfam10/northbridge.c
index 116789ce11..0c1971bbc4 100644
--- a/src/northbridge/amd/amdfam10/northbridge.c
+++ b/src/northbridge/amd/amdfam10/northbridge.c
@@ -766,53 +766,49 @@ static void amdfam10_domain_read_resources(device_t dev)
uint8_t num_nodes;
/* Find highest DRAM range (DramLimitAddr) */
+ num_nodes = 0;
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++;
+ if ((!node_dev) || (pci_read_config32(node_dev, PCI_VENDOR_ID) == 0xffffffff))
+ continue;
+
+ num_nodes++;
+ for (range = 0; range < 8; range++) {
+ dword = pci_read_config32(get_node_pci(node, 1), 0x40 + (range * 0x8));
+ if (!(dword & 0x3))
+ continue;
+
+ if ((dword >> 8) & 0x7)
+ interleaved = 1;
+
+ dword = pci_read_config32(get_node_pci(node, 1), 0x44 + (range * 0x8));
+ dword2 = pci_read_config32(get_node_pci(node, 1), 0x144 + (range * 0x8));
+ qword = 0xffffff;
+ 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;
+ }
+ }
}
- /* Calculate CC6 sotrage area size */
+ /* Calculate CC6 storage 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);
+ reserved_ram_resource(dev, 8, (max_range_limit + 1) >> 10, qword >> 10);
}
}
}