aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/amd/quadcore
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineeringinc.com>2015-10-16 13:51:51 -0500
committerMartin Roth <martinroth@google.com>2015-11-02 23:45:19 +0100
commit730a043fb6cb4dd3cb5af8f8640365727b598648 (patch)
tree59afe45caca1a8e1682939c7e44e95344104533e /src/cpu/amd/quadcore
parentd150006c4a4584bc9933c2d8ff580a54c4f0cc2a (diff)
cpu/amd: Add initial AMD Family 15h support
TEST: Booted ASUS KGPE-D16 with single Opteron 6380 * Unbuffered DDR3 DIMMs tested and working * Suspend to RAM (S3) tested and working Change-Id: Idffd2ce36ce183fbfa087e5ba69a9148f084b45e Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> Reviewed-on: http://review.coreboot.org/11966 Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/cpu/amd/quadcore')
-rw-r--r--src/cpu/amd/quadcore/quadcore.c109
-rw-r--r--src/cpu/amd/quadcore/quadcore_id.c43
2 files changed, 127 insertions, 25 deletions
diff --git a/src/cpu/amd/quadcore/quadcore.c b/src/cpu/amd/quadcore/quadcore.c
index df778bd020..0f7c728105 100644
--- a/src/cpu/amd/quadcore/quadcore.c
+++ b/src/cpu/amd/quadcore/quadcore.c
@@ -2,6 +2,7 @@
* This file is part of the coreboot project.
*
* Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * 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
@@ -22,16 +23,41 @@
#include "cpu/amd/quadcore/quadcore_id.c"
+/* get_boot_apic_id and wait_cpu_state located in init_cpus.c */
+uint32_t get_boot_apic_id(uint8_t node, uint32_t core);
+uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2);
+
+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;
+}
+
static u32 get_core_num_in_bsp(u32 nodeid)
{
u32 dword;
- dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
- dword >>= 12;
- /* Bit 15 is CmpCap[2] since Revision D. */
- if ((cpuid_ecx(0x80000008) & 0xff) > 3)
- dword = ((dword & 8) >> 1) | (dword & 3);
- else
- dword &= 3;
+ if (is_fam15h()) {
+ /* Family 15h moved CmpCap to F5x84 [7:0] */
+ dword = pci_read_config32(NODE_PCI(nodeid, 5), 0x84);
+ dword &= 0xff;
+ } else {
+ dword = pci_read_config32(NODE_PCI(nodeid, 3), 0xe8);
+ dword >>= 12;
+ /* Bit 15 is CmpCap[2] since Revision D. */
+ if ((cpuid_ecx(0x80000008) & 0xff) > 3)
+ dword = ((dword & 8) >> 1) | (dword & 3);
+ else
+ dword &= 3;
+ }
return dword;
}
@@ -46,28 +72,68 @@ static u8 set_apicid_cpuid_lo(void)
return 1;
}
-static void real_start_other_core(u32 nodeid, u32 cores)
+static void real_start_other_core(uint32_t nodeid, uint32_t cores)
{
- u32 dword, i;
+ ssize_t i;
+ uint32_t dword;
printk(BIOS_DEBUG, "Start other core - nodeid: %02x cores: %02x\n", nodeid, cores);
/* set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4
accesses and error logging to core0 */
dword = pci_read_config32(NODE_PCI(nodeid, 3), 0x44);
- dword |= 1 << 27; // NbMcaToMstCpuEn bit
+ dword |= 1 << 30; /* SyncFloodOnDramAdrParErr=1 */
+ dword |= 1 << 27; /* NbMcaToMstCpuEn=1 */
+ dword |= 1 << 21; /* SyncFloodOnAnyUcErr=1 */
+ dword |= 1 << 20; /* SyncFloodOnWDT=1 */
+ dword |= 1 << 2; /* SyncFloodOnDramUcEcc=1 */
pci_write_config32(NODE_PCI(nodeid, 3), 0x44, dword);
- // set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
- dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
- dword |= 1 << 5;
- pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);
-
- if(cores > 1) {
- dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
- for (i = 0; i < cores - 1; i++) {
- dword |= 1 << i;
+ if (is_fam15h()) {
+ uint32_t core_activation_flags = 0;
+ uint32_t active_cores = 0;
+
+ /* Set PCI_DEV(0, 0x18+nodeid, 0), 0x1dc bits 7:1 to start cores */
+ dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x1dc);
+ for (i = 1; i < cores + 1; i++) {
+ core_activation_flags |= 1 << i;
+ }
+
+ /* Start the first core of each compute unit */
+ active_cores |= core_activation_flags & 0x55;
+ pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword | active_cores);
+
+ /* Each core shares a single set of MTRR registers with
+ * another core in the same compute unit, therefore, it
+ * is important that one core in each CU starts in advance
+ * of the other in order to avoid one core stomping all over
+ * the other core's settings.
+ */
+
+ /* Wait for the first core of each compute unit to start... */
+ uint32_t timeout;
+ for (i = 1; i < cores + 1; i++) {
+ if (!(i & 0x1)) {
+ uint32_t ap_apicid = get_boot_apic_id(nodeid, i);
+ timeout = wait_cpu_state(ap_apicid, F10_APSTATE_ASLEEP, F10_APSTATE_ASLEEP);
+ }
+ }
+
+ /* Start the second core of each compute unit */
+ active_cores |= core_activation_flags & 0xaa;
+ pci_write_config32(NODE_PCI(nodeid, 0), 0x1dc, dword | active_cores);
+ } else {
+ // set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
+ dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x68);
+ dword |= 1 << 5;
+ pci_write_config32(NODE_PCI(nodeid, 0), 0x68, dword);
+
+ if (cores > 1) {
+ dword = pci_read_config32(NODE_PCI(nodeid, 0), 0x168);
+ for (i = 0; i < cores - 1; i++) {
+ dword |= 1 << i;
+ }
+ pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
}
- pci_write_config32(NODE_PCI(nodeid, 0), 0x168, dword);
}
}
@@ -87,10 +153,9 @@ static void start_other_cores(void)
for (nodeid = 0; nodeid < nodes; nodeid++) {
u32 cores = get_core_num_in_bsp(nodeid);
- printk(BIOS_DEBUG, "init node: %02x cores: %02x \n", nodeid, cores);
+ printk(BIOS_DEBUG, "init node: %02x cores: %02x pass 1 \n", nodeid, cores);
if (cores > 0) {
real_start_other_core(nodeid, cores);
}
}
-
}
diff --git a/src/cpu/amd/quadcore/quadcore_id.c b/src/cpu/amd/quadcore/quadcore_id.c
index cd62a60a5b..acfdb4967a 100644
--- a/src/cpu/amd/quadcore/quadcore_id.c
+++ b/src/cpu/amd/quadcore/quadcore_id.c
@@ -39,9 +39,12 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
{
struct node_core_id id;
uint8_t apicid;
+ uint8_t fam15h = 0;
uint8_t rev_gte_d = 0;
uint8_t dual_node = 0;
uint32_t f3xe8;
+ uint32_t family;
+ uint32_t model;
#ifdef __PRE_RAM__
f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
@@ -49,7 +52,17 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
f3xe8 = pci_read_config32(get_node_pci(0, 3), 0xe8);
#endif
- if (cpuid_eax(0x80000001) >= 0x8)
+ family = model = cpuid_eax(0x80000001);
+ model = ((model & 0xf0000) >> 12) | ((model & 0xf0) >> 4);
+ family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
+
+ if (family >= 0x6f) {
+ /* Family 15h or later */
+ fam15h = 1;
+ nb_cfg_54 = 1;
+ }
+
+ if ((model >= 0x8) || fam15h)
/* Revision D or later */
rev_gte_d = 1;
@@ -63,7 +76,13 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
*/
apicid = (cpuid_ebx(1) >> 24) & 0xff;
if( nb_cfg_54) {
- if (rev_gte_d && dual_node) {
+ if (fam15h && dual_node) {
+ id.coreid = apicid & 0x1f;
+ id.nodeid = (apicid & 0x60) >> 5;
+ } else if (fam15h && !dual_node) {
+ id.coreid = apicid & 0xf;
+ id.nodeid = (apicid & 0x70) >> 4;
+ } else if (rev_gte_d && dual_node) {
id.coreid = apicid & 0xf;
id.nodeid = (apicid & 0x30) >> 4;
} else if (rev_gte_d && !dual_node) {
@@ -86,7 +105,25 @@ struct node_core_id get_node_core_id(u32 nb_cfg_54)
}
}
- if (rev_gte_d && dual_node) {
+ if (fam15h && dual_node) {
+ /* Coreboot expects each separate processor die to be on a different nodeid.
+ * Since the code above returns nodeid 0 even on internal node 1 some fixup is needed...
+ */
+ uint32_t f5x84;
+ uint8_t core_count;
+
+#ifdef __PRE_RAM__
+ f5x84 = pci_read_config32(NODE_PCI(0, 5), 0x84);
+#else
+ f5x84 = pci_read_config32(get_node_pci(0, 5), 0x84);
+#endif
+ core_count = (f5x84 & 0xff) + 1;
+ id.nodeid = id.nodeid * 2;
+ if (id.coreid >= core_count) {
+ id.nodeid += 1;
+ id.coreid = id.coreid - core_count;
+ }
+ } else if (rev_gte_d && dual_node) {
/* Coreboot expects each separate processor die to be on a different nodeid.
* Since the code above returns nodeid 0 even on internal node 1 some fixup is needed...
*/