summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorMarc Jones <marc.jones@amd.com>2008-04-22 22:11:31 +0000
committerMarc Jones <marc.jones@amd.com>2008-04-22 22:11:31 +0000
commitda4ce6b45157060447cb02fa15349f7de3f531ff (patch)
treeb2b8c34dbff559f715f7832f59a6703a6870625c /src/cpu
parent0ab8cddf02f592a34f3c555ba78a11eaf66a59c0 (diff)
Add early MSR and PCI register initialization.
This fixes many default setting as well as erratas. Some CPU core functions were moved from the HT init and platform specific code to the generic Fam10 CPU code. Signed-off-by: Marc Jones <marc.jones@amd.com> Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3248 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/amd/model_10xxx/init_cpus.c438
1 files changed, 427 insertions, 11 deletions
diff --git a/src/cpu/amd/model_10xxx/init_cpus.c b/src/cpu/amd/model_10xxx/init_cpus.c
index 819f9b1666..5c17a9a118 100644
--- a/src/cpu/amd/model_10xxx/init_cpus.c
+++ b/src/cpu/amd/model_10xxx/init_cpus.c
@@ -1,7 +1,7 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
*
* 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
@@ -17,6 +17,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "defaults.h"
//it takes the ENABLE_APIC_EXT_ID and APIC_ID_OFFSET and LIFT_BSP_APIC_ID
#ifndef FAM10_SET_FIDVID
@@ -29,7 +30,6 @@
#define FAM10_SET_FIDVID_CORE0_ONLY 0
#endif
-
static inline void print_initcpu8 (const char *strval, u8 val)
{
printk_debug("%s%02x\n", strval, val);
@@ -55,6 +55,7 @@ static inline void print_initcpu(const char *strval, u32 val)
static void prep_fid_change(void);
static void init_fidvid_stage2(u32 apicid, u32 nodeid);
+void cpuSetAMDMSR(void);
#if PCI_IO_CFG_EXT == 1
static inline void set_EnableCf8ExtCfg(void)
@@ -261,12 +262,6 @@ static void wait_ap_started(u32 ap_apicid, void *gp )
}
-static void wait_all_aps_started(u32 bsp_apicid)
-{
- for_each_ap(bsp_apicid, 0 , wait_ap_started, (void *)0);
-}
-
-
static void wait_all_other_cores_started(u32 bsp_apicid)
{
// all aps other than core0
@@ -287,6 +282,15 @@ static void allow_all_aps_stop(u32 bsp_apicid)
lapic_write(LAPIC_MSG_REG, (bsp_apicid << 24) | 0x14);
}
+static void enable_apic_ext_id(u32 node)
+{
+ u32 val;
+
+ val = pci_read_config32(NODE_HT(node), 0x68);
+ val |= (HTTC_APIC_EXT_SPUR | HTTC_APIC_EXT_ID | HTTC_APIC_EXT_BRD_CST);
+ pci_write_config32(NODE_HT(node), 0x68, val);
+}
+
static void STOP_CAR_AND_CPU()
{
@@ -383,6 +387,13 @@ static u32 init_cpus(u32 cpu_init_detectedx)
if(apicid != bsp_apicid) {
+ /* Setup each AP's cores MSRs.
+ * This happens after HTinit.
+ * The BSP runs this code in it's own path.
+ */
+ cpuSetAMDMSR();
+
+
#if FAM10_SET_FIDVID == 1
#if (CONFIG_LOGICAL_CPUS == 1) && (FAM10_SET_FIDVID_CORE0_ONLY == 1)
// Run on all AP for proper FID/VID setup.
@@ -512,13 +523,415 @@ static void setup_remote_node(u8 node)
}
printk_debug(" done\n");
}
-#endif
+#endif /* CONFIG_MAX_PHYSICAL_CPUS > 1 */
+
+void AMD_Errata281(u8 node, u32 revision, u32 platform)
+{
+ /* Workaround for Transaction Scheduling Conflict in
+ * Northbridge Cross Bar. Implement XCS Token adjustment
+ * for ganged links. Also, perform fix up for the mixed
+ * revision case.
+ */
+
+ u32 reg, val;
+ u8 i;
+ u8 mixed = 0;
+ u8 nodes = get_nodes();
+
+ if (platform & AMD_PTYPE_SVR) {
+ /* For each node we need to check for a "broken" node */
+ if (!(revision & (AMD_DR_B0 | AMD_DR_B1))) {
+ for (i = 0; i < nodes; i++) {
+ if (mctGetLogicalCPUID(i) & (AMD_DR_B0 | AMD_DR_B1)) {
+ mixed = 1;
+ break;
+ }
+ }
+ }
+
+ if ((revision & (AMD_DR_B0 | AMD_DR_B1)) || mixed) {
+
+ /* F0X68[22:21] DsNpReqLmt0 = 01b */
+ val = pci_read_config32(NODE_PCI(node, 0), 0x68);
+ val &= ~0x00600000;
+ val |= 0x00200000;
+ pci_write_config32(NODE_PCI(node, 0), 0x68, val);
+
+ /* F3X6C */
+ val = pci_read_config32(NODE_PCI(node, 3), 0x6C);
+ val &= ~0x700780F7;
+ val |= 0x00010094;
+ pci_write_config32(NODE_PCI(node, 3), 0x6C, val);
+
+ /* F3X7C */
+ val = pci_read_config32(NODE_PCI(node, 3), 0x7C);
+ val &= ~0x707FFF1F;
+ val |= 0x00144514;
+ pci_write_config32(NODE_PCI(node, 3), 0x7C, val);
+
+ /* F3X144[3:0] RspTok = 0001b */
+ val = pci_read_config32(NODE_PCI(node, 3), 0x144);
+ val &= ~0x0000000F;
+ val |= 0x00000001;
+ pci_write_config32(NODE_PCI(node, 3), 0x144, val);
+
+ for (i = 0; i < 3; i++) {
+ reg = 0x148 + (i * 4);
+ val = pci_read_config32(NODE_PCI(node, 3), reg);
+ val &= ~0x000000FF;
+ val |= 0x000000DB;
+ pci_write_config32(NODE_PCI(node, 3), reg, val);
+ }
+ }
+ }
+}
+
+
+void AMD_Errata298(void)
+{
+ /* Workaround for L2 Eviction May Occur during operation to
+ * set Accessed or dirty bit.
+ */
+
+ msr_t msr;
+ u8 i;
+ u8 affectedRev = 0;
+ u8 nodes = get_nodes();
+
+ /* For each core we need to check for a "broken" node */
+ for (i = 0; i < nodes; i++) {
+ if (mctGetLogicalCPUID(i) & (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2)) {
+ affectedRev = 1;
+ break;
+ }
+ }
+
+ if (affectedRev) {
+ msr = rdmsr(HWCR);
+ msr.lo |= 0x08; /* Set TlbCacheDis bit[3] */
+ wrmsr(HWCR, msr);
+
+ msr = rdmsr(BU_CFG);
+ msr.lo |= 0x02; /* Set TlbForceMemTypeUc bit[1] */
+ wrmsr(BU_CFG, msr);
+
+ msr = rdmsr(OSVW_ID_Length);
+ msr.lo |= 0x01; /* OS Visible Workaround - MSR */
+ wrmsr(OSVW_ID_Length, msr);
+
+ msr = rdmsr(OSVW_Status);
+ msr.lo |= 0x01; /* OS Visible Workaround - MSR */
+ wrmsr(OSVW_Status, msr);
+ }
+
+ if (!affectedRev && (mctGetLogicalCPUID(0xFF) & AMD_DR_B3)) {
+ msr = rdmsr(OSVW_ID_Length);
+ msr.lo |= 0x01; /* OS Visible Workaround - MSR */
+ wrmsr(OSVW_ID_Length, msr);
+
+ }
+}
+
+
+u32 get_platform_type(void)
+{
+ u32 ret = 0;
+
+ switch(SYSTEM_TYPE) {
+ case 1:
+ ret |= AMD_PTYPE_DSK;
+ break;
+ case 2:
+ ret |= AMD_PTYPE_MOB;
+ break;
+ case 0:
+ ret |= AMD_PTYPE_SVR;
+ break;
+ default:
+ break;
+ }
+
+ /* FIXME: add UMA support. */
+
+ /* All Fam10 are multi core */
+ ret |= AMD_PTYPE_MC;
+
+ return ret;
+}
+
+
+/**
+ * AMD_CpuFindCapability - Traverse PCI capability list to find host HT links.
+ * HT Phy operations are not valid on links that aren't present, so this
+ * prevents invalid accesses.
+ *
+ * Returns the offset of the link register.
+ */
+BOOL AMD_CpuFindCapability (u8 node, u8 cap_count, u8 *offset)
+{
+ u32 val;
+
+ /* get start of CPU HT Host Capabilities */
+ val = pci_read_config32(NODE_PCI(node, 0), 0x34);
+ val &= 0xFF;
+
+ cap_count++;
+
+ /* Traverse through the capabilities. */
+ do {
+ val = pci_read_config32(NODE_PCI(node, 0), val);
+ /* Is the capability block a HyperTransport capability block? */
+ if ((val & 0xFF) == 0x08)
+ /* Is the HT capability block an HT Host Capability? */
+ if ((val & 0xE0000000) == (1 << 29))
+ cap_count--;
+ val = (val >> 8) & 0xFF;
+ } while (cap_count && val);
+
+ *offset = (u8) val;
+
+ /* If requested capability found val != 0 */
+ if (!cap_count)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+/**
+ * AMD_checkLinkType - Compare desired link characteristics using a logical
+ * link type mask.
+ *
+ * Returns the link characteristic mask.
+ */
+u32 AMD_checkLinkType (u8 node, u8 link, u8 regoff)
+{
+ u32 val;
+ u32 linktype;
+
+ /* Check coherency */
+ val = pci_read_config32(NODE_PCI(node, 0), regoff + 0x18);
+ val &= 0x1F;
+
+ if (val == 3)
+ linktype |= HTPHY_LINKTYPE_COHERENT;
+
+ if (val == 7)
+ linktype |= HTPHY_LINKTYPE_NONCOHERENT;
+
+ /* Check gen3 */
+ val = pci_read_config32(NODE_PCI(node, 0), regoff + 0x08);
+
+ if (((val >> 8) & 0x0F) > 6)
+ linktype |= HTPHY_LINKTYPE_HT3;
+ else
+ linktype |= HTPHY_LINKTYPE_HT1;
+
+
+ /* Check ganged */
+ val = pci_read_config32(NODE_PCI(node, 0), (link << 2) + 0x170);
+
+ if ( val & 1)
+ linktype |= HTPHY_LINKTYPE_GANGED;
+ else
+ linktype |= HTPHY_LINKTYPE_UNGANGED;
+
+ return linktype;
+}
+
+
+/**
+ * AMD_SetHtPhyRegister - Use the HT link's HT Phy portal registers to update
+ * a phy setting for that link.
+ */
+void AMD_SetHtPhyRegister (u8 node, u8 link, u8 entry)
+{
+ u32 phyReg;
+ u32 phyBase;
+ u32 val;
+
+ /* Determine this link's portal */
+ if (link > 3)
+ link -= 4;
+
+ phyBase = ((u32)link << 3) | 0x180;
+
+
+ /* Get the portal control register's initial value
+ * and update it to access the desired phy register
+ */
+ phyReg = pci_read_config32(NODE_PCI(node, 4), phyBase);
+
+ if (fam10_htphy_default[entry].htreg > 0x1FF) {
+ phyReg &= ~HTPHY_DIRECT_OFFSET_MASK;
+ phyReg |= HTPHY_DIRECT_MAP;
+ } else {
+ phyReg &= ~HTPHY_OFFSET_MASK;
+ }
+
+ /* Now get the current phy register data
+ * LinkPhyDone = 0, LinkPhyWrite = 0 is a read
+ */
+ phyReg |= fam10_htphy_default[entry].htreg;
+ pci_write_config32(NODE_PCI(node, 4), phyBase, phyReg);
+
+ do {
+ val = pci_read_config32(NODE_PCI(node, 4), phyBase);
+ } while (!(val & HTPHY_IS_COMPLETE_MASK));
+
+ /* Now we have the phy register data, apply the change */
+ val = pci_read_config32(NODE_PCI(node, 4), phyBase + 4);
+ val &= ~fam10_htphy_default[entry].mask;
+ val |= fam10_htphy_default[entry].data;
+ pci_write_config32(NODE_PCI(node, 4), phyBase + 4, val);
+
+ /* write it through the portal to the phy
+ * LinkPhyDone = 0, LinkPhyWrite = 1 is a write
+ */
+ phyReg |= HTPHY_WRITE_CMD;
+ pci_write_config32(NODE_PCI(node, 4), phyBase, phyReg);
+
+ do {
+ val = pci_read_config32(NODE_PCI(node, 4), phyBase);
+ } while (!(val & HTPHY_IS_COMPLETE_MASK));
+}
+
+
+void cpuSetAMDMSR(void)
+{
+ /* 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
+ * Hypertransport initialization has taken place. Also note
+ * that it is run on the current processor only, and only for the current
+ * processor core.
+ */
+ msr_t msr;
+ u8 i;
+ u32 revision, platform;
+
+ printk_debug("cpuSetAMDMSR ");
+
+ revision = mctGetLogicalCPUID(0xFF);
+ platform = get_platform_type();
+
+ for(i = 0; i < sizeof(fam10_msr_default)/sizeof(fam10_msr_default[0]); i++) {
+ if ((fam10_msr_default[i].revision & revision) &&
+ (fam10_msr_default[i].platform & platform)) {
+ msr = rdmsr(fam10_msr_default[i].msr);
+ msr.hi &= ~fam10_msr_default[i].mask_hi;
+ msr.hi |= fam10_msr_default[i].data_hi;
+ msr.lo &= ~fam10_msr_default[i].mask_lo;
+ msr.lo |= fam10_msr_default[i].data_lo;
+ wrmsr(fam10_msr_default[i].msr, msr);
+ }
+ }
+ AMD_Errata298();
+
+ printk_debug(" done\n");
+}
+
+
+void cpuSetAMDPCI(u8 node)
+{
+ /* This routine loads the CPU with default settings in fam10_pci_default
+ * table . It must be run after Cache-As-RAM has been enabled, and
+ * Hypertransport initialization has taken place. Also note
+ * that it is run for the first core on each node
+ */
+ u8 i, j;
+ u32 revision, platform;
+ u32 val;
+ u8 offset;
+
+ printk_debug("cpuSetAMDPCI %02d", node);
+
+ revision = mctGetLogicalCPUID(node);
+ platform = get_platform_type();
+
+ for(i = 0; i < sizeof(fam10_pci_default)/sizeof(fam10_pci_default[0]); i++) {
+ if ((fam10_pci_default[i].revision & revision) &&
+ (fam10_pci_default[i].platform & platform)) {
+ val = pci_read_config32(NODE_PCI(node,
+ fam10_pci_default[i].function),
+ fam10_pci_default[i].offset);
+ val &= ~fam10_pci_default[i].mask;
+ val |= fam10_pci_default[i].data;
+ pci_write_config32(NODE_PCI(node,
+ fam10_pci_default[i].function),
+ fam10_pci_default[i].offset, val);
+ }
+ }
+
+ for(i = 0; i < sizeof(fam10_htphy_default)/sizeof(fam10_htphy_default[0]); i++) {
+ if ((fam10_htphy_default[i].revision & revision) &&
+ (fam10_htphy_default[i].platform & platform)) {
+ /* HT Phy settings either apply to both sublinks or have
+ * separate registers for sublink zero and one, so there
+ * will be two table entries. So, here we only loop
+ cd t * through the sublink zeros in function zero.
+ */
+ for (j = 0; j < 4; j++) {
+ if (AMD_CpuFindCapability(node, j, &offset)) {
+ if (AMD_checkLinkType(node, j, offset)
+ & fam10_htphy_default[i].linktype) {
+ AMD_SetHtPhyRegister(node, j, i);
+ }
+ } else {
+ /* No more capabilities,
+ * link not present
+ */
+ break;
+ }
+ }
+ }
+ }
+
+ /* FIXME: add UMA support and programXbarToSriReg(); */
+
+ AMD_Errata281(node, revision, platform);
+
+ /* FIXME: if the dct phy doesn't init correct it needs to reset.
+ if (revision & (AMD_DR_B2 | AMD_DR_B3))
+ dctPhyDiag(); */
+
+ printk_debug(" done\n");
+}
+
+
+void cpuInitializeMCA(void)
+{
+ /* Clears Machine Check Architecture (MCA) registers, which power on
+ * containing unknown data, on currently running processor.
+ * This routine should only be executed on initial power on (cold boot),
+ * not across a warm reset because valid data is present at that time.
+ */
+
+ msr_t msr;
+ u32 reg;
+ u8 i;
+
+ if (cpuid_edx(1) & 0x4080) { /* MCE and MCA (edx[7] and edx[14]) */
+ msr = rdmsr(MCG_CAP);
+ if (msr.lo & MCG_CTL_P){ /* MCG_CTL_P bit is set? */
+ msr.lo &= 0xFF;
+ msr.lo--;
+ msr.lo <<= 2; /* multiply the count by 4 */
+ reg = MC0_STA + msr.lo;
+ msr.lo = msr.hi = 0;
+ for (i=0; i < 4; i++) {
+ wrmsr (reg, msr);
+ reg -=4; /* Touch status regs for each bank */
+ }
+ }
+ }
+}
+
+
/**
* finalize_node_setup()
*
* Do any additional post HT init
*
- * This could really be moved to cache_as_ram_auto.c since it really isn't HT init.
*/
void finalize_node_setup(struct sys_info *sysinfo)
{
@@ -535,7 +948,10 @@ void finalize_node_setup(struct sys_info *sysinfo)
sysinfo->sbdn = get_sbdn(sysinfo->sbbusn);
#endif
- setup_link_trans_cntrl();
+
+ for (i = 0; i < nodes; i++) {
+ cpuSetAMDPCI(i);
+ }
#if FAM10_SET_FIDVID == 1
// Prep each node for FID/VID setup.