summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/amd/model_10xxx/Config.lb1
-rw-r--r--src/cpu/amd/model_10xxx/fidvid_common.c312
-rw-r--r--src/cpu/amd/model_10xxx/model_10xxx_init.c343
-rw-r--r--src/cpu/amd/model_10xxx/pstate.c456
4 files changed, 16 insertions, 1096 deletions
diff --git a/src/cpu/amd/model_10xxx/Config.lb b/src/cpu/amd/model_10xxx/Config.lb
index cf651e052b..406722eaf5 100644
--- a/src/cpu/amd/model_10xxx/Config.lb
+++ b/src/cpu/amd/model_10xxx/Config.lb
@@ -37,4 +37,3 @@ dir /cpu/amd/microcode
driver model_10xxx_init.o
object update_microcode.o
object apic_timer.o
-object pstate.o
diff --git a/src/cpu/amd/model_10xxx/fidvid_common.c b/src/cpu/amd/model_10xxx/fidvid_common.c
deleted file mode 100644
index aa82323b97..0000000000
--- a/src/cpu/amd/model_10xxx/fidvid_common.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2007 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-
-#include <cpu/x86/tsc.h>
-
-
-static u32 get_vstime(u32 nodeid, u32 slam)
-{
- u32 val;
- u32 v;
- device_t dev;
-
-#if defined(__ROMCC__)
- dev = NODE_PCI(nodeid, 3);
-#else
- dev = get_node_pci(nodeid, 3);
-#endif
-
- val = pci_read_config32(dev, 0xd8);
-
- val >>= slam?0:4;
- val &= 7;
-
- switch (val) {
- case 4: v = 60; break;
- case 5: v = 100; break;
- case 6: v = 200; break;
- case 7: v = 500; break;
- default:
- v = (val+1)*10; // in us
- }
-
- return v;
-}
-
-static void udelay_tsc(u32 us)
-{
- /* Use TSC to delay because it is fixed, ie. it will not changed with p-states.
- * Also, We use the APIC TIMER register is to hold flags for AP init.
- */
- u32 dword;
- tsc_t tsc, tsc1, tscd;
- u32 d = 0x00000200; //800Mhz or 200Mhz or 1.6G or get the NBFID at first
- u32 dn = 0x1000000/2; // howmany us need to use hi
-
- tscd.hi = us/dn;
- tscd.lo = (us - tscd.hi * dn) * d;
-
- tsc1 = rdtsc();
- dword = tsc1.lo + tscd.lo;
- if((dword<tsc1.lo) || (dword<tscd.lo)) {
- tsc1.hi++;
- }
- tsc1.lo = dword;
- tsc1.hi+= tscd.hi;
-
- do {
- tsc = rdtsc();
- } while ((tsc.hi>tsc1.hi) || ((tsc.hi==tsc1.hi) && (tsc.lo>tsc1.lo)));
-
-}
-
-#ifdef __ROMCC__
-void udelay(u32 usecs)
-{
- udelay_tsc(usecs);
-}
-#endif
-
-static u32 set_vid(u32 newvid, u32 bit_offset, u32 nodeid, u32 coreid)
-{
- u32 val;
- msr_t msr;
- u32 curvid;
- u32 slam;
- u32 delay;
- u32 count = 3;
- device_t dev;
-
- msr = rdmsr(0xc0010071);//status
- curvid = (msr.lo >> bit_offset) & 0x7f; // seven bits
-
- if(newvid == curvid) return curvid;
-
-#if defined(__ROMCC__)
- dev = NODE_PCI(nodeid, 3);
-#else
- dev = get_node_pci(nodeid, 3);
-#endif
-
- val = pci_read_config32(dev, 0xa0);
-
- slam = (val >> 29) & 1;
- delay = get_vstime(nodeid, slam);
-
- if(!slam) {
- if(curvid>newvid) {
- count = (curvid - newvid) * 2;
- } else {
- count = (newvid - curvid) * 2;
- }
- }
-
- while(count-->0) {
- if(slam) {
- curvid = newvid;
- }
- else { //ramp
- if(curvid>newvid) {
- curvid--;
- } else {
- curvid++;
- }
- }
-
- msr = rdmsr(0xc0010070); //control
- msr.lo &= ~(0x7f<<bit_offset);
- msr.lo |= (curvid<<bit_offset);
- wrmsr(0xc0010070, msr); // how about all copys, APIC or PCI conf space?
-
- udelay_tsc(delay);
-
- msr = rdmsr(0xc0010071);//status
- curvid = (msr.lo >> bit_offset) & 0x7f; // seven bits
-
- if(curvid == newvid) break;
-
- }
-
- return curvid;
-}
-
-
-static u32 set_nb_vid(u32 newvid, u32 nodeid, u32 coreid)
-{
- return set_vid(newvid, 25, nodeid, coreid);
-}
-
-
-static u32 set_core_vid(u32 newvid, u32 nodeid, u32 coreid)
-{
- return set_vid(newvid, 9, nodeid, coreid);
-}
-
-
-static unsigned set_cof(u32 val, u32 mask, u32 nodeid, u32 coreid)
-{
- msr_t msr;
- int count = 3;
-
- val &= mask;
-
- // FIXME: What is count for? Why 3 times? What about node and core id?
- while(count-- > 0) {
-
- msr = rdmsr(0xc0010071);
- msr.lo &= mask;
- if(msr.lo == val) break;
-
- msr = rdmsr(0xc0010070);
- msr.lo &= ~(mask);
- msr.lo |= val;
- wrmsr(0xc0010070, msr);
- }
-
- return msr.lo;
-}
-
-static u32 set_core_cof(u32 fid, u32 did, u32 nodeid, u32 coreid)
-{
- u32 val;
- u32 mask;
-
- mask = (7<<6) | 0x3f;
- val = ((did & 7)<<6) | (fid & 0x3f);
-
- return set_cof(val, mask, nodeid, coreid);
-
-}
-
-
-static u32 set_nb_cof(u32 did, u32 nodeid, u32 coreid) // fid need warmreset
-{
- u32 val;
- u32 mask;
-
- mask = 1<<22;
- val = (did & 1)<<22;
-
- return set_cof(val, mask, nodeid, coreid);
-
-}
-
-
-/* set vid and cof for core and nb after warm reset is not started by BIOS */
-static void set_core_nb_max_pstate_after_other_warm_reset(u32 nodeid, u32 coreid) // P0
-{
- msr_t msr;
- u32 val;
- u32 vid;
- u32 mask;
- u32 did;
- device_t dev;
-
- msr = rdmsr(0xc0010064);
-
-#if defined(__ROMCC__)
- dev = NODE_PCI(nodeid, 3);
-#else
- dev = get_node_pci(nodeid, 3);
-#endif
-
- val = pci_read_config32(dev, 0xa0);
- if((val>>8) & 1) { // PVI
- vid = (msr.lo >> 25) & 0x7f;
- } else { //SVI
- vid = (msr.lo >> 9) & 0x7f;
- }
- set_core_vid(vid, nodeid, coreid);
-
- mask = (0x7<<6) | 0x3f;
- val = msr.lo & mask;
- set_cof(val, mask, nodeid, coreid);
-
- //set nb cof and vid
- did = (msr.lo >> 22) & 1;
- vid = (msr.lo >> 25) & 0x7f;
- if(did) {
- set_nb_cof(did, nodeid, coreid);
- set_nb_vid(vid, nodeid, coreid);
- } else {
- set_nb_vid(vid, nodeid, coreid);
- set_nb_cof(did, nodeid, coreid);
- }
-
- //set the p state
- msr.hi = 0;
- msr.lo = 0;
- wrmsr(0xc0010062, msr);
-
-}
-
-
-/* set vid and cof for core and nb after warm reset is not started by BIOS */
-static void set_core_nb_min_pstate_after_other_warm_reset(u32 nodeid, u32 coreid) // Px
-{
- msr_t msr;
- u32 val;
- u32 vid;
- u32 mask;
- u32 did;
- u32 pstate;
- device_t dev;
-
-#if defined(__ROMCC__)
- dev = NODE_PCI(nodeid, 3);
-#else
- dev = get_node_pci(nodeid, 3);
-#endif
-
-
- val = pci_read_config32(dev, 0xdc); //PstateMaxVal
-
- pstate = (val >> 8) & 0x7;
-
- msr = rdmsr(0xc0010064 + pstate);
-
- mask = (7<<6) | 0x3f;
- val = msr.lo & mask;
- set_cof(val, mask, nodeid, coreid);
-
- val = pci_read_config32(dev, 0xa0);
- if((val>>8) & 1) { // PVI
- vid = (msr.lo>>25) & 0x7f;
- } else { //SVI
- vid = (msr.lo>>9) & 0x7f;
- }
- set_core_vid(vid, nodeid, coreid);
-
- //set nb cof and vid
- did = (msr.lo >> 22) & 1;
- vid = (msr.lo >> 25) & 0x7f;
- if(did) {
- set_nb_cof(did, nodeid, coreid);
- set_nb_vid(vid, nodeid, coreid);
- } else {
- set_nb_vid(vid, nodeid, coreid);
- set_nb_cof(did, nodeid, coreid);
- }
-
- //set the p state
- msr.hi = 0;
- msr.lo = pstate;
- wrmsr(0xc0010062, msr);
-}
diff --git a/src/cpu/amd/model_10xxx/model_10xxx_init.c b/src/cpu/amd/model_10xxx/model_10xxx_init.c
index 697ab0382c..bf40458c3c 100644
--- a/src/cpu/amd/model_10xxx/model_10xxx_init.c
+++ b/src/cpu/amd/model_10xxx/model_10xxx_init.c
@@ -35,28 +35,13 @@
#include <cpu/x86/cache.h>
#include <cpu/x86/mtrr.h>
#include <cpu/x86/mem.h>
-
#include <cpu/amd/quadcore.h>
-
#include <cpu/amd/model_10xxx_msr.h>
-extern void prep_pstates_all(void);
-extern void init_pstates(device_t dev, u32 nodeid, u32 coreid);
extern device_t get_node_pci(u32 nodeid, u32 fn);
-void cpus_ready_for_init(void)
-{
- prep_pstates_all();
-#if MEM_TRAIN_SEQ == 1
- struct sys_info *sysinfox = (struct sys_info *)((CONFIG_LB_MEM_TOPK<<10) - DCACHE_RAM_GLOBAL_VAR_SIZE);
- // wait for ap memory to trained
- wait_all_core0_mem_trained(sysinfox);
-#endif
-}
-
-
#define MCI_STATUS 0x401
@@ -82,304 +67,18 @@ static inline void wrmsr_amd(u32 index, msr_t msr)
}
-#define MTRR_COUNT 8
-#define ZERO_CHUNK_KB 0x800UL /* 2M */
-#define TOLM_KB 0x400000UL
-
-struct mtrr {
- msr_t base;
- msr_t mask;
-};
-
-
-struct mtrr_state {
- struct mtrr mtrrs[MTRR_COUNT];
- msr_t top_mem, top_mem2;
- msr_t def_type;
-};
-
-
-static void save_mtrr_state(struct mtrr_state *state)
-{
- int i;
- for(i = 0; i < MTRR_COUNT; i++) {
- state->mtrrs[i].base = rdmsr(MTRRphysBase_MSR(i));
- state->mtrrs[i].mask = rdmsr(MTRRphysMask_MSR(i));
- }
- state->top_mem = rdmsr(TOP_MEM);
- state->top_mem2 = rdmsr(TOP_MEM2);
- state->def_type = rdmsr(MTRRdefType_MSR);
-}
-
-
-static void restore_mtrr_state(struct mtrr_state *state)
-{
- int i;
- disable_cache();
-
- for(i = 0; i < MTRR_COUNT; i++) {
- wrmsr(MTRRphysBase_MSR(i), state->mtrrs[i].base);
- wrmsr(MTRRphysMask_MSR(i), state->mtrrs[i].mask);
- }
- wrmsr(TOP_MEM, state->top_mem);
- wrmsr(TOP_MEM2, state->top_mem2);
- wrmsr(MTRRdefType_MSR, state->def_type);
-
- enable_cache();
-}
-
-
-#if 0
-static void print_mtrr_state(struct mtrr_state *state)
-{
- int i;
- for(i = 0; i < MTRR_COUNT; i++) {
- printk_debug("var mtrr %d: %08x%08x mask: %08x%08x\n",
- i,
- state->mtrrs[i].base.hi, state->mtrrs[i].base.lo,
- state->mtrrs[i].mask.hi, state->mtrrs[i].mask.lo);
- }
- printk_debug("top_mem: %08x%08x\n",
- state->top_mem.hi, state->top_mem.lo);
- printk_debug("top_mem2: %08x%08x\n",
- state->top_mem2.hi, state->top_mem2.lo);
- printk_debug("def_type: %08x%08x\n",
- state->def_type.hi, state->def_type.lo);
-}
-#endif
-
-
-static void set_init_ecc_mtrrs(void)
-{
- msr_t msr;
- int i;
- disable_cache();
-
- /* First clear all of the msrs to be safe */
- for(i = 0; i < MTRR_COUNT; i++) {
- msr_t zero;
- zero.lo = zero.hi = 0;
- wrmsr(MTRRphysBase_MSR(i), zero);
- wrmsr(MTRRphysMask_MSR(i), zero);
- }
-
- /* Write back cache the first 1MB */
- msr.hi = 0x00000000;
- msr.lo = 0x00000000 | MTRR_TYPE_WRBACK;
- wrmsr(MTRRphysBase_MSR(0), msr);
- msr.hi = 0x000000ff;
- msr.lo = ~((CONFIG_LB_MEM_TOPK << 10) - 1) | 0x800;
- wrmsr(MTRRphysMask_MSR(0), msr);
-
- /* Set the default type to write combining */
- msr.hi = 0x00000000;
- msr.lo = 0xc00 | MTRR_TYPE_WRCOMB;
- wrmsr(MTRRdefType_MSR, msr);
-
- /* Set TOP_MEM to 4G */
- msr.hi = 0x00000001;
- msr.lo = 0x00000000;
- wrmsr(TOP_MEM, msr);
-
- enable_cache();
-}
-
-
-static inline void clear_2M_ram(unsigned long basek, struct mtrr_state *mtrr_state)
-{
- unsigned long limitk;
- unsigned long size;
- void *addr;
-
- /* Report every 64M */
- if ((basek % (64*1024)) == 0) {
-
- /* Restore the normal state */
- map_2M_page(0);
- restore_mtrr_state(mtrr_state);
- enable_lapic();
-
- /* Print a status message */
- printk_debug("%c", (basek >= TOLM_KB)?'+':'-');
-
- /* Return to the initialization state */
- set_init_ecc_mtrrs();
- disable_lapic();
-
- }
-
- limitk = (basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1);
-
- size = (limitk - basek) << 10;
- addr = map_2M_page(basek >> 11);
- if (addr == MAPPING_ERROR) {
- printk_err("Cannot map page: %x\n", basek >> 11);
- return;
- }
-
- /* clear memory 2M (limitk - basek) */
- addr = (void *)(((u32)addr) | ((basek & 0x7ff) << 10));
- clear_memory(addr, size);
-}
-
-
-static void init_ecc_memory(u32 node_id)
-{
- unsigned long startk, begink, endk;
- unsigned long hole_startk = 0;
- unsigned long basek;
- struct mtrr_state mtrr_state;
-
- device_t f1_dev, f2_dev, f3_dev;
- int enable_scrubbing;
- u32 dcl;
-
- f1_dev = get_node_pci(node_id, 1);
-
- if (!f1_dev) {
- die("Cannot find cpu function 1\n");
- }
- f2_dev = get_node_pci(node_id, 2);
- if (!f2_dev) {
- die("Cannot find cpu function 2\n");
- }
- f3_dev = get_node_pci(node_id, 3);
- if (!f3_dev) {
- die("Cannot find cpu function 3\n");
- }
-
- /* See if we scrubbing should be enabled */
- enable_scrubbing = 1;
- get_option(&enable_scrubbing, "hw_scrubber");
-
- /* Enable cache scrubbing at the lowest possible rate */
- if (enable_scrubbing) {
- pci_write_config32(f3_dev, DRAM_SCRUB_RATE_CTRL,
- (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_NONE << 0));
- } else {
- pci_write_config32(f3_dev, DRAM_SCRUB_RATE_CTRL,
- (SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0));
- printk_debug("Scrubbing Disabled\n");
- }
-
-
- /* If ecc support is not enabled don't touch memory */
- dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW);
- if (!(dcl & DCL_DimmEccEn)) {
- printk_debug("ECC Disabled\n");
- return;
- }
-
- startk = (pci_read_config32(f1_dev, 0x40 + (node_id*8)) & 0xffff0000) >> 2;
- endk = ((pci_read_config32(f1_dev, 0x44 + (node_id*8)) & 0xffff0000) >> 2) + 0x4000;
-
-#if HW_MEM_HOLE_SIZEK != 0
- u32 val;
- val = pci_read_config32(f1_dev, 0xf0);
- if(val & 1) {
- hole_startk = ((val & (0xff<<24)) >> 10);
- }
-#endif
-
-
- /* Don't start too early */
- begink = startk;
- if (begink < CONFIG_LB_MEM_TOPK) {
- begink = CONFIG_LB_MEM_TOPK;
- }
-
- printk_debug("Clearing memory %uK - %uK: ", begink, endk);
-
- /* Save the normal state */
- save_mtrr_state(&mtrr_state);
-
- /* Switch to the init ecc state */
- set_init_ecc_mtrrs();
- disable_lapic();
-
- /* Walk through 2M chunks and zero them */
-#if HW_MEM_HOLE_SIZEK != 0
- /* here hole_startk can not be equal to begink, never. Also hole_startk is in 2M boundary, 64M? */
- if ( (hole_startk != 0) && ((begink < hole_startk) && (endk>(4*1024*1024)))) {
- for(basek = begink; basek < hole_startk;
- basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1)))
- {
- clear_2M_ram(basek, &mtrr_state);
- }
- for(basek = 4*1024*1024; basek < endk;
- basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1)))
- {
- clear_2M_ram(basek, &mtrr_state);
- }
- } else
-#endif
- for(basek = begink; basek < endk;
- basek = ((basek + ZERO_CHUNK_KB) & ~(ZERO_CHUNK_KB - 1))) {
- clear_2M_ram(basek, &mtrr_state);
- }
-
-
- /* Restore the normal state */
- map_2M_page(0);
- restore_mtrr_state(&mtrr_state);
- enable_lapic();
-
- /* Set the scrub base address registers */
- pci_write_config32(f3_dev, DRAM_SCRUB_ADDR_LOW, startk << 10);
- pci_write_config32(f3_dev, DRAM_SCRUB_ADDR_HIGH, startk >> 22);
-
- /* Enable the scrubber? */
- if (enable_scrubbing) {
- /* Enable scrubbing at the lowest possible rate */
- pci_write_config32(f3_dev, DRAM_SCRUB_RATE_CTRL,
- (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0));
- }
-
- printk_debug(" done\n");
-}
-
-
-static inline void fam10_errata(void)
-{
- msr_t msr;
- /* FIXME: Is doing errata here too late? */
-
- /* 298 : FIXME: Fixed in B3/C1 */
-/* msr = rdmsr(0xC0010015);
- msr.lo |= 1 << 3;
- wrmsr(0xC0010015, msr);
-
- msr = rdmsr(0xC0010023);
- msr.lo |= 1 << 1;
- wrmsr(0xC0010023, msr);
-*/
-}
-
-static void smash1Gpages(void)
-{
- msr_t msr;
-
- /* 1G pages are smashed and installed in the TLB as 2M pages.
- BIOS must set this bit for revision B. */
- /* FIXME: What about RevC? */
-
- msr = rdmsr(0xC001102A);
- msr.lo |= 1 << 29;
- wrmsr(0xC001102A, msr);
-
-}
-
-
-
void model_10xxx_init(device_t dev)
{
- unsigned long i;
+ u8 i;
msr_t msr;
struct node_core_id id;
#if CONFIG_LOGICAL_CPUS == 1
- unsigned siblings;
+ u32 siblings;
#endif
+ id = get_node_core_id(read_nb_cfg_54()); /* nb_cfg_54 can not be set */
+ printk_debug("nodeid = %02d, coreid = %02d\n", id.nodeid, id.coreid);
+
/* Turn on caching if we haven't already */
x86_enable_cache();
amd_setup_mtrrs();
@@ -394,13 +93,14 @@ void model_10xxx_init(device_t dev)
wrmsr(MCI_STATUS + (i * 4),msr);
}
- fam10_errata();
enable_cache();
/* Enable the local cpu apics */
setup_lapic();
+ /* FIXME: Update CPUID name strings here */
+
#if CONFIG_LOGICAL_CPUS == 1
siblings = cpuid_ecx(0x80000008) & 0xff;
@@ -409,34 +109,23 @@ void model_10xxx_init(device_t dev)
msr.lo |= 1 << 28;
wrmsr_amd(CPU_ID_FEATURES_MSR, msr);
- msr = rdmsr_amd(LOGICAL_CPUS_NUM_MSR);
- msr.lo = (siblings+1)<<16;
- wrmsr_amd(LOGICAL_CPUS_NUM_MSR, msr);
-
msr = rdmsr_amd(CPU_ID_EXT_FEATURES_MSR);
- msr.hi |= 1<<(33-32);
+ msr.hi |= 1 << (33-32);
wrmsr_amd(CPU_ID_EXT_FEATURES_MSR, msr);
}
printk_debug("siblings = %02d, ", siblings);
#endif
- id = get_node_core_id(read_nb_cfg_54()); // pre e0 nb_cfg_54 can not be set
-
- printk_debug("nodeid = %02d, coreid = %02d\n", id.nodeid, id.coreid);
+ /* DisableCf8ExtCfg */
+ msr = rdmsr(NB_CFG_MSR);
+ msr.hi &= ~(1 << (46-32));
+ wrmsr(NB_CFG_MSR, msr);
- init_pstates(dev, id.nodeid, id.coreid); // is it a good place? some cores are clearing their ram
-
- /* Is this a bad location? In particular can another node prefecth
- * data from this node before we have initialized it?
- */
- if (id.coreid == 0) init_ecc_memory(id.nodeid); // only do it for core 0
-
-#if CONFIG_LOGICAL_CPUS==1
- /* Start up my cpu siblings */
-// if(id.coreid==0) amd_sibling_init(dev); // Don't need core1 is already be put in the CPU BUS in bus_cpu_scan
-#endif
+ /* Write protect SMM space with SMMLOCK. */
+ msr = rdmsr(HWCR_MSR);
+ msr.lo |= (1 << 0);
+ wrmsr(HWCR_MSR, msr);
- smash1Gpages();
}
static struct device_operations cpu_dev_ops = {
diff --git a/src/cpu/amd/model_10xxx/pstate.c b/src/cpu/amd/model_10xxx/pstate.c
deleted file mode 100644
index 240f47e4b2..0000000000
--- a/src/cpu/amd/model_10xxx/pstate.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2007 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <console/console.h>
-#include <cpu/x86/msr.h>
-#include <cpu/amd/mtrr.h>
-#include <device/device.h>
-#include <device/pci.h>
-#include <string.h>
-#include <cpu/x86/msr.h>
-#include <cpu/x86/pae.h>
-#include <pc80/mc146818rtc.h>
-#include <cpu/x86/lapic.h>
-
-#include "../../../northbridge/amd/amdfam10/amdfam10.h"
-
-#include <cpu/amd/model_10xxx_rev.h>
-#include <cpu/cpu.h>
-#include <cpu/x86/cache.h>
-#include <cpu/x86/mtrr.h>
-#include <cpu/x86/mem.h>
-
-#include <cpu/amd/quadcore.h>
-
-#include <cpu/amd/model_10xxx_msr.h>
-#include <cpu/amd/amdfam10_sysconf.h>
-
-extern device_t get_node_pci(u32 nodeid, u32 fn);
-
-#include "fidvid_common.c"
-
-#define PSTATES_DEBUG 0
-
-
-
-static void inline dump_msr_pstates(u32 nodes)
-{
-#if PSTATES_DEBUG==1
- int i, j;
- for(j=0; j<5; j++) {
- printk_debug("P%d:", j);
- for(i=0;i<nodes;i++) {
- printk_debug(" [%08x %08x] ", sysconf.msr_pstate[i*5+j].hi, sysconf.msr_pstate[i*5+j].lo);
- }
- printk_debug("\n");
- }
-#endif
-}
-
-
-static void inline dump_p(const char *p_c, u32 nodes, u32 *p)
-{
-#if PSTATES_DEBUG==1
- int i, j;
- printk_debug(p_c);
- printk_debug("p:");
- for(i=0;i<nodes;i++) {
- printk_debug(" %d ", p[i]);
- }
- printk_debug("\n");
-
-#endif
-}
-
-
-//according the pstate and make it work conformed to mixed conf system
-static u32 get_pwrvalue(u32 val)
-{
- u32 times;
- switch((val>>8)&3) {
- case 0: times = 1000; break;
- case 1: times = 100; break;
- case 2: times = 10; break;
- default:
- //error
- times = 1;
- }
-
- return (val & 0xff) * times;
-
-}
-
-
-static u32 get_powerstep(u32 val)
-{
- u32 time;
- if(val<4) {time = (4 - val)*100;}
- else if(val<8) { time = (9+4-val)*10;}
- else { time = (10+8-val) * 5; }
-
- return time;
-
-}
-
-
-static u32 get_plllocktime(u32 val)
-{
- u32 time;
- switch(val) {
- case 0:
- case 1:
- case 2:
- case 3:
- time = val+1; break;
- case 4: time = 8; break;
- case 5: time = 16; break;
- default:
- //erro2
- time = 1;
- }
- return time;
-}
-
-
-static void disable_pstate(u32 nodes, u32 *p)
-{
- int i;
-
- for(i=0;i<nodes; i++) {
- sysconf.msr_pstate[i*5+p[i]].hi &= ~(1<<(63-32));
- }
-}
-
-
-static void match_pstate(u32 nodes, u32 *p)
-{
- int i;
- u32 corecof_min, pwrvalue_max, pwrval_max;
- u32 enable;
- enable = (sysconf.msr_pstate[0*5+p[0]].hi >> 31);
- if(!enable) {
- disable_pstate(nodes, p);
- return;
- }
- corecof_min = ((sysconf.msr_pstate[0*5+p[0]].lo & 0x3f) + 0x10)>>((sysconf.msr_pstate[0*5+p[0]].lo>>6) & 7);
- pwrval_max = sysconf.msr_pstate[0*5+p[0]].hi & 0x3ff;
- pwrvalue_max = get_pwrvalue(pwrval_max);
-
- for(i=1; i<nodes; i++) {
- enable = (sysconf.msr_pstate[0*5+p[i]].hi >> 31);
- if(!enable) {
- disable_pstate(nodes, p);
- return;
- }
-
- u32 coredid = ((sysconf.msr_pstate[i*5+p[i]].lo>>6) & 7);
- u32 corecof = ((sysconf.msr_pstate[i*5+p[i]].lo & 0x3f) + 0x10)>>coredid;
- if(corecof<corecof_min) corecof_min = corecof;
- u32 pwrval, pwrvalue;
- pwrval = sysconf.msr_pstate[i*5+p[i]].hi & 0x3ff;
- pwrvalue = get_pwrvalue(pwrval);
- if(pwrvalue>pwrvalue_max) {
- pwrvalue_max = pwrvalue;
- pwrval_max = pwrval;
- }
- }
-
- for(i=0; i<nodes; i++) {
- u32 coredid = ((sysconf.msr_pstate[i*5+p[i]].lo>>6) & 7);
- u32 corefid = (corecof_min<<coredid);
- while(corefid<0x10) {
- coredid++;
- corefid = (corecof_min<<coredid);
- }
- sysconf.msr_pstate[i*5+p[i]].lo &= ~(0x1ff);
- sysconf.msr_pstate[i*5+p[i]].lo |= (corefid - 0x10) | (coredid << 6);
- sysconf.msr_pstate[i*5+p[i]].hi &= ~(0x3ff);
- sysconf.msr_pstate[i*5+p[i]].hi |= pwrval_max;
- }
-}
-
-
-static void match_pstates(u32 nodes, u32 *p, u32 *px)
-{
- int i;
- int j;
- u32 p_int[NODE_NUMS];
-
- int jj=1;
- u32 end = 0;
- for(i=0;i<nodes; i++) {
- p_int[i] = px[i];
- }
- while(1){
- for(i=0;i<nodes; i++) {
- if(px[i]<=(p[i]+jj)) {
- end = 1;
- break;
- }
- }
- if(!end) {
- for(i=0; i<nodes; i++) {
- p_int[i] = px[i] - jj;
- }
- match_pstate(nodes, p_int);
- dump_p("P int\n", nodes, p_int);
- jj++;
- }
- else {
- for(i=0;i<nodes; i++) {
- for(j=p[i]+1; j<p_int[i]; j++) {
- sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
- }
- }
- break;
- }
- }
-}
-
-
-void prep_pstates_all(void)
-{
- device_t f3_dev[NODE_NUMS], f4_dev[NODE_NUMS];
- u32 p[NODE_NUMS];
- u32 p_htc[NODE_NUMS];
- u32 p_lowest[NODE_NUMS];
- u32 htc_cap = 1;
- u32 lowest_htc_equal = 0;
-
- u32 nodes = sysconf.nodes;
- int i;
- int j;
- u32 val;
- u32 nbdid;
- u32 nbvid0;
- u32 nbvid1;
-
- for(i=0;i<nodes; i++) { // get the value from F4x1F0:E0 or we can get that msr in CAR stage...
- f3_dev[i] = get_node_pci(i, 3);
- f4_dev[i] = get_node_pci(i, 4);
- }
-
- for(i=0;i<nodes; i++) { // get the value from F4x1F0:E0 or we can get that msr in CAR stage...
- val = pci_read_config32(f4_dev[i], 0x1f4);
- nbvid0 = val & 0x3f;
- nbvid1 = (val>>7) & 0x3f;
- for(j=0; j<5; j++) {
- val = pci_read_config32(f4_dev[i], 0x1e0 + (j<<2));
- nbdid = ((val>>16) & 1);
- sysconf.msr_pstate[i*5+j].lo = (val & 0xffff) | (nbdid<<22) | ((nbdid?nbvid1:nbvid0)<<25);
- sysconf.msr_pstate[i*5+j].hi = (((val>>17) & 0x3ff) << (32-32)) | (((val>>27) & 1)<<(63-32));
- }
- }
-
- dump_msr_pstates(nodes);
-
- sysconf.needs_update_pstate_msrs = 0; // normal case for all sockets are installed same conf CPU
-
- for(i=1; (i<nodes) && (!sysconf.needs_update_pstate_msrs); i++) {
- for(j=0; j<5; j++) {
- if((sysconf.msr_pstate[i*5+j].lo != sysconf.msr_pstate[0*5+j].lo) || (sysconf.msr_pstate[i*5+j].hi != sysconf.msr_pstate[0*5+j].hi)) {
- sysconf.needs_update_pstate_msrs = 1;
- break;
- }
- }
- }
-
- if(sysconf.needs_update_pstate_msrs) {
-
- // update msr_pstate for mixed conf
-
- //P0
- /* Match P0 cpu cof for all cpu cores to the lowest P0 cpu cof value in the coherent fabric, and match P0 power for all cpu cores to the highest P0 power value */
- for(i=0;i<nodes; i++) p[i] = 0;
- match_pstate(nodes, p);
- dump_p("P0\n", nodes, p);
- dump_msr_pstates(nodes);
-
-
- //p_htc
- for(i=0;i<nodes; i++) {
- val = pci_read_config32(f3_dev[i], 0xe8); //htc cap
- if(!(val & (1<<10))) {
- htc_cap = 0;
- break;
- }
-
- //HtcPstateLimit
- val = pci_read_config32(f3_dev[i], 0x64);
- p_htc[i] = (((val>>28) & 7));
- if(p_htc[i] == 0) {
- val |= 1<<28;
- pci_write_config32(f3_dev[i], 0x64, val);
- val = pci_read_config32(f3_dev[i], 0x68); //stc
- val &= ~(7<<28);
- val |= (1<<28);
- pci_write_config32(f3_dev[i], 0x68, val);
-
- p_htc[i] = 1;
- }
- }
- if(htc_cap) {
- match_pstate(nodes, p_htc);
-
- dump_p("P_htc\n", nodes, p_htc);
- dump_msr_pstates(nodes);
- }
-
- //p_lowest
- for(i=0;i<nodes; i++) {
- p_lowest[i] = 0;
- for(j=1; j<5; j++) {
- if(sysconf.msr_pstate[i*5+j].hi & (1<<(63-32))) {
- p_lowest[i] = j;
- }
- }
- // PstateMaxVal
- val = pci_read_config32(f3_dev[i], 0xdc);
- if(p_lowest[i]>((val>>8) & 7)) {
- val &= ~(7<<8);
- val |= (p_lowest[i])<<8;
- pci_write_config32(f3_dev[i], 0xdc, val);
- }
- else {
- p_lowest[i] = (val>>8) & 7;
- }
- }
- if(htc_cap) {
- for(i=0;i<nodes; i++) {
- if(p_lowest[i]==p_htc[i]){
- lowest_htc_equal = 1;
- break;
- }
- }
- }
- if(lowest_htc_equal) {
- for(i=0;i<nodes; i++) {
- // PstateMaxVal
- val = pci_read_config32(f3_dev[i], 0xdc);
- val &= ~(7<<8);
- val |= p_htc[i];
- pci_write_config32(f3_dev[i], 0xdc, val);
- for(j=p_htc[i]+1; j<5; j++) {
- sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
- }
- }
- } else {
- match_pstate(nodes, p_lowest);
- for(i=0; i<nodes; i++) {
- for(j=p_lowest[i]+1; j<5; j++) {
- sysconf.msr_pstate[i*5+j].hi &= ~(1<<(63-32));
- }
- }
-
- }
-
- dump_p("Px\n", nodes, p_lowest);
- dump_msr_pstates(nodes);
-
-
- if(htc_cap) {
- //p_up_int
- match_pstates(nodes, p, p_htc);
-
- dump_msr_pstates(nodes);
-
- //p_lower_int
- match_pstates(nodes, p_htc, p_lowest);
- } else {
- match_pstates(nodes, p, p_lowest);
- }
-
- dump_msr_pstates(nodes);
-
- }
-
- // fill data into p_state
- for(i=0; i<nodes; i++) {
- sysconf.p_state_num = 0;
- u32 corefid_equal = 1;
- u32 corefid;
- corefid = (sysconf.msr_pstate[i*5+0].lo & 0x3f);
- for(j=1; j<5; j++) {
- msr_t *msr_pstate;
- msr_pstate = &(sysconf.msr_pstate[i*5+j]);
- if(!(msr_pstate->hi & (1<<(63-32)) )) continue;
- if((msr_pstate->lo & 0x3f) != corefid) {
- corefid_equal = 0;
- break;
- }
- }
- for(j=0; j<5; j++) {
- struct p_state_t *p_state;
- msr_t *msr_pstate;
- msr_pstate = &sysconf.msr_pstate[i*5+j];
- if(!(msr_pstate->hi & (1<<(63-32)) )) continue;
- p_state = &sysconf.p_state[i*5+sysconf.p_state_num];
- u32 coredid = ((msr_pstate->lo>>6) & 7);
- u32 corecof = ((msr_pstate->lo & 0x3f) + 0x10)>>coredid;
- p_state->corefreq = corecof;
-
- u32 pwrval, pwrvalue;
- pwrval = msr_pstate->hi & 0x3ff;
- pwrvalue = get_pwrvalue(pwrval);
- p_state->power = pwrvalue;
-
- u32 lat;
- val = pci_read_config32(f3_dev[i], 0xd4);
- lat = 15 * (get_powerstep((val>>24)& 0xf)+get_powerstep((val>>20)& 0xf)) /1000;
- if(!corefid_equal) {
- val = pci_read_config32(f3_dev[i], 0xa0);
- lat += get_plllocktime((val >> 11 ) & 7);
- }
- p_state->transition_lat = lat;
- p_state->busmaster_lat = lat;
-
- p_state->control = j;
- p_state->status = j;
-
- sysconf.p_state_num++;
- }
- // don't need look at other nodes
- if(!sysconf.p_state_num) break;
- }
-}
-
-
-//it will update pstates info from ram into MSR
-void init_pstates(device_t dev, u32 nodeid, u32 coreid)
-{
- int j;
- msr_t msr;
-
- if(sysconf.needs_update_pstate_msrs) {
- for(j=0; j < 5; j++) {
- wrmsr(0xC0010064 + j, sysconf.msr_pstate[nodeid * 5 + j]);
- }
- }
-
- /* Set TSC Freq Select: TSC increments at the rate of the core P-state 0 */
- msr = rdmsr(0xC0010015);
- msr.lo |= 1 << 24;
- wrmsr(0xC0010015, msr);
-
- // Enter the state P0
- //FIXME I don't think that this works correctly. May depend on early fid/vid setup.
- if(sysconf.p_state_num)
- set_core_nb_max_pstate_after_other_warm_reset(nodeid, coreid);
-
-}