This patch adds support for the AMD LX cpu.

There is one global change to pci_ids.h. The rest are changes for LX. I
ran abuild and it is ok.  Not all artec design changes are included as
some of them would adversely affect other mainboards. Indrek will need
to test.


Signed-off-by: Ron Minnich
Signed-off-by: Indrek Kruusa, indrek.kruusa@artecdesign.ee, artec
design. 


git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2350 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Ron Minnich 2006-07-28 16:06:16 +00:00 committed by Ronald G. Minnich
parent e534daa05a
commit 5e9dc23120
29 changed files with 5512 additions and 0 deletions

View File

@ -0,0 +1,8 @@
dir /cpu/x86/tsc
dir /cpu/x86/fpu
dir /cpu/x86/mmx
dir /cpu/x86/lapic
dir /cpu/x86/cache
driver model_lx_init.o
object cpubug.o
object vsmsetup.o

View File

@ -0,0 +1,391 @@
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include <cpu/amd/lxdef.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/cache.h>
#if 0
void
bug645(void){
msr_t msr;
rdmsr(CPU_ID_CONFIG);
msr.whatever |= ID_CONFIG_SERIAL_SET;
wrmsr(msr);
}
void
bug573(void){
msr_t msr;
msr = rdmsr(MC_GLD_MSR_PM);
msr.eax &= 0xfff3;
wrmsr(MC_GLD_MSR_PM);
}
#endif
/**************************************************************************
*
* pcideadlock
*
* Bugtool #465 and #609
* PCI cache deadlock
* There is also fix code in cache and PCI functions. This bug is very is pervasive.
*
* Entry:
* Exit:
* Modified:
*
**************************************************************************/
static void
pcideadlock(void)
{
msr_t msr;
/*
* forces serialization of all load misses. Setting this bit prevents the
* DM pipe from backing up if a read request has to be held up waiting
* for PCI writes to complete.
*/
msr = rdmsr(CPU_DM_CONFIG0);
msr.hi &= ~(7<<DM_CONFIG0_UPPER_WSREQ_SHIFT);
msr.hi |= (2<<DM_CONFIG0_UPPER_WSREQ_SHIFT);
msr.lo |= DM_CONFIG0_LOWER_MISSER_SET;
wrmsr(CPU_DM_CONFIG0, msr);
/* interlock instruction fetches to WS regions with data accesses.
* This prevents an instruction fetch from going out to PCI if the
* data side is about to make a request.
*/
msr = rdmsr(CPU_IM_CONFIG);
msr.lo |= IM_CONFIG_LOWER_QWT_SET;
wrmsr(CPU_IM_CONFIG, msr);
/* write serialize memory hole to PCI. Need to unWS when something is
* shadowed regardless of cachablility.
*/
msr.lo = 0x021212121;
msr.hi = 0x021212121;
wrmsr( CPU_RCONF_A0_BF, msr);
wrmsr( CPU_RCONF_C0_DF, msr);
wrmsr( CPU_RCONF_E0_FF, msr);
}
/****************************************************************************
*
* CPUbug784
*
* Bugtool #784 + #792
*
* Fix CPUID instructions for < 3.0 CPUs
*
* Entry:
* Exit:
* Modified:
*
****************************************************************************/
void bug784(void)
{
msr_t msr;
//static char *name = "Geode by NSC";
/* we'll do this the stupid way, for now, but that's the string they want. NO ONE KNOWS why you
* would do this -- the OS can figure this type of stuff out!
*/
msr = rdmsr(0x3006);
msr.hi = 0x646f6547;
wrmsr(0x3006, msr);
msr = rdmsr(0x3007);
msr.hi = 0x79622065;
msr.lo = 0x43534e20;
wrmsr(0x3007, msr);
msr = rdmsr(0x3002);
wrmsr(0x3008, msr);
/* More CPUID to match AMD better. #792*/
msr = rdmsr(0x3009);
msr.hi = 0x0C0C0A13D;
msr.lo = 0x00000000;
wrmsr(0x3009, msr);
}
/* cpubug 1398: enable MC if we KNOW we have DDR*/
/**************************************************************************
*
* CPUbugIAENG1398
*
* ClearQuest #IAENG1398
* The MC can not be enabled with SDR memory but can for DDR. Enable for
* DDR here if the setup token is "Default"
* Add this back to core by default once 2.0 CPUs are not supported.
* Entry:
* Exit:
* Modified:
*
**************************************************************************/
void eng1398(void)
{
msr_t msr;
msr = rdmsr(MSR_GLCP+0x17);
if ((msr.lo & 0xff) <= CPU_REV_2_0) {
msr = rdmsr(GLCP_SYS_RSTPLL);
if (msr.lo & (1<<RSTPPL_LOWER_SDRMODE_SHIFT))
return;
}
/* no CMOS/NVRAM to check, so enable MC Clock Gating */
msr = rdmsr(MC_GLD_MSR_PM);
msr.lo |= 3; /* enable MC clock gating.*/
wrmsr(MC_GLD_MSR_PM, msr);
}
/***************************************************************************
*
* CPUbugIAENG2900
*
* Clear Quest IAENG00002900, VSS 118.150
*
* BTB issue causes blue screen in windows, but the fix is required
* for all operating systems.
*
* Entry:
* Exit:
* Modified:
*
**************************************************************************/
void
eng2900(void)
{
msr_t msr;
printk_debug("CPU_BUG:%s\n", __FUNCTION__);
/* Clear bit 43, disables the sysenter/sysexit in CPUID3 */
msr = rdmsr(0x3003);
msr.hi &= 0xFFFFF7FF;
wrmsr(0x3003, msr);
/* change this value to zero if you need to disable this BTB SWAPSiF. */
if (1) {
/* Disable enable_actions in DIAGCTL while setting up GLCP */
msr.hi = 0;
msr.lo = 0;
wrmsr(MSR_GLCP + 0x005f, msr);
/* Changing DBGCLKCTL register to GeodeLink */
msr.hi = 0;
msr.lo = 0;
wrmsr(MSR_GLCP + 0x0016, msr);
msr.hi = 0;
msr.lo = 2;
wrmsr(MSR_GLCP + 0x0016, msr);
/* The code below sets up the CPU to stall for 4 GeodeLink
* clocks when CPU is snooped. Because setting XSTATE to 0
* overrides any other XSTATE action, the code will always
* stall for 4 GeodeLink clocks after a snoop request goes
* away even if it occured a clock or two later than a
* different snoop; the stall signal will never 'glitch high'
* for only one or two CPU clocks with this code.
*/
/* Send mb0 port 3 requests to upper GeodeLink diag bits
[63:32] */
msr.hi = 0;
msr.lo = 0x80338041;
wrmsr(MSR_GLIU0 + 0x2005, msr);
/* set5m watches request ready from mb0 to CPU (snoop) */
msr.hi = 0x5ad68000;
msr.lo = 0;
wrmsr(MSR_GLCP + 0x0045, msr);
/* SET4M will be high when state is idle (XSTATE=11) */
msr.hi = 0;
msr.lo = 0x0140;
wrmsr(MSR_GLCP + 0x0044, msr);
/* SET5n to watch for processor stalled state */
msr.hi = 0x2000;
msr.lo = 0;
wrmsr(MSR_GLCP + 0x004D, msr);
/* Writing action number 13: XSTATE=0 to occur when CPU is
snooped unless we're stalled */
msr.hi = 0;
msr.lo = 0x00400000;
wrmsr(MSR_GLCP + 0x0075, msr);
/* Writing action number 11: inc XSTATE every GeodeLink clock
unless we're idle */
msr.hi = 0;
msr.lo = 0x30000;
wrmsr(MSR_GLCP + 0x0073, msr);
/* Writing action number 5: STALL_CPU_PIPE when exitting idle
state or not in idle state */
msr.hi = 0;
msr.lo = 0x00430000;
wrmsr(MSR_GLCP + 0x006D, msr);
/* Writing DIAGCTL Register to enable the stall action and to
let set5m watch the upper GeodeLink diag bits. */
msr.hi = 0;
msr.lo = 0x80004000;
wrmsr(MSR_GLCP + 0x005f, msr);
}
}
void bug118253(void)
{
/* GLPCI PIO Post Control shouldn't be enabled */
msr_t msr;
msr = rdmsr(GLPCI_SPARE);
msr.lo &= ~GLPCI_SPARE_LOWER_PPC_SET;
wrmsr(GLPCI_SPARE, msr);
}
void bug118339(void)
{
/* per AMD, do this always */
msr_t msr = {0,0};
int msrnum;
/* Disable enable_actions in DIAGCTL while setting up GLCP */
wrmsr(MSR_GLCP + 0x005f, msr);
/* SET2M fires if VG pri is odd (3, not 2) and Ystate=0 */
msrnum = MSR_GLCP + 0x042;
/* msr.hi = 2d6b8000h */;
msr.hi = 0x596b8000;
msr.lo = 0x00000a00;
wrmsr(msrnum, msr);
/* SET3M fires if MBUS changed and VG pri is odd */
msrnum = MSR_GLCP + 0x043;
msr.hi = 0x596b8040;
msr.lo = 0;
wrmsr(msrnum, msr);
/* Put VG request data on lower diag bus */
msrnum = MSR_GLIU0 + 0x2005;
msr.hi = 0;
msr.lo = 0x80338041;
wrmsr(msrnum, msr);
/* Increment Y state if SET3M if true */
msrnum = MSR_GLCP + 0x074;
msr.hi = 0;
msr.lo = 0x0000c000;
wrmsr(msrnum, msr);
/* Set up MBUS action to PRI=3 read of MBIU */
msrnum = MSR_GLCP + 0x020;
msr.hi = 0x0000d863;
msr.lo = 0x20002000;
wrmsr(msrnum, msr);
/* Trigger MBUS action if VG=pri3 and Y=0, this blocks most PCI */
msrnum = MSR_GLCP + 0x071;
msr.hi = 0;
msr.lo = 0x00000c00;
wrmsr(msrnum, msr);
/* Writing DIAGCTL */
msrnum = MSR_GLCP + 0x005f;
msr.hi = 0;
msr.lo = 0x80004000;
wrmsr(msrnum, msr);
/* Code to enable FS2 even when BTB and VGTEAR SWAPSiFs are enabled */
/* As per Todd Roberts in PBz1094 and PBz1095 */
/* Moved from CPUREG to CPUBUG per Tom Sylla */
msrnum = 0x04C000042; /* GLCP SETMCTL Register */;
msr = rdmsr(msrnum);
msr.hi |= 8; /* Bit 35 = MCP_IN */
wrmsr(msrnum, msr);
}
/****************************************************************************/
/***/
/** DisableMemoryReorder*/
/***/
/** PBZ 3659:*/
/** The MC reordered transactions incorrectly and breaks coherency.*/
/** Disable reording and take a potential performance hit.*/
/** This is safe to do here and not in MC init since there is nothing*/
/** to maintain coherency with and the cache is not enabled yet.*/
/***/
/***/
/** Entry:*/
/** Exit:*/
/** Modified:*/
/***/
/****************************************************************************/
void disablememoryreadorder(void)
{
msr_t msr;
msr = rdmsr(MC_CF8F_DATA);
msr.hi |= CF8F_UPPER_REORDER_DIS_SET;
wrmsr(MC_CF8F_DATA, msr);
}
void
cpubug(void)
{
msr_t msr;
int rev;
#if 0 //GX3
msr = rdmsr(GLCP_CHIP_REVID);
rev = msr.lo & 0xff;
if (rev < 0x20) {
printk_err("%s: rev < 0x20! bailing!\n");
return;
}
printk_debug("Doing cpubug fixes for rev 0x%x\n", rev);
switch(rev)
{
case 0x20:
pcideadlock();
eng1398();
/* cs 5530 bug; ignore
bug752();
*/
break;
case 0x21:
pcideadlock();
eng1398();
eng2900();
bug118339();
break;
case 0x22:
case 0x30:
break;
default:
printk_err("unknown rev %x, bailing\n", rev);
return;
}
bug784();
bug118253();
disablememoryreadorder();
printk_debug("Done cpubug fixes \n");
#endif
}

View File

@ -0,0 +1,251 @@
/* ***************************************************************************/
/* **/
/* * BIST */
/* **/
/* * GX2 BISTs need to be run before BTB or caches are enabled.*/
/* * BIST result left in registers on failure to be checked with FS2.*/
/* **/
/* ***************************************************************************/
static void
BIST(void){
int msrnum;
msr_t msr;
/* DM*/
msrnum = CPU_DM_CONFIG0;
msr = rdmsr(msrnum);
msr.lo |= DM_CONFIG0_LOWER_DCDIS_SET;
wrmsr(msrnum, msr);
msr.lo = 0x00000003F;
msr.hi = 0x000000000;
msrnum = CPU_DM_BIST;
wrmsr(msrnum, msr);
outb(POST_CPU_DM_BIST_FAILURE, 0x80); /* 0x29*/
msr = rdmsr(msrnum); /* read back for pass fail*/
msr.lo &= 0x0F3FF0000;
if (msr.lo != 0xfeff0000)
goto BISTFail;
msrnum = CPU_DM_CONFIG0;
msr = rdmsr(msrnum);
msr.lo &= ~ DM_CONFIG0_LOWER_DCDIS_SET;
wrmsr(msrnum, msr);
/* FPU*/
msr.lo = 0x000000131;
msr.hi = 0;
msrnum = CPU_FP_UROM_BIST;
wrmsr(msrnum, msr);
outb(POST_CPU_FPU_BIST_FAILURE, 0x80); /* 0x89*/
inb(0x80); /* IO delay*/
msr = rdmsr(msrnum); /* read back for pass fail*/
while ((msr.lo&0x884) != 0x884)
msr = rdmsr(msrnum); /* Endless loop if BIST is broken*/
if ((msr.lo&0x642) != 0x642)
goto BISTFail;
msr.lo = msr.hi = 0; /* clear FPU BIST bits*/
msrnum = CPU_FP_UROM_BIST;
wrmsr(msrnum, msr);
/* BTB*/
msr.lo = 0x000000303;
msr.hi = 0x000000000;
msrnum = CPU_PF_BTBRMA_BIST;
wrmsr(msrnum, msr);
outb(POST_CPU_BTB_BIST_FAILURE , 0x80); /* 0x8A*/
msr = rdmsr(msrnum); /* read back for pass fail*/
if ((msr.lo & 0x3030) != 0x3030)
goto BISTFail;
return;
BISTFail:
print_err("BIST failed!\n");
while(1);
}
/* ***************************************************************************/
/* * cpuRegInit*/
/* ***************************************************************************/
void
cpuRegInit (void){
int msrnum;
msr_t msr;
//GX3 suspend: what is desired?
/* Enable Suspend on Halt*/
/*msrnum = CPU_XC_CONFIG;
msr = rdmsr(msrnum);
msr.lo |= XC_CONFIG_SUSP_ON_HLT;
wrmsr(msrnum, msr);*/
/* ENable SUSP and allow TSC to run in Suspend */
/* to keep speed detection happy*/
/*msrnum = CPU_BC_CONF_0;
msr = rdmsr(msrnum);
msr.lo |= TSC_SUSP_SET | SUSP_EN_SET;
wrmsr(msrnum, msr);*/
/* Setup throttling to proper mode if it is ever enabled.*/
msrnum = 0x04C00001E;
msr.hi = 0x000000000;
msr.lo = 0x00000603C;
wrmsr(msrnum, msr); // GX3 OK +/-
/* Only do this if we are building for 5535*/
/* */
/* FooGlue Setup*/
/* */
#if 0
/* Enable CIS mode B in FooGlue*/
msrnum = MSR_FG + 0x10;
msr = rdmsr(msrnum);
msr.lo &= ~3;
msr.lo |= 2; /* ModeB*/
wrmsr(msrnum, msr);
#endif
/* */
/* Disable DOT PLL. Graphics init will enable it if needed.*/
/* */
// GX3: Disable DOT PLL? No. Lets tick.
/* msrnum = GLCP_DOTPLL;
msr = rdmsr(msrnum);
msr.lo |= DOTPPL_LOWER_PD_SET;
wrmsr(msrnum, msr); */
/* */
/* Enable RSDC*/
/* */
msrnum = 0x1301 ;
msr = rdmsr(msrnum);
msr.lo |= 0x08;
wrmsr(msrnum, msr); //GX3 OK
/* */
/* BIST*/
/* */
/*if (getnvram( TOKEN_BIST_ENABLE) & == TVALUE_DISABLE) {*/
{
// BIST();
}
/* */
/* Enable BTB*/
/* */
/* I hate to put this check here but it doesn't really work in cpubug.asm*/
//GX3: BTB is enabled by default
/* msrnum = MSR_GLCP+0x17;
msr = rdmsr(msrnum);
if (msr.lo >= CPU_REV_2_1){
msrnum = CPU_PF_BTB_CONF;
msr = rdmsr(msrnum);
msr.lo |= BTB_ENABLE_SET | RETURN_STACK_ENABLE_SET;
wrmsr(msrnum, msr);
}
*/
/* */
/* FPU impercise exceptions bit*/
/* */
/*if (getnvram( TOKEN_FPU_IE_ENABLE) != TVALUE_DISABLE) {*/
// GX3: FPU impercise exceptions bit - what's that?
/* {
msrnum = CPU_FPU_MSR_MODE;
msr = rdmsr(msrnum);
msr.lo |= FPU_IE_SET;
wrmsr(msrnum, msr);
}
*/
#if 0
/* */
/* Cache Overides*/
/* */
/* This code disables the data cache. Don't execute this
* unless you're testing something.
*/
/* Allow NVRam to override DM Setup*/
/*if (getnvram( TOKEN_CACHE_DM_MODE) != 1) {*/
{
msrnum = CPU_DM_CONFIG0;
msr = rdmsr(msrnum);
msr.lo |= DM_CONFIG0_LOWER_DCDIS_SET;
wrmsr(msrnum, msr);
}
/* This code disables the instruction cache. Don't execute
* this unless you're testing something.
*/
/* Allow NVRam to override IM Setup*/
/*if (getnvram( TOKEN_CACHE_IM_MODE) ==1) {*/
{
msrnum = CPU_IM_CONFIG;
msr = rdmsr(msrnum);
msr.lo |= IM_CONFIG_LOWER_ICD_SET;
wrmsr(msrnum, msr);
}
#endif
}
/* ***************************************************************************/
/* **/
/* * MTestPinCheckBX*/
/* **/
/* * Set MTEST pins to expected values from OPTIONS.INC/NVRAM*/
/* * This version is called when there isn't a stack available*/
/* **/
/* ***************************************************************************/
static void
MTestPinCheckBX (void){
int msrnum;
msr_t msr;
/*if (getnvram( TOKEN_MTEST_ENABLE) ==TVALUE_DISABLE ) {*/
/* return ; */
/* } */
/* Turn on MTEST*/
msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum);
msr.hi |= CFCLK_UPPER_MTST_B2B_DIS_SET | CFCLK_UPPER_MTEST_EN_SET;
wrmsr(msrnum, msr);
msrnum = GLCP_SYS_RSTPLL /* Get SDR/DDR mode from GLCP*/;
msr = rdmsr(msrnum);
msr.lo >>= RSTPPL_LOWER_SDRMODE_SHIFT;
if (msr.lo & 1) {
msrnum = MC_CFCLK_DBUG; /* Turn on SDR MTEST stuff*/
msr = rdmsr(msrnum);
msr.lo |= CFCLK_LOWER_SDCLK_SET;
msr.hi |= CFCLK_UPPER_MTST_DQS_EN_SET;
wrmsr(msrnum, msr);
}
/* Lock the cache down here.*/
__asm__("wbinvd\n");
}

View File

@ -0,0 +1,47 @@
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <string.h>
#include <cpu/cpu.h>
#include <cpu/x86/lapic.h>
#include <cpu/x86/cache.h>
static void vsm_end_post_smi(void)
{
__asm__ volatile (
"push %ax\n"
"mov $0x5000, %ax\n"
".byte 0x0f, 0x38\n"
"pop %ax\n"
);
}
static void model_lx_init(device_t dev)
{
printk_debug("model_lx_init\n");
/* Turn on caching if we haven't already */
x86_enable_cache();
/* Enable the local cpu apics */
//setup_lapic();
vsm_end_post_smi();
printk_debug("model_lx_init DONE\n");
};
static struct device_operations cpu_dev_ops = {
.init = model_lx_init,
};
static struct cpu_device_id cpu_table[] = {
{ X86_VENDOR_AMD, 0x05A2 },
{ 0, 0 },
};
static struct cpu_driver driver __cpu_driver = {
.ops = &cpu_dev_ops,
.id_table = cpu_table,
};

View File

@ -0,0 +1,22 @@
/* ***************************************************************************/
/* **/
/* * StartTimer1*/
/* **/
/* * Entry: none*/
/* * Exit: Starts Timer 1 for port 61 use*/
/* * Destroys: Al,*/
/* **/
/* ***************************************************************************/
void
StartTimer1(void){
outb(0x56, 0x43);
outb(0x12, 0x41);
}
void
SystemPreInit(void){
/* they want a jump ... */
__asm__("jmp .+2\ninvd\njmp.+2\n");
StartTimer1();
}

View File

@ -0,0 +1,855 @@
#include <console/console.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#undef __KERNEL__
#include <arch/io.h>
#include <string.h>
#include <cpu/amd/lxdef.h>
/* what a mess this uncompress thing is. I am not at all happy about how this
* was done, but can't fix it yet. RGM
*/
#warning "Fix the uncompress once linuxbios knows how to do it"
// This GETBIT is supposed to work on little endian
// 32bit systems. The algorithm will definitely need
// some fixing on other systems, but it might not be
// a problem since the nrv2b binary behaves the same..
#ifndef ENDIAN
#define ENDIAN 0
#endif
#ifndef BITSIZE
#define BITSIZE 32
#endif
#define GETBIT_8(bb, src, ilen) \
(((bb = bb & 0x7f ? bb*2 : ((unsigned)src[ilen++]*2+1)) >> 8) & 1)
#define GETBIT_LE16(bb, src, ilen) \
(bb*=2,bb&0xffff ? (bb>>16)&1 : (ilen+=2,((bb=(src[ilen-2]+src[ilen-1]*256u)*2+1)>>16)&1))
#define GETBIT_LE32(bb, src, ilen) \
(bc > 0 ? ((bb>>--bc)&1) : (bc=31,\
bb=*(const uint32_t *)((src)+ilen),ilen+=4,(bb>>31)&1))
#if ENDIAN == 0 && BITSIZE == 8
#define GETBIT(bb, src, ilen) GETBIT_8(bb, src, ilen)
#endif
#if ENDIAN == 0 && BITSIZE == 16
#define GETBIT(bb, src, ilen) GETBIT_LE16(bb, src, ilen)
#endif
#if ENDIAN == 0 && BITSIZE == 32
#define GETBIT(bb, src, ilen) GETBIT_LE32(bb, src, ilen)
#endif
static unsigned long unrv2b(uint8_t * src, uint8_t * dst)
{
unsigned long ilen = 0, olen = 0, last_m_off = 1;
uint32_t bb = 0;
unsigned bc = 0;
const uint8_t *m_pos;
unsigned long file_len = *(unsigned long *) src;
printk_debug("compressed file len is supposed to be %d bytes\n", file_len);
// skip length
src += 4;
/* FIXME: check olen with the length stored in first 4 bytes */
for (;;) {
unsigned int m_off, m_len;
while (GETBIT(bb, src, ilen)) {
dst[olen++] = src[ilen++];
}
m_off = 1;
do {
m_off = m_off * 2 + GETBIT(bb, src, ilen);
} while (!GETBIT(bb, src, ilen));
if (m_off == 2) {
m_off = last_m_off;
} else {
m_off = (m_off - 3) * 256 + src[ilen++];
if (m_off == 0xffffffffU)
break;
last_m_off = ++m_off;
}
m_len = GETBIT(bb, src, ilen);
m_len = m_len * 2 + GETBIT(bb, src, ilen);
if (m_len == 0) {
m_len++;
do {
m_len = m_len * 2 + GETBIT(bb, src, ilen);
} while (!GETBIT(bb, src, ilen));
m_len += 2;
}
m_len += (m_off > 0xd00);
m_pos = dst + olen - m_off;
dst[olen++] = *m_pos++;
do {
dst[olen++] = *m_pos++;
} while (--m_len > 0);
}
printk_debug("computed len is %d, file len is %d\n", olen, file_len);
return olen;
}
/* vsmsetup.c derived from vgabios.c. Derived from: */
/*------------------------------------------------------------ -*- C -*-
* 2 Kernel Monte a.k.a. Linux loading Linux on x86
*
* Erik Arjan Hendriks <hendriks@lanl.gov>
*
* This version is a derivative of the original two kernel monte
* which is (C) 2000 Scyld.
*
* Copyright (C) 2000 Scyld Computing Corporation
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Portions related to the alpha architecture are:
*
* Copyright(C) 2001 University of California. LA-CC Number 01-67.
* This software has been authored by an employee or employees of the
* University of California, operator of the Los Alamos National
* Laboratory under Contract No. W-7405-ENG-36 with the U.S.
* Department of Energy. The U.S. Government has rights to use,
* reproduce, and distribute this software. If the software is
* modified to produce derivative works, such modified software should
* be clearly marked, so as not to confuse it with the version
* available from LANL.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by
* reference to http://www.gnu.org/licenses/gpl.html.
*
* This software is provided by the author(s) "as is" and any express
* or implied warranties, including, but not limited to, the implied
* warranties of merchantability and fitness for a particular purpose
* are disclaimed. In no event shall the author(s) be liable for any
* direct, indirect, incidental, special, exemplary, or consequential
* damages (including, but not limited to, procurement of substitute
* goods or services; loss of use, data, or profits; or business
* interruption) however caused and on any theory of liability,
* whether in contract, strict liability, or tort (including
* negligence or otherwise) arising in any way out of the use of this
* software, even if advised of the possibility of such damage.
*
* $Id: Exp $
*--------------------------------------------------------------------*/
/* Modified to be a self sufficient plug in so that it can be used
without reliance on other parts of core Linuxbios
(C) 2005 Nick.Barker9@btinternet.com
Used initially for epia-m where there are problems getting the bios
emulator to successfully run this bios.
*/
/* Declare a temporary global descriptor table - necessary because the
Core part of the bios no longer sets up any 16 bit segments */
__asm__ (
/* pointer to original gdt */
"gdtarg: \n"
" .word gdt_limit \n"
" .long gdt \n"
/* compute the table limit */
"__mygdt_limit = __mygdt_end - __mygdt - 1 \n"
"__mygdtaddr: \n"
" .word __mygdt_limit \n"
" .long __mygdt \n"
"__mygdt: \n"
/* selgdt 0, unused */
" .word 0x0000, 0x0000 \n"
" .byte 0x00, 0x00, 0x00, 0x00 \n"
/* selgdt 8, unused */
" .word 0x0000, 0x0000 \n"
" .byte 0x00, 0x00, 0x00, 0x00 \n"
/* selgdt 0x10, flat code segment */
" .word 0xffff, 0x0000 \n"
" .byte 0x00, 0x9b, 0xcf, 0x00 \n"
/* selgdt 0x18, flat data segment */
" .word 0xffff, 0x0000 \n"
" .byte 0x00, 0x93, 0xcf, 0x00 \n"
/* selgdt 0x20, unused */
" .word 0x0000, 0x0000 \n"
" .byte 0x00, 0x00, 0x00, 0x00 \n"
/* selgdt 0x28 16-bit 64k code at 0x00000000 */
" .word 0xffff, 0x0000 \n"
" .byte 0, 0x9a, 0, 0 \n"
/* selgdt 0x30 16-bit 64k data at 0x00000000 */
" .word 0xffff, 0x0000 \n"
" .byte 0, 0x92, 0, 0 \n"
"__mygdt_end: \n"
);
/* Declare a pointer to where our idt is going to be i.e. at mem zero */
__asm__ ("__myidt: \n"
/* 16-bit limit */
" .word 1023 \n"
/* 24-bit base */
" .long 0 \n"
" .word 0 \n"
);
/* The address arguments to this function are PHYSICAL ADDRESSES */
static void real_mode_switch_call_vsm(unsigned long smm, unsigned long sysm)
{
__asm__ __volatile__ (
// paranoia -- does ecx get saved? not sure. This is
// the easiest safe thing to do.
" pushal \n"
/* save the stack */
" mov %esp, __stack \n"
" jmp 1f \n"
"__stack: .long 0 \n"
"1:\n"
/* get devfn into %ecx */
" movl %esp, %ebp \n"
#if 0
/* I'm not happy about that pushal followed by esp-relative references.
* just do hard-codes for now
*/
" movl 8(%ebp), %ecx \n"
" movl 12(%ebp), %edx \n"
#endif
" movl $0x10000026, %ecx \n"
" movl $0x10000028, %edx \n"
/* load 'our' gdt */
" lgdt %cs:__mygdtaddr \n"
/* This configures CS properly for real mode. */
" ljmp $0x28, $__rms_16bit\n"
"__rms_16bit: \n"
" .code16 \n"
/* 16 bit code from here on... */
/* Load the segment registers w/ properly configured segment
* descriptors. They will retain these configurations (limits,
* writability, etc.) once protected mode is turned off. */
" mov $0x30, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* Turn off protection (bit 0 in CR0) */
" movl %cr0, %eax \n"
" andl $0xFFFFFFFE, %eax \n"
" movl %eax, %cr0 \n"
/* Now really going into real mode */
" ljmp $0, $__rms_real\n"
"__rms_real: \n"
/* put the stack at the end of page zero.
* that way we can easily share it between real and protected,
* since the 16-bit ESP at segment 0 will work for any case. */
/* Setup a stack */
" mov $0x0, %ax \n"
" mov %ax, %ss \n"
" movl $0x1000, %eax \n"
" movl %eax, %esp \n"
/* Load our 16 it idt */
" xor %ax, %ax \n"
" mov %ax, %ds \n"
" lidt __myidt \n"
/* Dump zeros in the other segregs */
" mov %ax, %es \n"
/* FixMe: Big real mode for gs, fs? */
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov $0x40, %ax \n"
" mov %ax, %ds \n"
//" mov %cx, %ax \n"
" movl $0x10000026, %ecx \n"
" movl $0x10000028, %edx \n"
/* run VGA BIOS at 0x6000:0020 */
" lcall $0x6000, $0x0020\n"
/* if we got here, just about done.
* Need to get back to protected mode */
" movl %cr0, %eax \n"
" orl $0x0000001, %eax\n" /* PE = 1 */
" movl %eax, %cr0 \n"
/* Now that we are in protected mode jump to a 32 bit code segment. */
" data32 ljmp $0x10, $vsmrestart\n"
"vsmrestart:\n"
" .code32\n"
" movw $0x18, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* restore proper gdt and idt */
" lgdt %cs:gdtarg \n"
" lidt idtarg \n"
".globl vsm_exit \n"
"vsm_exit: \n"
" mov __stack, %esp \n"
" popal \n"
);
}
__asm__ (".text\n""real_mode_switch_end:\n");
extern char real_mode_switch_end[];
void do_vsmbios(void)
{
device_t dev;
unsigned long busdevfn;
unsigned int rom = 0;
unsigned char *buf;
unsigned int size = SMM_SIZE*1024;
int i;
printk_err("do_vsmbios\n");
/* clear vsm bios data area */
for (i = 0x400; i < 0x500; i++) {
*(unsigned char *) i = 0;
}
/* declare rom address here - keep any config data out of the way
* of core LXB stuff */
/* this is the base of rom on the GX2 at present. At some point, this has to be
* much better parameterized
*/
//rom = 0xfff80000;
//rom = 0xfffc0000;
/* the VSA starts at the base of rom - 64 */
//rom = ((unsigned long) 0) - (ROM_SIZE + 64*1024);
rom = 0xfffc0000;
buf = (unsigned char *) 0x60000;
unrv2b((uint8_t *)rom, buf);
printk_debug("buf %p *buf %d buf[256k] %d\n",
buf, buf[0], buf[SMM_SIZE*1024]);
printk_debug("buf[0x20] signature is %x:%x:%x:%x\n",
buf[0x20] ,buf[0x21] ,buf[0x22],buf[0x23]);
/* check for post code at start of vsainit.bin. If you don't see it,
don't bother. */
if ((buf[0x20] != 0xb0) || (buf[0x21] != 0x10) ||
(buf[0x22] != 0xe6) || (buf[0x23] != 0x80)) {
printk_err("do_vsmbios: no vsainit.bin signature, skipping!\n");
return;
}
//memcpy((void *) 0x60000, buf, size);
//for (i = 0; i < 0x800000; i++)
// outb(0xaa, 0x80);
/* ecx gets smm, edx gets sysm */
printk_err("Call real_mode_switch_call_vsm\n");
real_mode_switch_call_vsm(0x10000026, 0x10000028);
/* restart timer 1 */
outb(0x56, 0x43);
outb(0x12, 0x41);
}
// we had hoped to avoid this.
// this is a stub IDT only. It's main purpose is to ignore calls
// to the BIOS.
// no longer. Dammit. We have to respond to these.
struct realidt {
unsigned short offset, cs;
};
// from a handy writeup that andrey found.
// handler.
// There are some assumptions we can make here.
// First, the Top Of Stack (TOS) is located on the top of page zero.
// we can share this stack between real and protected mode.
// that simplifies a lot of things ...
// we'll just push all the registers on the stack as longwords,
// and pop to protected mode.
// second, since this only ever runs as part of linuxbios,
// we know all the segment register values -- so we don't save any.
// keep the handler that calls things small. It can do a call to
// more complex code in linuxbios itself. This helps a lot as we don't
// have to do address fixup in this little stub, and calls are absolute
// so the handler is relocatable.
void handler(void)
{
__asm__ __volatile__ (
" .code16 \n"
"idthandle: \n"
" pushal \n"
" movb $0, %al \n"
" ljmp $0, $callbiosint16\n"
"end_idthandle: \n"
" .code32 \n"
);
}
void debughandler(void)
{
__asm__ __volatile__ (
" .code16 \n"
"debughandle: \n"
" pushw %cx \n"
" movw $250, %cx \n"
"dbh1: \n"
" loop dbh1 \n"
" popw %cx \n"
" iret \n"
"end_debughandle: \n"
".code32 \n"
);
}
// Calling conventions. The first C function is called with this stuff
// on the stack. They look like value parameters, but note that if you
// modify them they will go back to the INTx function modified.
// the C function will call the biosint function with these as
// REFERENCE parameters. In this way, we can easily get
// returns back to the INTx caller (i.e. vgabios)
void callbiosint(void)
{
__asm__ __volatile__ (
" .code16 \n"
"callbiosint16: \n"
" push %ds \n"
" push %es \n"
" push %fs \n"
" push %gs \n"
// clean up the int #. To save space we put it in the lower
// byte. But the top 24 bits are junk.
" andl $0xff, %eax\n"
// this push does two things:
// - put the INT # on the stack as a parameter
// - provides us with a temp for the %cr0 mods.
" pushl %eax \n"
" movb $0xbb, %al\n"
" outb %al, $0x80\n"
" movl %cr0, %eax\n"
" orl $0x00000001, %eax\n" /* PE = 1 */
" movl %eax, %cr0\n"
/* Now that we are in protected mode jump to a 32 bit code segment. */
" data32 ljmp $0x10, $biosprotect\n"
"biosprotect: \n"
" .code32 \n"
" movw $0x18, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
" lidt idtarg \n"
" call biosint \n"
// back to real mode ...
" ljmp $0x28, $__rms_16bit2\n"
"__rms_16bit2: \n"
" .code16 \n"
/* 16 bit code from here on... */
/* Load the segment registers w/ properly configured segment
* descriptors. They will retain these configurations (limits,
* writability, etc.) once protected mode is turned off. */
" mov $0x30, %ax \n"
" mov %ax, %ds \n"
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov %ax, %ss \n"
/* Turn off protection (bit 0 in CR0) */
" movl %cr0, %eax \n"
" andl $0xFFFFFFFE, %eax \n"
" movl %eax, %cr0 \n"
/* Now really going into real mode */
" ljmp $0, $__rms_real2 \n"
"__rms_real2: \n"
/* Setup a stack
* FixME: where is esp? */
/* no need for a fix here. The esp is shared from 32-bit and 16-bit mode.
* you have to hack on the ss, but the esp remains the same across
* modes.
*/
" mov $0x0, %ax \n"
" mov %ax, %ss \n"
/* debugging for RGM */
" mov $0x11, %al \n"
" outb %al, $0x80 \n"
/* Load our 16 bit idt */
" xor %ax, %ax \n"
" mov %ax, %ds \n"
" lidt __myidt \n"
/* Dump zeros in the other segregs */
" mov %ax, %es \n"
" mov %ax, %fs \n"
" mov %ax, %gs \n"
" mov $0x40, %ax \n"
" mov %ax, %ds \n"
/* pop the INT # that you pushed earlier */
" popl %eax \n"
" pop %gs \n"
" pop %fs \n"
" pop %es \n"
" pop %ds \n"
" popal \n"
" iret \n"
" .code32 \n"
);
}
enum {
PCIBIOS = 0x1a,
MEMSIZE = 0x12
};
int pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
unsigned long *pecx, unsigned long *peax, unsigned long *pflags);
int handleint21(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
unsigned long *pecx, unsigned long *peax, unsigned long *pflags
);
int biosint(unsigned long intnumber,
unsigned long gsfs, unsigned long dses,
unsigned long edi, unsigned long esi,
unsigned long ebp, unsigned long esp,
unsigned long ebx, unsigned long edx,
unsigned long ecx, unsigned long eax,
unsigned long cs_ip, unsigned short stackflags)
{
unsigned long ip;
unsigned long cs;
unsigned long flags;
int ret = -1;
ip = cs_ip & 0xffff;
cs = cs_ip >> 16;
flags = stackflags;
printk_debug("biosint: INT# 0x%lx\n", intnumber);
printk_debug("biosint: eax 0x%lx ebx 0x%lx ecx 0x%lx edx 0x%lx\n",
eax, ebx, ecx, edx);
printk_debug("biosint: ebp 0x%lx esp 0x%lx edi 0x%lx esi 0x%lx\n",
ebp, esp, edi, esi);
printk_debug("biosint: ip 0x%x cs 0x%x flags 0x%x\n",
ip, cs, flags);
printk_debug("biosint: gs 0x%x fs 0x%x ds 0x%x es 0x%x\n",
gsfs >> 16, gsfs & 0xffff, dses >> 16, dses & 0xffff);
// cases in a good compiler are just as good as your own tables.
switch (intnumber) {
case 0 ... 15:
// These are not BIOS service, but the CPU-generated exceptions
printk_info("biosint: Oops, exception %u\n", intnumber);
if (esp < 0x1000) {
printk_debug("Stack contents: ");
while (esp < 0x1000) {
printk_debug("0x%04x ", *(unsigned short *) esp);
esp += 2;
}
printk_debug("\n");
}
printk_debug("biosint: Bailing out ... not now\n");
// "longjmp"
//vga_exit();
break;
case PCIBIOS:
ret = pcibios( &edi, &esi, &ebp, &esp,
&ebx, &edx, &ecx, &eax, &flags);
break;
case MEMSIZE:
// who cares.
eax = 64 * 1024;
ret = 0;
break;
case 0x15:
ret=handleint21( &edi, &esi, &ebp, &esp,
&ebx, &edx, &ecx, &eax, &flags);
break;
default:
printk_info("BIOSINT: Unsupport int #0x%x\n",
intnumber);
break;
}
if (ret)
flags |= 1; // carry flags
else
flags &= ~1;
stackflags = flags;
return ret;
}
void setup_realmode_idt(void)
{
extern unsigned char idthandle, end_idthandle;
extern unsigned char debughandle, end_debughandle;
int i;
struct realidt *idts = (struct realidt *) 0;
int codesize = &end_idthandle - &idthandle;
unsigned char *intbyte, *codeptr;
// for each int, we create a customized little handler
// that just pushes %ax, puts the int # in %al,
// then calls the common interrupt handler.
// this necessitated because intel didn't know much about
// architecture when they did the 8086 (it shows)
// (hmm do they know anymore even now :-)
// obviously you can see I don't really care about memory
// efficiency. If I did I would probe back through the stack
// and get it that way. But that's really disgusting.
for (i = 0; i < 256; i++) {
idts[i].cs = 0;
codeptr = (char*) 4096 + i * codesize;
idts[i].offset = (unsigned) codeptr;
memcpy(codeptr, &idthandle, codesize);
intbyte = codeptr + 3;
*intbyte = i;
}
// fixed entry points
// VGA BIOSes tend to hardcode f000:f065 as the previous handler of
// int10.
// calling convention here is the same as INTs, we can reuse
// the int entry code.
codeptr = (char*) 0xff065;
memcpy(codeptr, &idthandle, codesize);
intbyte = codeptr + 3;
*intbyte = 0x42; /* int42 is the relocated int10 */
/* debug handler - useful to set a programmable delay between instructions if the
TF bit is set upon call to real mode */
idts[1].cs = 0;
idts[1].offset = 16384;
memcpy(16384, &debughandle, &end_debughandle - &debughandle);
}
enum {
CHECK = 0xb001,
FINDDEV = 0xb102,
READCONFBYTE = 0xb108,
READCONFWORD = 0xb109,
READCONFDWORD = 0xb10a,
WRITECONFBYTE = 0xb10b,
WRITECONFWORD = 0xb10c,
WRITECONFDWORD = 0xb10d
};
// errors go in AH. Just set these up so that word assigns
// will work. KISS.
enum {
PCIBIOS_NODEV = 0x8600,
PCIBIOS_BADREG = 0x8700
};
int
pcibios(unsigned long *pedi, unsigned long *pesi, unsigned long *pebp,
unsigned long *pesp, unsigned long *pebx, unsigned long *pedx,
unsigned long *pecx, unsigned long *peax, unsigned long *pflags)
{
unsigned long edi = *pedi;
unsigned long esi = *pesi;
unsigned long ebp = *pebp;
unsigned long esp = *pesp;
unsigned long ebx = *pebx;
unsigned long edx = *pedx;
unsigned long ecx = *pecx;
unsigned long eax = *peax;
unsigned long flags = *pflags;
unsigned short func = (unsigned short) eax;
int retval = 0;
unsigned short devid, vendorid, devfn;
short devindex; /* Use short to get rid of gabage in upper half of 32-bit register */
unsigned char bus;
device_t dev;
switch(func) {
case CHECK:
*pedx = 0x4350;
*pecx = 0x2049;
retval = 0;
break;
case FINDDEV:
{
devid = *pecx;
vendorid = *pedx;
devindex = *pesi;
dev = 0;
while ((dev = dev_find_device(vendorid, devid, dev))) {
if (devindex <= 0)
break;
devindex--;
}
if (dev) {
unsigned short busdevfn;
*peax = 0;
// busnum is an unsigned char;
// devfn is an int, so we mask it off.
busdevfn = (dev->bus->secondary << 8)
| (dev->path.u.pci.devfn & 0xff);
printk_debug("0x%x: return 0x%x\n", func, busdevfn);
*pebx = busdevfn;
retval = 0;
} else {
*peax = PCIBIOS_NODEV;
retval = -1;
}
}
break;
case READCONFDWORD:
case READCONFWORD:
case READCONFBYTE:
case WRITECONFDWORD:
case WRITECONFWORD:
case WRITECONFBYTE:
{
unsigned long dword;
unsigned short word;
unsigned char byte;
unsigned char reg;
devfn = *pebx & 0xff;
bus = *pebx >> 8;
reg = *pedi;
dev = dev_find_slot(bus, devfn);
if (! dev) {
printk_debug("0x%x: BAD DEVICE bus %d devfn 0x%x\n", func, bus, devfn);
// idiots. the pcibios guys assumed you'd never pass a bad bus/devfn!
*peax = PCIBIOS_BADREG;
retval = -1;
}
switch(func) {
case READCONFBYTE:
byte = pci_read_config8(dev, reg);
*pecx = byte;
break;
case READCONFWORD:
word = pci_read_config16(dev, reg);
*pecx = word;
break;
case READCONFDWORD:
dword = pci_read_config32(dev, reg);
*pecx = dword;
break;
case WRITECONFBYTE:
byte = *pecx;
pci_write_config8(dev, reg, byte);
break;
case WRITECONFWORD:
word = *pecx;
pci_write_config16(dev, reg, word);
break;
case WRITECONFDWORD:
dword = *pecx;
pci_write_config32(dev, reg, dword);
break;
}
if (retval)
retval = PCIBIOS_BADREG;
printk_debug("0x%x: bus %d devfn 0x%x reg 0x%x val 0x%lx\n",
func, bus, devfn, reg, *pecx);
*peax = 0;
retval = 0;
}
break;
default:
printk_err("UNSUPPORTED PCIBIOS FUNCTION 0x%x\n", func);
break;
}
return retval;
}
int handleint21(unsigned long *edi, unsigned long *esi, unsigned long *ebp,
unsigned long *esp, unsigned long *ebx, unsigned long *edx,
unsigned long *ecx, unsigned long *eax, unsigned long *flags)
{
int res=-1;
printk_debug("handleint21, eax 0x%x\n", *eax);
switch(*eax&0xffff)
{
case 0x5f19:
break;
case 0x5f18:
*eax=0x5f;
*ebx=0x545; // MCLK = 133, 32M frame buffer, 256 M main memory
*ecx=0x060;
res=0;
break;
case 0x5f00:
*eax = 0x8600;
break;
case 0x5f01:
*eax = 0x5f;
*ecx = (*ecx & 0xffffff00 ) | 2; // panel type = 2 = 1024 * 768
res = 0;
break;
case 0x5f02:
*eax=0x5f;
*ebx= (*ebx & 0xffff0000) | 2;
*ecx= (*ecx & 0xffff0000) | 0x401; // PAL + crt only
*edx= (*edx & 0xffff0000) | 0; // TV Layout - default
res=0;
break;
case 0x5f0f:
*eax=0x860f;
break;
case 0xBEA7:
*eax=33;
break;
case 0xBEA4:
*eax=333;
break;
}
return res;
}

1136
src/include/cpu/amd/lxdef.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -399,6 +399,7 @@
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
#define PCI_DEVICE_ID_AMD_LX 0x1054
#define PCI_DEVICE_ID_AMD_SCSI 0x2020
#define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006
#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007

View File

@ -0,0 +1,158 @@
##
## Compute the location and size of where this firmware image
## (linuxBIOS plus bootloader) will live in the boot rom chip.
##
if USE_FALLBACK_IMAGE
default ROM_SECTION_SIZE = FALLBACK_SIZE
default ROM_SECTION_OFFSET = ( ROM_SIZE - FALLBACK_SIZE )
else
default ROM_SECTION_SIZE = ( ROM_SIZE - FALLBACK_SIZE )
default ROM_SECTION_OFFSET = 0
end
##
## Compute the start location and size size of
## The linuxBIOS bootloader.
##
default CONFIG_ROM_STREAM_START = (0xffffffff - ROM_SIZE + ROM_SECTION_OFFSET + 1)
default PAYLOAD_SIZE = ( ROM_SECTION_SIZE - ROM_IMAGE_SIZE )
##
## Compute where this copy of linuxBIOS will start in the boot rom
##
default _ROMBASE = ( CONFIG_ROM_STREAM_START + PAYLOAD_SIZE )
##
## Compute a range of ROM that can cached to speed up linuxBIOS,
## execution speed.
##
## XIP_ROM_SIZE must be a power of 2.
## XIP_ROM_BASE must be a multiple of XIP_ROM_SIZE
##
default XIP_ROM_SIZE=65536
default XIP_ROM_BASE = ( _ROMBASE + ROM_IMAGE_SIZE - XIP_ROM_SIZE )
##
## Set all of the defaults for an x86 architecture
##
arch i386 end
##
## Build the objects we have code for in this directory.
##
driver mainboard.o
if HAVE_PIRQ_TABLE object irq_tables.o end
#object reset.o
##
## Romcc output
##
makerule ./failover.E
depends "$(MAINBOARD)/failover.c ./romcc"
action "./romcc -E -O --label-prefix=failover -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/failover.c -o $@"
end
makerule ./failover.inc
depends "$(MAINBOARD)/failover.c ./romcc"
action "./romcc -O --label-prefix=failover -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/failover.c -o $@"
end
makerule ./auto.E
depends "$(MAINBOARD)/auto.c option_table.h ./romcc"
action "./romcc -E -mcpu=p2 -O -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/auto.c -o $@"
end
makerule ./auto.inc
depends "$(MAINBOARD)/auto.c option_table.h ./romcc"
action "./romcc -mcpu=p2 -O -I$(TOP)/src -I. $(CPPFLAGS) $(MAINBOARD)/auto.c -o $@"
end
##
## Build our 16 bit and 32 bit linuxBIOS entry code
##
mainboardinit cpu/x86/16bit/entry16.inc
mainboardinit cpu/x86/32bit/entry32.inc
ldscript /cpu/x86/16bit/entry16.lds
ldscript /cpu/x86/32bit/entry32.lds
##
## Build our reset vector (This is where linuxBIOS is entered)
##
if USE_FALLBACK_IMAGE
mainboardinit cpu/x86/16bit/reset16.inc
ldscript /cpu/x86/16bit/reset16.lds
else
mainboardinit cpu/x86/32bit/reset32.inc
ldscript /cpu/x86/32bit/reset32.lds
end
### Should this be in the northbridge code?
mainboardinit arch/i386/lib/cpu_reset.inc
##
## Include an id string (For safe flashing)
##
mainboardinit arch/i386/lib/id.inc
ldscript /arch/i386/lib/id.lds
###
### This is the early phase of linuxBIOS startup
### Things are delicate and we test to see if we should
### failover to another image.
###
if USE_FALLBACK_IMAGE
ldscript /arch/i386/lib/failover.lds
mainboardinit ./failover.inc
end
###
### O.k. We aren't just an intermediary anymore!
###
##
## Setup RAM
##
mainboardinit cpu/x86/fpu/enable_fpu.inc
mainboardinit ./auto.inc
##
## Include the secondary Configuration files
##
dir /pc80
config chip.h
chip northbridge/amd/lx
register "irqmap" = "0xcab9"
register "setupflash" = "0"
device apic_cluster 0 on
chip cpu/amd/model_lx
device apic 0 on end
end
end
device pci_domain 0 on
device pci 1.0 on end
device pci 1.1 on end
chip southbridge/amd/cs5536
register "enable_gpio0_inta" = "1"
register "enable_ide_nand_flash" = "1"
register "enable_uarta" = "1"
register "audio_irq" = "5"
register "usbf4_irq" = "10"
register "usbf5_irq" = "10"
register "usbf6_irq" = "0"
register "usbf7_irq" = "0"
device pci d.0 on end # Realtek 8139 LAN
device pci f.0 on end # ISA Bridge
device pci f.2 on end # IDE Controller
device pci f.3 on end # Audio
device pci f.4 on end # OHCI
device pci f.5 on end # EHCI
register "unwanted_vpci[0]" = "0x80007E00" # USB/UDC
register "unwanted_vpci[1]" = "0x80007F00" # USB/OTG
register "unwanted_vpci[2]" = "0" # End of list has a zero
end
end
end

View File

@ -0,0 +1,161 @@
uses HAVE_MP_TABLE
uses HAVE_PIRQ_TABLE
uses USE_FALLBACK_IMAGE
uses HAVE_FALLBACK_BOOT
uses HAVE_HARD_RESET
uses HAVE_OPTION_TABLE
uses USE_OPTION_TABLE
uses CONFIG_ROM_STREAM
uses IRQ_SLOT_COUNT
uses MAINBOARD
uses MAINBOARD_VENDOR
uses MAINBOARD_PART_NUMBER
uses LINUXBIOS_EXTRA_VERSION
uses ARCH
uses FALLBACK_SIZE
uses STACK_SIZE
uses HEAP_SIZE
uses ROM_SIZE
uses ROM_SECTION_SIZE
uses ROM_IMAGE_SIZE
uses ROM_SECTION_SIZE
uses ROM_SECTION_OFFSET
uses CONFIG_ROM_STREAM_START
uses CONFIG_COMPRESSED_ROM_STREAM
uses PAYLOAD_SIZE
uses _ROMBASE
uses _RAMBASE
uses XIP_ROM_SIZE
uses XIP_ROM_BASE
uses HAVE_MP_TABLE
uses CROSS_COMPILE
uses CC
uses HOSTCC
uses OBJCOPY
uses DEFAULT_CONSOLE_LOGLEVEL
uses MAXIMUM_CONSOLE_LOGLEVEL
uses CONFIG_CONSOLE_SERIAL8250
uses TTYS0_BAUD
uses TTYS0_BASE
uses TTYS0_LCS
uses CONFIG_UDELAY_TSC
uses CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2
## ROM_SIZE is the size of boot ROM that this board will use.
default ROM_SIZE = 256*1024
###
### Build options
###
##
## Build code for the fallback boot
##
default HAVE_FALLBACK_BOOT=1
##
## no MP table
##
default HAVE_MP_TABLE=0
##
## Build code to reset the motherboard from linuxBIOS
##
default HAVE_HARD_RESET=0
## Delay timer options
##
default CONFIG_UDELAY_TSC=1
default CONFIG_TSC_X86RDTSC_CALIBRATE_WITH_TIMER2=1
##
## Build code to export a programmable irq routing table
##
default HAVE_PIRQ_TABLE=1
default IRQ_SLOT_COUNT=2
#object irq_tables.o
##
## Build code to export a CMOS option table
##
default HAVE_OPTION_TABLE=0
###
### LinuxBIOS layout values
###
## ROM_IMAGE_SIZE is the amount of space to allow linuxBIOS to occupy.
default ROM_IMAGE_SIZE = 65536
default FALLBACK_SIZE = 131072
##
## Use a small 8K stack
##
default STACK_SIZE=0x2000
##
## Use a small 16K heap
##
default HEAP_SIZE=0x4000
##
## Only use the option table in a normal image
##
#default USE_OPTION_TABLE = !USE_FALLBACK_IMAGE
default USE_OPTION_TABLE = 0
default _RAMBASE = 0x00004000
default CONFIG_ROM_STREAM = 1
##
## The default compiler
##
default CROSS_COMPILE=""
default CC="$(CROSS_COMPILE)gcc-3.4 -m32"
default HOSTCC="gcc-3.4"
##
## The Serial Console
##
# To Enable the Serial Console
default CONFIG_CONSOLE_SERIAL8250=1
## Select the serial console baud rate
default TTYS0_BAUD=115200
#default TTYS0_BAUD=57600
#default TTYS0_BAUD=38400
#default TTYS0_BAUD=19200
#default TTYS0_BAUD=9600
#default TTYS0_BAUD=4800
#default TTYS0_BAUD=2400
#default TTYS0_BAUD=1200
# Select the serial console base port
default TTYS0_BASE=0x3f8
# Select the serial protocol
# This defaults to 8 data bits, 1 stop bit, and no parity
default TTYS0_LCS=0x3
##
### Select the linuxBIOS loglevel
##
## EMERG 1 system is unusable
## ALERT 2 action must be taken immediately
## CRIT 3 critical conditions
## ERR 4 error conditions
## WARNING 5 warning conditions
## NOTICE 6 normal but significant condition
## INFO 7 informational
## DEBUG 8 debug-level messages
## SPEW 9 Way too many details
## Request this level of debugging output
default DEFAULT_CONSOLE_LOGLEVEL=8
## At a maximum only compile in this level of debugging
default MAXIMUM_CONSOLE_LOGLEVEL=8
end

View File

@ -0,0 +1,193 @@
#define ASSEMBLY 1
#include <stdint.h>
#include <device/pci_def.h>
#include <arch/io.h>
#include <device/pnp_def.h>
#include <arch/romcc_io.h>
#include <arch/hlt.h>
#include "pc80/serial.c"
#include "arch/i386/lib/console.c"
#include "ram/ramtest.c"
//#include "superio/winbond/w83627hf/w83627hf_early_serial.c"
#include "cpu/x86/bist.h"
#include "cpu/x86/msr.h"
#include <cpu/amd/lxdef.h>
//#define SERIAL_DEV PNP_DEV(0x2e, W83627HF_SP1)
#include "southbridge/amd/cs5536/cs5536_early_smbus.c"
#include "southbridge/amd/cs5536/cs5536_early_setup.c"
static inline int spd_read_byte(unsigned device, unsigned address)
{
return smbus_read_byte(device, address);
}
#include "northbridge/amd/lx/raminit.h"
static inline unsigned int fls(unsigned int x)
{
int r;
__asm__("bsfl %1,%0\n\t"
"jnz 1f\n\t"
"movl $32,%0\n"
"1:" : "=r" (r) : "g" (x));
return r;
}
/* sdram parameters for OLPC:
row address = 13
col address = 9
banks = 4
dimm0size=128MB
d0_MB=1 (module banks)
d0_cb=4 (component banks)
do_psz=4KB (page size)
Trc=10 (clocks) (ref2act)
Tras=7 (act2pre)
Trcd=3 (act2cmd)
Trp=3 (pre2act)
Trrd=2 (act2act)
Tref=17.8ms
*/
static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
/* Total size of DIMM = 2^row address (byte 3) * 2^col address (byte 4) *
* component Banks (byte 17) * module banks, side (byte 5) *
* width in bits (byte 6,7)
* = Density per side (byte 31) * number of sides (byte 5) */
/* 1. Initialize GLMC registers base on SPD values, do one DIMM for now */
msr_t msr;
unsigned char module_banks, val;
#if 0 //GX3
msr = rdmsr(MC_CF07_DATA);
/* get module banks (sides) per dimm, SPD byte 5 */
module_banks = 1;
module_banks >>= 1;
msr.hi &= ~(1 << CF07_UPPER_D0_MB_SHIFT);
msr.hi |= (module_banks << CF07_UPPER_D0_MB_SHIFT);
/* get component banks per module bank, SPD byte 17 */
val = 4;
val >>= 2;
msr.hi &= ~(0x1 << CF07_UPPER_D0_CB_SHIFT);
msr.hi |= (val << CF07_UPPER_D0_CB_SHIFT);
/* get the module bank density, SPD byte 31 */
/* this is multiples of 8 MB */
/* actually it is 2^x*4, where x is the value you put in */
/* for OLPC, set default size */
/* dimm size - hardcoded 128Mb */
val = 5;
msr.hi &= ~(0xf << CF07_UPPER_D0_SZ_SHIFT);
msr.hi |= (val << CF07_UPPER_D0_SZ_SHIFT);
/* page size = 2^col address */
val = 2; /* 4096 bytes */
msr.hi &= ~(0x7 << CF07_UPPER_D0_PSZ_SHIFT);
msr.hi |= (val << CF07_UPPER_D0_PSZ_SHIFT);
print_debug("computed msr.hi ");
print_debug_hex32(msr.hi);
print_debug("\r\n");
/* this is a standard value, DOES NOT PROBABLY MATCH FROM ABOVE */
/* well, it may be close. It's about 200,000 ticks */
msr.lo = 0x00003000;
wrmsr(MC_CF07_DATA, msr);
#endif
msr.hi = 0x00005012;
msr.lo = 0x05000040;
wrmsr(MC_CF07_DATA, msr); //GX3
/* timing and mode ... */
//msr = rdmsr(0x20000019);
/* per standard bios settings */
/*
msr.hi = 0x18000108;
msr.lo =
(6<<28) | // cas_lat
(10<<24)| // ref2act
(7<<20)| // act2pre
(3<<16)| // pre2act
(3<<12)| // act2cmd
(2<<8)| // act2act
(2<<6)| // dplwr
(2<<4)| // dplrd
(3); // dal
* the msr value reported by quanta is very, very different.
* we will go with that value for now.
*
//msr.lo = 0x286332a3;
*/
//wrmsr(0x20000019, msr); //GX3
}
#include "northbridge/amd/lx/raminit.c"
#include "sdram/generic_sdram.c"
#define PLLMSRhi 0x00001490
#define PLLMSRlo 0x02000030
#define PLLMSRlo1 ((0xde << 16) | (1 << 26) | (1 << 24))
#define PLLMSRlo2 ((1<<14) |(1<<13) | (1<<0))
#include "northbridge/amd/lx/pll_reset.c"
#include "cpu/amd/model_lx/cpureginit.c"
#include "cpu/amd/model_lx/syspreinit.c"
static void msr_init(void)
{
__builtin_wrmsr(0x1808, 0x10f3bf00, 0x22fffc02);
__builtin_wrmsr(0x10000020, 0xfff80, 0x20000000);
__builtin_wrmsr(0x10000021, 0x80fffe0, 0x20000000);
__builtin_wrmsr(0x40000020, 0xfff80, 0x20000000);
__builtin_wrmsr(0x40000021, 0x80fffe0, 0x20000000);
}
static void main(unsigned long bist)
{
static const struct mem_controller memctrl [] = {
{.channel0 = {(0xa<<3)|0, (0xa<<3)|1}}
};
SystemPreInit(); //GX3 OK
msr_init(); //GX3 OK
cs5536_early_setup(); //GX3 OK
/* NOTE: must do this AFTER the early_setup!
* it is counting on some early MSR setup
* for cs5536
*/
cs5536_setup_onchipuart(); //GX3 OK
uart_init(); //GX3 OK
console_init(); //GX3 OK
pll_reset(); //GX3 OK
cpuRegInit(); //GX3 OK
print_err("done cpuRegInit\n");
sdram_initialize(1, memctrl); //GX3 OK almost
/* Check all of memory */
//ram_check(0x00000000, 640*1024);
}

View File

@ -0,0 +1,5 @@
extern struct chip_operations mainboard_artecgroup_dbe61_ops;
struct mainboard_artecgroup_dbe61_config {
int nothing;
};

View File

@ -0,0 +1,74 @@
entries
#start-bit length config config-ID name
#0 8 r 0 seconds
#8 8 r 0 alarm_seconds
#16 8 r 0 minutes
#24 8 r 0 alarm_minutes
#32 8 r 0 hours
#40 8 r 0 alarm_hours
#48 8 r 0 day_of_week
#56 8 r 0 day_of_month
#64 8 r 0 month
#72 8 r 0 year
#80 4 r 0 rate_select
#84 3 r 0 REF_Clock
#87 1 r 0 UIP
#88 1 r 0 auto_switch_DST
#89 1 r 0 24_hour_mode
#90 1 r 0 binary_values_enable
#91 1 r 0 square-wave_out_enable
#92 1 r 0 update_finished_enable
#93 1 r 0 alarm_interrupt_enable
#94 1 r 0 periodic_interrupt_enable
#95 1 r 0 disable_clock_updates
#96 288 r 0 temporary_filler
0 384 r 0 reserved_memory
384 1 e 4 boot_option
385 1 e 4 last_boot
386 1 e 1 ECC_memory
388 4 r 0 reboot_bits
392 3 e 5 baud_rate
400 1 e 1 power_on_after_fail
412 4 e 6 debug_level
416 4 e 7 boot_first
420 4 e 7 boot_second
424 4 e 7 boot_third
428 4 h 0 boot_index
432 8 h 0 boot_countdown
1008 16 h 0 check_sum
enumerations
#ID value text
1 0 Disable
1 1 Enable
2 0 Enable
2 1 Disable
4 0 Fallback
4 1 Normal
5 0 115200
5 1 57600
5 2 38400
5 3 19200
5 4 9600
5 5 4800
5 6 2400
5 7 1200
6 6 Notice
6 7 Info
6 8 Debug
6 9 Spew
7 0 Network
7 1 HDD
7 2 Floppy
7 8 Fallback_Network
7 9 Fallback_HDD
7 10 Fallback_Floppy
#7 3 ROM
checksums
checksum 392 1007 1008

View File

@ -0,0 +1,66 @@
static void print_debug_pci_dev(unsigned dev)
{
print_debug("PCI: ");
print_debug_hex8((dev >> 16) & 0xff);
print_debug_char(':');
print_debug_hex8((dev >> 11) & 0x1f);
print_debug_char('.');
print_debug_hex8((dev >> 8) & 7);
}
static void print_pci_devices(void)
{
device_t dev;
for(dev = PCI_DEV(0, 0, 0);
dev <= PCI_DEV(0, 0x1f, 0x7);
dev += PCI_DEV(0,0,1)) {
uint32_t id;
id = pci_read_config32(dev, PCI_VENDOR_ID);
if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
(((id >> 16) & 0xffff) == 0xffff) ||
(((id >> 16) & 0xffff) == 0x0000)) {
continue;
}
print_debug_pci_dev(dev);
print_debug("\r\n");
}
}
static void dump_pci_device(unsigned dev)
{
int i;
print_debug_pci_dev(dev);
print_debug("\r\n");
for(i = 0; i <= 255; i++) {
unsigned char val;
if ((i & 0x0f) == 0) {
print_debug_hex8(i);
print_debug_char(':');
}
val = pci_read_config8(dev, i);
print_debug_char(' ');
print_debug_hex8(val);
if ((i & 0x0f) == 0x0f) {
print_debug("\r\n");
}
}
}
static void dump_pci_devices(void)
{
device_t dev;
for(dev = PCI_DEV(0, 0, 0);
dev <= PCI_DEV(0, 0x1f, 0x7);
dev += PCI_DEV(0,0,1)) {
uint32_t id;
id = pci_read_config32(dev, PCI_VENDOR_ID);
if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
(((id >> 16) & 0xffff) == 0xffff) ||
(((id >> 16) & 0xffff) == 0x0000)) {
continue;
}
dump_pci_device(dev);
}
}

View File

@ -0,0 +1,32 @@
#define ASSEMBLY 1
#include <stdint.h>
#include <device/pci_def.h>
#include <device/pci_ids.h>
#include <arch/io.h>
#include "arch/romcc_io.h"
#include "pc80/mc146818rtc_early.c"
static unsigned long main(unsigned long bist)
{
/* This is the primary cpu how should I boot? */
if (do_normal_boot()) {
goto normal_image;
}
else {
goto fallback_image;
}
normal_image:
asm volatile ("jmp __normal_image"
: /* outputs */
: "a" (bist) /* inputs */
: /* clobbers */
);
cpu_reset:
asm volatile ("jmp __cpu_reset"
: /* outputs */
: "a"(bist) /* inputs */
: /* clobbers */
);
fallback_image:
return bist;
}

View File

@ -0,0 +1,31 @@
/* This file was generated by getpir.c, do not modify!
(but if you do, please run checkpir on it to verify)
* Contains the IRQ Routing Table dumped directly from your memory, which BIOS sets up
*
* Documentation at : http://www.microsoft.com/hwdev/busbios/PCIIRQ.HTM
*/
#include <arch/pirq_routing.h>
const struct irq_routing_table intel_irq_routing_table = {
PIRQ_SIGNATURE, /* u32 signature */
PIRQ_VERSION, /* u16 version */
32+16*2, /* there can be total 2 devices on the bus */
0x00, /* Where the interrupt router lies (bus) */
(0x12<<3)|0x0, /* Where the interrupt router lies (dev) */
0x800, /* IRQs devoted exclusively to PCI usage */
0x1078, /* Vendor */
0x2, /* Device */
0, /* Crap (miniport) */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* u8 rfu[11] */
0xdf, /* u8 checksum , this hase to set to some value that would give 0 after the sum of all bytes for this structure (including checksum) */
{
/* bus, dev|fn, {link, bitmap}, {link, bitmap}, {link, bitmap}, {link, bitmap}, slot, rfu */
{0x00,(0x0e<<3)|0x0, {{0x02, 0xdeb8}, {0x03, 0xdeb8}, {0x04, 0xdeb8}, {0x01, 0x0deb8}}, 0x1, 0x0},
{0x00,(0x0f<<3)|0x0, {{0x03, 0xdeb8}, {0x04, 0xdeb8}, {0x01, 0xdeb8}, {0x02, 0x0deb8}}, 0x2, 0x0},
}
};
unsigned long write_pirq_routing_table(unsigned long addr)
{
return copy_pirq_routing_table(addr);
}

View File

@ -0,0 +1,47 @@
#include <console/console.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#include <arch/io.h>
#include "chip.h"
static void init(struct device *dev) {
/*
unsigned bus = 0;
unsigned devfn = PCI_DEVFN(0xf, 4);
device_t usb = NULL;
unsigned char usbirq = 0xa;
*/
printk_debug("ARTECGROUP DBE61 ENTER %s\n", __FUNCTION__);
#if 0
/* I can't think of any reason NOT to just set this. If it turns out we want this to be
* conditional we can make it a config variable later.
*/
printk_debug("%s (%x,%x)SET USB PCI interrupt line to %d\n",
__FUNCTION__, bus, devfn, usbirq);
usb = dev_find_slot(bus, devfn);
if (! usb){
printk_err("Could not find USB\n");
} else {
pci_write_config8(usb, PCI_INTERRUPT_LINE, usbirq);
}
#endif
printk_debug("ARTECGROUP DBE61 EXIT %s\n", __FUNCTION__);
}
static void enable_dev(struct device *dev)
{
dev->ops->init = init;
}
struct chip_operations mainboard_artecgroup_dbe61_ops = {
CHIP_NAME("artecgroup dbe61 mainboard ")
.enable_dev = enable_dev,
};

View File

@ -0,0 +1,43 @@
#if 0
//#include "arch/romcc_io.h"
#include <arch/io.h>
typedef unsigned device_t;
#define PCI_DEV(BUS, DEV, FN) ( \
(((BUS) & 0xFF) << 16) | \
(((DEV) & 0x1f) << 11) | \
(((FN) & 0x7) << 8))
static void pci_write_config8(device_t dev, unsigned where, unsigned char value)
{
unsigned addr;
addr = dev | where;
outl(0x80000000 | (addr & ~3), 0xCF8);
outb(value, 0xCFC + (addr & 3));
}
static void pci_write_config32(device_t dev, unsigned where, unsigned value)
{
unsigned addr;
addr = dev | where;
outl(0x80000000 | (addr & ~3), 0xCF8);
outl(value, 0xCFC);
}
static unsigned pci_read_config32(device_t dev, unsigned where)
{
unsigned addr;
addr = dev | where;
outl(0x80000000 | (addr & ~3), 0xCF8);
return inl(0xCFC);
}
#include "../../../northbridge/amd/amdk8/reset_test.c"
void hard_reset(void)
{
set_bios_reset();
pci_write_config8(PCI_DEV(1, 0x04, 0), 0x47, 1);
}
#endif

View File

@ -0,0 +1,5 @@
config chip.h
object northbridge.o
object northbridgeinit.o
object chipsetinit.o
object grphinit.o

View File

@ -0,0 +1,7 @@
struct northbridge_amd_lx_config
{
uint16_t irqmap;
int setupflash;
};
extern struct chip_operations northbridge_amd_lx_ops;

View File

@ -0,0 +1,384 @@
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include "chip.h"
#include "northbridge.h"
#include <cpu/amd/lxdef.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/cache.h>
/* the structs in this file only set msr.lo. But ... that may not always be true */
struct msrinit {
unsigned long msrnum;
msr_t msr;
};
/* Master Configuration Register for Bus Masters.*/
struct msrinit SB_MASTER_CONF_TABLE[] = {
{USB1_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00008f000}}, /* NOTE: Must be 1st entry in table*/
{USB2_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00008f000}},
{ATA_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00048f000}},
{AC97_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00008f000}},
{MDD_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00000f000}},
/* GLPCI_SB_GLD_MSR_CONF, 0x0FFFFFFFF*/
/* GLCP_SB_GLD_MSR_CONF, 0x0FFFFFFFF*/
/* GLIU_SB_GLD_MSR_CONF, 0x0*/
{0,{0,0}}
};
/* 5535_A3 Clock Gating*/
struct msrinit CS5535_CLOCK_GATING_TABLE[] = {
{ USB1_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{ USB2_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{ GLIU_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}},
{ GLPCI_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{ GLCP_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}},
{ MDD_SB_GLD_MSR_PM, {.hi=0,.lo=0x050554111}},
{ ATA_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{ AC97_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{0,{0,0}}
};
/* 5536 Clock Gating*/
struct msrinit CS5536_CLOCK_GATING_TABLE[] = {
/* MSR Setting*/
{ GLIU_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}},
{ GLPCI_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{ GLCP_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}},
{ MDD_SB_GLD_MSR_PM, {.hi=0,.lo=0x050554111}}, /* SMBus clock gating errata (PBZ 2226 & SiBZ 3977)*/
{ ATA_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{ AC97_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}},
{0,{0,0}}
};
struct acpiinit {
unsigned short ioreg;
unsigned long regdata;
unsigned short iolen;
};
struct acpiinit acpi_init_table[] = {
{ACPI_BASE+0x00, 0x01000000, 4},
{ACPI_BASE+0x08, 0, 4},
{ACPI_BASE+0x0C, 0, 4},
{ACPI_BASE+0x1C, 0, 4},
{ACPI_BASE+0x18, 0x0FFFFFFFF, 4},
{ACPI_BASE+0x00, 0x0000FFFF, 4},
{PM_SCLK, 0x000000E00, 4},
{PM_SED, 0x000004601, 4},
{PM_SIDD, 0x000008C02, 4},
{PM_WKD, 0x0000000A0, 4},
{PM_WKXD, 0x0000000A0, 4},
{0,0,0}
};
/* return 1 if we are a 5536-based system */
static int is_5536(void){
msr_t msr;
msr = rdmsr(GLIU_SB_GLD_MSR_CAP);
msr.lo >>= 20;
printk_debug("is_5536: msr.lo is 0x%x(==5 means 5536)\n", msr.lo&0xf);
return ((msr.lo&0xf) == 5);
}
/* ***************************************************************************/
/* **/
/* * pmChipsetInit*/
/* **/
/* * Program ACPI LBAR and initialize ACPI registers.*/
/* * */
/* **/
/* * Entry:*/
/* * None*/
/* **/
/* * Exit:*/
/* * None*/
/* **/
/* * Destroys:*/
/* * None*/
/* **/
/* ***************************************************************************/
static void
pmChipsetInit(void) {
unsigned long val = 0;
unsigned short port;
port = (PMLogic_BASE + 0x010);
val = 0x0E00 ; /* 1ms*/
outl(val, port);
/* PM_WKXD*/
/* Make sure bits[3:0]=0000b to clear the*/
/* saved Sx state*/
port = (PMLogic_BASE + 0x034);
val = 0x0A0 ; /* 5ms*/
outl(val, port);
/* PM_WKD*/
port = (PMLogic_BASE + 0x030);
outl(val, port);
/* PM_SED*/
port = (PMLogic_BASE + 0x014);
/* mov eax, 0x057642 ; 100ms, works*/
val = 0x04601 ; /* 5ms*/
outl(val, port);
/* PM_SIDD*/
port = (PMLogic_BASE + 0x020);
/* mov eax, 0x0AEC84 ; 200ms, works*/
val = 0x08C02 ; /* 10ms*/
outl(val, port);
/* GPIO24 OUT_AUX1 function is the external signal for 5535's vsb_working_aux*/
/* which is de-asserted when 5535 enters Standby(S3 or S5) state.*/
/* On Hawk, GPIO24 controls all voltage rails except Vmem and Vstandby. This means*/
/* GX2 will be fully de-powered if this control de-asserts in S3/S5.*/
/* */
/* GPIO24 is setup in preChipsetInit for two reasons*/
/* 1. GPIO24 at reset defaults to disabled, since this signal is vsb_work_aux on*/
/* Hawk it controls the FET's for all voltage rails except Vstanby & Vmem.*/
/* BIOS needs to enable GPIO24 as OUT_AUX1 & OUTPUT_EN early so it is driven*/
/* by 5535.*/
/* 2. Non-PM builds will require GPIO24 enabled for instant-off power button*/
/* */
/* GPIO11 OUT_AUX1 function is the external signal for 5535's slp_clk_n which is asserted*/
/* when 5535 enters Sleep(S1) state.*/
/* On Hawk, GPIO11 is connected to control input of external clock generator*/
/* for 14MHz, PCI, USB & LPC clocks.*/
/* Programming of GPIO11 will be done by VSA PM code. During VSA Init. BIOS writes*/
/* PM Core Virual Register indicating if S1 Clocks should be On or Off. This is based*/
/* on a Setup item. We do not want to leave GPIO11 enabled because of a Hawk board*/
/* problem. With GPIO11 enabled in S3, something is back-driving GPIO11 causing it to*/
/* float to 1.6-1.7V.*/
}
struct FLASH_DEVICE {
unsigned char fType; /* Flash type: NOR or NAND */
unsigned char fInterface; /* Flash interface: I/O or Memory */
unsigned long fMask; /* Flash size/mask */
};
struct FLASH_DEVICE FlashInitTable[] = {
{ FLASH_TYPE_NAND, FLASH_IF_MEM, FLASH_MEM_4K }, /* CS0, or Flash Device 0 */
{ FLASH_TYPE_NONE, 0, 0 }, /* CS1, or Flash Device 1 */
{ FLASH_TYPE_NONE, 0, 0 }, /* CS2, or Flash Device 2 */
{ FLASH_TYPE_NONE, 0, 0 }, /* CS3, or Flash Device 3 */
};
#define FlashInitTableLen (sizeof(FlashInitTable)/sizeof(FlashInitTable[0]))
uint32_t FlashPort[] = {
MDD_LBAR_FLSH0,
MDD_LBAR_FLSH1,
MDD_LBAR_FLSH2,
MDD_LBAR_FLSH3
};
/***************************************************************************
*
* ChipsetFlashSetup
*
* Flash LBARs need to be setup before VSA init so the PCI BARs have
* correct size info. Call this routine only if flash needs to be
* configured (don't call it if you want IDE).
*
* Entry:
* Exit:
* Destroys:
*
**************************************************************************/
static void ChipsetFlashSetup(void)
{
msr_t msr;
int i;
int numEnabled = 0;
printk_debug("ChipsetFlashSetup++\n");
for (i = 0; i < FlashInitTableLen; i++) {
if (FlashInitTable[i].fType != FLASH_TYPE_NONE) {
printk_debug("Enable CS%d\n", i);
/* we need to configure the memory/IO mask */
msr = rdmsr(FlashPort[i]);
msr.hi = 0; /* start with the "enabled" bit clear */
if (FlashInitTable[i].fType == FLASH_TYPE_NAND)
msr.hi |= 0x00000002;
else
msr.hi &= ~0x00000002;
if (FlashInitTable[i].fInterface == FLASH_IF_MEM)
msr.hi |= 0x00000004;
else
msr.hi &= ~0x00000004;
msr.hi |= FlashInitTable[i].fMask;
printk_debug("WRMSR(0x%08X, %08X_%08X)\n", FlashPort[i], msr.hi, msr.lo);
wrmsr(FlashPort[i], msr);
/* now write-enable the device */
msr = rdmsr(MDD_NORF_CNTRL);
msr.lo |= (1 << i);
printk_debug("WRMSR(0x%08X, %08X_%08X)\n", MDD_NORF_CNTRL, msr.hi, msr.lo);
wrmsr(MDD_NORF_CNTRL, msr);
/* update the number enabled */
numEnabled++;
}
}
/* enable the flash */
if (0 != numEnabled) {
msr = rdmsr(MDD_PIN_OPT);
msr.lo &= ~1; /* PIN_OPT_IDE */
printk_debug("WRMSR(0x%08X, %08X_%08X)\n", MDD_PIN_OPT, msr.hi, msr.lo);
wrmsr(MDD_PIN_OPT, msr);
}
printk_debug("ChipsetFlashSetup--\n");
}
/* ***************************************************************************/
/* **/
/* * ChipsetGeodeLinkInit*/
/* * Handle chipset specific GeodeLink settings here. */
/* * Called from GeodeLink init code.*/
/* **/
/* * Entry:*/
/* * Exit:*/
/* * Destroys: GS*/
/* **/
/* ***************************************************************************/
static void
ChipsetGeodeLinkInit(void){
msr_t msr;
unsigned long msrnum;
unsigned long totalmem;
if (is_5536())
return;
/* SWASIF for A1 DMA */
/* Set all memory to "just above systop" PCI so DMA will work*/
/* check A1*/
msrnum = MSR_SB_GLCP + 0x17;
msr = rdmsr(msrnum);
if ((msr.lo&0xff) == 0x11)
return;
totalmem = sizeram() << 20 - 1;
totalmem >>= 12;
totalmem = ~totalmem;
totalmem &= 0xfffff;
msr.lo = totalmem;
msr.hi = 0x20000000; /* Port 1 (PCI)*/
msrnum = MSR_SB_GLIU + 0x20; /* */;
wrmsr(msrnum, msr);
}
void
chipsetinit (struct northbridge_amd_lx_config *nb){
msr_t msr;
struct msrinit *csi;
int i;
unsigned long msrnum;
outb( P80_CHIPSET_INIT, 0x80);
ChipsetGeodeLinkInit();
#if 0
/* we hope NEVER to be in linuxbios when S3 resumes
if (! IsS3Resume()) */
{
struct acpiinit *aci = acpi_init_table;
while (aci->ioreg){
if (aci->iolen == 2) {
outw(aci->regdata, aci->ioreg);
inw(aci->ioreg);
} else {
outl(aci->regdata, aci->ioreg);
inl(aci->ioreg);
}
}
pmChipsetInit();
}
#endif
if (!is_5536()) {
/* Setup USB. Need more details. #118.18*/
msrnum = MSR_SB_USB1 + 8;
msr.lo = 0x00012090;
msr.hi = 0;
wrmsr(msrnum, msr);
msrnum = MSR_SB_USB2 + 8;
wrmsr(msrnum, msr);
}
/* set hd IRQ */
outl (GPIOL_2_SET, GPIOL_INPUT_ENABLE);
outl (GPIOL_2_SET, GPIOL_IN_AUX1_SELECT);
/* Allow IO read and writes during a ATA DMA operation.*/
/* This could be done in the HD rom but do it here for easier debugging.*/
msrnum = ATA_SB_GLD_MSR_ERR;
msr = rdmsr(msrnum);
msr.lo &= ~0x100;
wrmsr(msrnum, msr);
/* Enable Post Primary IDE.*/
msrnum = GLPCI_SB_CTRL;
msr = rdmsr(msrnum);
msr.lo |= GLPCI_CRTL_PPIDE_SET;
wrmsr(msrnum, msr);
/* Set up Master Configuration Register*/
/* If 5536, use same master config settings as 5535, except for OHCI MSRs*/
if (is_5536())
i = 2;
else
i = 0;
csi = &SB_MASTER_CONF_TABLE[i];
for(; csi->msrnum; csi++){
msr.lo = csi->msr.lo;
msr.hi = csi->msr.hi;
wrmsr(csi->msrnum, msr); // MSR - see table above
}
/* Flash Setup*/
printk_err("%sDOING ChipsetFlashSetup()!!!!!!!!!!!!!!!!!!\n", nb->setupflash? " " : "NOT");
if (nb->setupflash)
ChipsetFlashSetup();
/* */
/* Set up Hardware Clock Gating*/
/* */
/* if (getnvram(TOKEN_SB_CLK_GATE) != TVALUE_DISABLE) */
{
if (is_5536())
csi = CS5536_CLOCK_GATING_TABLE;
else
csi = CS5535_CLOCK_GATING_TABLE;
for(; csi->msrnum; csi++){
msr.lo = csi->msr.lo;
msr.hi = csi->msr.hi;
wrmsr(csi->msrnum, msr); // MSR - see table above
}
}
}

View File

@ -0,0 +1,43 @@
#include <arch/io.h>
#include <stdint.h>
#include <cpu/amd/vr.h>
#define VIDEO_MB 8 // MB of video memory
/*
* Write to a Virtual Register
* AX = Class/Index
* CX = data to write
*/
void vrWrite(uint16_t wClassIndex, uint16_t wData)
{
outl(((uint32_t) VR_UNLOCK << 16) | wClassIndex, VRC_INDEX);
outw(wData, VRC_DATA);
}
/*
* Read from a Virtual Register
* AX = Class/Index
* Returns a 16-bit word of data
*/
uint16_t vrRead(uint16_t wClassIndex)
{
uint16_t wData;
outl(((uint32_t) VR_UNLOCK << 16) | wClassIndex, VRC_INDEX);
wData = inw(VRC_DATA);
return wData;
}
/*
* This function mirrors the Graphics_Init routine in GeodeROM.
*/
void graphics_init(void)
{
/* SoftVG initialization */
/* Call SoftVG with the main configuration parameters. */
/* NOTE: SoftVG expects the memory size to be given in 512 KB pages */
vrWrite((VRC_VG << 8) + VG_MEM_SIZE, 0x0100 | (VIDEO_MB * 2));
}

View File

@ -0,0 +1,480 @@
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include "chip.h"
#include "northbridge.h"
#include <cpu/amd/lxdef.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/cache.h>
#include <cpu/amd/vr.h>
#define VIDEO_MB 8
extern void graphics_init(void);
#define NORTHBRIDGE_FILE "northbridge.c"
/* todo: add a resource record. We don't do this here because this may be called when
* very little of the platform is actually working.
*/
int
sizeram(void)
{
msr_t msr;
int sizem = 0;
unsigned short dimm;
msr = rdmsr(0x20000018);
printk_debug("sizeram: %08x:%08x\n", msr.hi, msr.lo);
/* dimm 0 */
dimm = msr.hi;
/* installed? */
if ((dimm & 7) != 7)
sizem = (1 << ((dimm >> 12)-1)) * 8;
/* dimm 1*/
dimm = msr.hi >> 16;
/* installed? */
if ((dimm & 7) != 7)
sizem += (1 << ((dimm >> 12)-1)) * 8;
printk_debug("sizeram: sizem 0x%x\n", sizem);
return sizem;
}
/* here is programming for the various MSRs.*/
#define IM_QWAIT 0x100000
#define DMCF_WRITE_SERIALIZE_REQUEST (2<<12) /* 2 outstanding */ /* in high */
#define DMCF_SERIAL_LOAD_MISSES (2) /* enabled */
/* these are the 8-bit attributes for controlling RCONF registers */
#define CACHE_DISABLE (1<<0)
#define WRITE_ALLOCATE (1<<1)
#define WRITE_PROTECT (1<<2)
#define WRITE_THROUGH (1<<3)
#define WRITE_COMBINE (1<<4)
#define WRITE_SERIALIZE (1<<5)
/* ram has none of this stuff */
#define RAM_PROPERTIES (0)
#define DEVICE_PROPERTIES (WRITE_SERIALIZE|CACHE_DISABLE)
#define ROM_PROPERTIES (WRITE_SERIALIZE|WRITE_PROTECT|CACHE_DISABLE)
#define MSR_WS_CD_DEFAULT (0x21212121)
/* 1810-1817 give you 8 registers with which to program protection regions */
/* the are region configuration range registers, or RRCF */
/* in msr terms, the are a straight base, top address assign, since they are 4k aligned. */
/* so no left-shift needed for top or base */
#define RRCF_LOW(base,properties) (base|(1<<8)|properties)
#define RRCF_LOW_CD(base) RRCF_LOW(base, CACHE_DISABLE)
/* build initializer for P2D MSR */
#define P2D_BM(msr, pdid1, bizarro, pbase, pmask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(pbase>>24), .lo=(pbase<<8)|pmask}}
#define P2D_BMO(msr, pdid1, bizarro, poffset, pbase, pmask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(poffset<<8)|(pbase>>24), .lo=(pbase<<8)|pmask}}
#define P2D_R(msr, pdid1, bizarro, pmax, pmin) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(pmax>>12), .lo=(pmax<<20)|pmin}}
#define P2D_RO(msr, pdid1, bizarro, poffset, pmax, pmin) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(poffset<<8)|(pmax>>12), .lo=(pmax<<20)|pmin}}
#define P2D_SC(msr, pdid1, bizarro, wen, ren,pscbase) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(wen), .lo=(ren<<16)|(pscbase>>18)}}
#define IOD_BM(msr, pdid1, bizarro, ibase, imask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(ibase>>12), .lo=(ibase<<20)|imask}}
#define IOD_SC(msr, pdid1, bizarro, en, wen, ren, ibase) {msr, {.hi=(pdid1<<29)|(bizarro<<28), .lo=(en<<24)|(wen<<21)|(ren<<20)|(ibase<<3)}}
struct msr_defaults {
int msr_no;
msr_t msr;
} msr_defaults [] = {
{0x1700, {.hi = 0, .lo = IM_QWAIT}},
{0x1800, {.hi = DMCF_WRITE_SERIALIZE_REQUEST, .lo = DMCF_SERIAL_LOAD_MISSES}},
/* 1808 will be done down below, so we have to do 180a->1817 (well, 1813 really) */
/* for 180a, for now, we assume VSM will configure it */
/* 180b is left at reset value,a0000-bffff is non-cacheable */
/* 180c, c0000-dffff is set to write serialize and non-cachable */
/* oops, 180c will be set by cpu bug handling in cpubug.c */
//{0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}},
/* 180d is left at default, e0000-fffff is non-cached */
/* we will assume 180e, the ssm region configuration, is left at default or set by VSM */
/* we will not set 0x180f, the DMM,yet */
//{0x1810, {.hi=0xee7ff000, .lo=RRCF_LOW(0xee000000, WRITE_COMBINE|CACHE_DISABLE)}},
//{0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
//{0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}},
//{0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}},
/* now for GLPCI routing */
/* GLIU0 */
P2D_BM(0x10000020, 0x1, 0x0, 0x0, 0xfff80),
P2D_BM(0x10000021, 0x1, 0x0, 0x80000, 0xfffe0),
P2D_SC(0x1000002c, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
/* GLIU1 */
P2D_BM(0x40000020, 0x1, 0x0, 0x0, 0xfff80),
P2D_BM(0x40000021, 0x1, 0x0, 0x80000, 0xfffe0),
P2D_SC(0x4000002e, 0x1, 0x0, 0x0, 0xff03, 0xC0000), // GX3 0x4000002d -> 0x4000002e
{0}
};
/* note that dev is NOT used -- yet */
static void irq_init_steering(struct device *dev, uint16_t irq_map) {
/* Set up IRQ steering */
uint32_t pciAddr = 0x80000000 | (CHIPSET_DEV_NUM << 11) | 0x5C;
printk_debug("%s(%08X [%08X], %04X)\n", __FUNCTION__, dev, pciAddr, irq_map);
/* The IRQ steering values (in hex) are effectively dcba, where:
* <a> represents the IRQ for INTA,
* <b> represents the IRQ for INTB,
* <c> represents the IRQ for INTC, and
* <d> represents the IRQ for INTD.
* Thus, a value of irq_map = 0xAA5B translates to:
* INTA = IRQB (IRQ 11)
* INTB = IRQ5 (IRQ 5)
* INTC = IRQA (IRQ 10)
* INTD = IRQA (IRQ 10)
*/
outl(pciAddr & ~3, 0xCF8);
outl(irq_map, 0xCFC);
}
/*
* setup_lx_cache
*
* Returns the amount of memory (in KB) available to the system. This is the
* total amount of memory less the amount of memory reserved for SMM use.
*
*/
static int
setup_lx_cache(void)
{
msr_t msr;
unsigned long long val;
int sizekbytes, sizereg;
sizekbytes = sizeram() * 1024;
printk_debug("setup_lx_cache: enable for %d KB\n", sizekbytes);
/* build up the rconf word. */
/* the SYSTOP bits 27:8 are actually the top bits from 31:12. Book fails to say that */
/* set romrp */
val = ((unsigned long long) ROM_PROPERTIES) << 56;
/* make rom base useful for 1M roms */
/* Flash base address -- sized for 1M for now*/
val |= ((unsigned long long) 0xfff00)<<36;
/* set the devrp properties */
val |= ((unsigned long long) DEVICE_PROPERTIES) << 28;
/* Take our TOM, RIGHT shift 12, since it page-aligned, then LEFT-shift 8 for reg. */
/* yank off memory for the SMM handler */
sizekbytes -= SMM_SIZE;
sizereg = sizekbytes;
sizereg *= 1024; // convert to bytes
sizereg >>= 12;
sizereg <<= 8;
val |= sizereg;
val |= RAM_PROPERTIES;
msr.lo = val;
msr.hi = (val >> 32);
printk_debug("msr 0x%08X will be set to %08x:%08x\n", CPU_RCONF_DEFAULT, msr.hi, msr.lo);
wrmsr(CPU_RCONF_DEFAULT, msr);
enable_cache();
wbinvd();
return sizekbytes;
}
/* we have to do this here. We have not found a nicer way to do it */
void
setup_lx(void)
{
unsigned long tmp, tmp2;
msr_t msr;
unsigned long size_kb, membytes;
size_kb = setup_lx_cache();
membytes = size_kb * 1024;
/* NOTE! setup_lx_cache returns the SIZE OF RAM - RAMADJUST!
* so it is safe to use. You should NOT at this point call
* sizeram() directly.
*/
/* we need to set 0x10000028 and 0x40000029 */
/*
* These two descriptors cover the range from 1 MB (0x100000) to
* SYSTOP (a.k.a. TOM, or Top of Memory)
*/
#if 0
/* This has already been done elsewhere */
printk_debug("size_kb 0x%x, membytes 0x%x\n", size_kb, membytes);
msr.hi = 0x20000000 | membytes>>24;
msr.lo = 0x100 | ( ((membytes >>12) & 0xfff) << 20);
wrmsr(0x10000028, msr);
msr.hi = 0x20000000 | membytes>>24;
msr.lo = 0x100 | ( ((membytes >>12) & 0xfff) << 20);
wrmsr(0x40000029, msr);
#endif
#if 0
msr = rdmsr(0x10000028);
printk_debug("MSR 0x%x is now 0x%x:0x%x\n", 0x10000028, msr.hi,msr.lo);
msr = rdmsr(0x40000029);
printk_debug("MSR 0x%x is now 0x%x:0x%x\n", 0x40000029, msr.hi,msr.lo);
#endif
#if 1
/* fixme: SMM MSR 0x10000026 and 0x400000023 */
/* calculate the OFFSET field */
tmp = membytes - SMM_OFFSET;
tmp >>= 12;
tmp <<= 8;
tmp |= 0x20000000;
tmp |= (SMM_OFFSET >> 24);
/* calculate the PBASE and PMASK fields */
tmp2 = (SMM_OFFSET << 8) & 0xFFF00000; /* shift right 12 then left 20 == left 8 */
tmp2 |= (((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff);
printk_debug("MSR 0x%x is now 0x%x:0x%x\n", 0x10000026, tmp, tmp2);
msr.hi = tmp;
msr.lo = tmp2;
wrmsr(0x10000026, msr);
#endif
#if 0
msr.hi = 0x2cfbc040;
msr.lo = 0x400fffc0;
wrmsr(0x10000026, msr);
msr = rdmsr(0x10000026);
printk_debug("MSR 0x%x is now 0x%x:0x%x\n", 0x10000026, msr.hi, msr.lo);
#endif
#if 0
msr.hi = 0x22fffc02;
msr.lo = 0x10ffbf00;
wrmsr(0x1808, msr);
msr = rdmsr(0x1808);
printk_debug("MSR 0x%x is now 0x%x:0x%x\n", 0x1808, msr.hi, msr.lo);
#endif
#if 0 // SDG - don't do this
/* now do the default MSR values */
for(i = 0; msr_defaults[i].msr_no; i++) {
msr_t msr;
wrmsr(msr_defaults[i].msr_no, msr_defaults[i].msr); // MSR - see table above
msr = rdmsr(msr_defaults[i].msr_no);
printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", msr_defaults[i].msr_no, msr.hi,msr.lo);
}
#endif
}
static void enable_shadow(device_t dev)
{
}
static void northbridge_init(device_t dev)
{
struct northbridge_amd_lx_config *nb = (struct northbridge_amd_lx_config *)dev->chip_info;
printk_debug("northbridge: %s()\n", __FUNCTION__);
enable_shadow(dev);
irq_init_steering(dev, nb->irqmap);
}
static struct device_operations northbridge_operations = {
.read_resources = pci_dev_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = northbridge_init,
.enable = 0,
.ops_pci = 0,
};
static struct pci_driver northbridge_driver __pci_driver = {
.ops = &northbridge_operations,
.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_DEVICE_ID_AMD_LX,
};
#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
static void pci_domain_read_resources(device_t dev)
{
struct resource *resource;
printk_spew("%s:%s()\n", NORTHBRIDGE_FILE, __FUNCTION__);
/* Initialize the system wide io space constraints */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0));
resource->limit = 0xffffUL;
resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
/* Initialize the system wide memory resources constraints */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0));
resource->limit = 0xffffffffULL;
resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
}
static void ram_resource(device_t dev, unsigned long index,
unsigned long basek, unsigned long sizek)
{
struct resource *resource;
if (!sizek) {
return;
}
resource = new_resource(dev, index);
resource->base = ((resource_t)basek) << 10;
resource->size = ((resource_t)sizek) << 10;
resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
}
static void tolm_test(void *gp, struct device *dev, struct resource *new)
{
struct resource **best_p = gp;
struct resource *best;
best = *best_p;
if (!best || (best->base > new->base)) {
best = new;
}
*best_p = best;
}
#if 0
static uint32_t find_pci_tolm(struct bus *bus)
{
struct resource *min;
uint32_t tolm;
min = 0;
search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
tolm = 0xffffffffUL;
if (min && tolm > min->base) {
tolm = min->base;
}
return tolm;
}
#endif
#define FRAMEBUFFERK 4096
static void pci_domain_set_resources(device_t dev)
{
#if 0
device_t mc_dev;
uint32_t pci_tolm;
pci_tolm = find_pci_tolm(&dev->link[0]);
mc_dev = dev->link[0].children;
if (mc_dev) {
unsigned int tomk, tolmk;
unsigned int ramreg = 0;
int i, idx;
unsigned int *bcdramtop = (unsigned int *)(GX_BASE + BC_DRAM_TOP);
unsigned int *mcgbaseadd = (unsigned int *)(GX_BASE + MC_GBASE_ADD);
for(i=0; i<0x20; i+= 0x10) {
unsigned int *mcreg = (unsigned int *)(GX_BASE + MC_BANK_CFG);
unsigned int mem_config = *mcreg;
if (((mem_config & (DIMM_PG_SZ << i)) >> (4 + i)) == 7)
continue;
ramreg += 1 << (((mem_config & (DIMM_SZ << i)) >> (i + 8)) + 2);
}
tomk = ramreg << 10;
/* Sort out the framebuffer size */
tomk -= FRAMEBUFFERK;
*bcdramtop = ((tomk << 10) - 1);
*mcgbaseadd = (tomk >> 9);
printk_debug("BC_DRAM_TOP = 0x%08x\n", *bcdramtop);
printk_debug("MC_GBASE_ADD = 0x%08x\n", *mcgbaseadd);
printk_debug("I would set ram size to %d Mbytes\n", (tomk >> 10));
/* Compute the top of Low memory */
tolmk = pci_tolm >> 10;
if (tolmk >= tomk) {
/* The PCI hole does does not overlap the memory.
*/
tolmk = tomk;
}
/* Report the memory regions */
idx = 10;
ram_resource(dev, idx++, 0, tolmk);
}
#endif
assign_resources(&dev->link[0]);
}
static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
{
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
return max;
}
static struct device_operations pci_domain_ops = {
.read_resources = pci_domain_read_resources,
.set_resources = pci_domain_set_resources,
.enable_resources = enable_childrens_resources,
.init = 0,
.scan_bus = pci_domain_scan_bus,
};
static void cpu_bus_init(device_t dev)
{
initialize_cpus(&dev->link[0]);
}
static void cpu_bus_noop(device_t dev)
{
}
static struct device_operations cpu_bus_ops = {
.read_resources = cpu_bus_noop,
.set_resources = cpu_bus_noop,
.enable_resources = cpu_bus_noop,
.init = cpu_bus_init,
.scan_bus = 0,
};
void chipsetInit (void);
static void enable_dev(struct device *dev)
{
printk_debug("lx north: enable_dev\n");
void northbridgeinit(void);
void chipsetinit(struct northbridge_amd_lx_config *nb);
void setup_realmode_idt(void);
void do_vsmbios(void);
/* Set the operations if it is a special bus type */
if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
struct northbridge_amd_lx_config *nb = (struct northbridge_amd_lx_config *)dev->chip_info;
extern void cpubug(void);
printk_debug("DEVICE_PATH_PCI_DOMAIN\n");
/* cpubug MUST be called before setup_lx(), so we force the issue here */
northbridgeinit();
cpubug();
chipsetinit(nb);
setup_lx();
/* do this here for now -- this chip really breaks our device model */
setup_realmode_idt();
do_vsmbios();
graphics_init();
dev->ops = &pci_domain_ops;
pci_set_method(dev);
ram_resource(dev, 0, 0, ((sizeram() - VIDEO_MB) * 1024) - SMM_SIZE);
} else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
printk_debug("DEVICE_PATH_APIC_CLUSTER\n");
dev->ops = &cpu_bus_ops;
}
printk_debug("lx north: end enable_dev\n");
}
struct chip_operations northbridge_amd_lx_ops = {
CHIP_NAME("AMD LX Northbridge")
.enable_dev = enable_dev,
};

View File

@ -0,0 +1,6 @@
#ifndef NORTHBRIDGE_AMD_LX_H
#define NORTHBRIDGE_AMD_LX_H
extern unsigned int lx_scan_root_bus(device_t root, unsigned int max);
#endif /* NORTHBRIDGE_AMD_LX_H */

View File

@ -0,0 +1,808 @@
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
#include <device/device.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include "chip.h"
#include "northbridge.h"
#include <cpu/amd/lxdef.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/cache.h>
/* put this here for now, we are not sure where it belongs */
struct gliutable {
unsigned long desc_name;
unsigned short desc_type;
unsigned long hi, lo;
};
struct gliutable gliu0table[] = {
{.desc_name=MSR_GLIU0_BASE1, .desc_type= BM,.hi= MSR_MC + 0x0,.lo= 0x0FFF80}, /* 0-7FFFF to MC*/
{.desc_name=MSR_GLIU0_BASE2, .desc_type= BM,.hi= MSR_MC + 0x0,.lo=(0x80 << 20) + 0x0FFFE0}, /* 80000-9ffff to Mc*/
{.desc_name=MSR_GLIU0_SHADOW, .desc_type= SC_SHADOW,.hi= MSR_MC + 0x0,.lo= 0x03}, /* C0000-Fffff split to MC and PCI (sub decode) A0000-Bffff handled by SoftVideo*/
{.desc_name=MSR_GLIU0_SYSMEM, .desc_type= R_SYSMEM,.hi= MSR_MC,.lo= 0x0}, /* Catch and fix dynamicly.*/
{.desc_name=MSR_GLIU0_DMM, .desc_type= BMO_DMM,.hi= MSR_MC,.lo= 0x0}, /* Catch and fix dynamicly.*/
{.desc_name=MSR_GLIU0_SMM, .desc_type= BMO_SMM,.hi= MSR_MC,.lo= 0x0}, /* Catch and fix dynamicly.*/
{.desc_name=GLIU0_GLD_MSR_COH,.desc_type= OTHER,.hi= 0x0,.lo= GL0_CPU},
{.desc_name=GL_END, .desc_type= GL_END,.hi= 0x0,.lo= 0x0},
};
struct gliutable gliu1table[] = {
{.desc_name=MSR_GLIU1_BASE1,.desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= 0x0FFF80}, /* 0-7FFFF to MC*/
{.desc_name=MSR_GLIU1_BASE2,.desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= (0x80 << 20) +0x0FFFE0}, /* 80000-9ffff to Mc*/
{.desc_name=MSR_GLIU1_SHADOW,.desc_type= SC_SHADOW,.hi= MSR_GL0 + 0x0,.lo= 0x03}, /* C0000-Fffff split to MC and PCI (sub decode)*/
{.desc_name=MSR_GLIU1_SYSMEM,.desc_type= R_SYSMEM,.hi= MSR_GL0,.lo= 0x0}, /* Cat0xc and fix dynamicly.*/
{.desc_name=MSR_GLIU1_DMM,.desc_type= BM_DMM,.hi= MSR_GL0,.lo= 0x0}, /* Cat0xc and fix dynamicly.*/
{.desc_name=MSR_GLIU1_SMM,.desc_type= BM_SMM,.hi= MSR_GL0,.lo= 0x0}, /* Cat0xc and fix dynamicly.*/
{.desc_name=GLIU1_GLD_MSR_COH,.desc_type= OTHER,.hi= 0x0,.lo= GL1_GLIU0},
{.desc_name=MSR_GLIU1_FPU_TRAP,.desc_type= SCIO,.hi= (GL1_GLCP << 29) + 0x0,.lo= 0x033000F0}, /* FooGlue FPU 0xF0*/
{.desc_name=GL_END,.desc_type= GL_END,.hi= 0x0,.lo= 0x0},
};
struct gliutable *gliutables[] = {gliu0table, gliu1table, 0};
struct msrinit {
unsigned long msrnum;
msr_t msr;
};
struct msrinit ClockGatingDefault [] = {
{GLIU0_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}},
/* MC must stay off in SDR mode. It is turned on in CPUBug??? lotus #77.142*/
{MC_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}},
{GLIU1_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}},
{VG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, /* lotus #77.163*/
{GP_GLD_MSR_PM, {.hi=0x00,.lo=0x0001}},
/*{DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0155}},*/ //GX3
{GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}},
{GLPCI_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}},
/*{FG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, */ /* Always on*/ //GX3
{0xffffffff, {0xffffffff, 0xffffffff}},
};
/* All On*/
struct msrinit ClockGatingAllOn[] = {
{GLIU0_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
{MC_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
{GLIU1_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
{VG_GLD_MSR_PM, {.hi=0x00, .lo=0x00}},
{GP_GLD_MSR_PM, {.hi=0x00,.lo=0x000000001}},
/*{DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}}, */ //GX3
{GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
{GLPCI_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}},
/*{FG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, */ //GX3
{0xffffffff, {0xffffffff, 0xffffffff}},
};
/* Performance*/
struct msrinit ClockGatingPerformance[] = {
{VG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, /* lotus #77.163*/
{GP_GLD_MSR_PM, {.hi=0x00,.lo=0x0001}},
/*{DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0155}}, */ //GX3
{GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}},
{0xffffffff, {0xffffffff, 0xffffffff}},
};
/* */
/* SET GeodeLink PRIORITY*/
/* */
struct msrinit GeodeLinkPriorityTable [] = {
{CPU_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0220}}, /* CPU Priority.*/
/*{DF_GLD_MSR_MASTER_CONF, {.hi=0x00,.lo=0x0000}},*/ /* DF Priority.*/ //GX3
{VG_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0720}}, /* VG Primary and Secondary Priority.*/
{GP_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0010}}, /* Graphics Priority.*/
{GLPCI_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0027}}, /* GLPCI Priority + PID*/
{GLCP_GLD_MSR_CONF, {.hi=0x00,.lo=0x0001}}, /* GLCP Priority + PID*/
{VIP_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0622}}, /* VIP PID*/
{AES_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0013}}, /* AES PID*/
{0x0FFFFFFFF, {0x0FFFFFFFF, 0x0FFFFFFFF}}, /* END*/
};
/* do we have dmi or not? assume NO per AMD */
int havedmi = 0;
static void
writeglmsr(struct gliutable *gl){
msr_t msr;
msr.lo = gl->lo;
msr.hi = gl->hi;
wrmsr(gl->desc_name, msr); // MSR - see table above
printk_debug("%s: write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo);
/* they do this, so we do this */
msr = rdmsr(gl->desc_name);
printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo);
}
static void
ShadowInit(struct gliutable *gl)
{
msr_t msr;
msr = rdmsr(gl->desc_name);
if (msr.lo == 0) {
writeglmsr(gl);
}
}
/* NOTE: transcribed from assembly code. There is the usual redundant assembly nonsense in here.
* CLEAN ME UP
*/
/* yes, this duplicates later code, but it seems that is how they want it done.
*/
extern int sizeram(void);
static void
SysmemInit(struct gliutable *gl)
{
msr_t msr;
int sizembytes, sizebytes;
/*
* Figure out how much RAM is in the machine and alocate all to the
* system. We will adjust for SMM and DMM now and Frame Buffer later.
*/
sizembytes = sizeram();
printk_debug("%s: enable for %dm bytes\n", __FUNCTION__, sizembytes);
sizebytes = sizembytes << 20;
sizebytes -= SMM_SIZE*1024 +1;
if (havedmi)
sizebytes -= DMM_SIZE * 1024 + 1;
sizebytes -= 1;
msr.hi = (gl->hi & 0xFFFFFF00) | (sizebytes >> 24);
/* set up sizebytes to fit into msr.lo */
sizebytes <<= 8; /* what? well, we want bits 23:12 in bits 31:20. */
sizebytes &= 0xfff00000;
sizebytes |= 0x100;
msr.lo = sizebytes;
wrmsr(gl->desc_name, msr); // MSR - see table above
msr = rdmsr(gl->desc_name);
printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__,
gl->desc_name, msr.hi, msr.lo);
}
static void
DMMGL0Init(struct gliutable *gl) {
msr_t msr;
int sizebytes = sizeram()<<20;
long offset;
if (! havedmi)
return;
printk_debug("%s: %d bytes\n", __FUNCTION__, sizebytes);
sizebytes -= DMM_SIZE*1024;
offset = sizebytes - DMM_OFFSET;
printk_debug("%s: offset is 0x%08x\n", __FUNCTION__, offset);
offset >>= 12;
msr.hi = (gl->hi) | (offset << 8);
/* I don't think this is needed */
msr.hi &= 0xffffff00;
msr.hi |= (DMM_OFFSET >> 24);
msr.lo = DMM_OFFSET << 8;
msr.lo |= ((~(DMM_SIZE*1024)+1)>>12)&0xfffff;
wrmsr(gl->desc_name, msr); // MSR - See table above
msr = rdmsr(gl->desc_name);
printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo);
}
static void
DMMGL1Init(struct gliutable *gl) {
msr_t msr;
if (! havedmi)
return;
printk_debug("%s:\n", __FUNCTION__ );
msr.hi = gl->hi;
/* I don't think this is needed */
msr.hi &= 0xffffff00;
msr.hi |= (DMM_OFFSET >> 24);
msr.lo = DMM_OFFSET << 8;
/* hmm. AMD source has SMM here ... SMM, not DMM? We think DMM */
printk_err("%s: warning, using DMM_SIZE even though AMD used SMM_SIZE\n", __FUNCTION__);
msr.lo |= ((~(DMM_SIZE*1024)+1)>>12)&0xfffff;
wrmsr(gl->desc_name, msr); // MSR - See table above
msr = rdmsr(gl->desc_name);
printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo);
}
static void
SMMGL0Init(struct gliutable *gl) {
msr_t msr;
int sizebytes = sizeram()<<20;
long offset;
sizebytes -= SMM_SIZE*1024;
if (havedmi)
sizebytes -= DMM_SIZE * 1024;
printk_debug("%s: %d bytes\n", __FUNCTION__, sizebytes);
offset = sizebytes - SMM_OFFSET;
printk_debug("%s: offset is 0x%08x\n", __FUNCTION__, offset);
offset >>= 12;
msr.hi = offset << 8;
msr.hi |= SMM_OFFSET>>24;
msr.lo = SMM_OFFSET << 8;
msr.lo |= ((~(SMM_SIZE*1024)+1)>>12)&0xfffff;
wrmsr(gl->desc_name, msr); // MSR - See table above
msr = rdmsr(gl->desc_name);
printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo);
}
static void
SMMGL1Init(struct gliutable *gl) {
msr_t msr;
printk_debug("%s:\n", __FUNCTION__ );
msr.hi = gl->hi;
/* I don't think this is needed */
msr.hi &= 0xffffff00;
msr.hi |= (SMM_OFFSET >> 24);
msr.lo = SMM_OFFSET << 8;
msr.lo |= ((~(SMM_SIZE*1024)+1)>>12)&0xfffff;
wrmsr(gl->desc_name, msr); // MSR - See table above
msr = rdmsr(gl->desc_name);
printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo);
}
static void
GLIUInit(struct gliutable *gl){
while (gl->desc_type != GL_END){
switch(gl->desc_type){
default:
/* For Unknown types: Write then read MSR */
writeglmsr(gl);
case SC_SHADOW: /* Check for a Shadow entry*/
ShadowInit(gl);
break;
case R_SYSMEM: /* check for a SYSMEM entry*/
SysmemInit(gl);
break;
case BMO_DMM: /* check for a DMM entry*/
DMMGL0Init(gl);
break;
case BM_DMM : /* check for a DMM entry*/
DMMGL1Init(gl);
break;
case BMO_SMM : /* check for a SMM entry*/
SMMGL0Init(gl);
break;
case BM_SMM : /* check for a SMM entry*/
SMMGL1Init(gl);
break;
}
gl++;
}
}
/* ***************************************************************************/
/* **/
/* * GLPCIInit*/
/* **/
/* * Set up GLPCI settings for reads/write into memory*/
/* * R0: 0-640KB,*/
/* * R1: 1MB - Top of System Memory*/
/* * R2: SMM Memory*/
/* * R3: Framebuffer? - not set up yet*/
/* * R4: ??*/
/* **/
/* * Entry:*/
/* * Exit:*/
/* * Modified:*/
/* **/
/* ***************************************************************************/
static void GLPCIInit(void){
struct gliutable *gl = 0;
int i;
msr_t msr;
int msrnum;
/* */
/* R0 - GLPCI settings for Conventional Memory space.*/
/* */
msr.hi = (0x09F000 >> 12) << GLPCI_RC_UPPER_TOP_SHIFT /* 640*/;
msr.lo = 0 /* 0*/;
msr.lo |= GLPCI_RC_LOWER_EN_SET+ GLPCI_RC_LOWER_PF_SET + GLPCI_RC_LOWER_WC_SET;
msrnum = GLPCI_RC0;
wrmsr(msrnum, msr);
/* */
/* R1 - GLPCI settings for SysMem space.*/
/* */
/* Get systop from GLIU0 SYSTOP Descriptor*/
for(i = 0; gliu0table[i].desc_name != GL_END; i++) {
if (gliu0table[i].desc_type == R_SYSMEM) {
gl = &gliu0table[i];
break;
}
}
if (gl) {
unsigned long pah, pal;
msrnum = gl->desc_name;
msr = rdmsr(msrnum);
/* example R_SYSMEM value: 20:00:00:0f:fb:f0:01:00
* translates to a base of 0x00100000 and top of 0xffbf0000
* base of 1M and top of around 256M
*/
/* we have to create a page-aligned (4KB page) address for base and top */
/* So we need a high page aligned addresss (pah) and low page aligned address (pal)
* pah is from msr.hi << 12 | msr.low >> 20. pal is msr.lo << 12
*/
printk_debug("GLPCI r1: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi);
pah = ((msr.hi &0xff) << 12) | ((msr.lo >> 20) & 0xfff);
/* we have the page address. Now make it a page-aligned address */
pah <<= 12;
pal = msr.lo << 12;
msr.hi = pah;
msr.lo = pal;
msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET | GLPCI_RC_LOWER_WC_SET;
printk_debug("GLPCI r1: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi);
msrnum = GLPCI_RC1;
wrmsr(msrnum, msr);
}
/* */
/* R2 - GLPCI settings for SMM space.*/
/* */
msr.hi = ((SMM_OFFSET+(SMM_SIZE*1024-1)) >> 12) << GLPCI_RC_UPPER_TOP_SHIFT;
msr.lo = (SMM_OFFSET >> 12) << GLPCI_RC_LOWER_BASE_SHIFT;
msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET;
msrnum = GLPCI_RC2;
wrmsr(msrnum, msr);
/* this is done elsewhere already, but it does no harm to do it more than once */
/* write serialize memory hole to PCI. Need to to unWS when something is shadowed regardless of cachablility.*/
msr.lo = 0x021212121 /* cache disabled and write serialized*/;
msr.hi = 0x021212121 /* cache disabled and write serialized*/;
msrnum = CPU_RCONF_A0_BF;
wrmsr(msrnum, msr);
msrnum = CPU_RCONF_C0_DF;
wrmsr(msrnum, msr);
msrnum = CPU_RCONF_E0_FF;
wrmsr(msrnum, msr);
/* Set Non-Cacheable Read Only for NorthBound Transactions to Memory. The Enable bit is handled in the Shadow setup.*/
msrnum = GLPCI_A0_BF;
msr.hi = 0x35353535;
msr.lo = 0x35353535;
wrmsr(msrnum, msr);
msrnum = GLPCI_C0_DF;
msr.hi = 0x35353535;
msr.lo = 0x35353535;
wrmsr(msrnum, msr);
msrnum = GLPCI_E0_FF;
msr.hi = 0x35353535;
msr.lo = 0x35353535;
wrmsr(msrnum, msr);
/* Set WSREQ*/
msrnum = CPU_DM_CONFIG0;
msr = rdmsr(msrnum);
msr.hi &= ~ (7 << DM_CONFIG0_UPPER_WSREQ_SHIFT);
msr.hi |= 2 << DM_CONFIG0_UPPER_WSREQ_SHIFT ; /* reduce to 1 for safe mode.*/
wrmsr(msrnum, msr);
/* we are ignoring the 5530 case for now, and perhaps forever. */
/* */
/* 5535 NB Init*/
/* */
msrnum = GLPCI_ARB;
msr = rdmsr(msrnum);
msr.hi |= GLPCI_ARB_UPPER_PRE0_SET | GLPCI_ARB_UPPER_PRE1_SET;
msr.lo |= GLPCI_ARB_LOWER_IIE_SET;
wrmsr(msrnum, msr);
msrnum = GLPCI_CTRL;
msr = rdmsr(msrnum);
msr.lo |= GLPCI_CTRL_LOWER_ME_SET | GLPCI_CTRL_LOWER_OWC_SET | GLPCI_CTRL_LOWER_PCD_SET; /* (Out will be disabled in CPUBUG649 for < 2.0 parts .)*/
msr.lo |= GLPCI_CTRL_LOWER_LDE_SET;
msr.lo &= ~ (0x03 << GLPCI_CTRL_LOWER_IRFC_SHIFT);
msr.lo |= 0x02 << GLPCI_CTRL_LOWER_IRFC_SHIFT;
msr.lo &= ~ (0x07 << GLPCI_CTRL_LOWER_IRFT_SHIFT);
msr.lo |= 0x06 << GLPCI_CTRL_LOWER_IRFT_SHIFT;
msr.hi &= ~ (0x0f << GLPCI_CTRL_UPPER_FTH_SHIFT);
msr.hi |= 0x0F << GLPCI_CTRL_UPPER_FTH_SHIFT;
msr.hi &= ~ (0x0f << GLPCI_CTRL_UPPER_RTH_SHIFT);
msr.hi |= 0x0F << GLPCI_CTRL_UPPER_RTH_SHIFT;
msr.hi &= ~ (0x0f << GLPCI_CTRL_UPPER_SBRTH_SHIFT);
msr.hi |= 0x0F << GLPCI_CTRL_UPPER_SBRTH_SHIFT;
msr.hi &= ~ (0x03 << GLPCI_CTRL_UPPER_WTO_SHIFT);
msr.hi |= 0x06 << GLPCI_CTRL_UPPER_WTO_SHIFT;
msr.hi &= ~ (0x03 << GLPCI_CTRL_UPPER_ILTO_SHIFT);
msr.hi |= 0x00 << GLPCI_CTRL_UPPER_ILTO_SHIFT;
wrmsr(msrnum, msr);
/* Set GLPCI Latency Timer.*/
msrnum = GLPCI_CTRL;
msr = rdmsr(msrnum);
msr.hi |= 0x1F << GLPCI_CTRL_UPPER_LAT_SHIFT; /* Change once 1.x is gone.*/
wrmsr(msrnum, msr);
/* GLPCI_SPARE*/
msrnum = GLPCI_SPARE;
msr = rdmsr(msrnum);
msr.lo &= ~ 0x7;
msr.lo |= GLPCI_SPARE_LOWER_AILTO_SET | GLPCI_SPARE_LOWER_PPD_SET | GLPCI_SPARE_LOWER_PPC_SET | GLPCI_SPARE_LOWER_MPC_SET | GLPCI_SPARE_LOWER_NSE_SET | GLPCI_SPARE_LOWER_SUPO_SET;
wrmsr(msrnum, msr);
}
/* ***************************************************************************/
/* **/
/* * ClockGatingInit*/
/* **/
/* * Enable Clock Gating.*/
/* **/
/* * Entry:*/
/* * Exit:*/
/* * Modified:*/
/* **/
/* ***************************************************************************/
static void
ClockGatingInit (void){
msr_t msr;
struct msrinit *gating = ClockGatingDefault;
int i;
#if 0
mov cx, TOKEN_CLK_GATE
NOSTACK bx, GetNVRAMValueBX
cmp al, TVALUE_CG_OFF
je gatingdone
cmp al, TVALUE_CG_DEFAULT
jb allon
ja performance
lea si, ClockGatingDefault
jmp nextdevice
allon:
lea si, ClockGatingAllOn
jmp nextdevice
performance:
lea si, ClockGatingPerformance
#endif
for(i = 0; gating->msrnum != 0xffffffff; i++) {
msr = rdmsr(gating->msrnum);
printk_debug("%s: MSR 0x%08x is 0x%08x:0x%08x\n", __FUNCTION__, gating->msrnum, msr.hi, msr.lo);
msr.hi |= gating->msr.hi;
msr.lo |= gating->msr.lo;
printk_debug("%s: MSR 0x%08x will be set to 0x%08x:0x%08x\n", __FUNCTION__,
gating->msrnum, msr.hi, msr.lo);
wrmsr(gating->msrnum, msr); // MSR - See the table above
gating +=1;
}
}
static void
GeodeLinkPriority(void){
msr_t msr;
struct msrinit *prio = GeodeLinkPriorityTable;
int i;
for(i = 0; prio->msrnum != 0xffffffff; i++) {
msr = rdmsr(prio->msrnum);
printk_debug("%s: MSR 0x%08x is 0x%08x:0x%08x\n", __FUNCTION__, prio->msrnum, msr.hi, msr.lo);
msr.hi |= prio->msr.hi;
msr.lo &= ~0xfff;
msr.lo |= prio->msr.lo;
printk_debug("%s: MSR 0x%08x will be set to 0x%08x:0x%08x\n", __FUNCTION__,
prio->msrnum, msr.hi, msr.lo);
wrmsr(prio->msrnum, msr); // MSR - See the table above
prio +=1;
}
}
/*
* Get the GLIU0 shadow register settings
* If the setShadow function is used then all shadow descriptors
* will stay sync'ed.
*/
static uint64_t getShadow(void)
{
msr_t msr;
msr = rdmsr(MSR_GLIU0_SHADOW);
return ( ( (uint64_t) msr.hi ) << 32 ) | msr.lo;
}
/*
* Set the cache RConf registers for the memory hole.
* Keeps all cache shadow descriptors sync'ed.
* This is part of the PCI lockup solution
* Entry: EDX:EAX is the shadow settings
*/
static void setShadowRCONF(uint32_t shadowHi, uint32_t shadowLo)
{
// ok this is whacky bit translation time.
int bit;
uint8_t shadowByte;
msr_t msr;
shadowByte = (uint8_t) (shadowLo >> 16);
// load up D000 settings in edx.
for (bit = 8; (bit > 4); bit--) {
msr.hi <<= 8;
msr.hi |= 1; // cache disable PCI/Shadow memory
if (shadowByte && (1 << bit))
msr.hi |= 0x20; // write serialize PCI memory
}
// load up C000 settings in eax.
for ( ; bit; bit--) {
msr.lo <<= 8;
msr.lo |= 1; // cache disable PCI/Shadow memory
if (shadowByte && (1 << bit))
msr.lo |= 0x20; // write serialize PCI memory
}
wrmsr(CPU_RCONF_C0_DF, msr);
shadowByte = (uint8_t) (shadowLo >> 24);
// load up F000 settings in edx.
for (bit = 8; (bit > 4); bit--) {
msr.hi <<= 8;
msr.hi |= 1; // cache disable PCI/Shadow memory
if (shadowByte && (1 << bit))
msr.hi |= 0x20; // write serialize PCI memory
}
// load up E000 settings in eax.
for ( ; bit; bit--) {
msr.lo <<= 8;
msr.lo |= 1; // cache disable PCI/Shadow memory
if (shadowByte && (1 << bit))
msr.lo |= 0x20; // write serialize PCI memory
}
wrmsr(CPU_RCONF_E0_FF, msr);
}
/*
* Set the GLPCI registers for the memory hole.
* Keeps all cache shadow descriptors sync'ed.
* Entry: EDX:EAX is the shadow settings
*/
static void setShadowGLPCI(uint32_t shadowHi, uint32_t shadowLo)
{
msr_t msr;
// Set the Enable Register.
msr = rdmsr(GLPCI_REN);
msr.lo &= 0xFFFF00FF;
msr.lo |= ( (shadowLo & 0xFFFF0000) >> 8);
wrmsr(GLPCI_REN, msr);
}
/*
* Set the GLIU SC register settings. Scans descriptor tables for SC_SHADOW.
* Keeps all shadow descriptors sync'ed.
* Entry: EDX:EAX is the shadow settings
*/
static void setShadow(uint64_t shadowSettings)
{
int i;
msr_t msr;
struct gliutable* pTable;
uint32_t shadowLo, shadowHi;
shadowLo = (uint32_t) shadowSettings;
shadowHi = (uint32_t) (shadowSettings >> 32);
setShadowRCONF(shadowHi, shadowLo);
setShadowGLPCI(shadowHi, shadowLo);
for(i = 0; gliutables[i]; i++) {
for (pTable = gliutables[i]; pTable->desc_type != GL_END; pTable++) {
if (pTable->desc_type == SC_SHADOW) {
msr = rdmsr(pTable->desc_name);
msr.lo = (uint32_t) shadowSettings;
msr.hi &= 0xFFFF0000; // maintain PDID in upper EDX
msr.hi |= ((uint32_t) (shadowSettings >> 32)) & 0x0000FFFF;
wrmsr(pTable->desc_name, msr); // MSR - See the table above
}
}
}
}
/**************************************************************************
*
* shadowRom
*
* Set up a stack for ease of further testing
*
* Entry:
* Exit:
* Destroys:
*
**************************************************************************/
static void
shadowRom(void)
{
uint64_t shadowSettings = getShadow();
shadowSettings &= (uint64_t) 0xFFFF00000000FFFFULL; // Disable read & writes
shadowSettings |= (uint64_t) 0x00000000F0000000ULL; // Enable reads for F0000-FFFFF
setShadow(shadowSettings);
}
/***************************************************************************
*
* RCONFInit
* Set up RCONF_DEFAULT and any other RCONF registers needed
*
* DEVRC_RCONF_DEFAULT:
* ROMRC(63:56) = 04h ; write protect ROMBASE
* ROMBASE(36:55) = 0FFFC0h ; Top of PCI/bottom of rom chipselect area
* DEVRC(35:28) = 39h ; cache disabled in PCI memory + WS bit on + Write Combine + write burst.
* SYSTOP(27:8) = top of system memory
* SYSRC(7:0) = 00h ; writeback, can set to 08h to make writethrough
*
***************************************************************************/
#define SYSMEM_RCONF_WRITETHROUGH 8
#define DEVRC_RCONF_DEFAULT 0x21
#define ROMBASE_RCONF_DEFAULT 0xFFFC0000
#define ROMRC_RCONF_DEFAULT 0x25
static void
RCONFInit(void)
{
struct gliutable *gl = 0;
int i;
msr_t msr;
uint8_t SysMemCacheProp;
uint8_t RegionProp;
/* Locate SYSMEM entry in GLIU0table */
for(i = 0; gliu0table[i].desc_name != GL_END; i++) {
if (gliu0table[i].desc_type == R_SYSMEM) {
gl = &gliu0table[i];
break;
}
}
if (gl == 0) {
post_code(0xCE); /* POST_RCONFInitError */
while (1);
}
// sysdescfound:
/* found the descriptor... get its contents */
msr = rdmsr(gl->desc_name);
/* 20 bit address - The bottom 12 bits go into bits 20-31 in eax, the
* top 8 bits go into 0-7 of edx.
*/
msr.lo = (msr.lo & 0xFFFFFF00) | (msr.hi & 0xFF);
msr.lo = ((msr.lo << 12) | (msr.lo >> 20)) & 0x000FFFFF;
msr.lo <<= RCONF_DEFAULT_LOWER_SYSTOP_SHIFT; // 8
// Set Default SYSMEM region properties
msr.lo &= ~SYSMEM_RCONF_WRITETHROUGH; // 8 (or ~8)
// Set PCI space cache properties
msr.hi = (DEVRC_RCONF_DEFAULT >> 4); // only need the bottom bits and lets clean the rest of edx
msr.lo |= (DEVRC_RCONF_DEFAULT << 28);
// Set the ROMBASE. This is usually FFFC0000h
msr.hi |= (ROMBASE_RCONF_DEFAULT >> 12) << RCONF_DEFAULT_UPPER_ROMBASE_SHIFT;
// Set ROMBASE cache properties.
msr.hi |= ((ROMRC_RCONF_DEFAULT >> 8) | (ROMRC_RCONF_DEFAULT << 24));
// now program RCONF_DEFAULT
wrmsr(CPU_RCONF_DEFAULT, msr);
// RCONF_BYPASS: Cache tablewalk properties and SMM/DMM header access properties.
// Set to match system memory cache properties.
msr = rdmsr(CPU_RCONF_DEFAULT);
SysMemCacheProp = (uint8_t) (msr.lo & 0xFF);
msr = rdmsr(CPU_RCONF_BYPASS);
msr.lo = (msr.lo & 0xFFFF0000) | (SysMemCacheProp << 8) | SysMemCacheProp;
wrmsr(CPU_RCONF_BYPASS, msr);
}
/* ***************************************************************************/
/* **/
/* * northBridgeInit*/
/* **/
/* * Core Logic initialization: Host bridge*/
/* **/
/* * Entry:*/
/* * Exit:*/
/* * Modified:*/
/* **/
/* ***************************************************************************/
void
northbridgeinit(void)
{
msr_t msr;
int i;
printk_debug("Enter %s\n", __FUNCTION__);
for(i = 0; gliutables[i]; i++)
GLIUInit(gliutables[i]);
GeodeLinkPriority();
shadowRom();
// GeodeROM ensures that the BIOS waits the required 1 second before
// allowing anything to access PCI
// PCIDelay();
RCONFInit();
// The cacheInit function in GeodeROM tests cache and, among other things,
// makes sure all INVD instructions are treated as WBINVD. We do this
// because we've found some programs which require this behavior.
// That subset of cacheInit() is implemented here:
msr = rdmsr(CPU_DM_CONFIG0);
msr.lo |= DM_CONFIG0_LOWER_WBINVD_SET;
wrmsr(CPU_DM_CONFIG0, msr);
/* Now that the descriptor to memory is set up.*/
/* The memory controller needs one read to synch its lines before it can be used.*/
i = *(int *) 0;
GLPCIInit();
ClockGatingInit();
__asm__("FINIT\n");
/* CPUBugsFix -- called elsewhere */
printk_debug("Exit %s\n", __FUNCTION__);
}

View File

@ -0,0 +1,85 @@
#define POST_CODE(x) outb(0x80, x)
static void pll_reset(void)
{
msr_t msrGlcpSysRstpll;
msrGlcpSysRstpll = rdmsr(GLCP_SYS_RSTPLL);
print_debug("MSR GLCP_SYS_RSTPLL (");
print_debug_hex32(GLCP_SYS_RSTPLL);
print_debug(") value is: ");
print_debug_hex32(msrGlcpSysRstpll.hi);
print_debug(":");
print_debug_hex32(msrGlcpSysRstpll.lo);
print_debug("\n");
msrGlcpSysRstpll.lo &= 0x80000000;
// If the "we've already been here" flag is set, don't reconfigure the pll
if ( !(msrGlcpSysRstpll.lo) )
{ // we haven't configured the PLL; do it now
POST_CODE(0x77);
/*
* 64 - 32 | 31-0
*
* (03FB)
* 0000 0011 1111 1011 | 1000 0000 1101 1110 0000 0000 1000 0001
*
* (039C)
* 0000 0011 1001 1100 | 1000 0000 1101 1110 0000 0000 1000 0001
*
* (029C)
* 0000 0010 1001 1100 | 1000 0000 1101 1110 0000 0000 1000 0001
*
* (02CB)
* 0000 0010 1100 1011 | 1000 0000 1101 1110 0000 0000 1000 0001
*
* 00101 1 00101 1 | 100000 0 0 11011110 0000 0000 1000 0001
* GLIUMULT GLIUDIV COREMULT COREDIV | SWFLAGS (RO) (RO) HOLD_COUNT
*/
/* ### 02CB ###
* GLIUMULT = 6
* GLIUDIV = 2
* COREMULT = 6
* COREDIV = 2
*
* ### 03FB ###
* GLIUMULT = 8
* GLIUDIV = 2
* COREMULT = 30
* COREDIV = 2
*
* ### 039C ### bad... why?
* GLIUMULT = 8
* GLIUDIV = 0
* COREMULT = 15
* COREDIV = 0
*
* ### 029C ### good...
* GLIUMULT = 6
* GLIUDIV = 0
* COREMULT = 15
* COREDIV = 0
*
* CLOCK = 33 MHz
*
*/
/* CPU and GLIU mult/div (GLMC_CLK = GLIU_CLK / 2) */
msrGlcpSysRstpll.hi = 0x0000029C;
/* Hold Count - how long we will sit in reset */
msrGlcpSysRstpll.lo = 0x00DE0000;
/* Use SWFLAGS to remember: "we've already been here" */
msrGlcpSysRstpll.lo |= 0x80000000;
/* "reset the chip" value */
msrGlcpSysRstpll.lo |= 0x00000001;
wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll);
}
}

View File

@ -0,0 +1,143 @@
#include <cpu/amd/lxdef.h>
#if 0
static void sdram_set_registers(const struct mem_controller *ctrl)
{
}
#endif
/* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence
* Section 4.1.4, GX/CS5535 GeodeROM Porting guide */
static void sdram_enable(int controllers, const struct mem_controller *ctrl)
{
int i;
msr_t msr;
/* DRAM initialization sequence according to the documentation:
* 1) Initialize the following GLMC registers/bits based on Serial Presence Detect (SPD) values:
* MSR 20000018h except REF_INT bits [23:8]
* MSR 20000019h
*/
// This is done by sdram_set_spd_registers()
/*WR_MSR MC_CF07_DATA, DIMMCONFIG, 0x05000040
;WR_MSR MC_CF07_DATA, DIMMCONFIG, 0x00000040 ; MSR 20000018h except REF_INT bits [23:8]. REF_STAG value from DOCS*/
/*
* 0x18000100 : 0x696332A3
*
* 63 - 32 | 31 15 0
* xxxxxxx | 0110 1001 0110 0011 0011 0010 1010 0011
*
* 30:28 CAS latency
*
* 010 - 2.0
* 110 - 2.5
*
*/
msr.hi = 0x18000100;
msr.lo = 0x696332A3;
wrmsr(MC_CF8F_DATA, msr);
/* 2) Initialize the following GLMC registers:
* MSR 2000001Ah[15:8] = C8h
* MSR 20002004h[2] = 0, [0] = 1
*/
msr.hi = 0x00000000;
msr.lo = 0x130AD101;
wrmsr(MC_CF1017_DATA, msr);
msr.hi = 0x00000000;
msr.lo = 0x00000001;
wrmsr(MC_GLD_MSR_PM, msr);
/* 3) Release MASK_CKE[1:0] (MSR 2000001Dh[9:8] = 11) */
msr.hi = 0x00000000;
msr.lo = 0x00001000;
wrmsr(MC_CFCLK_DBUG, msr);
//print_debug("sdram_enable step 3\r\n");
/* 4. set and clear REF_TST 16 times, more shouldn't hurt
* why this is before EMRS and MRS ? */
for (i = 0; i < 19; i++) {
msr = rdmsr(MC_CF07_DATA);
msr.lo |= (0x01 << 3);
wrmsr(MC_CF07_DATA, msr);
msr.lo &= ~(0x01 << 3);
wrmsr(MC_CF07_DATA, msr);
}
/* 5) Initialize REF_INT (MSR 20000018h[23:8]) to set refresh interval. */
msr.lo |= 0x2B00;
wrmsr(MC_CF07_DATA, msr);
/* set refresh staggering to 4 SDRAM clocks */
msr = rdmsr(0x20000018);
msr.lo &= ~(0x03 << 6);
msr.lo |= (0x00 << 6);
wrmsr(0x20000018, msr);
//print_debug("sdram_enable step 5\r\n");
/* 6) Perform load-mode with MSR_BA = 01 (MSR 200000018h[29:28] = 01)
* to initialize DIMM Extended Mode register.
* Load-mode is performed by setting/clearing PROG_DRAM (MSR 200000018h[0]).
*/
msr.lo |= ((0x01 << 28) | 0x01);
wrmsr(MC_CF07_DATA, msr);
msr.lo &= ~((0x01 << 28) | 0x01);
wrmsr(MC_CF07_DATA, msr);
/* 7. Reset DLL, Bit 27 is undocumented in GX datasheet,
* it is documented in LX datasheet */
/* load Mode Register by set and clear PROG_DRAM */
msr = rdmsr(MC_CF07_DATA);
msr.lo |= ((0x01 << 27) | 0x01);
wrmsr(MC_CF07_DATA, msr);
msr.lo &= ~((0x01 << 27) | 0x01);
wrmsr(MC_CF07_DATA, msr);
//print_debug("sdram_enable step 7\r\n");
/* 8. load Mode Register by set and clear PROG_DRAM */
msr = rdmsr(MC_CF07_DATA);
msr.lo |= 0x01;
wrmsr(MC_CF07_DATA, msr);
msr.lo &= ~0x01;
wrmsr(MC_CF07_DATA, msr);
//print_debug("sdram_enable step 8\r\n");
/* wait 200 SDCLKs */
for (i = 0; i < 200; i++)
outb(0xaa, 0x80);
/* load RDSYNC */
/*msr = rdmsr(0x2000001f);
msr.hi = 0x000ff310;
msr.lo = 0x00000000;
wrmsr(0x2000001f, msr);*/
/* set delay control */
msr = rdmsr(0x4c00000f);
msr.hi = 0x830d415a;
msr.lo = 0x8ea0ad6a;
wrmsr(0x4c00000f, msr);
print_debug("DRAM controller init done.\r\n");
/* DRAM working now?? */
}

View File

@ -0,0 +1,10 @@
#ifndef RAMINIT_H
#define RAMINIT_H
#define DIMM_SOCKETS 2
struct mem_controller {
uint16_t channel0[DIMM_SOCKETS];
};
#endif /* RAMINIT_H */

View File

@ -0,0 +1,20 @@
# Config file for the olpc rev_a
target dbe61
mainboard artecgroup/dbe61
# leave 128k for vsa
option CONFIG_COMPRESSED_ROM_STREAM=0
option ROM_SIZE=1024*256-128*1024
option FALLBACK_SIZE=ROM_SIZE
option DEFAULT_CONSOLE_LOGLEVEL = 11
option MAXIMUM_CONSOLE_LOGLEVEL = 11
romimage "fallback"
option USE_FALLBACK_IMAGE=1
option ROM_IMAGE_SIZE=32*1024
option LINUXBIOS_EXTRA_VERSION=".0Fallback"
payload /tmp/rtl8139--filo.zelf
end
buildrom ./linuxbios.rom ROM_SIZE "fallback"