diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-10-16 13:51:51 -0500 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2015-11-02 23:45:19 +0100 |
commit | 730a043fb6cb4dd3cb5af8f8640365727b598648 (patch) | |
tree | 59afe45caca1a8e1682939c7e44e95344104533e /src/cpu/amd/quadcore | |
parent | d150006c4a4584bc9933c2d8ff580a54c4f0cc2a (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.c | 109 | ||||
-rw-r--r-- | src/cpu/amd/quadcore/quadcore_id.c | 43 |
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... */ |