This code is not in a working state but I want to get it into the repo
since the box it is on is kinda old. I realize it is wrong but it is getting there. The k8 startup is a work of genius. I hope at some point it will be a work of genius that the rest of us can understand :-) But it's very impressive code in how it works. Discussions with AMD: we're in agreement that the structure of this code will change for the better, but it's helpful to have this audit trail of changes. Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> Acked-by: Ronald G. Minnich <rminnich@gmail.com> git-svn-id: svn://coreboot.org/repository/coreboot-v3@837 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
parent
b0144f19c7
commit
d130a25c0d
1 changed files with 180 additions and 0 deletions
180
arch/x86/amd/model_fxx/dualcore.c
Normal file
180
arch/x86/amd/model_fxx/dualcore.c
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
/* 2004.12 yhlu add dual core support */
|
||||
#include <mainboard.h>
|
||||
#include <types.h>
|
||||
#include <lib.h>
|
||||
#include <console.h>
|
||||
#include <globalvars.h>
|
||||
#include <device/device.h>
|
||||
#include <device/pci.h>
|
||||
#include <string.h>
|
||||
#include <msr.h>
|
||||
#include <io.h>
|
||||
#include <cpu.h>
|
||||
#include <amd/k8/k8.h>
|
||||
#include <mc146818rtc.h>
|
||||
#include <spd.h>
|
||||
|
||||
|
||||
#ifndef SET_NB_CFG_54
|
||||
#define SET_NB_CFG_54 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Given a nodeid, return the count of the number of cores in that node.
|
||||
* @param nodeid The nodeid
|
||||
* @returns The number of cores in that node.
|
||||
*/
|
||||
unsigned int get_core_count(unsigned nodeid)
|
||||
{
|
||||
u32 dword;
|
||||
dword = pci_read_config32(PCI_BDF(0, 0x18+nodeid, 3), NORTHBRIDGE_CAP);
|
||||
dword >>= NBCAP_CmpCap_SHIFT;
|
||||
dword &= NBCAP_CmpCap_MASK;
|
||||
return dword;
|
||||
}
|
||||
|
||||
#if SET_NB_CFG_54 == 1
|
||||
static inline uint8_t set_apicid_cpuid_lo(void)
|
||||
{
|
||||
#if K8_REV_F_SUPPORT == 0
|
||||
if(is_cpu_pre_e0()) return 0; // pre_e0 can not be set
|
||||
#endif
|
||||
|
||||
// set the NB_CFG[54]=1; why the OS will be happy with that ???
|
||||
msr_t msr;
|
||||
msr = rdmsr(NB_CFG_MSR);
|
||||
msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
|
||||
wrmsr(NB_CFG_MSR, msr);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
|
||||
static inline void set_apicid_cpuid_lo(void) { }
|
||||
|
||||
#endif
|
||||
|
||||
static inline void real_start_other_core(unsigned nodeid)
|
||||
{
|
||||
uint32_t dword;
|
||||
// set PCI_DEV(0, 0x18+nodeid, 3), 0x44 bit 27 to redirect all MC4 accesses and error logging to core0
|
||||
dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 3), 0x44);
|
||||
dword |= 1<<27; // NbMcaToMstCpuEn bit
|
||||
pci_write_config32(PCI_DEV(0, 0x18+nodeid, 3), 0x44, dword);
|
||||
// set PCI_DEV(0, 0x18+nodeid, 0), 0x68 bit 5 to start core1
|
||||
dword = pci_read_config32(PCI_DEV(0, 0x18+nodeid, 0), 0x68);
|
||||
dword |= 1<<5;
|
||||
pci_write_config32(PCI_DEV(0, 0x18+nodeid, 0), 0x68, dword);
|
||||
}
|
||||
|
||||
//it is running on core0 of node0
|
||||
static inline void start_other_cores(void)
|
||||
{
|
||||
unsigned nodes;
|
||||
unsigned nodeid;
|
||||
|
||||
if(read_option(CMOS_VSTART_dual_core, CMOS_VLEN_dual_core, 0) != 0) { // disable dual_core
|
||||
return;
|
||||
}
|
||||
|
||||
nodes = get_nodes();
|
||||
|
||||
for(nodeid=0; nodeid<nodes; nodeid++) {
|
||||
if( get_core_num_in_bsp(nodeid) > 0) {
|
||||
real_start_other_core(nodeid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#if USE_DCACHE_RAM == 0
|
||||
static void do_k8_init_and_stop_secondaries(void)
|
||||
{
|
||||
struct node_core_id id;
|
||||
device_t dev;
|
||||
unsigned apicid;
|
||||
unsigned max_siblings;
|
||||
msr_t msr;
|
||||
|
||||
/* Skip this if there was a built in self test failure */
|
||||
|
||||
if (is_cpu_pre_e0()) {
|
||||
id.nodeid = lapicid() & 0x7;
|
||||
id.coreid = 0;
|
||||
} else {
|
||||
/* Which cpu are we on? */
|
||||
id = get_node_core_id_x();
|
||||
|
||||
/* Set NB_CFG_MSR
|
||||
* Linux expect the core to be in the least signficant bits.
|
||||
*/
|
||||
msr = rdmsr(NB_CFG_MSR);
|
||||
msr.hi |= (1<<(54-32)); // InitApicIdCpuIdLo
|
||||
wrmsr(NB_CFG_MSR, msr);
|
||||
}
|
||||
|
||||
/* For now assume all cpus have the same number of siblings */
|
||||
max_siblings = (cpuid_ecx(0x80000008) & 0xff) + 1;
|
||||
|
||||
/* Enable extended apic ids */
|
||||
device_t dev_f0 = PCI_DEV(0, 0x18+id.nodeid, 0);
|
||||
unsigned val = pci_read_config32(dev_f0, 0x68);
|
||||
val |= (1 << 18) | (1 << 17);
|
||||
pci_write_config32(dev_f0, 0x68, val);
|
||||
|
||||
/* Set the lapicid */
|
||||
#if (ENABLE_APIC_EXT_ID == 1)
|
||||
unsigned initial_apicid = get_initial_apicid();
|
||||
#if LIFT_BSP_APIC_ID == 0
|
||||
if( initial_apicid != 0 ) // other than bsp
|
||||
#endif
|
||||
{
|
||||
/* use initial apic id to lift it */
|
||||
uint32_t dword = lapic_read(LAPIC_ID);
|
||||
dword &= ~(0xff<<24);
|
||||
dword |= (((initial_apicid + APIC_ID_OFFSET) & 0xff)<<24);
|
||||
|
||||
lapic_write(LAPIC_ID, dword);
|
||||
}
|
||||
|
||||
#if LIFT_BSP_APIC_ID == 1
|
||||
bsp_apicid += APIC_ID_OFFSET;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Remember the cpuid */
|
||||
if (id.coreid == 0) {
|
||||
dev = PCI_DEV(0, 0x18 + id.nodeid, 2);
|
||||
pci_write_config32(dev, 0x9c, cpuid_eax(1));
|
||||
}
|
||||
|
||||
/* Maybe call distinguish_cpu_resets only on the last core? */
|
||||
distinguish_cpu_resets(id.nodeid);
|
||||
if (!boot_cpu()) {
|
||||
stop_this_cpu();
|
||||
}
|
||||
}
|
||||
|
||||
static void k8_init_and_stop_secondaries(void)
|
||||
{
|
||||
/* This doesn't work with Cache As Ram because it messes with
|
||||
the MTRR state, which breaks the init detection.
|
||||
do_k8_init_and_stop_secondaries should be usable by CAR code.
|
||||
*/
|
||||
|
||||
int init_detected;
|
||||
|
||||
init_detected = early_mtrr_init_detected();
|
||||
amd_early_mtrr_init();
|
||||
|
||||
enable_lapic();
|
||||
init_timer();
|
||||
if (init_detected) {
|
||||
asm volatile ("jmp __cpu_reset");
|
||||
}
|
||||
|
||||
do_k8_init_and_stop_secondaries();
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue