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 | |
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')
-rw-r--r-- | src/cpu/amd/car/cache_as_ram.inc | 130 | ||||
-rw-r--r-- | src/cpu/amd/car/disable_cache_as_ram.c | 89 | ||||
-rw-r--r-- | src/cpu/amd/car/post_cache_as_ram.c | 16 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/defaults.h | 266 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/fidvid.c | 237 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/init_cpus.c | 232 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/model_10xxx_init.c | 92 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/powernow_acpi.c | 50 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/processor_name.c | 194 | ||||
-rw-r--r-- | src/cpu/amd/family_10h-family_15h/update_microcode.c | 6 | ||||
-rw-r--r-- | src/cpu/amd/model_fxx/init_cpus.c | 2 | ||||
-rw-r--r-- | src/cpu/amd/quadcore/quadcore.c | 109 | ||||
-rw-r--r-- | src/cpu/amd/quadcore/quadcore_id.c | 43 |
13 files changed, 1090 insertions, 376 deletions
diff --git a/src/cpu/amd/car/cache_as_ram.inc b/src/cpu/amd/car/cache_as_ram.inc index 8fe91a0147..9874ec47a2 100644 --- a/src/cpu/amd/car/cache_as_ram.inc +++ b/src/cpu/amd/car/cache_as_ram.inc @@ -28,19 +28,24 @@ #define CacheSizeAPStack CONFIG_DCACHE_AP_STACK_SIZE #define MSR_MCFG_BASE 0xC0010058 -#define MSR_FAM10 0xC001102A +#define MSR_BU_CFG2 0xC001102A #define jmp_if_not_k8(x) comisd %xmm2, %xmm1; jae x #define jmp_if_k8(x) comisd %xmm2, %xmm1; jb x +#define jmp_if_not_fam15h(x) comisd %xmm3, %xmm1; jb x +#define jmp_if_fam15h(x) comisd %xmm3, %xmm1; jae x #define CPUID_MASK 0x0ff00f00 #define CPUID_VAL_FAM10_ROTATED 0x0f000010 +#define CPUID_VAL_FAM15_ROTATED 0x0f000060 /* * XMM map: * xmm1: CPU family * xmm2: Fam10h comparison value - * xmm3: Backup EBX + * xmm3: Fam15h comparison value + * xmm4: Backup EBX + * xmm5: Coreboot init detect */ /* Save the BIST result. */ @@ -60,7 +65,7 @@ cache_as_ram_setup: movl %eax, %cr4 /* Figure out the CPU family. */ - cvtsi2sd %ebx, %xmm3 + cvtsi2sd %ebx, %xmm4 movl $0x01, %eax cpuid /* Base family is bits 8..11, extended family is bits 20..27. */ @@ -70,13 +75,16 @@ cache_as_ram_setup: cvtsi2sd %eax, %xmm1 movl $CPUID_VAL_FAM10_ROTATED, %eax cvtsi2sd %eax, %xmm2 - cvtsd2si %xmm3, %ebx + movl $CPUID_VAL_FAM15_ROTATED, %eax + cvtsi2sd %eax, %xmm3 + cvtsd2si %xmm4, %ebx /* Check if cpu_init_detected. */ movl $MTRR_DEF_TYPE_MSR, %ecx rdmsr andl $MTRR_DEF_TYPE_EN, %eax movl %eax, %ebx /* We store the status. */ + cvtsi2sd %ebx, %xmm5 jmp_if_k8(CAR_FAM10_out_post_errata) @@ -117,21 +125,24 @@ cache_as_ram_setup: CAR_FAM10_out: + jmp_if_fam15h(CAR_FAM10_errata_applied) /* * Errata 193: Disable clean copybacks to L3 cache to allow cached ROM. * Re-enable it in after RAM is initialized and before CAR is disabled. */ - movl $MSR_FAM10, %ecx + movl $MSR_BU_CFG2, %ecx rdmsr - bts $15, %eax + bts $15, %eax /* Set bit 15 in EDX:EAX (bit 15 in EAX). */ wrmsr /* Erratum 343, RevGuide for Fam10h, Pub#41322 Rev. 3.33 */ - movl $MSR_FAM10, %ecx + movl $MSR_BU_CFG2, %ecx rdmsr bts $35-32, %edx /* Set bit 35 in EDX:EAX (bit 3 in EDX). */ wrmsr +CAR_FAM10_errata_applied: + #if CONFIG_MMCONF_SUPPORT #if (CONFIG_MMCONF_BASE_ADDRESS > 0xFFFFFFFF) #error "MMCONF_BASE_ADDRESS too big" @@ -166,6 +177,63 @@ CAR_FAM10_out: CAR_FAM10_out_post_errata: + /* Fam15h APIC IDs do not depend on NB config bit 54 */ + jmp_if_not_fam15h(skip_nb54_set) + movl $0xc001001f, %ecx /* NB_CFG_MSR */ + rdmsr + bts $(54 - 32), %edx /* Set NB config bit 54 */ + wrmsr + +skip_nb54_set: + /* On Fam15h CPUs each compute unit's MTRRs are shared between two cores */ + jmp_if_not_fam15h(skip_cu_check) + + /* Get the initial APIC ID. */ + movl $1, %eax + cpuid + movl %ebx, %eax + + /* Restore init detect */ + cvtsd2si %xmm5, %ebx + + /* Determine if this is the second core to start in a compute unit; if so, wait for first core start, clear init detect and skip MTRR init */ + bt $24, %eax + jnc skip_cu_check /* First core in the compute unit jumps to skip_cu_check */ + + /* Determine if this is the second core to start in a compute unit; if so, clear init detect and skip MTRR init */ + /* Busywait until the first core sets up the MTRRs */ +check_init_detect_1: + /* Check if cpu_init_detected. */ + movl $MTRR_DEF_TYPE_MSR, %ecx + rdmsr + andl $MTRR_DEF_TYPE_EN, %eax + cmp $0x00000000, %eax + je check_init_detect_1 /* First core has not yet started */ + +check_init_detect_2: + movl $SYSCFG_MSR, %ecx + rdmsr + andl $(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrVarDramEn), %eax + cmp $0x00000000, %eax + je check_init_detect_2 /* First core has not yet started */ + + /* First core has now started */ + movl $0x00000000, %ebx /* Clear init detect flag */ + cvtsi2sd %ebx, %xmm5 + jmp fam10_mtrr_setup_complete + +skip_cu_check: + + jmp_if_not_fam15h(CAR_FAM15_errata_applied) + + /* Erratum 714, RevGuide for Fam15h, Pub#48063 Rev. 3.24 */ + movl $MSR_BU_CFG2, %ecx + rdmsr + bts $8, %eax /* Set bit 8 in EDX:EAX (bit 8 in EAX). */ + wrmsr + +CAR_FAM15_errata_applied: + /* Set MtrrFixDramModEn for clear fixed MTRR. */ enable_fixed_mtrr_dram_modify: movl $SYSCFG_MSR, %ecx @@ -334,8 +402,42 @@ wbcache_post_fam10_setup: orl $(SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn), %eax wrmsr +fam10_mtrr_setup_complete: post_code(0xa1) + /* Disable conversion of INVD to WBINVD (INVDWBINVD = 0) */ + mov $0xc0010015, %ecx + rdmsr + btr $4, %eax + wrmsr + +jmp_if_not_fam15h(fam15_car_msr_setup_complete) + /* Disable streaming store (DisSS = 1) */ + mov $0xc0011020, %ecx + rdmsr + bts $28, %eax + wrmsr + + /* Disable speculative ITLB reloads (DisSpecTlbRld = 1) */ + mov $0xc0011021, %ecx + rdmsr + bts $9, %eax + wrmsr + + /* Disable speculative DTLB reloads (DisSpecTlbRld = 1) and set DisHwPf = 1 */ + mov $0xc0011022, %ecx + rdmsr + bts $4, %eax + bts $13, %eax + wrmsr + + /* Disable CR0 combining (CombineCr0Cd = 0) */ + mov $0xc001102b, %ecx + rdmsr + btr $49-32, %edx + wrmsr +fam15_car_msr_setup_complete: + /* Enable cache. */ movl %cr0, %eax andl $(~(CR0_CacheDisable | CR0_NoWriteThrough)), %eax @@ -416,9 +518,6 @@ CAR_FAM10_ap: * to reverse it. */ - /* Store our init detected. */ - movl %ebx, %esi - /* Get the coreid bits at first. */ movl $0x80000008, %eax cpuid @@ -437,6 +536,8 @@ CAR_FAM10_ap: movl %edi, %ecx /* CoreID bits */ bt $(54 - 32), %edx jc roll_cfg + + /* Fam10h NB config bit 54 was not set */ rolb %cl, %bl roll_cfg: @@ -446,8 +547,8 @@ roll_cfg: movl $(CacheBase + (CacheSize - (CacheSizeBSPStack + CacheSizeBSPSlush))), %esp subl %eax, %esp - /* Retrive init detected. */ - movl %esi, %ebx + /* Restore init detect */ + cvtsd2si %xmm5, %ebx post_code(0xa4) @@ -460,6 +561,8 @@ CAR_FAM10_ap_out: andl $~(3 << 9), %eax movl %eax, %cr4 + post_code(0xa6) + /* Restore the BIST result. */ movl %ebp, %eax @@ -467,6 +570,9 @@ CAR_FAM10_ap_out: movl %esp, %ebp pushl %ebx /* Init detected. */ pushl %eax /* BIST */ + + post_code(0xa7) + call cache_as_ram_main /* We will not go back. */ diff --git a/src/cpu/amd/car/disable_cache_as_ram.c b/src/cpu/amd/car/disable_cache_as_ram.c index ae295d33ee..e8d5af8047 100644 --- a/src/cpu/amd/car/disable_cache_as_ram.c +++ b/src/cpu/amd/car/disable_cache_as_ram.c @@ -15,46 +15,95 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * be warned, this file will be used other cores and core 0 / node 0 + * WARNING: this file will be used by both any AP cores and core 0 / node 0 */ #include <cpu/x86/cache.h> -static inline __attribute__((always_inline)) void disable_cache_as_ram(void) +static inline __attribute__((always_inline)) uint32_t amd_fam1x_cpu_family(void) +{ + uint32_t family; + + family = cpuid_eax(0x80000001); + family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8); + + return family; +} + +static inline __attribute__((always_inline)) void disable_cache_as_ram(uint8_t skip_sharedc_config) { msr_t msr; + uint32_t family; - /* disable cache */ - write_cr0(read_cr0() | CR0_CacheDisable); + if (!skip_sharedc_config) { + /* disable cache */ + write_cr0(read_cr0() | CR0_CacheDisable); - msr.lo = 0; - msr.hi = 0; - wrmsr(MTRR_FIX_4K_C8000, msr); + msr.lo = 0; + msr.hi = 0; + wrmsr(MTRR_FIX_4K_C8000, msr); #if CONFIG_DCACHE_RAM_SIZE > 0x8000 - wrmsr(MTRR_FIX_4K_C0000, msr); + wrmsr(MTRR_FIX_4K_C0000, msr); #endif #if CONFIG_DCACHE_RAM_SIZE > 0x10000 - wrmsr(MTRR_FIX_4K_D0000, msr); + wrmsr(MTRR_FIX_4K_D0000, msr); #endif #if CONFIG_DCACHE_RAM_SIZE > 0x18000 - wrmsr(MTRR_FIX_4K_D8000, msr); + wrmsr(MTRR_FIX_4K_D8000, msr); #endif - /* disable fixed mtrr from now on, it will be enabled by ramstage again*/ + /* disable fixed mtrr from now on, it will be enabled by ramstage again */ + msr = rdmsr(SYSCFG_MSR); + msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrFixDramModEn); + wrmsr(SYSCFG_MSR, msr); + + /* Set the default memory type and disable fixed and enable variable MTRRs */ + msr.hi = 0; + msr.lo = (1 << 11); - msr = rdmsr(SYSCFG_MSR); - msr.lo &= ~(SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_MtrrFixDramModEn); - wrmsr(SYSCFG_MSR, msr); + wrmsr(MTRR_DEF_TYPE_MSR, msr); - /* Set the default memory type and disable fixed and enable variable MTRRs */ - msr.hi = 0; - msr.lo = (1 << 11); + enable_cache(); + } - wrmsr(MTRR_DEF_TYPE_MSR, msr); + /* INVDWBINVD = 1 */ + msr = rdmsr(0xc0010015); + msr.lo |= (0x1 << 4); + wrmsr(0xc0010015, msr); - enable_cache(); + family = amd_fam1x_cpu_family(); + +#if IS_ENABLED(CPU_AMD_MODEL_10XXX) + if (family >= 0x6f) { + /* Family 15h or later */ + + /* DisSS = 0 */ + msr = rdmsr(0xc0011020); + msr.lo &= ~(0x1 << 28); + wrmsr(0xc0011020, msr); + + if (!skip_sharedc_config) { + /* DisSpecTlbRld = 0 */ + msr = rdmsr(0xc0011021); + msr.lo &= ~(0x1 << 9); + wrmsr(0xc0011021, msr); + + /* Erratum 714: SpecNbReqDis = 0 */ + msr = rdmsr(BU_CFG2_MSR); + msr.lo &= ~(0x1 << 8); + wrmsr(BU_CFG2_MSR, msr); + } + + /* DisSpecTlbRld = 0 */ + /* DisHwPf = 0 */ + msr = rdmsr(0xc0011022); + msr.lo &= ~(0x1 << 4); + msr.lo &= ~(0x1 << 13); + wrmsr(0xc0011022, msr); + } +#endif } static void disable_cache_as_ram_bsp(void) { - disable_cache_as_ram(); + disable_cache_as_ram(0); } diff --git a/src/cpu/amd/car/post_cache_as_ram.c b/src/cpu/amd/car/post_cache_as_ram.c index 61d47a2ed9..49b9ee3fe3 100644 --- a/src/cpu/amd/car/post_cache_as_ram.c +++ b/src/cpu/amd/car/post_cache_as_ram.c @@ -84,18 +84,19 @@ static void prepare_ramstage_region(void *resume_backup_memory) static void vErrata343(void) { #ifdef BU_CFG2_MSR - msr_t msr; - unsigned int uiMask = 0xFFFFFFF7; + msr_t msr; + unsigned int uiMask = 0xFFFFFFF7; - msr = rdmsr(BU_CFG2_MSR); - msr.hi &= uiMask; // set bit 35 to 0 - wrmsr(BU_CFG2_MSR, msr); + msr = rdmsr(BU_CFG2_MSR); + msr.hi &= uiMask; // IcDisSpecTlbWr (bit 35) = 0 + wrmsr(BU_CFG2_MSR, msr); #endif } void post_cache_as_ram(void) { void *resume_backup_memory = NULL; + uint32_t family = amd_fam1x_cpu_family(); struct romstage_handoff *handoff; handoff = romstage_handoff_find_or_add(); @@ -112,7 +113,10 @@ void post_cache_as_ram(void) prepare_romstage_ramstack(resume_backup_memory); /* from here don't store more data in CAR */ - vErrata343(); + if (family < 0x6f) { + /* Family 10h or earlier */ + vErrata343(); + } size_t car_size = car_data_size(); void *migrated_car = (void *)(CONFIG_RAMTOP - car_size); diff --git a/src/cpu/amd/family_10h-family_15h/defaults.h b/src/cpu/amd/family_10h-family_15h/defaults.h index c4cf182764..94468c5ae2 100644 --- a/src/cpu/amd/family_10h-family_15h/defaults.h +++ b/src/cpu/amd/family_10h-family_15h/defaults.h @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright (C) 2008 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 @@ -21,41 +22,65 @@ */ static const struct { u32 msr; - u32 revision; + uint64_t revision; u32 platform; u32 data_lo; u32 data_hi; u32 mask_lo; u32 mask_hi; } fam10_msr_default[] = { - { TOP_MEM2, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { TOP_MEM2, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF }, - { SYSCFG, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { SYSCFG, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 3 << 21, 0x00000000, 3 << 21, 0x00000000 }, /* [MtrrTom2En]=1,[TOM2EnWB] = 1*/ - { HWCR, AMD_FAM10_ALL, AMD_PTYPE_ALL, - 1 << 4, 0x00000000, - 1 << 4, 0x00000000 }, /* [INVD_WBINVD]=1 */ + { MC1_CTL_MASK, AMD_OR_B2, AMD_PTYPE_ALL, + 1 << 18, 0x00000000, + 1 << 18, 0x00000000 }, /* Erratum 586: [DEIBP]=1 */ - { MC4_CTL_MASK, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { MC1_CTL_MASK, AMD_OR_B2, AMD_PTYPE_ALL, + 1 << 15, 0x00000000, + 1 << 15, 0x00000000 }, /* Erratum 593: [BSRP]=1 */ + + { MC1_CTL_MASK, AMD_OR_C0, AMD_PTYPE_ALL, + 1 << 15, 0x00000000, + 1 << 15, 0x00000000 }, /* Erratum 739: [BSRP]=1 */ + + { 0xc0011000, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 1 << 16, 0x00000000, + 1 << 16, 0x00000000 }, /* Erratum 608: [bit 16]=1 */ + + { 0xc0011000, AMD_OR_C0, AMD_PTYPE_ALL, + 1 << 15, 0x00000000, + 1 << 15, 0x00000000 }, /* Erratum 727: [bit 15]=1 */ + + { MC4_CTL_MASK, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0xF << 19, 0x00000000, 0xF << 19, 0x00000000 }, /* [RtryHt[0..3]]=1 */ + { MC4_CTL_MASK, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, + 1 << 10, 0x00000000, + 1 << 10, 0x00000000 }, /* [GartTblWkEn]=1 */ + { DC_CFG, AMD_FAM10_ALL, AMD_PTYPE_SVR, 0x00000000, 0x00000004, - 0x00000000, 0x0000000C }, /* [REQ_CTR] = 1 for Server */ + 0x00000000, 0x0000000C }, /* Family 10h: [REQ_CTR] = 1 for Server */ { DC_CFG, AMD_DR_Bx, AMD_PTYPE_SVR, 0x00000000, 0x00000000, 0x00000000, 0x00000C00 }, /* Erratum 326 */ - { NB_CFG, AMD_FAM10_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC, + { NB_CFG, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC | AMD_PTYPE_MC, 0x00000000, 1 << 22, 0x00000000, 1 << 22 }, /* [ApicInitIDLo]=1 */ + { NB_CFG, AMD_FAM15_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC, + 1 << 23, 0x00000000, + 1 << 23, 0x00000000 }, /* Erratum 663: [bit 23]=1 */ + { BU_CFG2, AMD_DR_Bx, AMD_PTYPE_ALL, 1 << 29, 0x00000000, 1 << 29, 0x00000000 }, /* For Bx Smash1GPages=1 */ @@ -68,6 +93,14 @@ static const struct { 0 << 1, 0x00000000, 1 << 1, 0x00000000 }, /* IDX_MATCH_ALL=0 */ + { IC_CFG, AMD_OR_C0, AMD_PTYPE_ALL, + 0x00000000, 1 << (39-32), + 0x00000000, 1 << (39-32)}, /* C0 or above [DisLoopPredictor]=1 */ + + { IC_CFG, AMD_OR_C0, AMD_PTYPE_ALL, + 0xf << 1, 0x00000000, + 0xf << 1, 0x00000000}, /* C0 or above [DisIcWayFilter]=0xf */ + { BU_CFG, AMD_DR_LT_B3, AMD_PTYPE_ALL, 1 << 21, 0x00000000, 1 << 21, 0x00000000 }, /* Erratum #254 DR B1 BU_CFG[21]=1 */ @@ -76,19 +109,51 @@ static const struct { 1 << 23, 0x00000000, 1 << 23, 0x00000000 }, /* Erratum #309 BU_CFG[23]=1 */ + { BU_CFG, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0 << 10, 0x00000000, + 1 << 10, 0x00000000 }, /* [DcacheAgressivePriority]=0 */ + /* CPUID_EXT_FEATURES */ - { CPUIDFEATURES, AMD_FAM10_ALL, AMD_PTYPE_DC | AMD_PTYPE_MC, + { CPUIDFEATURES, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC | AMD_PTYPE_MC, 1 << 28, 0x00000000, 1 << 28, 0x00000000 }, /* [HyperThreadFeatEn]=1 */ - { CPUIDFEATURES, AMD_FAM10_ALL, AMD_PTYPE_DC, + { CPUIDFEATURES, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_DC, 0x00000000, 1 << (33-32), 0x00000000, 1 << (33-32) }, /* [ExtendedFeatEn]=1 */ + { DE_CFG, AMD_OR_B2, AMD_PTYPE_ALL, + 1 << 10, 0x00000000, + 1 << 10, 0x00000000 }, /* Bx [ResyncPredSingleDispDis]=1 */ + { BU_CFG2, AMD_DRBH_Cx, AMD_PTYPE_ALL, 0x00000000, 1 << (35-32), 0x00000000, 1 << (35-32) }, /* Erratum 343 (set to 0 after CAR, in post_cache_as_ram()/model_10xxx_init() ) */ + { BU_CFG3, AMD_OR_B2, AMD_PTYPE_ALL, + 0x00000000, 1 << (42-32), + 0x00000000, 1 << (42-32)}, /* Bx [PwcDisableWalkerSharing]=1 */ + + { BU_CFG3, AMD_OR_C0, AMD_PTYPE_ALL, + 1 << 22, 0x00000000, + 1 << 22, 0x00000000}, /* C0 or above [PfcDoubleStride]=1 */ + + { EX_CFG, AMD_OR_C0, AMD_PTYPE_ALL, + 0x00000000, 1 << (54-32), + 0x00000000, 1 << (54-32)}, /* C0 or above [LateSbzResync]=1 */ + + { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL, + 1 << 23, 0x00000000, + 1 << 23, 0x00000000}, /* C0 or above [DisScbThreshold]=1 */ + + { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL, + 1 << 14, 0x00000000, + 1 << 14, 0x00000000}, /* C0 or above [ForceSmcCheckFlowStDis]=1 */ + + { LS_CFG2, AMD_OR_C0, AMD_PTYPE_ALL, + 1 << 12, 0x00000000, + 1 << 12, 0x00000000}, /* C0 or above [ForceBusLockDis]=1 */ + { OSVW_ID_Length, AMD_DR_Bx | AMD_DR_Cx | AMD_DR_Dx, AMD_PTYPE_ALL, 0x00000004, 0x00000000, 0x00000004, 0x00000000}, /* B0 or Above, OSVW_ID_Length is 0004h */ @@ -101,9 +166,45 @@ static const struct { 0x00000000, 1 << (50-32), 0x00000000, 1 << (50-32)}, /* D0 or Above, RdMmExtCfgQwEn*/ + { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000000, 0x0 << (36-32), + 0x00000000, 0x3 << (36-32)}, /* [ThrottleNbInterface]=0 */ + + { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 1 << 10, 0x00000000, + 1 << 10, 0x00000000}, /* [VicResyncChkEn]=1 */ + + { BU_CFG2, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 1 << 11, 0x00000000, + 1 << 11, 0x00000000}, /* Erratum 503: [bit 11]=1 */ + { CPU_ID_EXT_FEATURES_MSR, AMD_DR_Dx, AMD_PTYPE_ALL, 0x00000000, 1 << (51 - 32), 0x00000000, 1 << (51 - 32)}, /* G34_PKG | C32_PKG | S1G4_PKG | ASB2_PKG */ + + { CPU_ID_EXT_FEATURES_MSR, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000000, 1 << (56 - 32), + 0x00000000, 1 << (56 - 32)}, /* [PerfCtrExtNB]=1 */ + + { CPU_ID_EXT_FEATURES_MSR, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000000, 1 << (55 - 32), + 0x00000000, 1 << (55 - 32)}, /* [PerfCtrExtCore]=1 */ + + { IBS_OP_DATA3, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0 << 16, 0x00000000, + 1 << 16, 0x00000000}, /* [IbsDcMabHit]=0 */ + + { MC4_MISC0, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000000, 0x1 << (52-32), + 0x00000000, 0xf << (52-32)}, /* [LvtOffset]=1 */ + + { MC4_MISC1, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000000, 0x1 << (52-32), + 0x00000000, 0xf << (52-32)}, /* [LvtOffset]=1 */ + + { MC4_MISC2, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000000, 0x1 << (52-32), + 0x00000000, 0xf << (52-32)}, /* [LvtOffset]=1 */ }; @@ -113,37 +214,46 @@ static const struct { static const struct { u8 function; u16 offset; - u32 revision; + uint64_t revision; u32 platform; u32 data; u32 mask; } fam10_pci_default[] = { /* Function 0 - HT Config */ + { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, + 0x000e0000, 0x000e0000 }, /* [19:17] for 8bit APIC config */ + + { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, + 0x00400000, 0x00600000 }, /* [22:21] DsNpReqLmt = 10b */ - { 0, 0x68, AMD_FAM10_ALL, AMD_PTYPE_ALL, - 0x004E4800, 0x006E6800 }, /* [19:17] for 8bit APIC config, - [14:13] BufPriRel = 2h [11] RspPassPW set, - [22:21] DsNpReqLmt = 10b */ + { 0, 0x68, AMD_FAM10_LT_D, AMD_PTYPE_ALL, + 0x00004000, 0x00006000 }, /* [14:13] BufRelPri = 2h */ + + { 0, 0x68, (AMD_FAM10_REV_D | AMD_FAM15_ALL), AMD_PTYPE_ALL, + 0x00002000, 0x00006000 }, /* [14:13] BufRelPri = 1h */ + + { 0, 0x68, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, + 0x00000800, 0x00000800 }, /* [11] RspPassPW = 1 */ /* Errata 281 Workaround */ { 0, 0x68, (AMD_DR_B0 | AMD_DR_B1), AMD_PTYPE_SVR, 0x00200000, 0x00600000 }, /* [22:21] DsNpReqLmt0 = 01b */ - { 0, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 0, 0x84, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00002000, 0x00002000 }, /* [13] LdtStopTriEn = 1 */ - { 0, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 0, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00002000, 0x00002000 }, /* [13] LdtStopTriEn = 1 */ - { 0, 0xC4, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 0, 0xC4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00002000, 0x00002000 }, /* [13] LdtStopTriEn = 1 */ - { 0, 0xE4, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 0, 0xE4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00002000, 0x00002000 }, /* [13] LdtStopTriEn = 1 */ /* Link Global Retry Control Register */ - { 0, 0x150, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 0, 0x150, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00073900, 0x00073F00 }, /* Errata 351 @@ -168,13 +278,39 @@ static const struct { 0x00000000, 0x00000100 }, { 0, 0x18C, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0x00000000, 0x00000100 }, - { 0, 0x170, AMD_FAM10_ALL, AMD_PTYPE_ALL, - 0x00000000, 0x00000100 }, /* Link Global Extended Control Register */ { 0, 0x16C, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0x00000014, 0x0000003F }, /* [15:13] ForceFullT0 = 0b, - * Set T0Time 14h per BKDG */ + * Set T0Time 14h per BKDG */ + + { 0, 0x170, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + { 0, 0x174, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + { 0, 0x178, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + { 0, 0x17C, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + { 0, 0x180, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + { 0, 0x184, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + { 0, 0x188, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + { 0, 0x18C, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000100, 0x00000100 }, + + /* Link Global Extended Control Register */ + { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000014, 0x0000003F }, /* [15:13] ForceFullT0 = 111b, + * Set T0Time 26h per BKDG */ + + { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x7 << 13, 0x7 << 13 }, /* [15:13] ForceFullT0 = 7h */ + + { 0, 0x16C, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x26, 0x3f }, /* [5:0] T0Time = 26h */ /* Function 1 - Map Init */ @@ -201,10 +337,10 @@ static const struct { /* Function 2 - DRAM Controller */ /* Function 3 - Misc. Control */ - { 3, 0x40, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0x40, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00000100, 0x00000100 }, /* [8] MstrAbrtEn */ - { 3, 0x44, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0x44, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x4A30005C, 0x4A30005C }, /* [30] SyncOnDramAdrParErrEn = 1, [27] NbMcaToMstCpuEn = 1, [25] DisPciCfgCpuErrRsp = 1, @@ -216,8 +352,12 @@ static const struct { [2] SyncOnUcEccEn = 1 */ /* XBAR buffer settings */ - { 3, 0x6C, AMD_FAM10_ALL, AMD_PTYPE_ALL, - 0x00018052, 0x700780F7 }, + { 3, 0x6c, AMD_FAM10_ALL, AMD_PTYPE_ALL, + 0x00018052, 0x700780f7 }, + + /* XBAR buffer settings */ + { 3, 0x6c, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x10010052, 0x700700f7 }, /* Errata 281 Workaround */ { 3, 0x6C, ( AMD_DR_B0 | AMD_DR_B1), @@ -229,12 +369,18 @@ static const struct { { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0x00041153, 0x777777F7 }, + { 3, 0x70, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x10171155, 0x777777f7 }, + { 3, 0x70, AMD_FAM10_ALL, AMD_PTYPE_UMA, 0x61221151, 0x777777F7 }, { 3, 0x74, AMD_FAM10_ALL, AMD_PTYPE_UMA, 0x00080101, 0x000F7777 }, + { 3, 0x74, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00172111, 0x77ff7777 }, + { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0x00090914, 0x707FFF1F }, @@ -242,12 +388,18 @@ static const struct { { 3, 0x7C, ( AMD_DR_B0 | AMD_DR_B1), AMD_PTYPE_SVR, 0x00144514, 0x707FFF1F }, + { 3, 0x7C, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x040d0f16, 0x07ffff1f }, + { 3, 0x7C, AMD_FAM10_ALL, AMD_PTYPE_UMA, 0x00070814, 0x007FFF1F }, { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0x00800756, 0x00F3FFFF }, + { 3, 0x140, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00a11755, 0x00f3ffff }, + { 3, 0x140, AMD_FAM10_ALL, AMD_PTYPE_UMA, 0x00C37756, 0x00F3FFFF }, @@ -259,6 +411,9 @@ static const struct { AMD_PTYPE_SVR, 0x00000001, 0x0000000F }, /* [3:0] RspTok = 0001b */ + { 3, 0x144, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x00000028, 0x000000ff }, + { 3, 0x148, AMD_FAM10_ALL, AMD_PTYPE_UMA, 0x8000052A, 0xD5FFFFFF }, @@ -266,41 +421,53 @@ static const struct { { 3, 0x80, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0xE6002200, 0xFFFFFFFF }, + /* ACPI Power State Control Reg1 */ + { 3, 0x80, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0xe20be200, 0xefefef00 }, + /* ACPI Power State Control Reg2 */ { 3, 0x84, AMD_FAM10_ALL, AMD_PTYPE_ALL, 0xA0E641E6, 0xFFFFFFFF }, + /* ACPI Power State Control Reg2 */ + { 3, 0x84, AMD_FAM15_ALL, AMD_PTYPE_ALL, + 0x01e200e2, 0xefef00ef }, + { 3, 0xA0, AMD_FAM10_ALL, AMD_PTYPE_MOB | AMD_PTYPE_DSK, 0x00000080, 0x00000080 }, /* [7] PSIVidEnable */ { 3, 0xA0, AMD_DR_Bx, AMD_PTYPE_ALL, 0x00002800, 0x000003800 }, /* [13:11] PllLockTime = 5 */ - { 3, 0xA0, (AMD_FAM10_ALL & ~(AMD_DR_Bx)), AMD_PTYPE_ALL, + { 3, 0xA0, ((AMD_FAM10_ALL | AMD_FAM15_ALL) & ~(AMD_DR_Bx)), AMD_PTYPE_ALL, 0x00000800, 0x000003800 }, /* [13:11] PllLockTime = 1 */ /* Reported Temp Control Register */ - { 3, 0xA4, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0xA4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00000080, 0x00000080 }, /* [7] TempSlewDnEn = 1 */ /* Clock Power/Timing Control 0 Register */ - { 3, 0xD4, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0xD4, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0xC0000F00, 0xF0000F00 }, /* [31] NbClkDivApplyAll = 1, [30:28] NbClkDiv = 100b,[11:8] ClkRampHystSel = 1111b */ /* Clock Power/Timing Control 1 Register */ + { 3, 0xD8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, + 0x03000010, 0x0F000070 }, /* [6:4] VSRampTime = 1, + * [27:24] ReConDel = 3 */ + + /* Clock Power/Timing Control 1 Register */ { 3, 0xD8, AMD_FAM10_ALL, AMD_PTYPE_ALL, - 0x03000016, 0x0F000077 }, /* [6:4] VSRampTime = 1, - [2:0] VSSlamTime = 6, [27:24] ReConDel = 3 */ + 0x00000006, 0x00000007 }, /* [2:0] VSSlamTime = 6 */ /* Clock Power/Timing Control 2 Register */ - { 3, 0xDC, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0xDC, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00005000, 0x00007000 }, /* [14:12] NbsynPtrAdj = 5 */ /* Extended NB MCA Config Register */ - { 3, 0x180, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0x180, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x007003E2, 0x007003E2 }, /* [22:20] = SyncFloodOn_Err = 7, [9] SyncOnUncNbAryEn = 1 , [8] SyncOnProtEn = 1, @@ -315,12 +482,17 @@ static const struct { 0x00400000, 0x00400000 }, /* L3 Control Register */ - { 3, 0x1B8, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0x1b8, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00001000, 0x00001000 }, /* [12] = L3PrivReplEn */ /* IBS Control Register */ - { 3, 0x1CC, AMD_FAM10_ALL, AMD_PTYPE_ALL, + { 3, 0x1cc, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, 0x00000100, 0x00000100 }, /* [8] = LvtOffsetVal */ + + /* Erratum 619 - Family 15h Bx + * System software should set F5x88[14] to 1b. */ + { 5, 0x88, AMD_OR_B2, AMD_PTYPE_ALL, + 1 << 14, 1 << 14 }, }; @@ -329,7 +501,7 @@ static const struct { */ static const struct { u16 htreg; /* HT Phy Register index */ - u32 revision; + uint64_t revision; u32 platform; u32 linktype; u32 data; @@ -438,38 +610,38 @@ static const struct { { 0x530A, AMD_DR_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL, 0x00004400, 0x00006400 }, /* HT_PHY_DLL_REG */ - { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, + { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, 0x00000000, 0x000000FF }, /* Provide clear setting for logical completeness */ - { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, + { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, 0x00000000, 0x000000FF }, /* Provide clear setting for logical completeness */ - { 0xCF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, + { 0xCF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, 0x0000006D, 0x000000FF }, /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */ - { 0xDF, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, + { 0xDF, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, 0x0000006D, 0x000000FF }, /* HT_PHY_HT1_FIFO_PTR_OPT_VALUE */ /* Link Phy Receiver Loop Filter Registers */ - { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, + { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, 0x08040000, 0x3FFFC000 }, /* [29:22] LfcMax = 20h, [21:14] LfcMin = 10h */ - { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, + { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT3, 0x08040000, 0x3FFFC000 }, /* [29:22] LfcMax = 20h, [21:14] LfcMin = 10h */ - { 0xD1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, + { 0xD1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, 0x04020000, 0x3FFFC000 }, /* [29:22] LfcMax = 10h, [21:14] LfcMin = 08h */ - { 0xC1, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, + { 0xC1, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_HT1, 0x04020000, 0x3FFFC000 }, /* [29:22] LfcMax = 10h, [21:14] LfcMin = 08h */ - { 0xC0, AMD_FAM10_ALL, AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL, + { 0xC0, (AMD_FAM10_ALL | AMD_FAM15_ALL), AMD_PTYPE_ALL, HTPHY_LINKTYPE_ALL, 0x40040000, 0xe01F0000 }, /* [31:29] RttCtl = 02h, [20:16] RttIndex = 04h */ }; diff --git a/src/cpu/amd/family_10h-family_15h/fidvid.c b/src/cpu/amd/family_10h-family_15h/fidvid.c index 3fac165f52..5eb7980514 100644 --- a/src/cpu/amd/family_10h-family_15h/fidvid.c +++ b/src/cpu/amd/family_10h-family_15h/fidvid.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 @@ -39,7 +40,7 @@ Fam10 Bios and Kernel Development Guide #31116, rev 3.48, April 22, 2010 3.- 2.4.2.7 dualPlaneOnly(dev) -4.- 2.4.2.8 applyBoostFIDOffset(dev) +4.- 2.4.2.8 applyBoostFIDOffset(dev, nodeid) 5.- enableNbPState1(dev) @@ -138,25 +139,33 @@ static void enable_fid_change(u8 fid) } } -static void applyBoostFIDOffset( device_t dev ) { - // BKDG 2.4.2.8 - // revision E only, but E is apparently not supported yet, therefore untested - if ((cpuid_edx(0x80000007) & CPB_MASK) - && ((cpuid_ecx(0x80000008) & NC_MASK) ==5) ) { - u32 core = get_node_core_id_x().coreid; - u32 asymetricBoostThisCore = ((pci_read_config32(dev, 0x10C) >> (core*2))) & 3; - msr_t msr = rdmsr(PS_REG_BASE); - u32 cpuFid = msr.lo & PS_CPU_FID_MASK; - cpuFid = cpuFid + asymetricBoostThisCore; - msr.lo &= ~PS_CPU_FID_MASK; - msr.lo |= cpuFid ; - wrmsr(PS_REG_BASE , msr); - - } +static void applyBoostFIDOffset(device_t dev, uint32_t nodeid) { + // BKDG 2.4.2.8 + // Fam10h revision E only, but E is apparently not supported yet, therefore untested + if ((cpuid_edx(0x80000007) & CPB_MASK) + && ((cpuid_ecx(0x80000008) & NC_MASK) == 5) ) { + u32 core = get_node_core_id_x().coreid; + u32 asymetricBoostThisCore = ((pci_read_config32(dev, 0x10C) >> (core*2))) & 3; + msr_t msr = rdmsr(PS_REG_BASE); + u32 cpuFid = msr.lo & PS_CPU_FID_MASK; + cpuFid = cpuFid + asymetricBoostThisCore; + msr.lo &= ~PS_CPU_FID_MASK; + msr.lo |= cpuFid ; + wrmsr(PS_REG_BASE , msr); + } else if (is_fam15h()) { + uint32_t dword = pci_read_config32(NODE_PCI(nodeid, 4), 0x15c); + uint8_t boost_count = (dword >> 2) & 0x7; + if (boost_count > 0) { + /* Enable boost */ + dword &= ~0x3; + dword |= 0x1; + pci_write_config32(NODE_PCI(nodeid, 4), 0x15c, dword); + } + } } static void enableNbPState1( device_t dev ) { - u32 cpuRev = mctGetLogicalCPUID(0xFF); + uint64_t cpuRev = mctGetLogicalCPUID(0xFF); if (cpuRev & AMD_FAM10_C3) { u32 nbPState = (pci_read_config32(dev, 0x1F0) & NB_PSTATE_MASK); if ( nbPState){ @@ -198,7 +207,7 @@ static u8 setPStateMaxVal( device_t dev ) { static void dualPlaneOnly( device_t dev ) { // BKDG 2.4.2.7 - u32 cpuRev = mctGetLogicalCPUID(0xFF); + uint64_t cpuRev = mctGetLogicalCPUID(0xFF); if ((mctGetProcessorPackageType() == AMD_PKGTYPE_AM3_2r2) && (cpuRev & AMD_DR_Cx)) { // should be rev C or rev E but there's no constant for E if ( (pci_read_config32(dev, 0x1FC) & DUAL_PLANE_ONLY_MASK) @@ -278,12 +287,16 @@ static void recalculateVsSlamTimeSettingOnCorePre(device_t dev) */ /* Determine if this is a PVI or SVI system */ - dtemp = pci_read_config32(dev, 0xA0); - - if (dtemp & PVI_MODE) - pviModeFlag = 1; - else + if (is_fam15h()) { pviModeFlag = 0; + } else { + dtemp = pci_read_config32(dev, 0xa0); + + if (dtemp & PVI_MODE) + pviModeFlag = 1; + else + pviModeFlag = 0; + } /* Get P0's voltage */ /* MSRC001_00[68:64] are not programmed yet when called from @@ -510,59 +523,67 @@ static void config_nb_syn_ptr_adj(device_t dev, u32 cpuRev) { } static void config_acpi_pwr_state_ctrl_regs(device_t dev, u32 cpuRev, u8 procPkg) { - /* step 1, chapter 2.4.2.6 of AMD Fam 10 BKDG #31116 Rev 3.48 22.4.2010 */ - u32 dword; - u32 c1= 1; - if (cpuRev & (AMD_DR_Bx)) { - // will coreboot ever enable cache scrubbing ? - // if it does, will it be enough to check the current state - // or should we configure for what we'll set up later ? - dword = pci_read_config32(dev, 0x58); - u32 scrubbingCache = dword & - ( (0x1F << 16) // DCacheScrub - | (0x1F << 8) ); // L2Scrub - if (scrubbingCache) { - c1 = 0x80; - } else { - c1 = 0xA0; - } - } else { // rev C or later - // same doubt as cache scrubbing: ok to check current state ? - dword = pci_read_config32(dev, 0xDC); - u32 cacheFlushOnHalt = dword & (7 << 16); - if (!cacheFlushOnHalt) { - c1 = 0x80; - } - } - dword = (c1 << 24) | (0xE641E6); - pci_write_config32(dev, 0x84, dword); - - - /* FIXME: BKDG Table 100 says if the link is at a Gen1 -frequency and the chipset does not support a 10us minimum LDTSTOP -assertion time, then { If ASB2 && SVI then smaf001 = F6h else -smaf001=87h. } else ... I hardly know what it means or how to check -it from here, so I bluntly assume it is false and code here the else, -which is easier */ - - u32 smaf001 = 0xE6; - if (cpuRev & AMD_DR_Bx ) { - smaf001 = 0xA6; - } else { - #if CONFIG_SVI_HIGH_FREQ - if (cpuRev & (AMD_RB_C3 | AMD_DA_C3)) { - smaf001 = 0xF6; - } - #endif - } - u32 fidvidChange = 0; - if (((cpuRev & AMD_DA_Cx) && (procPkg & AMD_PKGTYPE_S1gX)) - || (cpuRev & AMD_RB_C3) ) { - fidvidChange=0x0B; - } - dword = (0xE6 << 24) | (fidvidChange << 16) - | (smaf001 << 8) | 0x81; - pci_write_config32(dev, 0x80, dword); + if (is_fam15h()) { + /* Family 15h BKDG Rev. 3.14 D18F3x80 recommended settings */ + pci_write_config32(dev, 0x80, 0xe20be281); + + /* Family 15h BKDG Rev. 3.14 D18F3x84 recommended settings */ + pci_write_config32(dev, 0x84, 0x01e200e2); + } else { + /* step 1, chapter 2.4.2.6 of AMD Fam 10 BKDG #31116 Rev 3.48 22.4.2010 */ + u32 dword; + u32 c1= 1; + if (cpuRev & (AMD_DR_Bx)) { + // will coreboot ever enable cache scrubbing ? + // if it does, will it be enough to check the current state + // or should we configure for what we'll set up later ? + dword = pci_read_config32(dev, 0x58); + u32 scrubbingCache = dword & + ( (0x1F << 16) // DCacheScrub + | (0x1F << 8) ); // L2Scrub + if (scrubbingCache) { + c1 = 0x80; + } else { + c1 = 0xA0; + } + } else { // rev C or later + // same doubt as cache scrubbing: ok to check current state ? + dword = pci_read_config32(dev, 0xDC); + u32 cacheFlushOnHalt = dword & (7 << 16); + if (!cacheFlushOnHalt) { + c1 = 0x80; + } + } + dword = (c1 << 24) | (0xE641E6); + pci_write_config32(dev, 0x84, dword); + + /* FIXME: BKDG Table 100 says if the link is at a Gen1 + * frequency and the chipset does not support a 10us minimum LDTSTOP + * assertion time, then { If ASB2 && SVI then smaf001 = F6h else + * smaf001=87h. } else ... I hardly know what it means or how to check + * it from here, so I bluntly assume it is false and code here the else, + * which is easier + */ + + u32 smaf001 = 0xE6; + if (cpuRev & AMD_DR_Bx ) { + smaf001 = 0xA6; + } else { + #if CONFIG_SVI_HIGH_FREQ + if (cpuRev & (AMD_RB_C3 | AMD_DA_C3)) { + smaf001 = 0xF6; + } + #endif + } + u32 fidvidChange = 0; + if (((cpuRev & AMD_DA_Cx) && (procPkg & AMD_PKGTYPE_S1gX)) + || (cpuRev & AMD_RB_C3) ) { + fidvidChange=0x0B; + } + dword = (0xE6 << 24) | (fidvidChange << 16) + | (smaf001 << 8) | 0x81; + pci_write_config32(dev, 0x80, dword); + } } static void prep_fid_change(void) @@ -579,7 +600,7 @@ static void prep_fid_change(void) for (i = 0; i < nodes; i++) { printk(BIOS_DEBUG, "Prep FID/VID Node:%02x\n", i); dev = NODE_PCI(i, 3); - u32 cpuRev = mctGetLogicalCPUID(0xFF) ; + uint64_t cpuRev = mctGetLogicalCPUID(0xFF) ; u8 procPkg = mctGetProcessorPackageType(); setVSRamp(dev); @@ -607,7 +628,7 @@ static void prep_fid_change(void) } } -static void waitCurrentPstate(u32 target_pstate){ +static void waitCurrentPstate(u32 target_pstate) { msr_t initial_msr = rdmsr(TSC_MSR); msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR); msr_t tsc_msr; @@ -640,7 +661,7 @@ static void waitCurrentPstate(u32 target_pstate){ if (pstate_msr.lo != target_pstate) { msr_t limit_msr = rdmsr(0xc0010061); - printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state %01x P-state current limit MSRC001_0061=%02x\n", target_pstate, pstate_msr.lo, limit_msr.lo); + printk(BIOS_ERR, "*** Time out waiting for P-state %01x. Current P-state %01x P-state current limit MSRC001_0061=%08x %08x\n", target_pstate, pstate_msr.lo, limit_msr.hi, limit_msr.lo); do { // should we just go on instead ? pstate_msr = rdmsr(CUR_PSTATE_MSR); @@ -650,6 +671,7 @@ static void waitCurrentPstate(u32 target_pstate){ static void set_pstate(u32 nonBoostedPState) { msr_t msr; + uint8_t skip_wait; // Transition P0 for calling core. msr = rdmsr(0xC0010062); @@ -657,12 +679,21 @@ static void set_pstate(u32 nonBoostedPState) { msr.lo = nonBoostedPState; wrmsr(0xC0010062, msr); - /* Wait for P0 to set. */ - waitCurrentPstate(nonBoostedPState); -} - - + if (is_fam15h()) { + /* Do not wait for the first (even) set of cores to transition on Family 15h systems */ + if ((cpuid_ebx(0x00000001) & 0x01000000)) + skip_wait = 0; + else + skip_wait = 1; + } else { + skip_wait = 0; + } + if (!skip_wait) { + /* Wait for core to transition to P0 */ + waitCurrentPstate(nonBoostedPState); + } +} static void UpdateSinglePlaneNbVid(void) { @@ -752,11 +783,14 @@ static u32 needs_NB_COF_VID_update(void) u8 nodes; u8 i; + if (is_fam15h()) + return 0; + /* If any node has nb_cof_vid_update set all nodes need an update. */ nodes = get_nodes(); nb_cof_vid_update = 0; for (i = 0; i < nodes; i++) { - u32 cpuRev = mctGetLogicalCPUID(i) ; + uint64_t cpuRev = mctGetLogicalCPUID(i); u32 nbCofVidUpdateDefined = (cpuRev & (AMD_FAM10_LT_D)); if (nbCofVidUpdateDefined && (pci_read_config32(NODE_PCI(i, 3), 0x1FC) @@ -780,9 +814,11 @@ static u32 init_fidvid_core(u32 nodeid, u32 coreid) /* Steps 1-6 of BIOS NB COF and VID Configuration * for SVI and Single-Plane PVI Systems. BKDG 2.4.2.9 #31116 rev 3.48 */ - dev = NODE_PCI(nodeid, 3); - pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE; + if (is_fam15h()) + pvimode = 0; + else + pvimode = pci_read_config32(dev, PW_CTL_MISC) & PVI_MODE; reg1fc = pci_read_config32(dev, 0x1FC); if (nb_cof_vid_update) { @@ -794,7 +830,7 @@ static u32 init_fidvid_core(u32 nodeid, u32 coreid) fid_max = fid_max + ((reg1fc & DUAL_PLANE_NB_FID_OFF_MASK ) >> DUAL_PLANE_NB_FID_SHIFT ); } /* write newNbVid to P-state Reg's NbVid always if NbVidUpdatedAll=1 */ - fixPsNbVidBeforeWR(vid_max, coreid,dev,pvimode); + fixPsNbVidBeforeWR(vid_max, coreid, dev, pvimode); /* fid setup is handled by the BSP at the end. */ @@ -814,7 +850,7 @@ static void init_fidvid_ap(u32 apicid, u32 nodeid, u32 coreid) printk(BIOS_DEBUG, "FIDVID on AP: %02x\n", apicid); - send = init_fidvid_core(nodeid,coreid); + send = init_fidvid_core(nodeid, coreid); send |= (apicid << 24); // ap apicid // Send signal to BSP about this AP max fid @@ -856,7 +892,8 @@ static void init_fidvid_bsp_stage1(u32 ap_apicid, void *gp) while (--loop > 0) { if (lapic_remote_read(ap_apicid, LAPIC_MSG_REG, &readback) != 0) continue; - if ((readback & 0x3f) == F10_APSTATE_RESET) { + if (((readback & 0x3f) == F10_APSTATE_RESET) + || (is_fam15h() && ((readback & 0x3f) == F10_APSTATE_ASLEEP))) { timeout = 0; break; /* target ap is in stage 1 */ } @@ -944,7 +981,10 @@ static void init_fidvid_stage2(u32 apicid, u32 nodeid) /* If any node has nb_cof_vid_update set all nodes need an update. */ dev = NODE_PCI(nodeid, 3); - pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; + if (is_fam15h()) + pvimode = 0; + else + pvimode = (pci_read_config32(dev, 0xA0) >> 8) & 1; reg1fc = pci_read_config32(dev, 0x1FC); nbvid = (reg1fc >> 7) & 0x7F; NbVidUpdateAll = (reg1fc >> 1) & 1; @@ -965,15 +1005,17 @@ static void init_fidvid_stage2(u32 apicid, u32 nodeid) pci_write_config32(dev, 0xA0, dtemp); dualPlaneOnly(dev); - applyBoostFIDOffset(dev); + applyBoostFIDOffset(dev, nodeid); enableNbPState1(dev); finalPstateChange(); - /* Set TSC to tick at the P0 ndfid rate */ - msr = rdmsr(HWCR); - msr.lo |= 1 << 24; - wrmsr(HWCR, msr); + if (!is_fam15h()) { + /* Set TSC to tick at the P0 ndfid rate */ + msr = rdmsr(HWCR); + msr.lo |= 1 << 24; + wrmsr(HWCR, msr); + } } @@ -1007,8 +1049,7 @@ static int init_fidvid_bsp(u32 bsp_apicid, u32 nodes) /* Steps 1-6 of BIOS NB COF and VID Configuration * for SVI and Single-Plane PVI Systems. */ - - fv.common_fid = init_fidvid_core(0,0); + fv.common_fid = init_fidvid_core(0, 0); print_debug_fv("BSP fid = ", fv.common_fid); diff --git a/src/cpu/amd/family_10h-family_15h/init_cpus.c b/src/cpu/amd/family_10h-family_15h/init_cpus.c index d618c0c277..85eb931ce9 100644 --- a/src/cpu/amd/family_10h-family_15h/init_cpus.c +++ b/src/cpu/amd/family_10h-family_15h/init_cpus.c @@ -26,9 +26,12 @@ #include <northbridge/amd/amdfam10/raminit_amdmct.c> #include <reset.h> +#if IS_ENABLED(CONFIG_SET_FIDVID) static void prep_fid_change(void); static void init_fidvid_stage2(u32 apicid, u32 nodeid); -void cpuSetAMDMSR(void); +#endif + +void cpuSetAMDMSR(uint8_t node_id); #if CONFIG_PCI_IO_CFG_EXT static void set_EnableCf8ExtCfg(void) @@ -47,43 +50,38 @@ static void set_EnableCf8ExtCfg(void) { } typedef void (*process_ap_t) (u32 apicid, void *gp); -//core_range = 0 : all cores -//core range = 1 : core 0 only -//core range = 2 : cores other than core0 +uint32_t get_boot_apic_id(uint8_t node, uint32_t core) { + uint32_t ap_apicid; -static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap, - void *gp) -{ - // here assume the OS don't change our apicid - u32 ap_apicid; + uint32_t nb_cfg_54; + uint32_t siblings; + uint32_t cores_found; - u32 nodes; - u32 siblings; - u32 disable_siblings; - u32 cores_found; - u32 nb_cfg_54; - int i, j; - u32 ApicIdCoreIdSize; + uint8_t fam15h = 0; uint8_t rev_gte_d = 0; uint8_t dual_node = 0; uint32_t f3xe8; + uint32_t family; + uint32_t model; - /* get_nodes define in ht_wrapper.c */ - nodes = get_nodes(); - - if (!CONFIG_LOGICAL_CPUS || - read_option(multi_core, 0) != 0) { // 0 means multi core - disable_siblings = 1; - } else { - disable_siblings = 0; - } + uint32_t ApicIdCoreIdSize; /* Assume that all node are same stepping, otherwise we can use use nb_cfg_54 from bsp for all nodes */ nb_cfg_54 = read_nb_cfg_54(); f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8); - 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; @@ -99,10 +97,63 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap, siblings = 3; //quad core } + cores_found = get_core_num_in_bsp(node); + if (siblings > cores_found) + siblings = cores_found; + + if (dual_node) { + ap_apicid = 0; + if (fam15h) { + ap_apicid |= ((node >> 1) & 0x3) << 5; /* Node ID */ + ap_apicid |= ((node & 0x1) * (siblings + 1)) + core; /* Core ID */ + } else { + if (nb_cfg_54) { + ap_apicid |= ((node >> 1) & 0x3) << 4; /* Node ID */ + ap_apicid |= ((node & 0x1) * (siblings + 1)) + core; /* Core ID */ + } else { + ap_apicid |= node & 0x3; /* Node ID */ + ap_apicid |= (((node & 0x1) * (siblings + 1)) + core) << 4; /* Core ID */ + } + } + } else { + if (fam15h) { + ap_apicid = (node * (siblings + 1)) + core; + } else { + ap_apicid = node * (nb_cfg_54 ? (siblings + 1) : 1) + + core * (nb_cfg_54 ? 1 : 64); + } + } + + return ap_apicid; +} + +//core_range = 0 : all cores +//core range = 1 : core 0 only +//core range = 2 : cores other than core0 + +static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap, + void *gp) +{ + // here assume the OS don't change our apicid + u32 ap_apicid; + + u32 nodes; + u32 disable_siblings; + u32 cores_found; + int i, j; + + /* get_nodes define in ht_wrapper.c */ + nodes = get_nodes(); + + if (!CONFIG_LOGICAL_CPUS || + read_option(multi_core, 0) != 0) { // 0 means multi core + disable_siblings = 1; + } else { + disable_siblings = 0; + } + for (i = 0; i < nodes; i++) { cores_found = get_core_num_in_bsp(i); - if (siblings > cores_found) - siblings = cores_found; u32 jstart, jend; @@ -119,21 +170,7 @@ static void for_each_ap(u32 bsp_apicid, u32 core_range, process_ap_t process_ap, } for (j = jstart; j <= jend; j++) { - if (dual_node) { - ap_apicid = 0; - if (nb_cfg_54) { - ap_apicid |= ((i >> 1) & 0x3) << 4; /* Node ID */ - ap_apicid |= ((i & 0x1) * (siblings + 1)) + j; /* Core ID */ - } else { - ap_apicid |= i & 0x3; /* Node ID */ - ap_apicid |= (((i & 0x1) * (siblings + 1)) + j) << 4; /* Core ID */ - } - } else { - ap_apicid = - i * (nb_cfg_54 ? (siblings + 1) : 1) + - j * (nb_cfg_54 ? 1 : 64); - } - + ap_apicid = get_boot_apic_id(i, j); #if CONFIG_ENABLE_APIC_EXT_ID && (CONFIG_APIC_ID_OFFSET > 0) #if !CONFIG_LIFT_BSP_APIC_ID @@ -193,7 +230,7 @@ void print_apicid_nodeid_coreid(u32 apicid, struct node_core_id id, apicid, id.nodeid, id.coreid); } -static u32 wait_cpu_state(u32 apicid, u32 state) +uint32_t wait_cpu_state(uint32_t apicid, uint32_t state, uint32_t state2) { u32 readback = 0; u32 timeout = 1; @@ -201,7 +238,7 @@ static u32 wait_cpu_state(u32 apicid, u32 state) while (--loop > 0) { if (lapic_remote_read(apicid, LAPIC_MSG_REG, &readback) != 0) continue; - if ((readback & 0x3f) == state || (readback & 0x3f) == F10_APSTATE_RESET) { + if ((readback & 0x3f) == state || (readback & 0x3f) == state2 || (readback & 0x3f) == F10_APSTATE_RESET) { timeout = 0; break; //target cpu is in stage started } @@ -218,7 +255,7 @@ static u32 wait_cpu_state(u32 apicid, u32 state) static void wait_ap_started(u32 ap_apicid, void *gp) { u32 timeout; - timeout = wait_cpu_state(ap_apicid, F10_APSTATE_STARTED); + timeout = wait_cpu_state(ap_apicid, F10_APSTATE_STARTED, F10_APSTATE_ASLEEP); printk(BIOS_DEBUG, "* AP %02x", ap_apicid); if (timeout) { printk(BIOS_DEBUG, " timed out:%08x\n", timeout); @@ -254,16 +291,27 @@ static void enable_apic_ext_id(u32 node) pci_write_config32(NODE_HT(node), 0x68, val); } -static void STOP_CAR_AND_CPU(void) +static void STOP_CAR_AND_CPU(uint8_t skip_sharedc_config, uint32_t apicid) { msr_t msr; + uint32_t family; + + family = amd_fam1x_cpu_family(); // inline + + if (family < 0x6f) { + /* Family 10h or earlier */ + + /* Disable L2 IC to L3 connection (Only for CAR) */ + msr = rdmsr(BU_CFG2); + msr.lo &= ~(1 << ClLinesToNbDis); + wrmsr(BU_CFG2, msr); + } - /* Disable L2 IC to L3 connection (Only for CAR) */ - msr = rdmsr(BU_CFG2); - msr.lo &= ~(1 << ClLinesToNbDis); - wrmsr(BU_CFG2, msr); + disable_cache_as_ram(skip_sharedc_config); // inline + + /* Mark the core as sleeping */ + lapic_write(LAPIC_MSG_REG, (apicid << 24) | F10_APSTATE_ASLEEP); - disable_cache_as_ram(); // inline /* stop all cores except node0/core0 the bsp .... */ stop_this_cpu(); } @@ -272,6 +320,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct sys_info *sysinfo) { u32 bsp_apicid = 0; u32 apicid; + uint8_t set_mtrrs; struct node_core_id id; /* Please refer to the calculations and explaination in cache_as_ram.inc before modifying these values */ @@ -358,7 +407,7 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct sys_info *sysinfo) */ update_microcode(cpuid_eax(1)); - cpuSetAMDMSR(); + cpuSetAMDMSR(id.nodeid); #if CONFIG_SET_FIDVID #if CONFIG_LOGICAL_CPUS && CONFIG_SET_FIDVID_CORE0_ONLY @@ -381,10 +430,29 @@ static u32 init_cpus(u32 cpu_init_detectedx, struct sys_info *sysinfo) } #endif + if (is_fam15h()) { + /* core 1 on node 0 is special; to avoid corrupting the + * BSP do not alter MTRRs on that core */ + if (apicid == 1) + set_mtrrs = 0; + else + set_mtrrs = !!(apicid & 0x1); + } else { + set_mtrrs = 1; + } + /* AP is ready, configure MTRRs and go to sleep */ - set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK); + if (set_mtrrs) + set_var_mtrr(0, 0x00000000, CONFIG_RAMTOP, MTRR_TYPE_WRBACK); - STOP_CAR_AND_CPU(); + printk(BIOS_DEBUG, "Disabling CAR on AP %02x\n", apicid); + if (is_fam15h()) { + /* Only modify the MSRs on the odd cores (the last cores to finish booting) */ + STOP_CAR_AND_CPU(!set_mtrrs, apicid); + } else { + /* Modify MSRs on all cores */ + STOP_CAR_AND_CPU(0, apicid); + } printk(BIOS_DEBUG, "\nAP %02x should be halted but you are reading this....\n", @@ -492,7 +560,7 @@ static void setup_remote_node(u8 node) } #endif /* CONFIG_MAX_PHYSICAL_CPUS > 1 */ -static void AMD_Errata281(u8 node, u32 revision, u32 platform) +static void AMD_Errata281(u8 node, uint64_t revision, u32 platform) { /* Workaround for Transaction Scheduling Conflict in * Northbridge Cross Bar. Implement XCS Token adjustment @@ -790,7 +858,7 @@ static void AMD_SetHtPhyRegister(u8 node, u8 link, u8 entry) } while (!(val & HTPHY_IS_COMPLETE_MASK)); } -void cpuSetAMDMSR(void) +void cpuSetAMDMSR(uint8_t node_id) { /* This routine loads the CPU with default settings in fam10_msr_default * table . It must be run after Cache-As-RAM has been enabled, and @@ -800,7 +868,8 @@ void cpuSetAMDMSR(void) */ msr_t msr; u8 i; - u32 revision, platform; + u32 platform; + uint64_t revision; printk(BIOS_DEBUG, "cpuSetAMDMSR "); @@ -820,6 +889,49 @@ void cpuSetAMDMSR(void) } AMD_Errata298(); + if (revision & AMD_FAM15_ALL) { + uint32_t f5x80; + uint8_t enabled; + uint8_t compute_unit_count = 0; + f5x80 = pci_read_config32(NODE_PCI(node_id, 5), 0x80); + enabled = f5x80 & 0xf; + if (enabled == 0x1) + compute_unit_count = 1; + if (enabled == 0x3) + compute_unit_count = 2; + if (enabled == 0x7) + compute_unit_count = 3; + if (enabled == 0xf) + compute_unit_count = 4; + msr = rdmsr(BU_CFG2); + msr.lo &= ~(0x3 << 6); /* ThrottleNbInterface[1:0] */ + msr.lo |= (((compute_unit_count - 1) & 0x3) << 6); + wrmsr(BU_CFG2, msr); + } + + /* Revision C0 and above */ + if (revision & AMD_OR_C0) { + uint32_t f3x1fc = pci_read_config32(NODE_PCI(node_id, 3), 0x1fc); + msr = rdmsr(FP_CFG); + msr.hi &= ~(0x7 << (42-32)); /* DiDtCfg4 */ + msr.hi |= (((f3x1fc >> 17) & 0x7) << (42-32)); + msr.hi &= ~(0x1 << (41-32)); /* DiDtCfg5 */ + msr.hi |= (((f3x1fc >> 22) & 0x1) << (41-32)); + msr.hi &= ~(0x1 << (40-32)); /* DiDtCfg3 */ + msr.hi |= (((f3x1fc >> 16) & 0x1) << (40-32)); + msr.hi &= ~(0x7 << (32-32)); /* DiDtCfg1 (1) */ + msr.hi |= (((f3x1fc >> 11) & 0x7) << (32-32)); + msr.lo &= ~(0x1f << 27); /* DiDtCfg1 (2) */ + msr.lo |= (((f3x1fc >> 6) & 0x1f) << 27); + msr.lo &= ~(0x3 << 25); /* DiDtCfg2 */ + msr.lo |= (((f3x1fc >> 14) & 0x3) << 25); + msr.lo &= ~(0x1f << 18); /* DiDtCfg0 */ + msr.lo |= (((f3x1fc >> 1) & 0x1f) << 18); + msr.lo &= ~(0x1 << 16); /* DiDtMode */ + msr.lo |= ((f3x1fc & 0x1) << 16); + wrmsr(FP_CFG, msr); + } + printk(BIOS_DEBUG, " done\n"); } @@ -831,9 +943,10 @@ static void cpuSetAMDPCI(u8 node) * that it is run for the first core on each node */ u8 i, j; - u32 revision, platform; + u32 platform; u32 val; u8 offset; + uint64_t revision; printk(BIOS_DEBUG, "cpuSetAMDPCI %02d", node); @@ -895,6 +1008,7 @@ static void cpuSetAMDPCI(u8 node) } #ifdef UNUSED_CODE +/* Clearing the MCA registers is apparently handled in the ramstage CPU Function 3 driver */ static void cpuInitializeMCA(void) { /* Clears Machine Check Architecture (MCA) registers, which power on diff --git a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c index 8d6610ceef..0a86966537 100644 --- a/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c +++ b/src/cpu/amd/family_10h-family_15h/model_10xxx_init.c @@ -35,6 +35,23 @@ #define MCI_STATUS 0x401 +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 volatile uint8_t fam15h_startup_flags[MAX_NODES_SUPPORTED][MAX_CORES_SUPPORTED] = {{ 0 }}; + static void model_10xxx_init(device_t dev) { u8 i; @@ -43,13 +60,44 @@ static void model_10xxx_init(device_t dev) #if CONFIG_LOGICAL_CPUS u32 siblings; #endif + uint8_t delay_start; id = get_node_core_id(read_nb_cfg_54()); /* nb_cfg_54 can not be set */ printk(BIOS_DEBUG, "nodeid = %02d, coreid = %02d\n", id.nodeid, id.coreid); + if (is_fam15h()) + delay_start = !!(id.coreid & 0x1); + else + delay_start = 0; + /* Turn on caching if we haven't already */ x86_enable_cache(); - amd_setup_mtrrs(); + + if (!delay_start) { + /* Initialize all variable MTRRs except the first pair. + * This prevents Linux from having to correct an inconsistent + * MTRR setup, which would crash Family 15h CPUs due to the + * compute unit structure sharing MTRR MSRs between AP cores. + */ + msr.hi = 0x00000000; + msr.lo = 0x00000000; + + disable_cache(); + + for (i = 0x2; i < 0x10; i++) { + wrmsr(0x00000200 | i, msr); + } + + enable_cache(); + + /* Set up other MTRRs */ + amd_setup_mtrrs(); + } else { + while (!fam15h_startup_flags[id.nodeid][id.coreid - 1]) { + /* Wait for CU first core startup */ + } + } + x86_mtrr_check(); disable_cache(); @@ -84,17 +132,24 @@ static void model_10xxx_init(device_t dev) printk(BIOS_DEBUG, "siblings = %02d, ", siblings); #endif - /* DisableCf8ExtCfg */ + /* Disable Cf8ExtCfg */ msr = rdmsr(NB_CFG_MSR); msr.hi &= ~(1 << (46 - 32)); wrmsr(NB_CFG_MSR, msr); - msr = rdmsr(BU_CFG2_MSR); - /* Clear ClLinesToNbDis */ - msr.lo &= ~(1 << 15); - /* Clear bit 35 as per Erratum 343 */ - msr.hi &= ~(1 << (35-32)); - wrmsr(BU_CFG2_MSR, msr); + if (is_fam15h()) { + msr = rdmsr(BU_CFG3_MSR); + /* Set CombineCr0Cd */ + msr.hi |= (1 << (49-32)); + wrmsr(BU_CFG3_MSR, msr); + } else { + msr = rdmsr(BU_CFG2_MSR); + /* Clear ClLinesToNbDis */ + msr.lo &= ~(1 << 15); + /* Clear bit 35 as per Erratum 343 */ + msr.hi &= ~(1 << (35-32)); + wrmsr(BU_CFG2_MSR, msr); + } if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) { printk(BIOS_DEBUG, "Initializing SMM ASeg memory\n"); @@ -127,6 +182,7 @@ static void model_10xxx_init(device_t dev) msr.lo |= (1 << 0); wrmsr(HWCR_MSR, msr); + fam15h_startup_flags[id.nodeid][id.coreid] = 1; } static struct device_operations cpu_dev_ops = { @@ -143,15 +199,17 @@ static struct cpu_device_id cpu_table[] = { { X86_VENDOR_AMD, 0x100f22 }, { X86_VENDOR_AMD, 0x100f23 }, { X86_VENDOR_AMD, 0x100f40 }, /* RB-C0 */ - { X86_VENDOR_AMD, 0x100F42 }, /* RB-C2 */ - { X86_VENDOR_AMD, 0x100F43 }, /* RB-C3 */ - { X86_VENDOR_AMD, 0x100F52 }, /* BL-C2 */ - { X86_VENDOR_AMD, 0x100F62 }, /* DA-C2 */ - { X86_VENDOR_AMD, 0x100F63 }, /* DA-C3 */ - { X86_VENDOR_AMD, 0x100F80 }, /* HY-D0 */ - { X86_VENDOR_AMD, 0x100F81 }, /* HY-D1 */ - { X86_VENDOR_AMD, 0x100F91 }, /* HY-D1 */ - { X86_VENDOR_AMD, 0x100FA0 }, /* PH-E0 */ + { X86_VENDOR_AMD, 0x100f42 }, /* RB-C2 */ + { X86_VENDOR_AMD, 0x100f43 }, /* RB-C3 */ + { X86_VENDOR_AMD, 0x100f52 }, /* BL-C2 */ + { X86_VENDOR_AMD, 0x100f62 }, /* DA-C2 */ + { X86_VENDOR_AMD, 0x100f63 }, /* DA-C3 */ + { X86_VENDOR_AMD, 0x100f80 }, /* HY-D0 */ + { X86_VENDOR_AMD, 0x100f81 }, /* HY-D1 */ + { X86_VENDOR_AMD, 0x100f91 }, /* HY-D1 */ + { X86_VENDOR_AMD, 0x100fa0 }, /* PH-E0 */ + { X86_VENDOR_AMD, 0x600f12 }, /* OR-B2 */ + { X86_VENDOR_AMD, 0x600f20 }, /* OR-C0 */ { 0, 0 }, }; diff --git a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c index 295a0bfe96..0c53e86b4a 100644 --- a/src/cpu/amd/family_10h-family_15h/powernow_acpi.c +++ b/src/cpu/amd/family_10h-family_15h/powernow_acpi.c @@ -70,8 +70,7 @@ static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 *pstate_p /* Revision C or greater single-link processor */ cpuid1 = cpuid(0x80000008); acpigen_write_PSD_package(0, (cpuid1.ecx & 0xff) + 1, SW_ALL); - } - else { + } else { /* Find the local APIC ID for the specified core ID */ struct device* cpu; int cpu_index = 0; @@ -95,7 +94,9 @@ static void write_pstates_for_core(u8 pstate_num, u16 *pstate_feq, u32 *pstate_p } /* -* For details of this algorithm, please refer to the BDKG 3.62 page 69 +* For details of this algorithm, please refer to: +* Family 10h BDKG 3.62 page 69 +* Family 15h BDKG 3.14 page 74 * * WARNING: The core count algorithm below assumes that all processors * are identical, with the same number of active cores. While the BKDG @@ -145,6 +146,13 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) uint8_t node_count; uint8_t cores_per_node; uint8_t total_core_count; + uint8_t fam15h; + uint8_t fam10h_rev_e = 0; + + /* Detect Revision E processors via method used in fidvid.c */ + if ((cpuid_edx(0x80000007) & CPB_MASK) + && ((cpuid_ecx(0x80000008) & NC_MASK) == 5)) + fam10h_rev_e = 1; /* * Based on the CPU socket type,cmp_cap and pwr_lmt , get the power limit. @@ -152,11 +160,17 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) * cmp_cap : 0x0 SingleCore ; 0x1 DualCore ; 0x2 TripleCore ; 0x3 QuadCore ; 0x4 QuintupleCore ; 0x5 HexCore */ printk(BIOS_INFO, "Pstates algorithm ...\n"); + fam15h = !!(mctGetLogicalCPUID(0) & AMD_FAM15_ALL); /* Get number of cores */ - dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xE8); - cmp_cap = (dtemp & 0x3000) >> 12; - if (mctGetLogicalCPUID(0) & AMD_FAM10_REV_D) /* revision D */ - cmp_cap |= (dtemp & 0x8000) >> 13; + if (fam15h) { + cmp_cap = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 5)), 0x84) & 0xff; + } else { + dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 3)), 0xe8); + cmp_cap = (dtemp & 0x3000) >> 12; + if (mctGetLogicalCPUID(0) & (AMD_FAM10_REV_D | AMD_FAM15_ALL)) /* revision D or higher */ + cmp_cap |= (dtemp & 0x8000) >> 13; + } + /* Get number of nodes */ dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 0)), 0x60); node_count = ((dtemp & 0x70) >> 4) + 1; @@ -165,6 +179,14 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) /* Compute total number of cores installed in system */ total_core_count = cores_per_node * node_count; + /* Get number of boost states */ + uint8_t boost_count = 0; + dtemp = pci_read_config32(dev_find_slot(0, PCI_DEVFN(0x18, 4)), 0x15c); + if (fam10h_rev_e) + boost_count = (dtemp >> 2) & 0x1; + else if (mctGetLogicalCPUID(0) & AMD_FAM15_ALL) + boost_count = (dtemp >> 2) & 0x7; + Pstate_num = 0; /* See if the CPUID(0x80000007) returned EDX[7]==1b */ @@ -201,7 +223,7 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) /* Get PSmax's index */ msr = rdmsr(0xC0010061); - Pstate_max = (uint8_t) ((msr.lo >> PS_MAX_VAL_SHFT) & BIT_MASK_3); + Pstate_max = (uint8_t) ((msr.lo >> PS_MAX_VAL_SHFT) & ((fam15h)?BIT_MASK_7:BIT_MASK_3)); /* Determine if all enabled Pstates have the same fidvid */ uint8_t i; @@ -215,10 +237,14 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) } } + /* Family 15h uses slightly different PSmax numbering */ + if (fam15h) + Pstate_max++; + /* Populate tables with all Pstate information */ for (Pstate_num = 0; Pstate_num < Pstate_max; Pstate_num++) { /* Get power state information */ - msr = rdmsr(0xC0010064 + Pstate_num); + msr = rdmsr(0xC0010064 + Pstate_num + boost_count); cpufid = (msr.lo & 0x3f); cpudid = (msr.lo & 0x1c0) >> 6; cpuvid = (msr.lo & 0xfe00) >> 9; @@ -228,12 +254,10 @@ void amd_generate_powernow(u32 pcontrol_blk, u8 plen, u8 onlyBSP) if (pviModeFlag) { if (cpuvid >= 0x20) { core_voltage = 7625 - (((cpuvid - 0x20) * 10000) / 80); - } - else { + } else { core_voltage = 15500 - ((cpuvid * 10000) / 40); } - } - else { + } else { cpuvid = cpuvid & 0x7f; if (cpuvid >= 0x7c) core_voltage = 0; diff --git a/src/cpu/amd/family_10h-family_15h/processor_name.c b/src/cpu/amd/family_10h-family_15h/processor_name.c index 9fe896e136..ac0392b7d9 100644 --- a/src/cpu/amd/family_10h-family_15h/processor_name.c +++ b/src/cpu/amd/family_10h-family_15h/processor_name.c @@ -29,6 +29,10 @@ #include <cpu/amd/mtrr.h> #include <cpu/cpu.h> #include <cpu/amd/model_10xxx_rev.h> +#include <device/device.h> +#include <device/pci.h> +#include <device/pnp.h> +#include <device/pci_ops.h> /* The maximum length of CPU names is 48 bytes, including the final NULL byte. * If you change these names your BIOS will _NOT_ pass the AMD validation and @@ -208,104 +212,138 @@ static int strcpymax(char *dst, const char *src, int buflen) return i; } +#define NAME_STRING_MAXLEN 48 int init_processor_name(void) { - /* variable names taken from fam10 revision guide for clarity */ - u32 BrandId; /* CPUID Fn8000_0001_EBX */ - u8 String1; /* BrandID[14:11] */ - u8 String2; /* BrandID[3:0] */ - u8 Model; /* BrandID[10:4] */ - u8 Pg; /* BrandID[15] */ - u8 PkgTyp; /* BrandID[31:28] */ - u8 NC; /* CPUID Fn8000_0008_ECX */ - const char *processor_name_string = unknown; - char program_string[48]; - u32 *p_program_string = (u32 *)program_string; msr_t msr; - int i, j = 0, str2_checkNC = 1; - const struct str_s *str, *str2; + ssize_t i; + char program_string[NAME_STRING_MAXLEN]; + u32 *p_program_string = (u32 *)program_string; + uint8_t fam15h = 0; + uint32_t family; + family = cpuid_eax(0x80000001); + family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8); - /* Find out which CPU brand it is */ - BrandId = cpuid_ebx(0x80000001); - String1 = (u8)((BrandId >> 11) & 0x0F); - String2 = (u8)((BrandId >> 0) & 0x0F); - Model = (u8)((BrandId >> 4) & 0x7F); - Pg = (u8)((BrandId >> 15) & 0x01); - PkgTyp = (u8)((BrandId >> 28) & 0x0F); - NC = (u8)(cpuid_ecx(0x80000008) & 0xFF); + if (family >= 0x6f) + /* Family 15h or later */ + fam15h = 1; /* null the string */ memset(program_string, 0, sizeof(program_string)); - if (!Model) { - processor_name_string = Pg ? thermal : sample; - goto done; - } - - switch (PkgTyp) { - case 0: /* F1207 */ - str = String1_socket_F; - str2 = String2_socket_F; - str2_checkNC = 0; - break; - case 1: /* AM2 */ - str = String1_socket_AM2; - str2 = String2_socket_AM2; - break; - case 3: /* G34 */ - str = String1_socket_G34; - str2 = String2_socket_G34; - str2_checkNC = 0; - break; - case 5: /* C32 */ - str = String1_socket_C32; - str2 = String2_socket_C32; - break; - default: - goto done; - } + if (fam15h) { + /* Family 15h or later */ + uint32_t dword; + device_t cpu_fn5_dev = dev_find_slot(0, PCI_DEVFN(0x18, 5)); + pci_write_config32(cpu_fn5_dev, 0x194, 0); + dword = pci_read_config32(cpu_fn5_dev, 0x198); + if (dword == 0) { + strcpymax(program_string, sample, sizeof(program_string)); + } else { + /* Assemble the string from PCI configuration register contents */ + for (i = 0; i < 12; i++) { + pci_write_config32(cpu_fn5_dev, 0x194, i); + p_program_string[i] = pci_read_config32(cpu_fn5_dev, 0x198); + } + + /* Correctly place the null terminator */ + for (i = (NAME_STRING_MAXLEN - 2); i > 0; i--) { + if (program_string[i] != 0x20) + break; + } + program_string[i + 1] = 0; + } + } else { + /* variable names taken from fam10 revision guide for clarity */ + u32 BrandId; /* CPUID Fn8000_0001_EBX */ + u8 String1; /* BrandID[14:11] */ + u8 String2; /* BrandID[3:0] */ + u8 Model; /* BrandID[10:4] */ + u8 Pg; /* BrandID[15] */ + u8 PkgTyp; /* BrandID[31:28] */ + u8 NC; /* CPUID Fn8000_0008_ECX */ + const char *processor_name_string = unknown; + int j = 0, str2_checkNC = 1; + const struct str_s *str, *str2; + + /* Find out which CPU brand it is */ + BrandId = cpuid_ebx(0x80000001); + String1 = (u8)((BrandId >> 11) & 0x0F); + String2 = (u8)((BrandId >> 0) & 0x0F); + Model = (u8)((BrandId >> 4) & 0x7F); + Pg = (u8)((BrandId >> 15) & 0x01); + PkgTyp = (u8)((BrandId >> 28) & 0x0F); + NC = (u8)(cpuid_ecx(0x80000008) & 0xFF); + + if (!Model) { + processor_name_string = Pg ? thermal : sample; + goto done; + } - /* String1 */ - for (i = 0; str[i].value; i++) { - if ((str[i].Pg == Pg) && - (str[i].NC == NC) && - (str[i].String == String1)) { - processor_name_string = str[i].value; + switch (PkgTyp) { + case 0: /* F1207 */ + str = String1_socket_F; + str2 = String2_socket_F; + str2_checkNC = 0; + break; + case 1: /* AM2 */ + str = String1_socket_AM2; + str2 = String2_socket_AM2; + break; + case 3: /* G34 */ + str = String1_socket_G34; + str2 = String2_socket_G34; + str2_checkNC = 0; + break; + case 5: /* C32 */ + str = String1_socket_C32; + str2 = String2_socket_C32; break; + default: + goto done; } - } - if (!str[i].value) - goto done; + /* String1 */ + for (i = 0; str[i].value; i++) { + if ((str[i].Pg == Pg) && + (str[i].NC == NC) && + (str[i].String == String1)) { + processor_name_string = str[i].value; + break; + } + } - j = strcpymax(program_string, processor_name_string, - sizeof(program_string)); + if (!str[i].value) + goto done; - /* Translate Model from 01-99 to ASCII and put it on the end. - * Numbers less than 10 should include a leading zero, e.g., 09.*/ - if (Model < 100 && j < sizeof(program_string) - 2) { - program_string[j++] = (Model / 10) + '0'; - program_string[j++] = (Model % 10) + '0'; - } + j = strcpymax(program_string, processor_name_string, + sizeof(program_string)); - processor_name_string = unknown2; - - /* String 2 */ - for(i = 0; str2[i].value; i++) { - if ((str2[i].Pg == Pg) && - ((str2[i].NC == NC) || !str2_checkNC) && - (str2[i].String == String2)) { - processor_name_string = str2[i].value; - break; + /* Translate Model from 01-99 to ASCII and put it on the end. + * Numbers less than 10 should include a leading zero, e.g., 09.*/ + if (Model < 100 && j < sizeof(program_string) - 2) { + program_string[j++] = (Model / 10) + '0'; + program_string[j++] = (Model % 10) + '0'; } - } + processor_name_string = unknown2; + + /* String 2 */ + for(i = 0; str2[i].value; i++) { + if ((str2[i].Pg == Pg) && + ((str2[i].NC == NC) || !str2_checkNC) && + (str2[i].String == String2)) { + processor_name_string = str2[i].value; + break; + } + } -done: - strcpymax(&program_string[j], processor_name_string, - sizeof(program_string) - j); + done: + strcpymax(&program_string[j], processor_name_string, + sizeof(program_string) - j); + } printk(BIOS_DEBUG, "CPU model: %s\n", program_string); diff --git a/src/cpu/amd/family_10h-family_15h/update_microcode.c b/src/cpu/amd/family_10h-family_15h/update_microcode.c index c295de679d..2d776909f6 100644 --- a/src/cpu/amd/family_10h-family_15h/update_microcode.c +++ b/src/cpu/amd/family_10h-family_15h/update_microcode.c @@ -24,6 +24,7 @@ struct id_mapping { static u16 get_equivalent_processor_rev_id(u32 orig_id) { static const struct id_mapping id_mapping_table[] = { + /* Family 10h */ { 0x100f00, 0x1000 }, { 0x100f01, 0x1000 }, { 0x100f02, 0x1000 }, @@ -38,8 +39,13 @@ static u16 get_equivalent_processor_rev_id(u32 orig_id) { { 0x100f62, 0x1062 }, /* DA-C2 */ { 0x100f63, 0x1043 }, /* DA-C3 */ { 0x100f81, 0x1081 }, /* HY-D1 */ + { 0x100f91, 0x1081 }, /* HY-D1 */ { 0x100fa0, 0x10A0 }, /* PH-E0 */ + /* Family 15h */ + { 0x600f12, 0x6012 }, /* OR-B2 */ + { 0x600f20, 0x6020 }, /* OR-C0 */ + /* Array terminator */ { 0xffffff, 0x0000 }, }; diff --git a/src/cpu/amd/model_fxx/init_cpus.c b/src/cpu/amd/model_fxx/init_cpus.c index f30ff0a03e..85cd46df74 100644 --- a/src/cpu/amd/model_fxx/init_cpus.c +++ b/src/cpu/amd/model_fxx/init_cpus.c @@ -199,7 +199,7 @@ static void enable_apic_ext_id(u32 node) static void STOP_CAR_AND_CPU(void) { - disable_cache_as_ram(); // inline + disable_cache_as_ram(0); // inline /* stop all cores except node0/core0 the bsp .... */ stop_this_cpu(); } 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... */ |