blob: 1f38b0c0320296024d121cce9e7ca811bc08ce53 [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering
* 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
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <cpu/x86/msr.h>
#include <console/console.h>
#include <northbridge/amd/amdfam10/amdfam10.h>
#include "ht_wrapper.h"
/*----------------------------------------------------------------------------
* TYPEDEFS, DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
/* Single CPU system? */
#if (CONFIG_MAX_PHYSICAL_CPUS == 1)
/* FIXME
* This #define is used by other #included .c files
* When set, multiprocessor support is completely disabled
*/
#define HT_BUILD_NC_ONLY 1
#endif
/* Debugging Options */
#define AMD_DEBUG 1
//#define AMD_DEBUG_ERROR_STOP 1
/*----------------------------------------------------------------------------
* MODULES USED
*
*----------------------------------------------------------------------------
*/
#undef FILECODE
#define FILECODE 0xFF01
#include "comlib.h"
#include "h3gtopo.h"
#include "h3finit.h"
/* include the main HT source file */
#include "h3finit.c"
/*----------------------------------------------------------------------------
* LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/* FIXME: Find a better place for these pre-ram functions. */
#define NODE_HT(x) NODE_PCI(x,0)
#define NODE_MP(x) NODE_PCI(x,1)
#define NODE_MC(x) NODE_PCI(x,3)
#define NODE_LC(x) NODE_PCI(x,4)
static u32 get_nodes(void)
{
device_t dev;
u32 nodes;
dev = PCI_DEV(CONFIG_CBB, CONFIG_CDB, 0);
nodes = ((pci_read_config32(dev, 0x60)>>4) & 7) ;
#if CONFIG_MAX_PHYSICAL_CPUS > 8
nodes += (((pci_read_config32(dev, 0x160)>>4) & 7)<<3);
#endif
nodes++;
return nodes;
}
/**
* void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0)
*/
static void AMD_CB_EventNotify (u8 evtClass, u16 event, const u8 *pEventData0)
{
u8 i;
printk(BIOS_DEBUG, "AMD_CB_EventNotify()\n");
printk(BIOS_DEBUG, " event class: %02x\n event: %04x\n data: ", evtClass, event);
for (i = 0; i < *pEventData0; i++) {
printk(BIOS_DEBUG, " %02x ", *(pEventData0 + i));
}
printk(BIOS_DEBUG, "\n");
}
/**
* void getAmdTopolist(u8 ***p)
*
* point to the stock topo list array
*
*/
void getAmdTopolist(u8 ***p)
{
*p = (u8 **)amd_topo_list;
}
/**
* BOOL AMD_CB_IgnoreLink(u8 Node, u8 Link)
* Description:
* This routine is used to ignore connected yet faulty HT links,
* such as those present in a G34 processor package.
*
* Parameters:
* @param[in] node = The node on which this chain is located
* @param[in] link = The link on the host for this chain
*/
static BOOL AMD_CB_IgnoreLink (u8 node, u8 link)
{
return 0;
}
/**
* void amd_ht_init(struct sys_info *sysinfo)
*
* AMD HT init coreboot wrapper
*
*/
static void amd_ht_init(struct sys_info *sysinfo)
{
AMD_HTBLOCK ht_wrapper = {
NULL, // u8 **topolist;
0, // u8 AutoBusStart;
32, // u8 AutoBusMax;
6, // u8 AutoBusIncrement;
AMD_CB_IgnoreLink, // BOOL (*AMD_CB_IgnoreLink)();
NULL, // BOOL (*AMD_CB_OverrideBusNumbers)();
AMD_CB_ManualBUIDSwapList, // BOOL (*AMD_CB_ManualBUIDSwapList)();
NULL, // void (*AMD_CB_DeviceCapOverride)();
NULL, // void (*AMD_CB_Cpu2CpuPCBLimits)();
NULL, // void (*AMD_CB_IOPCBLimits)();
NULL, // BOOL (*AMD_CB_SkipRegang)();
NULL, // BOOL (*AMD_CB_CustomizeTrafficDistribution)();
NULL, // BOOL (*AMD_CB_CustomizeBuffers)();
NULL, // void (*AMD_CB_OverrideDevicePort)();
NULL, // void (*AMD_CB_OverrideCpuPort)();
AMD_CB_EventNotify, // void (*AMD_CB_EventNotify) ();
&sysinfo->ht_link_cfg // struct ht_link_config*
};
printk(BIOS_DEBUG, "Enter amd_ht_init()\n");
amdHtInitialize(&ht_wrapper);
printk(BIOS_DEBUG, "Exit amd_ht_init()\n");
}
/**
* void amd_ht_fixup(struct sys_info *sysinfo)
*
* AMD HT fixup
*
*/
void amd_ht_fixup(struct sys_info *sysinfo) {
printk(BIOS_DEBUG, "amd_ht_fixup()\n");
if (IS_ENABLED(CONFIG_CPU_AMD_MODEL_10XXX)) {
uint8_t rev_gte_d = 0;
uint8_t fam15h = 0;
uint8_t dual_node = 0;
uint32_t f3xe8;
uint32_t family;
uint32_t model;
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;
if ((model >= 0x8) || fam15h)
/* Family 10h Revision D or later */
rev_gte_d = 1;
if (rev_gte_d) {
f3xe8 = pci_read_config32(NODE_PCI(0, 3), 0xe8);
/* Check for dual node capability */
if (f3xe8 & 0x20000000)
dual_node = 1;
if (dual_node) {
/* Each G34 processor contains a defective HT link.
* See the Family 10h BKDG Rev 3.62 section 2.7.1.5 for details
* For Family 15h see the BKDG Rev. 3.14 section 2.12.1.5 for details.
*/
uint8_t node;
uint8_t node_count = get_nodes();
uint32_t dword;
for (node = 0; node < node_count; node++) {
f3xe8 = pci_read_config32(NODE_PCI(node, 3), 0xe8);
uint8_t internal_node_number = ((f3xe8 & 0xc0000000) >> 30);
printk(BIOS_DEBUG, "amd_ht_fixup(): node %d (internal node ID %d): disabling defective HT link\n", node, internal_node_number);
if (internal_node_number == 0) {
uint8_t package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x98:0xd8) & 0x1;
if (package_link_3_connected) {
/* Set WidthIn and WidthOut to 0 */
dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4);
dword &= ~0x77000000;
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x84:0xc4, dword);
/* Set Ganged to 1 */
dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178);
dword |= 0x00000001;
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x170:0x178, dword);
} else {
/* Set ConnDly to 1 */
dword = pci_read_config32(NODE_PCI(node, 0), 0x16c);
dword |= 0x00000100;
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
/* Set TransOff and EndOfChain to 1 */
dword = pci_read_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4);
dword |= 0x000000c0;
pci_write_config32(NODE_PCI(node, 4), (fam15h)?0x84:0xc4, dword);
}
} else if (internal_node_number == 1) {
uint8_t package_link_3_connected = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xf8:0xb8) & 0x1;
if (package_link_3_connected) {
/* Set WidthIn and WidthOut to 0 */
dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4);
dword &= ~0x77000000;
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0xe4:0xa4, dword);
/* Set Ganged to 1 */
dword = pci_read_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174);
dword |= 0x00000001;
pci_write_config32(NODE_PCI(node, 0), (fam15h)?0x18c:0x174, dword);
} else {
/* Set ConnDly to 1 */
dword = pci_read_config32(NODE_PCI(node, 0), 0x16c);
dword |= 0x00000100;
pci_write_config32(NODE_PCI(node, 0), 0x16c, dword);
/* Set TransOff and EndOfChain to 1 */
dword = pci_read_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4);
dword |= 0x000000c0;
pci_write_config32(NODE_PCI(node, 4), (fam15h)?0xe4:0xa4, dword);
}
}
}
}
}
}
}