Even more coding style fixes and other cosmetic fixes (trivial).

Signed-off-by: Uwe Hermann <uwe@hermann-uwe.de>
Acked-by: Uwe Hermann <uwe@hermann-uwe.de>



git-svn-id: svn://coreboot.org/repository/LinuxBIOSv3@439 f3766cd6-281f-0410-b1cd-43a5c92072e9
This commit is contained in:
Uwe Hermann 2007-07-08 00:19:26 +00:00
parent 203bffe9e7
commit 7f484d348f
3 changed files with 888 additions and 807 deletions

View file

@ -30,16 +30,17 @@
#include <io.h> #include <io.h>
#include <amd_geodelx.h> #include <amd_geodelx.h>
/* here is programming for the various MSRs.*/ /* Here is programming for the various MSRs. */
#define IM_QWAIT 0x100000 #define IM_QWAIT 0x100000
/* set in high nibl */ /* Set in high nibble. */
#define DMCF_WRITE_SERIALIZE_REQUEST (2 << 12) /* 2 outstanding */ #define DMCF_WRITE_SERIALIZE_REQUEST (2 << 12) /* 2 outstanding */
#define DMCF_SERIAL_LOAD_MISSES (2) /* enabled */ #define DMCF_SERIAL_LOAD_MISSES 2 /* Enabled */
/* these are the 8-bit attributes for controlling RCONF registers /* These are the 8-bit attributes for controlling RCONF registers.
* RCONF is Region CONFiguraiton, and controls caching and other *
* RCONF is Region CONFiguration, and controls caching and other
* attributes of a region. Just like MTRRs, only different. * attributes of a region. Just like MTRRs, only different.
*/ */
#define CACHE_DISABLE (1 << 0) #define CACHE_DISABLE (1 << 0)
@ -49,35 +50,54 @@
#define WRITE_COMBINE (1 << 4) #define WRITE_COMBINE (1 << 4)
#define WRITE_SERIALIZE (1 << 5) #define WRITE_SERIALIZE (1 << 5)
/* ram has none of this stuff */ /* RAM has none of this stuff. */
#define RAM_PROPERTIES (0) #define RAM_PROPERTIES 0
#define DEVICE_PROPERTIES (WRITE_SERIALIZE|CACHE_DISABLE) #define DEVICE_PROPERTIES (WRITE_SERIALIZE|CACHE_DISABLE)
#define ROM_PROPERTIES (WRITE_SERIALIZE|WRITE_PROTECT|CACHE_DISABLE) #define ROM_PROPERTIES (WRITE_SERIALIZE|WRITE_PROTECT|CACHE_DISABLE)
#define MSR_WS_CD_DEFAULT (0x21212121) #define MSR_WS_CD_DEFAULT 0x21212121
/* RCONF registers 1810-1817 give you 8 registers with which to /* RCONF registers 1810-1817 give you 8 registers with which to
* program protection regions the are region configuration range * program protection regions the are region configuration range
* registers, or RRCF in msr terms, the are a straight base, top * registers, or RRCF in msr terms, the are a straight base, top
* address assign, since they are 4k aligned. * address assign, since they are 4k aligned.
*/ */
/* so no left-shift needed for top or base */ /* So no left-shift needed for top or base. */
#define RRCF_LOW(base, properties) (base | (1 << 8) | properties) #define RRCF_LOW(base, properties) (base | (1 << 8) | properties)
#define RRCF_LOW_CD(base) RRCF_LOW(base, CACHE_DISABLE) #define RRCF_LOW_CD(base) RRCF_LOW(base, CACHE_DISABLE)
/* build initializer for P2D MSR */ /* Build initializer for P2D MSR.
/* this is complex enough that you are going to need to RTFM if you *
* This is complex enough that you are going to need to RTFM if you
* really want to understand it. * really want to understand it.
*/ */
#define P2D_BM(msr, pdid1, bizarro, pbase, pmask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(pbase>>24), .lo=(pbase<<8)|pmask}} #define P2D_BM(msr, pdid1, bizarro, pbase, pmask) \
#define P2D_BMO(msr, pdid1, bizarro, poffset, pbase, pmask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(poffset<<8)|(pbase>>24), .lo=(pbase<<8)|pmask}} {msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (pbase >> 24), \
#define P2D_R(msr, pdid1, bizarro, pmax, pmin) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(pmax>>12), .lo=(pmax<<20)|pmin}} .lo = (pbase << 8) | pmask}}
#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_BMO(msr, pdid1, bizarro, poffset, pbase, pmask) \
#define P2D_SC(msr, pdid1, bizarro, wen, ren,pscbase) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(wen), .lo=(ren<<16)|(pscbase>>18)}} {msr, {.hi = (pdid1 << 29) | (bizarro << 28) | \
#define IOD_BM(msr, pdid1, bizarro, ibase, imask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(ibase>>12), .lo=(ibase<<20)|imask}} (poffset << 8) | (pbase >> 24), \
#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)}} .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)}}
#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM) #define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
/* TODO: Should be in some header file? */
extern void graphics_init(void); extern void graphics_init(void);
extern void cpu_bug(void); extern void cpu_bug(void);
extern void chipsetinit(void); extern void chipsetinit(void);
@ -95,40 +115,51 @@ struct msr_defaults {
{ 0x1700, {.hi = 0,.lo = IM_QWAIT}}, { 0x1700, {.hi = 0,.lo = IM_QWAIT}},
{ 0x1800, {.hi = DMCF_WRITE_SERIALIZE_REQUEST, { 0x1800, {.hi = DMCF_WRITE_SERIALIZE_REQUEST,
.lo = DMCF_SERIAL_LOAD_MISSES}}, .lo = DMCF_SERIAL_LOAD_MISSES}},
/* 1808 will be done down below, so we have to do 180a->1817 /* 1808 will be done down below, so we have to do 180a->1817
* (well, 1813 really) * (well, 1813 really).
*/ */
/* for 180a, for now, we assume VSM will configure it */ /* For 180a, for now, we assume VSM will configure it. */
/* 180b is left at reset value,a0000-bffff is non-cacheable */ /* 180b is left at reset value, a0000-bffff is non-cacheable. */
/* 180c, c0000-dffff is set to write serialize and non-cachable */ /* 180c, c0000-dffff is set to write serialize and non-cachable. */
/* oops, 180c will be set by cpu bug handling in cpubug.c */ /* Oops, 180c will be set by CPU bug handling in cpubug.c. */
/* TODO: There's no cpubug.c. */
// {0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}}, // {0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}},
/* 180d is left at default, e0000-fffff is non-cached */ /* 180d is left at default, e0000-fffff is non-cached. */
/* we will assume 180e, the ssm region configuration, is left /* We will assume 180e, the ssm region configuration, is left
* at default or set by VSM */ * 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)}}, /* 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)}}, // {0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
// {0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}}, // {0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}},
// {0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}}, // {0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}},
/* now for GLPCI routing */
/* Now for GLPCI routing. */
/* GLIU0 */ /* GLIU0 */
P2D_BM(MSR_GLIU0_BASE1, 0x1, 0x0, 0x0, 0xfff80), P2D_BM(MSR_GLIU0_BASE1, 0x1, 0x0, 0x0, 0xfff80),
P2D_BM(MSR_GLIU0_BASE2, 0x1, 0x0, 0x80000, 0xfffe0), P2D_BM(MSR_GLIU0_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
P2D_SC(MSR_GLIU0_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000), P2D_SC(MSR_GLIU0_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
/* GLIU1 */ /* GLIU1 */
P2D_BM(MSR_GLIU1_BASE1, 0x1, 0x0, 0x0, 0xfff80), P2D_BM(MSR_GLIU1_BASE1, 0x1, 0x0, 0x0, 0xfff80),
P2D_BM(MSR_GLIU1_BASE2, 0x1, 0x0, 0x80000, 0xfffe0), P2D_BM(MSR_GLIU1_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
P2D_SC(MSR_GLIU1_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000), P2D_SC(MSR_GLIU1_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
{0}
{0},
}; };
/** /**
* Size up ram. All we need to here is read the MSR for DRAM and grab * Size up ram.
* out the sizing bits. Note that this code depends on initram *
* having run. It uses the MSRs, not the SPDs, and the MSRs of course * All we need to do here is read the MSR for DRAM and grab out the sizing
* are set up by initram. * bits. Note that this code depends on initram having run. It uses the MSRs,
* not the SPDs, and the MSRs of course are set up by initram.
*
* @return TODO
*/ */
int sizeram(void) int sizeram(void)
{ {
@ -137,32 +168,36 @@ int sizeram(void)
unsigned short dimm; unsigned short dimm;
/* Get the RAM size from the memory controller as calculated /* Get the RAM size from the memory controller as calculated
* and set by auto_size_dimm() * and set by auto_size_dimm().
*/ */
msr = rdmsr(MC_CF07_DATA); msr = rdmsr(MC_CF07_DATA);
printk(BIOS_DEBUG,"sizeram: _MSR MC_CF07_DATA: %08x:%08x\n", msr.hi, msr.lo); printk(BIOS_DEBUG, "sizeram: _MSR MC_CF07_DATA: %08x:%08x\n", msr.hi,
msr.lo);
/* dimm 0 */ /* DIMM 0 */
dimm = msr.hi; dimm = msr.hi;
/* installed? */ /* Installed? */
if ((dimm & 7) != 7) { if ((dimm & 7) != 7) {
/* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */ /* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */
sizem = 4 << ((dimm >> 12) & 0x0F); } sizem = 4 << ((dimm >> 12) & 0x0F);
}
/* dimm 1 */ /* DIMM 1 */
dimm = msr.hi >> 16; dimm = msr.hi >> 16;
/* installed? */ /* Installed? */
if ((dimm & 7) != 7) { if ((dimm & 7) != 7) {
/* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */ /* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */
sizem += 4 << ((dimm >> 12) & 0x0F); sizem += 4 << ((dimm >> 12) & 0x0F);
} }
printk(BIOS_DEBUG, "sizeram: sizem 0x%xMB\n", sizem); printk(BIOS_DEBUG, "sizeram: sizem 0x%xMB\n", sizem);
return sizem; return sizem;
} }
/** /**
* enable_shadow. Currently not set up. * Currently not set up.
*
* @param dev The nortbridge device. * @param dev The nortbridge device.
*/ */
static void enable_shadow(struct device *dev) static void enable_shadow(struct device *dev)
@ -170,50 +205,51 @@ static void enable_shadow(struct device * dev)
} }
/** /**
* init the northbridge pci device. Right now this a no op. We leave * Initialize the northbridge PCI device.
* it here as a hook for later use. * Right now this a no op. We leave it here as a hook for later use.
*
* @param dev The nortbridge device. * @param dev The nortbridge device.
*/ */
static void geodelx_northbridge_init(struct device *dev) static void geodelx_northbridge_init(struct device *dev)
{ {
//struct msr msr; /* struct msr msr; */
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__); printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
enable_shadow(dev); enable_shadow(dev);
/*
* Swiss cheese
*/
//msr = rdmsr(MSR_GLIU0_SHADOW);
//msr.hi |= 0x3; #if 0
//msr.lo |= 0x30000; /* Swiss cheese */
msr = rdmsr(MSR_GLIU0_SHADOW);
//printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU0_SHADOW, msr.hi, msr.lo); msr.hi |= 0x3;
//printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU1_SHADOW, msr.hi, msr.lo); msr.lo |= 0x30000;
printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU0_SHADOW, msr.hi, msr.lo);
printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU1_SHADOW, msr.hi, msr.lo);
#endif
} }
/** /**
* Set resources for the PCI northbridge device. This function is * Set resources for the PCI northbridge device.
* required due to VSA interactions. * This function is required due to VSA interactions.
*
* @param dev The nortbridge device. * @param dev The nortbridge device.
*/ */
void geodelx_northbridge_set_resources(struct device *dev) void geodelx_northbridge_set_resources(struct device *dev)
{ {
struct resource *resource, *last; struct resource *resource, *last;
unsigned link; unsigned int link;
u8 line; u8 line;
last = &dev->resource[dev->resources]; last = &dev->resource[dev->resources];
for (resource = &dev->resource[0]; resource < last; resource++) { for (resource = &dev->resource[0]; resource < last; resource++) {
/* From AMD: do not change the base address, it will
/* * make the VSA virtual registers unusable.
* from AMD: do not change the base address, it will
* make the VSA virtual registers unusable
*/ */
// pci_set_resource(dev, resource); // pci_set_resource(dev, resource);
// FIXME: static allocation may conflict with dynamic mappings! // FIXME: Static allocation may conflict with dynamic mappings!
} }
for (link = 0; link < dev->links; link++) { for (link = 0; link < dev->links; link++) {
@ -221,49 +257,50 @@ void geodelx_northbridge_set_resources(struct device *dev)
bus = &dev->link[link]; bus = &dev->link[link];
if (bus->children) { if (bus->children) {
printk(BIOS_DEBUG, printk(BIOS_DEBUG,
"my_dev_set_resources: phase4_assign_resources %d\n", bus); "my_dev_set_resources: phase4_assign_resources %d\n",
bus);
phase4_assign_resources(bus); phase4_assign_resources(bus);
} }
} }
/* set a default latency timer */ /* Set a default latency timer. */
pci_write_config8(dev, PCI_LATENCY_TIMER, 0x40); pci_write_config8(dev, PCI_LATENCY_TIMER, 0x40);
/* set a default secondary latency timer */ /* Set a default secondary latency timer. */
if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) { if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE)
pci_write_config8(dev, PCI_SEC_LATENCY_TIMER, 0x40); pci_write_config8(dev, PCI_SEC_LATENCY_TIMER, 0x40);
}
/* zero the irq settings */ /* Zero the IRQ settings. */
line = pci_read_config8(dev, PCI_INTERRUPT_PIN); line = pci_read_config8(dev, PCI_INTERRUPT_PIN);
if (line) { if (line)
pci_write_config8(dev, PCI_INTERRUPT_LINE, 0); pci_write_config8(dev, PCI_INTERRUPT_LINE, 0);
}
/* set the cache line size, so far 64 bytes is good for everyone */ /* Set the cache line size, so far 64 bytes is good for everyone. */
pci_write_config8(dev, PCI_CACHE_LINE_SIZE, 64 >> 2); pci_write_config8(dev, PCI_CACHE_LINE_SIZE, 64 >> 2);
} }
/** /**
* Set resources for the PCI domain. Just set up basic global ranges * Set resources for the PCI domain.
* for IO and memory Allocation of sub-resources draws on these *
* top-level resources in the usual hierarchical manner. * Just set up basic global ranges for I/O and memory. Allocation of
* sub-resources draws on these top-level resources in the usual
* hierarchical manner.
*
* @param dev The nortbridge device. * @param dev The nortbridge device.
*/ */
static void geodelx_pci_domain_read_resources(struct device *dev) static void geodelx_pci_domain_read_resources(struct device *dev)
{ {
struct resource *resource; struct resource *resource;
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__); printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
/* Initialize the system wide io space constraints */ /* Initialize the system wide I/O space constraints. */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0)); resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
resource->limit = 0xffffUL; resource->limit = 0xffffUL;
resource->flags = resource->flags =
IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
/* Initialize the system wide memory resources constraints */ /* Initialize the system wide memory resources constraints. */
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0)); resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
resource->limit = 0xffffffffULL; resource->limit = 0xffffffffULL;
resource->flags = resource->flags =
@ -271,12 +308,13 @@ static void geodelx_pci_domain_read_resources(struct device * dev)
} }
/** /**
* Create a ram resource, by taking the passed-in size and createing * Create a RAM resource, by taking the passed-in size and creating
* a resource record. * a resource record.
* @param dev the device *
* @param index a resource index * @param dev The device.
* @param basek base memory address in k * @param index A resource index.
* @param sizek size of memory in k * @param basek Base memory address in KB.
* @param sizek Size of memory in KB.
*/ */
static void ram_resource(struct device *dev, unsigned long index, static void ram_resource(struct device *dev, unsigned long index,
unsigned long basek, unsigned long sizek) unsigned long basek, unsigned long sizek)
@ -294,10 +332,13 @@ static void ram_resource(struct device * dev, unsigned long index,
} }
/** /**
* Set resources in the pci domain. Also, as a side effect, create a * Set resources in the PCI domain.
* ram resource in the child which, interestingly enough, is the *
* north bridge pci device, for later allocation of address space. * Also, as a side effect, create a RAM resource in the child which,
* @param dev the device * interestingly enough, is the northbridge PCI device, for later
* allocation of address space.
*
* @param dev The device.
*/ */
static void geodelx_pci_domain_set_resources(struct device *dev) static void geodelx_pci_domain_set_resources(struct device *dev)
{ {
@ -308,58 +349,63 @@ static void ram_resource(struct device * dev, unsigned long index,
mc_dev = dev->link[0].children; mc_dev = dev->link[0].children;
if (mc_dev) { if (mc_dev) {
/* Report the memory regions */ /* Report the memory regions. */
idx = 10; idx = 10;
/* 0 .. 640 KB */
ram_resource(dev, idx++, 0, 640); ram_resource(dev, idx++, 0, 640);
/* Systop - 1 MB -> KB*/ /* 1 MB .. (Systop - 1 MB) (converted to KB) */
ram_resource(dev, idx++, 1024, (get_systop() - 0x100000) / 1024); ram_resource(dev, idx++, 1024,
(get_systop() - (1 * 1024 * 1024)) / 1024);
} }
phase4_assign_resources(&dev->link[0]); phase4_assign_resources(&dev->link[0]);
} }
/** /**
* enable the pci domain. A littly tricky on this chipset due to the * Enable the PCI domain.
* VSA interactions. This must happen before any PCI scans happen. *
* we do early northbridge init to make sure pci scans will work, but * A littly tricky on this chipset due to the VSA interactions. This must
* the weird part is we actually have to run some code in x86 mode to * happen before any PCI scans happen. We do early northbridge init to make
* get the VSM installed, since the VSM actually handles some PCI bus * sure PCI scans will work, but the weird part is we actually have to run
* scan tasks via the System Management Interrupt. Yes, it gets * some code in x86 mode to get the VSM installed, since the VSM actually
* tricky ... * handles some PCI bus scan tasks via the System Management Interrupt.
* @param dev the device * Yes, it gets tricky...
*
* @param dev The device.
*/ */
static void geodelx_pci_domain_phase2(struct device *dev) static void geodelx_pci_domain_phase2(struct device *dev)
{ {
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__); printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
northbridge_init_early(); northbridge_init_early();
#warning cpu bug has been moved to initram stage #warning cpu bug has been moved to initram stage
// cpu_bug(); /* cpu_bug(); */
chipsetinit(); chipsetinit();
setup_realmode_idt(); setup_realmode_idt();
printk(BIOS_DEBUG, "Before VSA:\n"); printk(BIOS_DEBUG, "Before VSA:\n");
// print_conf(); /* print_conf(); */
#warning Not doing vsm bios -- linux will fail. #warning Not doing vsm bios -- linux will fail.
// do_vsmbios(); // do the magic stuff here, so prepare your tambourine ;) /* Do the magic stuff here, so prepare your tambourine ;) */
/* do_vsmbios(); */
printk(BIOS_DEBUG, "After VSA:\n"); printk(BIOS_DEBUG, "After VSA:\n");
// print_conf(); /* print_conf(); */
#warning graphics_init is disabled. #warning graphics_init is disabled.
// graphics_init(); /* graphics_init(); */
pci_set_method(dev); pci_set_method(dev);
} }
/** /**
* Support for scan bus from the "tippy top" -- i.e. the pci domain, * Support for scan bus from the "tippy top" -- i.e. the PCI domain,
* not the 0:0.0 device. * not the 0:0.0 device.
* @param dev The pci domain device *
* @param max max number of devices to scan. * @param dev The PCI domain device.
* @param max Maximum number of devices to scan.
*/ */
static unsigned int geodelx_pci_domain_scan_bus(struct device * dev, unsigned int max) static unsigned int geodelx_pci_domain_scan_bus(struct device *dev,
unsigned int max)
{ {
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__); printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
@ -367,31 +413,29 @@ static unsigned int geodelx_pci_domain_scan_bus(struct device * dev, unsigned in
return max; return max;
} }
/** /**
* Support for apic cluster init. TODO should we do this in phase 2? * Support for APIC cluster init.
* It is now done in phase 6 *
* @param dev The pci domain device * TODO: Should we do this in phase 2? It is now done in phase 6.
*
* @param dev The PCI domain device.
*/ */
static void cpu_bus_init(struct device *dev) static void cpu_bus_init(struct device *dev)
{ {
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__); printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
printk(BIOS_SPEW, ">> Exiting northbridge.c: %s\n", __FUNCTION__); printk(BIOS_SPEW, ">> Exiting northbridge.c: %s\n", __FUNCTION__);
} }
static void cpu_bus_noop(struct device *dev) static void cpu_bus_noop(struct device *dev)
{ {
} }
/* the same hardware, being multifunction, has several roles. In this /* The same hardware, being multifunction, has several roles. In this case,
* case, the north is a pci domain controller, apic cluster, and the * the northbridge is a PCI domain controller, APIC cluster, and the
* traditional 0:0.0 device * traditional 0:0.0 device.
*/ */
/* Here are the operations for when the northbridge is running a PCI /** Operations for when the northbridge is running a PCI domain. */
* domain.
*/
struct device_operations geodelx_pcidomainops = { struct device_operations geodelx_pcidomainops = {
.constructor = default_device_constructor, .constructor = default_device_constructor,
.phase2_setup_scan_bus = geodelx_pci_domain_phase2, .phase2_setup_scan_bus = geodelx_pci_domain_phase2,
@ -401,12 +445,9 @@ struct device_operations geodelx_pcidomainops = {
.phase5_enable_resources = enable_childrens_resources, .phase5_enable_resources = enable_childrens_resources,
.phase6_init = 0, .phase6_init = 0,
.ops_pci_bus = &pci_cf8_conf1, .ops_pci_bus = &pci_cf8_conf1,
}; };
/* Here are the operations for when the northbridge is running an APIC /** Operations for when the northbridge is running an APIC cluster. */
* cluster.
*/
struct device_operations geodelx_apicops = { struct device_operations geodelx_apicops = {
.constructor = default_device_constructor, .constructor = default_device_constructor,
.phase3_scan = 0, .phase3_scan = 0,
@ -417,9 +458,7 @@ struct device_operations geodelx_apicops = {
.ops_pci_bus = &pci_cf8_conf1, .ops_pci_bus = &pci_cf8_conf1,
}; };
/* Here are the operations for when the northbridge is running a PCI /** Operations for when the northbridge is running a PCI device. */
* device.
*/
struct device_operations geodelx_pci_ops = { struct device_operations geodelx_pci_ops = {
.constructor = default_device_constructor, .constructor = default_device_constructor,
.phase3_scan = geodelx_pci_domain_scan_bus, .phase3_scan = geodelx_pci_domain_scan_bus,
@ -428,21 +467,30 @@ struct device_operations geodelx_pci_ops = {
.phase5_enable_resources = enable_childrens_resources, .phase5_enable_resources = enable_childrens_resources,
.phase6_init = geodelx_northbridge_init, .phase6_init = geodelx_northbridge_init,
.ops_pci_bus = &pci_cf8_conf1, .ops_pci_bus = &pci_cf8_conf1,
}; };
/**
/* The constructor for the device. */ * The constructor for the device.
/* Domain ops and apic cluster ops and pci device ops are different */ * Domain ops and APIC cluster ops and PCI device ops are different.
*/
struct constructor geodelx_north_constructors[] = { struct constructor geodelx_north_constructors[] = {
/* Northbridge running a PCI domain. */
{.id = {.type = DEVICE_ID_PCI_DOMAIN, {.id = {.type = DEVICE_ID_PCI_DOMAIN,
.u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}}, .u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,
&geodelx_pcidomainops}, .device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.ops = &geodelx_pcidomainops},
/* Northbridge running an APIC cluster. */
{.id = {.type = DEVICE_ID_APIC_CLUSTER, {.id = {.type = DEVICE_ID_APIC_CLUSTER,
.u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}}, .u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,
&geodelx_apicops}, .device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.ops = &geodelx_apicops},
/* Northbridge running a PCI device. */
{.id = {.type = DEVICE_ID_PCI, {.id = {.type = DEVICE_ID_PCI,
.u = {.pci = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}}, .u = {.pci = {.vendor = PCI_VENDOR_ID_AMD,
&geodelx_pci_ops}, .device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.ops = &geodelx_pci_ops},
{.ops = 0}, {.ops = 0},
}; };

View file

@ -40,18 +40,18 @@ struct gliutable gliu0table[] = {
/* 0-7FFFF to MC */ /* 0-7FFFF to MC */
{.desc_name = MSR_GLIU0_BASE1,.desc_type = BM,.hi = MSR_MC + 0x0, {.desc_name = MSR_GLIU0_BASE1,.desc_type = BM,.hi = MSR_MC + 0x0,
.lo = 0x0FFF80}, .lo = 0x0FFF80},
/* 80000-9ffff to Mc */ /* 80000-9FFFF to MC */
{.desc_name = MSR_GLIU0_BASE2,.desc_type = BM,.hi = MSR_MC + 0x0, {.desc_name = MSR_GLIU0_BASE2,.desc_type = BM,.hi = MSR_MC + 0x0,
.lo = (0x80 << 20) + 0x0FFFE0}, .lo = (0x80 << 20) + 0x0FFFE0},
/* C0000-Fffff split to MC and PCI (sub decode) A0000-Bffff /* C0000-FFFFF split to MC and PCI (sub decode) A0000-BFFFF
* handled by SoftVideo * handled by SoftVideo.
*/ */
{.desc_name = MSR_GLIU0_SHADOW,.desc_type = SC_SHADOW, {.desc_name = MSR_GLIU0_SHADOW,.desc_type = SC_SHADOW,
.hi = MSR_MC + 0x0,.lo = 0x03}, .hi = MSR_MC + 0x0,.lo = 0x03},
/* Catch and fix dynamicly. */ /* Catch and fix dynamically. */
{.desc_name = MSR_GLIU0_SYSMEM,.desc_type = R_SYSMEM, {.desc_name = MSR_GLIU0_SYSMEM,.desc_type = R_SYSMEM,
.hi = MSR_MC,.lo = 0x0}, .hi = MSR_MC,.lo = 0x0},
/* Catch and fix dynamicly. */ /* Catch and fix dynamically. */
{.desc_name = MSR_GLIU0_SMM,.desc_type = BMO_SMM, {.desc_name = MSR_GLIU0_SMM,.desc_type = BMO_SMM,
.hi = MSR_MC,.lo = 0x0}, .hi = MSR_MC,.lo = 0x0},
{.desc_name = GLIU0_GLD_MSR_COH,.desc_type = OTHER, {.desc_name = GLIU0_GLD_MSR_COH,.desc_type = OTHER,
@ -63,16 +63,16 @@ struct gliutable gliu1table[] = {
/* 0-7FFFF to MC */ /* 0-7FFFF to MC */
{.desc_name = MSR_GLIU1_BASE1,.desc_type = BM,.hi = MSR_GL0 + 0x0, {.desc_name = MSR_GLIU1_BASE1,.desc_type = BM,.hi = MSR_GL0 + 0x0,
.lo = 0x0FFF80}, .lo = 0x0FFF80},
/* 80000-9ffff to Mc */ /* 80000-9FFFF to MC */
{.desc_name = MSR_GLIU1_BASE2,.desc_type = BM,.hi = MSR_GL0 + 0x0, {.desc_name = MSR_GLIU1_BASE2,.desc_type = BM,.hi = MSR_GL0 + 0x0,
.lo = (0x80 << 20) + 0x0FFFE0}, .lo = (0x80 << 20) + 0x0FFFE0},
/* C0000-Fffff split to MC and PCI (sub decode) */ /* C0000-Fffff split to MC and PCI (sub decode) */
{.desc_name = MSR_GLIU1_SHADOW,.desc_type = SC_SHADOW, {.desc_name = MSR_GLIU1_SHADOW,.desc_type = SC_SHADOW,
.hi = MSR_GL0 + 0x0,.lo = 0x03}, .hi = MSR_GL0 + 0x0,.lo = 0x03},
/* Catch and fix dynamicly. */ /* Catch and fix dynamically. */
{.desc_name = MSR_GLIU1_SYSMEM,.desc_type = R_SYSMEM, {.desc_name = MSR_GLIU1_SYSMEM,.desc_type = R_SYSMEM,
.hi = MSR_GL0,.lo = 0x0}, .hi = MSR_GL0,.lo = 0x0},
/* Catch and fix dynamicly. */ /* Catch and fix dynamically. */
{.desc_name = MSR_GLIU1_SMM,.desc_type = BM_SMM, {.desc_name = MSR_GLIU1_SMM,.desc_type = BM_SMM,
.hi = MSR_GL0,.lo = 0x0}, .hi = MSR_GL0,.lo = 0x0},
{.desc_name = GLIU1_GLD_MSR_COH,.desc_type = OTHER, {.desc_name = GLIU1_GLD_MSR_COH,.desc_type = OTHER,
@ -101,13 +101,11 @@ struct msrinit clock_gating_default[] = {
{GLPCI_GLD_MSR_PM, {.hi = 0x00,.lo = 0x0015}}, {GLPCI_GLD_MSR_PM, {.hi = 0x00,.lo = 0x0015}},
{VIP_GLD_MSR_PM, {.hi = 0x00,.lo = 0x0005}}, {VIP_GLD_MSR_PM, {.hi = 0x00,.lo = 0x0005}},
{AES_GLD_MSR_PM, {.hi = 0x00,.lo = 0x0015}}, {AES_GLD_MSR_PM, {.hi = 0x00,.lo = 0x0015}},
{CPU_BC_PMODE_MSR, {.hi = 0x00,.lo = 0x70303}}, {CPU_BC_PMODE_MSR, {.hi = 0x00,.lo = 0x70303}}, // TODO: Correct?
{0xffffffff, {0xffffffff, 0xffffffff}}, {0xffffffff, {0xffffffff, 0xffffffff}},
}; };
/* */ /** GeodeLink priority table. */
/* SET GeodeLink PRIORITY*/
/* */
struct msrinit geode_link_priority_table[] = { struct msrinit geode_link_priority_table[] = {
{CPU_GLD_MSR_CONFIG, {.hi = 0x00,.lo = 0x0220}}, {CPU_GLD_MSR_CONFIG, {.hi = 0x00,.lo = 0x0220}},
{DF_GLD_MSR_MASTER_CONF, {.hi = 0x00,.lo = 0x0000}}, {DF_GLD_MSR_MASTER_CONF, {.hi = 0x00,.lo = 0x0000}},
@ -117,14 +115,15 @@ struct msrinit geode_link_priority_table[] = {
{GLCP_GLD_MSR_CONF, {.hi = 0x00,.lo = 0x0001}}, {GLCP_GLD_MSR_CONF, {.hi = 0x00,.lo = 0x0001}},
{VIP_GLD_MSR_CONFIG, {.hi = 0x00,.lo = 0x0622}}, {VIP_GLD_MSR_CONFIG, {.hi = 0x00,.lo = 0x0622}},
{AES_GLD_MSR_CONFIG, {.hi = 0x00,.lo = 0x0013}}, {AES_GLD_MSR_CONFIG, {.hi = 0x00,.lo = 0x0013}},
{0x0FFFFFFFF, {0x0FFFFFFFF, 0x0FFFFFFFF}}, /* END */ {0x0FFFFFFFF, {0x0FFFFFFFF, 0x0FFFFFFFF}},
}; };
extern int sizeram(void); extern int sizeram(void);
/** /**
* Write a GeodeLink MSR. * Write a GeodeLink MSR.
* @param gl A Geode Link table descriptor *
* @param gl A GeodeLink table descriptor.
*/ */
static void writeglmsr(struct gliutable *gl) static void writeglmsr(struct gliutable *gl)
{ {
@ -132,44 +131,39 @@ static void writeglmsr(struct gliutable *gl)
msr.lo = gl->lo; msr.lo = gl->lo;
msr.hi = gl->hi; msr.hi = gl->hi;
wrmsr(gl->desc_name, msr); // MSR - see table above wrmsr(gl->desc_name, msr); /* MSR - see table above. */
printk(BIOS_SPEW, printk(BIOS_SPEW,
"%s: MSR 0x%08x, val 0x%08x:0x%08x\n", "%s: MSR 0x%08x, val 0x%08x:0x%08x\n",
__FUNCTION__, gl->desc_name, msr.hi, msr.lo); __FUNCTION__, gl->desc_name, msr.hi, msr.lo);
} }
/** /**
* Read the MSR specified in the gl struct. If the low 32 bits is zero, * Read the MSR specified in the gl struct. If the low 32 bits are zero,
* indicating * indicating it has not been set, set it.
* it has not been set, set it. *
* @param gl A Geode Link table descriptor * @param gl A GeodeLink table descriptor.
*/ */
static void ShadowInit(struct gliutable *gl) static void ShadowInit(struct gliutable *gl)
{ {
struct msr msr; struct msr msr;
msr = rdmsr(gl->desc_name); msr = rdmsr(gl->desc_name);
if (msr.lo == 0)
if (msr.lo == 0) {
writeglmsr(gl); writeglmsr(gl);
} }
}
extern int sizeram(void);
/** /**
* Set up the system memory registers, i.e. memory that can be used * Set up the system memory registers, i.e. memory that can be used
* for non-VSM (or SMM) purposes. * for non-VSM (or SMM) purposes.
* @param gl A Geode Link table descriptor *
* @param gl A GeodeLink table descriptor.
*/ */
static void sysmem_init(struct gliutable *gl) static void sysmem_init(struct gliutable *gl)
{ {
struct msr msr; struct msr msr;
int sizembytes, sizebytes; int sizembytes, sizebytes;
/* /* Figure out how much RAM is in the machine and allocate all to the
* Figure out how much RAM is in the machine and alocate all to the
* system. We will adjust for SMM now and Frame Buffer later. * system. We will adjust for SMM now and Frame Buffer later.
*/ */
sizembytes = sizeram(); sizembytes = sizeram();
@ -178,27 +172,28 @@ static void sysmem_init(struct gliutable *gl)
sizebytes = sizembytes << 20; sizebytes = sizembytes << 20;
sizebytes -= ((SMM_SIZE * 1024) + 1); sizebytes -= ((SMM_SIZE * 1024) + 1);
printk(BIOS_DEBUG, "usable RAM: %d bytes\n", sizebytes); printk(BIOS_DEBUG, "Usable RAM: %d bytes\n", sizebytes);
/* 20 bit address The bottom 12 bits go into bits 20-31 in msr.lo /* 20 bit address. The bottom 12 bits go into bits 20-31 in msr.lo.
The top 8 bits go into 0-7 of msr.hi. */ * The top 8 bits go into 0-7 of msr.hi.
*/
sizebytes--; sizebytes--;
msr.hi = (gl->hi & 0xFFFFFF00) | (sizebytes >> 24); msr.hi = (gl->hi & 0xFFFFFF00) | (sizebytes >> 24);
sizebytes <<= 8; /* move bits 23:12 in bits 31:20. */ sizebytes <<= 8; /* Move bits 23:12 in bits 31:20. */
sizebytes &= 0xfff00000; sizebytes &= 0xfff00000;
sizebytes |= 0x100; /* start at 1MB */ sizebytes |= 0x100; /* Start at 1 MB. */
msr.lo = sizebytes; msr.lo = sizebytes;
wrmsr(gl->desc_name, msr); // MSR - see table above wrmsr(gl->desc_name, msr); /* MSR - see table above. */
printk(BIOS_DEBUG, "%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, printk(BIOS_DEBUG, "%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__,
gl->desc_name, msr.hi, msr.lo); gl->desc_name, msr.hi, msr.lo);
} }
/** /**
* Set up GL0 memory mapping. Again, SMM memory is subtracted. * Set up GL0 memory mapping. Again, SMM memory is subtracted.
* @param gl A Geode Link table descriptor *
* @param gl A GeodeLink table descriptor.
*/ */
static void SMMGL0Init(struct gliutable *gl) static void SMMGL0Init(struct gliutable *gl)
{ {
struct msr msr; struct msr msr;
@ -209,7 +204,7 @@ static void SMMGL0Init(struct gliutable *gl)
printk(BIOS_DEBUG, "%s: %d bytes\n", __FUNCTION__, sizebytes); printk(BIOS_DEBUG, "%s: %d bytes\n", __FUNCTION__, sizebytes);
/* calculate the Two's complement offset */ /* Calculate the "two's complement" offset. */
offset = sizebytes - SMM_OFFSET; offset = sizebytes - SMM_OFFSET;
offset = (offset >> 12) & 0x000fffff; offset = (offset >> 12) & 0x000fffff;
printk(BIOS_DEBUG, "%s: offset is 0x%08x\n", __FUNCTION__, SMM_OFFSET); printk(BIOS_DEBUG, "%s: offset is 0x%08x\n", __FUNCTION__, SMM_OFFSET);
@ -220,94 +215,89 @@ static void SMMGL0Init(struct gliutable *gl)
msr.lo = SMM_OFFSET << 8; msr.lo = SMM_OFFSET << 8;
msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff; msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff;
wrmsr(gl->desc_name, msr); // MSR - See table above wrmsr(gl->desc_name, msr); /* MSR - See table above. */
printk(BIOS_DEBUG, "%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, printk(BIOS_DEBUG, "%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__,
gl->desc_name, msr.hi, msr.lo); gl->desc_name, msr.hi, msr.lo);
} }
/** /**
* Set up GL1 memory mapping. Again, SMM memory is subtracted. * Set up GL1 memory mapping. Again, SMM memory is subtracted.
* @param gl A Geode Link table descriptor *
* @param gl A GeodeLink table descriptor.
*/ */
static void SMMGL1Init(struct gliutable *gl) static void SMMGL1Init(struct gliutable *gl)
{ {
struct msr msr; struct msr msr;
printk(BIOS_DEBUG, "%s:\n", __FUNCTION__); printk(BIOS_DEBUG, "%s:\n", __FUNCTION__);
msr.hi = gl->hi; msr.hi = gl->hi;
/* I don't think this is needed */ /* I don't think this is needed. */
msr.hi &= 0xffffff00; msr.hi &= 0xffffff00;
msr.hi |= (SMM_OFFSET >> 24); msr.hi |= (SMM_OFFSET >> 24);
msr.lo = (SMM_OFFSET << 8) & 0xFFF00000; msr.lo = (SMM_OFFSET << 8) & 0xFFF00000;
msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff; msr.lo |= ((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff;
wrmsr(gl->desc_name, msr); // MSR - See table above wrmsr(gl->desc_name, msr); /* MSR - See table above. */
printk(BIOS_DEBUG, "%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, printk(BIOS_DEBUG, "%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__,
gl->desc_name, msr.hi, msr.lo); gl->desc_name, msr.hi, msr.lo);
} }
/** /**
* Set up all Geode Link Interfaces. Iterate over the table until done. * Set up all GeodeLink interfaces. Iterate over the table until done.
*
* Case out on the link type, and call the appropriate function. * Case out on the link type, and call the appropriate function.
* @param gl A Geode Link table descriptor *
* @param gl A GeodeLink table descriptor.
*/ */
static void GLIUInit(struct gliutable *gl) static void GLIUInit(struct gliutable *gl)
{ {
while (gl->desc_type != GL_END) { while (gl->desc_type != GL_END) {
switch (gl->desc_type) { switch (gl->desc_type) {
default: default:
/* For Unknown types: Write then read MSR */ /* For unknown types: Write then read MSR. */
writeglmsr(gl); writeglmsr(gl);
case SC_SHADOW: /* Check for a Shadow entry */ case SC_SHADOW: /* Check for a Shadow entry. */
ShadowInit(gl); ShadowInit(gl);
break; break;
case R_SYSMEM: /* Check for a SYSMEM entry. */
case R_SYSMEM: /* check for a SYSMEM entry */
sysmem_init(gl); sysmem_init(gl);
break; break;
case BMO_SMM: /* Check for a SMM entry. */
case BMO_SMM: /* check for a SMM entry */
SMMGL0Init(gl); SMMGL0Init(gl);
break; break;
case BM_SMM: /* Check for a SMM entry. */
case BM_SMM: /* check for a SMM entry */
SMMGL1Init(gl); SMMGL1Init(gl);
break; break;
} }
gl++; gl++;
} }
} }
/** /**
* Set up the region config registers for the GeodeLink PCI interface. * Set up the region config registers for the GeodeLink PCI interface.
* R0: 0-640KB, *
* R0: 0 - 640 KB
* R1: 1 MB - Top of System Memory * R1: 1 MB - Top of System Memory
* R2: SMM Memory * R2: SMM Memory
* R3: Framebuffer? - not set up yet * R3: Framebuffer? - not set up yet.
*/ */
static void GLPCI_init(void) static void GLPCI_init(void)
{ {
struct gliutable *gl = 0; struct gliutable *gl = NULL;
int i;
struct msr msr; struct msr msr;
int msrnum, enable_preempt, enable_cpu_override; int i, msrnum, enable_preempt, enable_cpu_override;
int nic_grants_control, enable_bus_parking; int nic_grants_control, enable_bus_parking;
/* R0 - GLPCI settings for Conventional Memory space. */ /* R0 - GLPCI settings for Conventional Memory space. */
msr.hi = (0x09F000 >> 12) << GLPCI_RC_UPPER_TOP_SHIFT; /* 640 */ msr.hi = (0x09F000 >> 12) << GLPCI_RC_UPPER_TOP_SHIFT; /* 640 */
msr.lo = 0; /* 0 */ msr.lo = 0; /* 0 */
msr.lo |= msr.lo |= GLPCI_RC_LOWER_EN_SET + GLPCI_RC_LOWER_PF_SET +
GLPCI_RC_LOWER_EN_SET + GLPCI_RC_LOWER_PF_SET +
GLPCI_RC_LOWER_WC_SET; GLPCI_RC_LOWER_WC_SET;
msrnum = GLPCI_RC0; msrnum = GLPCI_RC0;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* R1 - GLPCI settings for SysMem space. */ /* R1 - GLPCI settings for SysMem space. */
/* Get systop from GLIU0 SYSTOP Descriptor */ /* Get systop from GLIU0 SYSTOP Descriptor. */
for (i = 0; gliu0table[i].desc_name != GL_END; i++) { for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
if (gliu0table[i].desc_type == R_SYSMEM) { if (gliu0table[i].desc_type == R_SYSMEM) {
gl = &gliu0table[i]; gl = &gliu0table[i];
@ -318,26 +308,26 @@ static void GLPCI_init(void)
unsigned long pah, pal; unsigned long pah, pal;
msrnum = gl->desc_name; msrnum = gl->desc_name;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
/* example R_SYSMEM value: 20:00:00:0f:fb:f0:01:00
/* Example: R_SYSMEM value 20:00:00:0f:fb:f0:01:00
* translates to a base of 0x00100000 and top of 0xffbf0000 * translates to a base of 0x00100000 and top of 0xffbf0000
* base of 1M and top of around 256M * base of 1M and top of around 256M.
*/ */
/* we have to create a page-aligned (4KB page) address /* we have to create a page-aligned (4KB page) address
* for base and top */ * for base and top.
/* So we need a high page aligned addresss (pah) and * So we need a high page aligned addresss (pah) and
* low page aligned address (pal) pah is from msr.hi * low page aligned address (pal) pah is from msr.hi
* << 12 | msr.low >> 20. pal is msr.lo << 12 * << 12 | msr.low >> 20. pal is msr.lo << 12
*/ */
pah = ((msr.hi & 0xFF) << 12) | ((msr.lo >> 20) & 0xFFF); pah = ((msr.hi & 0xFF) << 12) | ((msr.lo >> 20) & 0xFFF);
/* we have the page address. Now make it a
* page-aligned address */ /* We have the page address. Now make it page-aligned. */
pah <<= 12; pah <<= 12;
pal = msr.lo << 12; pal = msr.lo << 12;
msr.hi = pah; msr.hi = pah;
msr.lo = pal; msr.lo = pal;
msr.lo |= msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET |
GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET |
GLPCI_RC_LOWER_WC_SET; GLPCI_RC_LOWER_WC_SET;
printk(BIOS_DEBUG, printk(BIOS_DEBUG,
"GLPCI R1: system msr.lo 0x%08x msr.hi 0x%08x\n", "GLPCI R1: system msr.lo 0x%08x msr.hi 0x%08x\n",
@ -346,9 +336,8 @@ static void GLPCI_init(void)
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
} }
/* R2 - GLPCI settings for SMM space */ /* R2 - GLPCI settings for SMM space. */
msr.hi = msr.hi = ((SMM_OFFSET +
((SMM_OFFSET +
(SMM_SIZE * 1024 - 1)) >> 12) << GLPCI_RC_UPPER_TOP_SHIFT; (SMM_SIZE * 1024 - 1)) >> 12) << GLPCI_RC_UPPER_TOP_SHIFT;
msr.lo = (SMM_OFFSET >> 12) << GLPCI_RC_LOWER_BASE_SHIFT; msr.lo = (SMM_OFFSET >> 12) << GLPCI_RC_LOWER_BASE_SHIFT;
msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET; msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET;
@ -357,12 +346,14 @@ static void GLPCI_init(void)
msrnum = GLPCI_RC2; msrnum = GLPCI_RC2;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* this is done elsewhere already, but it does no harm to do /* This is done elsewhere already, but it does no harm to do
* it more than once */ * it more than once.
/* write serialize memory hole to PCI. Need to to unWS when */
* something is shadowed regardless of cachablility. */ /* Write serialize memory hole to PCI. Need to to unWS when
msr.lo = 0x021212121; /* cache disabled and write serialized */ * something is shadowed regardless of cachablility.
msr.hi = 0x021212121; /* cache disabled and write serialized */ */
msr.lo = 0x021212121; /* Cache disabled and write serialized. */
msr.hi = 0x021212121; /* Cache disabled and write serialized. */
msrnum = CPU_RCONF_A0_BF; msrnum = CPU_RCONF_A0_BF;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
@ -374,7 +365,8 @@ static void GLPCI_init(void)
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Set Non-Cacheable Read Only for NorthBound Transactions to /* Set Non-Cacheable Read Only for NorthBound Transactions to
* Memory. The Enable bit is handled in the Shadow setup. */ * Memory. The Enable bit is handled in the Shadow setup.
*/
msrnum = GLPCI_A0_BF; msrnum = GLPCI_A0_BF;
msr.hi = 0x35353535; msr.hi = 0x35353535;
msr.lo = 0x35353535; msr.lo = 0x35353535;
@ -390,20 +382,19 @@ static void GLPCI_init(void)
msr.lo = 0x35353535; msr.lo = 0x35353535;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Set WSREQ */ /* Set WSREQ. */
msrnum = CPU_DM_CONFIG0; msrnum = CPU_DM_CONFIG0;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.hi &= ~(7 << DM_CONFIG0_UPPER_WSREQ_SHIFT); msr.hi &= ~(7 << DM_CONFIG0_UPPER_WSREQ_SHIFT);
/* reduce to 1 for safe mode */ /* Reduce to 1 for safe mode. */
msr.hi |= 2 << DM_CONFIG0_UPPER_WSREQ_SHIFT; msr.hi |= 2 << DM_CONFIG0_UPPER_WSREQ_SHIFT;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* The following settings will not work with a CS5530 southbridge */ /* The following settings will not work with a CS5530 southbridge.
/* we are ignoring the 5530 case for now, and perhaps forever. */ * We are ignoring the CS5530 case for now, and perhaps forever.
*/
/* */
/* 553x NB Init */ /* 553x NB Init */
/* */
/* Arbiter setup */ /* Arbiter setup */
enable_preempt = enable_preempt =
@ -424,9 +415,9 @@ static void GLPCI_init(void)
msrnum = GLPCI_CTRL; msrnum = GLPCI_CTRL;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
/* (Out will be disabled in CPUBUG649 for < 2.0 parts .) */ /* Out will be disabled in CPUBUG649 for < 2.0 parts. */
msr.lo |= GLPCI_CTRL_LOWER_ME_SET | GLPCI_CTRL_LOWER_OWC_SET msr.lo |= GLPCI_CTRL_LOWER_ME_SET | GLPCI_CTRL_LOWER_OWC_SET |
| GLPCI_CTRL_LOWER_PCD_SET; GLPCI_CTRL_LOWER_PCD_SET;
msr.lo |= GLPCI_CTRL_LOWER_LDE_SET; msr.lo |= GLPCI_CTRL_LOWER_LDE_SET;
msr.lo &= ~(0x03 << GLPCI_CTRL_LOWER_IRFC_SHIFT); msr.lo &= ~(0x03 << GLPCI_CTRL_LOWER_IRFC_SHIFT);
@ -454,7 +445,7 @@ static void GLPCI_init(void)
/* Set GLPCI Latency Timer */ /* Set GLPCI Latency Timer */
msrnum = GLPCI_CTRL; msrnum = GLPCI_CTRL;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
/* Change once 1.x is gone */ /* Change once 1.x is gone. */
msr.hi |= 0x1F << GLPCI_CTRL_UPPER_LAT_SHIFT; msr.hi |= 0x1F << GLPCI_CTRL_UPPER_LAT_SHIFT;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
@ -482,14 +473,13 @@ static void clock_gating_init(void)
msr = rdmsr(gating->msrnum); msr = rdmsr(gating->msrnum);
msr.hi |= gating->msr.hi; msr.hi |= gating->msr.hi;
msr.lo |= gating->msr.lo; msr.lo |= gating->msr.lo;
wrmsr(gating->msrnum, msr); // MSR - See the table above wrmsr(gating->msrnum, msr); /* MSR - See table above. */
gating += 1; gating += 1;
} }
} }
/** /**
* Set all Geode Link Priority register as determined by the * Set all GeodeLink priority registers as determined by the TODO.
*/ */
static void geode_link_priority(void) static void geode_link_priority(void)
{ {
@ -502,15 +492,18 @@ static void geode_link_priority(void)
msr.hi |= prio->msr.hi; msr.hi |= prio->msr.hi;
msr.lo &= ~0xfff; msr.lo &= ~0xfff;
msr.lo |= prio->msr.lo; msr.lo |= prio->msr.lo;
wrmsr(prio->msrnum, msr); // MSR - See the table above wrmsr(prio->msrnum, msr); /* MSR - See table above. */
prio += 1; prio += 1;
} }
} }
/** /**
* Get the GLIU0 shadow register settings * Get the GLIU0 shadow register settings.
* If the set_shadow function is used then all shadow descriptors *
* If the set_shadow() function is used then all shadow descriptors
* will stay sync'ed. * will stay sync'ed.
*
* @return TODO
*/ */
static u64 get_shadow(void) static u64 get_shadow(void)
{ {
@ -522,54 +515,55 @@ static u64 get_shadow(void)
/** /**
* Set the cache RConf registers for the memory hole. * Set the cache RConf registers for the memory hole.
*
* Keeps all cache shadow descriptors sync'ed. * Keeps all cache shadow descriptors sync'ed.
* This is part of the PCI lockup solution * This is part of the PCI lockup solution.
* @param Hi the high 32 bits of the msr setting *
* @param lo The low 32 bits of the msr setting * @param shadowHi The high 32 bits of the msr setting.
* @param shadowLo The low 32 bits of the msr setting.
*/ */
static void set_shadowRCONF(u32 shadowHi, u32 shadowLo) static void set_shadowRCONF(u32 shadowHi, u32 shadowLo)
{ {
/* Ok, this is whacky bit translation time. */
// ok this is whacky bit translation time.
int bit; int bit;
u8 shadowByte; u8 shadowByte;
struct msr msr = { 0, 0 }; struct msr msr = { 0, 0 };
shadowByte = (u8) (shadowLo >> 16); shadowByte = (u8) (shadowLo >> 16);
// load up D000 settings in edx. /* Load up D000 settings in edx. */
for (bit = 8; (bit > 4); bit--) { for (bit = 8; (bit > 4); bit--) {
msr.hi <<= 8; msr.hi <<= 8;
msr.hi |= 1; // cache disable PCI/Shadow memory msr.hi |= 1; /* Cache disable PCI/Shadow memory. */
if (shadowByte && (1 << bit)) if (shadowByte && (1 << bit))
msr.hi |= 0x20; // write serialize PCI memory msr.hi |= 0x20; /* Write serialize PCI memory. */
} }
// load up C000 settings in eax. /* Load up C000 settings in eax. */
for (; bit; bit--) { for (/* Nothing */; bit; bit--) {
msr.lo <<= 8; msr.lo <<= 8;
msr.lo |= 1; // cache disable PCI/Shadow memory msr.lo |= 1; /* Cache disable PCI/Shadow memory. */
if (shadowByte && (1 << bit)) if (shadowByte && (1 << bit))
msr.lo |= 0x20; // write serialize PCI memory msr.lo |= 0x20; /* Write serialize PCI memory. */
} }
wrmsr(CPU_RCONF_C0_DF, msr); wrmsr(CPU_RCONF_C0_DF, msr);
shadowByte = (u8) (shadowLo >> 24); shadowByte = (u8) (shadowLo >> 24);
// load up F000 settings in edx. /* Load up F000 settings in edx. */
for (bit = 8; (bit > 4); bit--) { for (bit = 8; (bit > 4); bit--) {
msr.hi <<= 8; msr.hi <<= 8;
msr.hi |= 1; // cache disable PCI/Shadow memory msr.hi |= 1; /* Cache disable PCI/Shadow memory. */
if (shadowByte && (1 << bit)) if (shadowByte && (1 << bit))
msr.hi |= 0x20; // write serialize PCI memory msr.hi |= 0x20; /* Write serialize PCI memory. */
} }
// load up E000 settings in eax. /* Load up E000 settings in eax. */
for (; bit; bit--) { for (/* Nothing */; bit; bit--) {
msr.lo <<= 8; msr.lo <<= 8;
msr.lo |= 1; // cache disable PCI/Shadow memory msr.lo |= 1; /* Cache disable PCI/Shadow memory. */
if (shadowByte && (1 << bit)) if (shadowByte && (1 << bit))
msr.lo |= 0x20; // write serialize PCI memory msr.lo |= 0x20; /* write serialize PCI memory. */
} }
wrmsr(CPU_RCONF_E0_FF, msr); wrmsr(CPU_RCONF_E0_FF, msr);
@ -577,15 +571,17 @@ static void set_shadowRCONF(u32 shadowHi, u32 shadowLo)
/** /**
* Set the GLPCI registers for the memory hole. * Set the GLPCI registers for the memory hole.
*
* Keeps all cache shadow descriptors sync'ed. * Keeps all cache shadow descriptors sync'ed.
* @param shadowhi the high 32 bits of the msr setting *
* @param shadowlo The low 32 bits of the msr setting * @param shadowhi The high 32 bits of the msr setting.
* @param shadowlo The low 32 bits of the msr setting.
*/ */
static void set_shadowGLPCI(u32 shadowhi, u32 shadowlo) static void set_shadowGLPCI(u32 shadowhi, u32 shadowlo)
{ {
struct msr msr; struct msr msr;
// Set the Enable Register. /* Set the Enable register. */
msr = rdmsr(GLPCI_REN); msr = rdmsr(GLPCI_REN);
msr.lo &= 0xFFFF00FF; msr.lo &= 0xFFFF00FF;
msr.lo |= ((shadowlo & 0xFFFF0000) >> 8); msr.lo |= ((shadowlo & 0xFFFF0000) >> 8);
@ -593,9 +589,12 @@ static void set_shadowGLPCI(u32 shadowhi, u32 shadowlo)
} }
/** /**
* Set the GLIU SC register settings. Scans descriptor tables for * Set the GLIU SC register settings.
* SC_SHADOW. Keeps all shadow descriptors sync'ed. *
* @param shadowSettings Shadow register settings * Scans descriptor tables for SC_SHADOW.
* Keeps all shadow descriptors sync'ed.
*
* @param shadowSettings Shadow register settings.
*/ */
static void set_shadow(u64 shadowSettings) static void set_shadow(u64 shadowSettings)
{ {
@ -614,61 +613,65 @@ static void set_shadow(u64 shadowSettings)
for (pTable = gliutables[i]; pTable->desc_type != GL_END; for (pTable = gliutables[i]; pTable->desc_type != GL_END;
pTable++) { pTable++) {
if (pTable->desc_type == SC_SHADOW) { if (pTable->desc_type == SC_SHADOW) {
msr = rdmsr(pTable->desc_name); msr = rdmsr(pTable->desc_name);
msr.lo = (u32) shadowSettings; msr.lo = (u32) shadowSettings;
/* maintain PDID in upper EDX*/ /* Maintain PDID in upper EDX. */
msr.hi &= 0xFFFF0000; msr.hi &= 0xFFFF0000;
msr.hi |= msr.hi |=
((u32) (shadowSettings >> 32)) & ((u32) (shadowSettings >> 32)) & 0x0000FFFF;
0x0000FFFF; /* MSR - See the table above. */
// MSR - See the table above
wrmsr(pTable->desc_name, msr); wrmsr(pTable->desc_name, msr);
} }
} }
} }
} }
/**
* TODO.
*/
static void rom_shadow_settings(void) static void rom_shadow_settings(void)
{ {
u64 shadowSettings = get_shadow(); u64 shadowSettings = get_shadow();
// Disable read & writes
/* Disable read & writes. */
shadowSettings &= (u64) 0xFFFF00000000FFFFULL; shadowSettings &= (u64) 0xFFFF00000000FFFFULL;
// Enable reads for F0000-FFFFF
/* Enable reads for F0000-FFFFF. */
shadowSettings |= (u64) 0x00000000F0000000ULL; shadowSettings |= (u64) 0x00000000F0000000ULL;
// Enable rw for C0000-CFFFF
/* Enable read & writes for C0000-CFFFF. */
shadowSettings |= (u64) 0x0000FFFFFFFF0000ULL; shadowSettings |= (u64) 0x0000FFFFFFFF0000ULL;
set_shadow(shadowSettings); set_shadow(shadowSettings);
} }
/** /**
* * Set up RCONF_DEFAULT and any other RCONF registers needed.
*
* Set up RCONF_DEFAULT and any other RCONF registers needed
* *
* DEVRC_RCONF_DEFAULT: * DEVRC_RCONF_DEFAULT:
* ROMRC(63:56) = 04h write protect ROMBASE * ROMRC(63:56) = 0x04 Write protect ROMBASE
* ROMBASE(36:55) = 0FFFC0h Top of PCI/bottom of rom chipselect area * ROMBASE(36:55) = 0x0FFFC0 Top of PCI/bottom of ROM chipselect area
* DEVRC(35:28) = 39h cache disabled in PCI memory + WS bit on * DEVRC(35:28) = 0x39 Cache disabled in PCI memory + WS bit on
+ Write Combine + write burst. * Write Combine + write burst.
* SYSTOP(27:8) = top of system memory * SYSTOP(27:8) = top of system memory
* SYSRC(7:0) = 0 writeback, can set to 08h to make writethrough * SYSRC(7:0) = 0 Writeback, can set to 0x08 to make writethrough
*
*/ */
#define SYSMEM_RCONF_WRITETHROUGH 8 #define SYSMEM_RCONF_WRITETHROUGH 8
#define DEVRC_RCONF_DEFAULT 0x21 #define DEVRC_RCONF_DEFAULT 0x21
#define ROMBASE_RCONF_DEFAULT 0xFFFC0000 #define ROMBASE_RCONF_DEFAULT 0xFFFC0000
#define ROMRC_RCONF_DEFAULT 0x25 #define ROMRC_RCONF_DEFAULT 0x25
/**
* TODO.
*/
static void enable_L1_cache(void) static void enable_L1_cache(void)
{ {
struct gliutable *gl = 0; struct gliutable *gl = NULL;
int i; int i;
struct msr msr; struct msr msr;
u8 SysMemCacheProp; u8 SysMemCacheProp;
/* Locate SYSMEM entry in GLIU0table */ /* Locate SYSMEM entry in GLIU0table. */
for (i = 0; gliu0table[i].desc_name != GL_END; i++) { for (i = 0; gliu0table[i].desc_name != GL_END; i++) {
if (gliu0table[i].desc_type == R_SYSMEM) { if (gliu0table[i].desc_type == R_SYSMEM) {
gl = &gliu0table[i]; gl = &gliu0table[i];
@ -676,9 +679,10 @@ static void enable_L1_cache(void)
} }
} }
if (gl == 0) { if (gl == 0) {
post_code(0xCE); /* POST_RCONFInitError */ post_code(POST_RCONFInitError);
while (1) ; while (1); /* TODO: Should be hlt()? */
} }
// sysdescfound: // sysdescfound:
msr = rdmsr(gl->desc_name); msr = rdmsr(gl->desc_name);
@ -689,30 +693,32 @@ static void enable_L1_cache(void)
msr.lo = ((msr.lo << 12) | (msr.lo >> 20)) & 0x000FFFFF; msr.lo = ((msr.lo << 12) | (msr.lo >> 20)) & 0x000FFFFF;
msr.lo <<= RCONF_DEFAULT_LOWER_SYSTOP_SHIFT; // 8 msr.lo <<= RCONF_DEFAULT_LOWER_SYSTOP_SHIFT; // 8
// Set Default SYSMEM region properties /* Set Default SYSMEM region properties.
// NOT writethrough == writeback 8 (or ~8) * NOT writethrough == writeback 8 (or ~8)
*/
msr.lo &= ~SYSMEM_RCONF_WRITETHROUGH; msr.lo &= ~SYSMEM_RCONF_WRITETHROUGH;
// Set PCI space cache properties /* Set PCI space cache properties.
// setting is split betwwen hi and lo... * Setting is split between hi and lo...
*/
msr.hi = (DEVRC_RCONF_DEFAULT >> 4); msr.hi = (DEVRC_RCONF_DEFAULT >> 4);
msr.lo |= (DEVRC_RCONF_DEFAULT << 28); msr.lo |= (DEVRC_RCONF_DEFAULT << 28);
// Set the ROMBASE. This is usually FFFC0000h /* Set the ROMBASE. This is usually 0xFFFC0000. */
msr.hi |= msr.hi |=
(ROMBASE_RCONF_DEFAULT >> 12) << RCONF_DEFAULT_UPPER_ROMBASE_SHIFT; (ROMBASE_RCONF_DEFAULT >> 12) << RCONF_DEFAULT_UPPER_ROMBASE_SHIFT;
// Set ROMBASE cache properties. /* Set ROMBASE cache properties. */
msr.hi |= ((ROMRC_RCONF_DEFAULT >> 8) | (ROMRC_RCONF_DEFAULT << 24)); msr.hi |= ((ROMRC_RCONF_DEFAULT >> 8) | (ROMRC_RCONF_DEFAULT << 24));
// now program RCONF_DEFAULT /* Now program RCONF_DEFAULT. */
wrmsr(CPU_RCONF_DEFAULT, msr); wrmsr(CPU_RCONF_DEFAULT, msr);
printk(BIOS_DEBUG, "CPU_RCONF_DEFAULT (1808): 0x%08X:0x%08X\n", msr.hi, printk(BIOS_DEBUG, "CPU_RCONF_DEFAULT (1808): 0x%08X:0x%08X\n", msr.hi,
msr.lo); msr.lo);
// RCONF_BYPASS: Cache tablewalk properties and /* RCONF_BYPASS: Cache tablewalk properties and SMM/DMM header access
// SMM/DMM header access properties. * properties. Set to match system memory cache properties.
// Set to match system memory cache properties. */
msr = rdmsr(CPU_RCONF_DEFAULT); msr = rdmsr(CPU_RCONF_DEFAULT);
SysMemCacheProp = (u8) (msr.lo & 0xFF); SysMemCacheProp = (u8) (msr.lo & 0xFF);
msr = rdmsr(CPU_RCONF_BYPASS); msr = rdmsr(CPU_RCONF_BYPASS);
@ -732,25 +738,25 @@ static void enable_L2_cache(void)
struct msr msr; struct msr msr;
/* Instruction Memory Configuration register /* Instruction Memory Configuration register
* set EBE bit, required when L2 cache is enabled * set EBE bit, required when L2 cache is enabled.
*/ */
msr = rdmsr(CPU_IM_CONFIG); msr = rdmsr(CPU_IM_CONFIG);
msr.lo |= 0x400; msr.lo |= 0x400;
wrmsr(CPU_IM_CONFIG, msr); wrmsr(CPU_IM_CONFIG, msr);
/* Data Memory Subsystem Configuration register /* Data Memory Subsystem Configuration register. Set EVCTONRPL bit,
* set EVCTONRPL bit, required when L2 cache is enabled in victim mode * required when L2 cache is enabled in victim mode.
*/ */
msr = rdmsr(CPU_DM_CONFIG0); msr = rdmsr(CPU_DM_CONFIG0);
msr.lo |= 0x4000; msr.lo |= 0x4000;
wrmsr(CPU_DM_CONFIG0, msr); wrmsr(CPU_DM_CONFIG0, msr);
/* invalidate L2 cache */ /* Invalidate L2 cache. */
msr.hi = 0x00; msr.hi = 0x00;
msr.lo = 0x10; msr.lo = 0x10;
wrmsr(CPU_BC_L2_CONF, msr); wrmsr(CPU_BC_L2_CONF, msr);
/* Enable L2 cache */ /* Enable L2 cache. */
msr.hi = 0x00; msr.hi = 0x00;
msr.lo = 0x0f; msr.lo = 0x0f;
wrmsr(CPU_BC_L2_CONF, msr); wrmsr(CPU_BC_L2_CONF, msr);
@ -764,7 +770,7 @@ static void enable_L2_cache(void)
#endif #endif
/** /**
* set up all LX cache registers, L1, L2, and x86. * Set up all LX cache registers, L1, L2, and x86.
*/ */
static void setup_lx_cache(void) static void setup_lx_cache(void)
{ {
@ -773,19 +779,25 @@ static void setup_lx_cache(void)
enable_L1_cache(); enable_L1_cache();
enable_L2_cache(); enable_L2_cache();
// Make sure all INVD instructions are treated as WBINVD. We do this /* Make sure all INVD instructions are treated as WBINVD. We do this
// because we've found some programs which require this behavior. * because we've found some programs which require this behavior.
*/
msr = rdmsr(CPU_DM_CONFIG0); msr = rdmsr(CPU_DM_CONFIG0);
msr.lo |= DM_CONFIG0_LOWER_WBINVD_SET; msr.lo |= DM_CONFIG0_LOWER_WBINVD_SET;
wrmsr(CPU_DM_CONFIG0, msr); wrmsr(CPU_DM_CONFIG0, msr);
enable_cache(); enable_cache();
__asm__("wbinvd\n"); __asm__("wbinvd\n"); /* TODO: Use wbinvd() function? */
} }
/**
* TODO.
*
* @return TODO.
*/
u32 get_systop(void) u32 get_systop(void)
{ {
struct gliutable *gl = 0; struct gliutable *gl = NULL;
u32 systop; u32 systop;
struct msr msr; struct msr msr;
int i; int i;
@ -798,45 +810,44 @@ u32 get_systop(void)
} }
if (gl) { if (gl) {
msr = rdmsr(gl->desc_name); msr = rdmsr(gl->desc_name);
systop = ((msr.hi & 0xFF) << 24) | systop = ((msr.hi & 0xFF) << 24) | ((msr.lo & 0xFFF00000) >> 8);
((msr.lo & 0xFFF00000) >> 8);
systop += 0x1000; /* 4K */ systop += 0x1000; /* 4K */
} else { } else {
systop = systop =
((sizeram() - CONFIG_VIDEO_MB) * 1024) - SMM_SIZE - 1024; ((sizeram() - CONFIG_VIDEO_MB) * 1024) - SMM_SIZE - 1024;
} }
return systop; return systop;
} }
/** northbridge_init_early Do all the Nasty Bits that have to /**
* happen. These can be done once memory is up, but before much else * Do all the Nasty Bits that have to happen.
* is done. So we do them in Phase 2. *
* These can be done once memory is up, but before much else is done.
* So we do them in phase 2.
*/ */
void northbridge_init_early(void) void northbridge_init_early(void)
{ {
struct msr msr;
int i; int i;
struct msr msr;
printk(BIOS_DEBUG, "Enter %s\n", __FUNCTION__); printk(BIOS_DEBUG, "Enter %s\n", __FUNCTION__);
for (i = 0; gliutables[i]; i++) for (i = 0; gliutables[i]; i++)
GLIUInit(gliutables[i]); GLIUInit(gliutables[i]);
/* Now that the descriptor to memory is set up. */ /* Now that the descriptor to memory is set up, the memory controller
/* The memory controller needs one read to synch its lines * needs one read to synch it's lines before it can be used.
* before it can be used.
*/ */
i = *(int *)0; i = *(int *)0;
geode_link_priority(); geode_link_priority();
setup_lx_cache(); setup_lx_cache();
rom_shadow_settings(); rom_shadow_settings();
GLPCI_init(); GLPCI_init();
clock_gating_init(); clock_gating_init();
__asm__ __volatile__("FINIT\n"); __asm__ __volatile__("FINIT\n"); /* TODO: Create finit() function? */
printk(BIOS_DEBUG, "Exit %s\n", __FUNCTION__); printk(BIOS_DEBUG, "Exit %s\n", __FUNCTION__);
} }

View file

@ -34,13 +34,16 @@
static const u8 num_col_addr[] = { static const u8 num_col_addr[] = {
0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
}; };
/** /**
* Auto-detect, using SPD, the DIMM size. It's the usual magic, with * Auto-detect, using SPD, the DIMM size. It's the usual magic, with
* all the usual failiure points that can happen. * all the usual failure points that can happen.
* @param dimm -- The SMBus address of the DIMM *
* @param dimm TODO
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*/ */
static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1) static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
{ {
@ -51,13 +54,10 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
dimm_setting = 0; dimm_setting = 0;
/* Check that we have a dimm */ /* Check that we have a DIMM. */
if (smbus_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF) { if (smbus_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF)
return; return;
}
/* Field: Module Banks per DIMM */
/* EEPROM byte usage: (5) Number of DIMM Banks */
spd_byte = smbus_read_byte(dimm, SPD_NUM_DIMM_BANKS); spd_byte = smbus_read_byte(dimm, SPD_NUM_DIMM_BANKS);
if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)) { if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)) {
printk(BIOS_EMERG, "Number of module banks not compatible\n"); printk(BIOS_EMERG, "Number of module banks not compatible\n");
@ -66,8 +66,6 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
} }
dimm_setting |= (spd_byte >> 1) << CF07_UPPER_D0_MB_SHIFT; dimm_setting |= (spd_byte >> 1) << CF07_UPPER_D0_MB_SHIFT;
/* Field: Banks per SDRAM device */
/* EEPROM byte usage: (17) Number of Banks on SDRAM Device */
spd_byte = smbus_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM); spd_byte = smbus_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM);
if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)) { if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)) {
printk(BIOS_EMERG, "Number of device banks not compatible\n"); printk(BIOS_EMERG, "Number of device banks not compatible\n");
@ -76,27 +74,25 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
} }
dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT; dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT;
/* Field: DIMM size
*; EEPROM byte usage: (3) Number or Row Addresses
*; (4) Number of Column Addresses
*; (5) Number of DIMM Banks
*; (31) Module Bank Density
*; Size = Module Density * Module Banks
*/
if ((smbus_read_byte(dimm, SPD_NUM_ROWS) & 0xF0) if ((smbus_read_byte(dimm, SPD_NUM_ROWS) & 0xF0)
|| (smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) { || (smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) {
printk(BIOS_EMERG, "Assymetirc DIMM not compatible\n"); printk(BIOS_EMERG, "Asymmetric DIMM not compatible\n");
post_code(ERROR_UNSUPPORTED_DIMM); post_code(ERROR_UNSUPPORTED_DIMM);
hlt(); hlt();
} }
/* Size = Module Density * Module Banks */
dimm_size = smbus_read_byte(dimm, SPD_BANK_DENSITY); dimm_size = smbus_read_byte(dimm, SPD_BANK_DENSITY);
/* align so 1GB(bit0) is bit 8, this is a little weird to get gcc to not optimize this out */ /* Align so 1 GB (bit 0) is bit 8. This is a little weird to get gcc
* to not optimize this out.
*/
dimm_size |= (dimm_size << 8); dimm_size |= (dimm_size << 8);
/* and off 2GB DIMM size : not supported and the 1GB size we just moved up to bit 8 as well as all the extra on top */ /* And off 2 GB DIMM size: not supported and the 1 GB size we just
* moved up to bit 8 as well as all the extra on top.
*/
dimm_size &= 0x01FC; dimm_size &= 0x01FC;
/* Module Density * Module Banks */ /* Module Density * Module Banks */
/* shift to multiply by # DIMM banks */ /* Shift to multiply by the number of DIMM banks. */
dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1; dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1;
dimm_size = __builtin_ctz(dimm_size); dimm_size = __builtin_ctz(dimm_size);
if (dimm_size > 8) { /* 8 is 1 GB only support 1 GB per DIMM */ if (dimm_size > 8) { /* 8 is 1 GB only support 1 GB per DIMM */
@ -106,13 +102,12 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
} }
dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT; dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT;
/* Field: PAGE size /* PageSize = 2 ^ (number of column addresses) * data width in bytes
* EEPROM byte usage: (4) Number of Column Addresses * (should be 8 bytes for a normal DIMM)
* PageSize = 2^# Column Addresses * Data width in bytes (should be 8bytes for a normal DIMM)
* *
* But this really works by magic. * If ma[12:0] is the memory address pins, and pa[12:0] is the
*If ma[12:0] is the memory address pins, and pa[12:0] is the physical column address * physical column address that the memory controller (MC) generates,
*that MC generates, here is how the MC assigns the pa onto the ma pins: * here is how the MC assigns the pa onto the ma pins:
* *
* ma 12 11 10 09 08 07 06 05 04 03 02 01 00 * ma 12 11 10 09 08 07 06 05 04 03 02 01 00
* ------------------------------------------- * -------------------------------------------
@ -122,12 +117,14 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
* pa 12 11 10 09 08 07 06 05 04 03 (10 col addr bits = 8K page size) * pa 12 11 10 09 08 07 06 05 04 03 (10 col addr bits = 8K page size)
* pa 13 AP 12 11 10 09 08 07 06 05 04 03 (11 col addr bits = 16K page size) * pa 13 AP 12 11 10 09 08 07 06 05 04 03 (11 col addr bits = 16K page size)
* pa 14 13 AP 12 11 10 09 08 07 06 05 04 03 (12 col addr bits = 32K page size) * pa 14 13 AP 12 11 10 09 08 07 06 05 04 03 (12 col addr bits = 32K page size)
* *AP=autoprecharge bit
* *
*Remember that pa[2:0] are zeroed out since it's a 64-bit data bus (8 bytes), * (AP = autoprecharge bit)
*so lower 3 address bits are dont_cares.So from the table above, *
*it's easier to see what the old code is doing: if for example,#col_addr_bits=7(06h), * Remember that pa[2:0] are zeroed out since it's a 64-bit data bus
*it adds 3 to get 10, then does 2^10=1K. Get it? * (8 bytes), so lower 3 address bits are dont_cares. So from the
* table above, it's easier to see what the old code is doing: if for
* example, #col_addr_bits = 7 (06h), it adds 3 to get 10, then does
* 2^10=1K. Get it?
*/ */
spd_byte = num_col_addr[smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF]; spd_byte = num_col_addr[smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF];
@ -137,10 +134,12 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
hlt(); hlt();
} }
spd_byte -= 7; spd_byte -= 7;
if (spd_byte > 5) { /* if the value is above 6 it means >12 address lines */ /* If the value is above 6 it means >12 address lines... */
spd_byte = 7; /* which means >32k so set to disabled */ if (spd_byte > 5) {
spd_byte = 7; /* ...which means >32k so set to disabled. */
} }
dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT; /* 0=1k,1=2k,2=4k,etc */ /* 0 = 1k, 1 = 2k, 2 = 4k, etc. */
dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT;
msr = rdmsr(MC_CF07_DATA); msr = rdmsr(MC_CF07_DATA);
if (dimm == dimm0) { if (dimm == dimm0) {
@ -153,10 +152,14 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
wrmsr(MC_CF07_DATA, msr); wrmsr(MC_CF07_DATA, msr);
} }
/** Try to compute the max DDR clock rate. The only bad news here is that if you have got a geode link /**
* speed that is too fast, you are going to pay for it: the system will hlt! * Try to compute the max. DDR clock rate.
* @param dimm0 dimm0 SMBus address *
* @param dimm1 dimm1 SMBus address * The only bad news here is that if you have got a GeodeLink speed that is
* too fast, you are going to pay for it: the system will hlt!
*
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*/ */
static void check_ddr_max(u8 dimm0, u8 dimm1) static void check_ddr_max(u8 dimm0, u8 dimm1)
{ {
@ -165,32 +168,32 @@ static void check_ddr_max(u8 dimm0, u8 dimm1)
/* PC133 identifier */ /* PC133 identifier */
spd_byte0 = smbus_read_byte(dimm0, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); spd_byte0 = smbus_read_byte(dimm0, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
if (spd_byte0 == 0xFF) { if (spd_byte0 == 0xFF)
spd_byte0 = 0; spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); spd_byte1 = smbus_read_byte(dimm1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
if (spd_byte1 == 0xFF) { if (spd_byte1 == 0xFF)
spd_byte1 = 0; spd_byte1 = 0;
}
/* I don't think you need this check. /* I don't think you need this check. */
#if 0
if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0) { if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0) {
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink Speed\n"); printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink speed\n");
post_code(POST_PLL_MEM_FAIL); post_code(POST_PLL_MEM_FAIL);
hlt(); hlt();
} */ }
#endif
/* Use the slowest DIMM */ /* Use the slowest DIMM. */
if (spd_byte0 < spd_byte1) { if (spd_byte0 < spd_byte1) {
spd_byte0 = spd_byte1; spd_byte0 = spd_byte1;
} }
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */ /* Turn SPD ns time into MHz. Check what the asm does to this math. */
speed = 2 * ((10000 / (((spd_byte0 >> 4) * 10) + (spd_byte0 & 0x0F)))); speed = 2 * ((10000 / (((spd_byte0 >> 4) * 10) + (spd_byte0 & 0x0F))));
/* current speed > max speed? */ /* Current speed > max speed? */
if (geode_link_speed() > speed) { if (geode_link_speed() > speed) {
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink Speed\n"); printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink speed\n");
post_code(POST_PLL_MEM_FAIL); post_code(POST_PLL_MEM_FAIL);
hlt(); hlt();
} }
@ -199,9 +202,12 @@ static void check_ddr_max(u8 dimm0, u8 dimm1)
const u16 REFRESH_RATE[] = { 15, 3, 7, 31, 62, 125 }; /* ns */ const u16 REFRESH_RATE[] = { 15, 3, 7, 31, 62, 125 }; /* ns */
/** /**
* compute a refresh rate. You have to read both dimms and take the one that requires a faster rate. * Compute a refresh rate.
* @param dimm0 dimm0 SMBus address *
* @param dimm1 dimm1 SMBus address * You have to read both DIMMs and take the one that requires a faster rate.
*
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*/ */
static void set_refresh_rate(u8 dimm0, u8 dimm1) static void set_refresh_rate(u8 dimm0, u8 dimm1)
{ {
@ -223,7 +229,7 @@ static void set_refresh_rate(u8 dimm0, u8 dimm1)
} }
rate1 = REFRESH_RATE[spd_byte1]; rate1 = REFRESH_RATE[spd_byte1];
/* Use the faster rate (lowest number) */ /* Use the faster rate (lowest number). */
if (rate0 > rate1) { if (rate0 > rate1) {
rate0 = rate1; rate0 = rate1;
} }
@ -234,28 +240,29 @@ static void set_refresh_rate(u8 dimm0, u8 dimm1)
wrmsr(MC_CF07_DATA, msr); wrmsr(MC_CF07_DATA, msr);
} }
const u8 CASDDR[] = { 5, 5, 2, 6, 3, 7, 4, 0 }; /* 1(1.5), 1.5, 2, 2.5, 3, 3.5, 4, 0 */ /* 1(1.5), 1.5, 2, 2.5, 3, 3.5, 4, 0 */
const u8 CASDDR[] = { 5, 5, 2, 6, 3, 7, 4, 0 };
/** /**
* Compute the CAS rate. * Compute the CAS rate.
* EEPROM byte usage: (18) SDRAM device attributes - CAS latency
* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5
* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1
* *
* The CAS setting is based on the information provided in each DIMMs SPD. * The CAS setting is based on the information provided in each DIMMs SPD.
*
* The speed at which a DIMM can run is described relative to the slowest * The speed at which a DIMM can run is described relative to the slowest
* CAS the DIMM supports. Each speed for the relative CAS settings is * CAS the DIMM supports. Each speed for the relative CAS settings is
* checked that it is within the GeodeLink speed. If it isn't within the GeodeLink * checked that it is within the GeodeLink speed. If it isn't within the
* speed, the CAS setting is removed from the list of good settings for * GeodeLink speed, the CAS setting is removed from the list of good settings
* the DIMM. This is done for both DIMMs and the lists are compared to * for the DIMM.
* find the lowest common CAS latency setting. If there are no CAS settings *
* in common we out a ERROR_DIFF_DIMMS (78h) to port 80h and halt. * This is done for both DIMMs and the lists are compared to find the lowest
* Result is that we will set fastest CAS Latency based on GeodeLink speed * common CAS latency setting. If there are no CAS settings
* in common we output a ERROR_DIFF_DIMMS (0x78) POST code and halt.
*
* Result is that we will set fastest CAS latency based on GeodeLink speed
* and SPD information. * and SPD information.
* *
* @param dimm0 dimm0 SMBus address * @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 dimm1 SMBus address * @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*
*/ */
static void set_cas(u8 dimm0, u8 dimm1) static void set_cas(u8 dimm0, u8 dimm1)
{ {
@ -265,32 +272,36 @@ static void set_cas(u8 dimm0, u8 dimm1)
glspeed = geode_link_speed(); glspeed = geode_link_speed();
/************************** dimm0 **********************************/ /* DIMM 0 */
casmap0 = smbus_read_byte(dimm0, SPD_ACCEPTABLE_CAS_LATENCIES); casmap0 = smbus_read_byte(dimm0, SPD_ACCEPTABLE_CAS_LATENCIES);
if (casmap0 != 0xFF) { if (casmap0 != 0xFF) {
/* IF -.5 timing is supported, check -.5 timing > GeodeLink */ /* If -.5 timing is supported, check -.5 timing > GeodeLink. */
/* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5 */
spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_2ND); spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_2ND);
if (spd_byte != 0) { if (spd_byte != 0) {
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */ /* Turn SPD ns time into MHz. Check what the asm does
* to this math.
*/
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) +
(spd_byte & 0x0F))); (spd_byte & 0x0F)));
if (dimm_speed >= glspeed) { if (dimm_speed >= glspeed) {
/* IF -1 timing is supported, check -1 timing > GeodeLink */ /* If -1 timing is supported, check -1 timing > GeodeLink. */
/* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1 */
spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_3RD); spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_3RD);
if (spd_byte != 0) { if (spd_byte != 0) {
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */ /* Turn SPD ns time into MHz. Check what the asm does to this math. */
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F))); dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
if (dimm_speed <= glspeed) { if (dimm_speed <= glspeed) {
/* set we can use -.5 timing but not -1 */ /* Set we can use -.5 timing but not -1. */
spd_byte = 31 - __builtin_clz((u32) casmap0); spd_byte = 31 - __builtin_clz((u32) casmap0);
/* just want bits in the lower byte since we have to cast to a 32 */ /* Just want bits in the lower byte since we have to cast to a 32. */
casmap0 &= 0xFF << (--spd_byte); casmap0 &= 0xFF << (--spd_byte);
} }
} /* MIN_CYCLE_10 != 0 */ } /* MIN_CYCLE_10 != 0 */
} else { } else {
/* Timing_05 < GLspeed, can't use -.5 or -1 timing */ /* Timing_05 < GLspeed, can't use -.5 or -1 timing. */
spd_byte = 31 - __builtin_clz((u32) casmap0); spd_byte = 31 - __builtin_clz((u32) casmap0);
/* just want bits in the lower byte since we have to cast to a 32 */ /* Just want bits in the lower byte since we have to cast to a 32. */
casmap0 &= 0xFF << (spd_byte); casmap0 &= 0xFF << (spd_byte);
} }
} /* MIN_CYCLE_05 != 0 */ } /* MIN_CYCLE_05 != 0 */
@ -298,31 +309,33 @@ static void set_cas(u8 dimm0, u8 dimm1)
casmap0 = 0; casmap0 = 0;
} }
/************************** dimm1 **********************************/ /* DIMM 1 */
casmap1 = smbus_read_byte(dimm1, SPD_ACCEPTABLE_CAS_LATENCIES); casmap1 = smbus_read_byte(dimm1, SPD_ACCEPTABLE_CAS_LATENCIES);
if (casmap1 != 0xFF) { if (casmap1 != 0xFF) {
/* IF -.5 timing is supported, check -.5 timing > GeodeLink */ /* If -.5 timing is supported, check -.5 timing > GeodeLink. */
/* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5 */
spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_2ND); spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_2ND);
if (spd_byte != 0) { if (spd_byte != 0) {
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */ /* Turn SPD ns time into MHz. Check what the asm does to this math. */
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F))); dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
if (dimm_speed >= glspeed) { if (dimm_speed >= glspeed) {
/* IF -1 timing is supported, check -1 timing > GeodeLink */ /* If -1 timing is supported, check -1 timing > GeodeLink. */
/* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1 */
spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_3RD); spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_3RD);
if (spd_byte != 0) { if (spd_byte != 0) {
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */ /* Turn SPD ns time into MHz. Check what the asm does to this math. */
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F))); dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
if (dimm_speed <= glspeed) { if (dimm_speed <= glspeed) {
/* set we can use -.5 timing but not -1 */ /* Set we can use -.5 timing but not -1. */
spd_byte = 31 - __builtin_clz((u32) casmap1); spd_byte = 31 - __builtin_clz((u32) casmap1);
/* just want bits in the lower byte since we have to cast to a 32 */ /* Just want bits in the lower byte since we have to cast to a 32. */
casmap1 &= 0xFF << (--spd_byte); casmap1 &= 0xFF << (--spd_byte);
} }
} /* MIN_CYCLE_10 != 0 */ } /* MIN_CYCLE_10 != 0 */
} else { } else {
/* Timing_05 < GLspeed, can't use -.5 or -1 timing */ /* Timing_05 < GLspeed, can't use -.5 or -1 timing. */
spd_byte = 31 - __builtin_clz((u32) casmap1); spd_byte = 31 - __builtin_clz((u32) casmap1);
/* just want bits in the lower byte since we have to cast to a 32 */ /* Just want bits in the lower byte since we have to cast to a 32. */
casmap1 &= 0xFF << (spd_byte); casmap1 &= 0xFF << (spd_byte);
} }
} /* MIN_CYCLE_05 != 0 */ } /* MIN_CYCLE_05 != 0 */
@ -330,7 +343,7 @@ static void set_cas(u8 dimm0, u8 dimm1)
casmap1 = 0; casmap1 = 0;
} }
/********************* CAS_LAT MAP COMPARE ***************************/ /* Compare CAS latencies. */
if (casmap0 == 0) { if (casmap0 == 0) {
spd_byte = CASDDR[__builtin_ctz((u32) casmap1)]; spd_byte = CASDDR[__builtin_ctz((u32) casmap1)];
} else if (casmap1 == 0) { } else if (casmap1 == 0) {
@ -338,7 +351,7 @@ static void set_cas(u8 dimm0, u8 dimm1)
} else if ((casmap0 &= casmap1)) { } else if ((casmap0 &= casmap1)) {
spd_byte = CASDDR[__builtin_ctz((u32) casmap0)]; spd_byte = CASDDR[__builtin_ctz((u32) casmap0)];
} else { } else {
printk(BIOS_EMERG, "DIMM CAS Latencies not compatible\n"); printk(BIOS_EMERG, "DIMM CAS latencies not compatible\n");
post_code(ERROR_DIFF_DIMMS); post_code(ERROR_DIFF_DIMMS);
hlt(); hlt();
} }
@ -350,10 +363,13 @@ static void set_cas(u8 dimm0, u8 dimm1)
} }
/** /**
* set latencies for DRAM. These are the famed ras and cas latencies. * Set latencies for DRAM.
* Take the one with the tightest requirements, and use that for both. *
* @param dimm0 dimm0 SMBus address * These are the famed RAS and CAS latencies. Take the one with the tightest
* @param dimm1 dimm1 SMBus address * requirements, and use that for both.
*
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*/ */
static void set_latencies(u8 dimm0, u8 dimm1) static void set_latencies(u8 dimm0, u8 dimm1)
{ {
@ -367,36 +383,29 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* MC_CF8F setup */ /* MC_CF8F setup */
/* tRAS */ /* tRAS */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRAS); spd_byte0 = smbus_read_byte(dimm0, SPD_tRAS);
if (spd_byte0 == 0xFF) { if (spd_byte0 == 0xFF)
spd_byte0 = 0; spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRAS); spd_byte1 = smbus_read_byte(dimm1, SPD_tRAS);
if (spd_byte1 == 0xFF) { if (spd_byte1 == 0xFF)
spd_byte1 = 0; spd_byte1 = 0;
} if (spd_byte0 < spd_byte1)
if (spd_byte0 < spd_byte1) {
spd_byte0 = spd_byte1; spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = (spd_byte0 * memspeed) / 1000; spd_byte1 = (spd_byte0 * memspeed) / 1000;
if (((spd_byte0 * memspeed) % 1000)) { if (((spd_byte0 * memspeed) % 1000))
++spd_byte1; ++spd_byte1;
}
dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT; dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT;
/* tRP */ /* tRP */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRP); spd_byte0 = smbus_read_byte(dimm0, SPD_tRP);
if (spd_byte0 == 0xFF) { if (spd_byte0 == 0xFF)
spd_byte0 = 0; spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRP); spd_byte1 = smbus_read_byte(dimm1, SPD_tRP);
if (spd_byte1 == 0xFF) { if (spd_byte1 == 0xFF)
spd_byte1 = 0; spd_byte1 = 0;
} if (spd_byte0 < spd_byte1)
if (spd_byte0 < spd_byte1) {
spd_byte0 = spd_byte1; spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000; spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
@ -407,16 +416,13 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* tRCD */ /* tRCD */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRCD); spd_byte0 = smbus_read_byte(dimm0, SPD_tRCD);
if (spd_byte0 == 0xFF) { if (spd_byte0 == 0xFF)
spd_byte0 = 0; spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRCD); spd_byte1 = smbus_read_byte(dimm1, SPD_tRCD);
if (spd_byte1 == 0xFF) { if (spd_byte1 == 0xFF)
spd_byte1 = 0; spd_byte1 = 0;
} if (spd_byte0 < spd_byte1)
if (spd_byte0 < spd_byte1) {
spd_byte0 = spd_byte1; spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000; spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
@ -427,16 +433,13 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* tRRD */ /* tRRD */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRRD); spd_byte0 = smbus_read_byte(dimm0, SPD_tRRD);
if (spd_byte0 == 0xFF) { if (spd_byte0 == 0xFF)
spd_byte0 = 0; spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRRD); spd_byte1 = smbus_read_byte(dimm1, SPD_tRRD);
if (spd_byte1 == 0xFF) { if (spd_byte1 == 0xFF)
spd_byte1 = 0; spd_byte1 = 0;
} if (spd_byte0 < spd_byte1)
if (spd_byte0 < spd_byte1) {
spd_byte0 = spd_byte1; spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000; spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
@ -459,33 +462,36 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* MC_CF1017 setup */ /* MC_CF1017 setup */
/* tRFC */ /* tRFC */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRFC); spd_byte0 = smbus_read_byte(dimm0, SPD_tRFC);
if (spd_byte0 == 0xFF) { if (spd_byte0 == 0xFF)
spd_byte0 = 0; spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRFC); spd_byte1 = smbus_read_byte(dimm1, SPD_tRFC);
if (spd_byte1 == 0xFF) { if (spd_byte1 == 0xFF)
spd_byte1 = 0; spd_byte1 = 0;
} if (spd_byte0 < spd_byte1)
if (spd_byte0 < spd_byte1) {
spd_byte0 = spd_byte1; spd_byte0 = spd_byte1;
}
if (spd_byte0) { if (spd_byte0) {
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = (spd_byte0 * memspeed) / 1000; spd_byte1 = (spd_byte0 * memspeed) / 1000;
if (((spd_byte0 * memspeed) % 1000)) { if (((spd_byte0 * memspeed) % 1000))
++spd_byte1; ++spd_byte1;
} } else {
} else { /* Not all SPDs have tRFC setting. Use this formula tRFC = tRC + 1 clk */ /* Not all SPDs have tRFC setting.
* Use this formula: tRFC = tRC + 1 clk.
*/
spd_byte1 = ((dimm_setting >> CF8F_LOWER_ACT2ACTREF_SHIFT) & 0x0F) + 1; spd_byte1 = ((dimm_setting >> CF8F_LOWER_ACT2ACTREF_SHIFT) & 0x0F) + 1;
} }
dimm_setting = spd_byte1 << CF1017_LOWER_REF2ACT_SHIFT; /* note this clears the cf8f dimm setting */
/* Note: This clears the cf8f DIMM setting. */
dimm_setting = spd_byte1 << CF1017_LOWER_REF2ACT_SHIFT;
msr = rdmsr(MC_CF1017_DATA); msr = rdmsr(MC_CF1017_DATA);
msr.lo &= ~(0x1F << CF1017_LOWER_REF2ACT_SHIFT); msr.lo &= ~(0x1F << CF1017_LOWER_REF2ACT_SHIFT);
msr.lo |= dimm_setting; msr.lo |= dimm_setting;
wrmsr(MC_CF1017_DATA, msr); wrmsr(MC_CF1017_DATA, msr);
/* tWTR: Set tWTR to 2 for 400MHz and above GLBUS (200Mhz mem) other wise it stay default(1) */ /* tWTR: Set tWTR to 2 for 400 MHz and above GLBUS (200 Mhz mem)
* otherwise it stay default (1).
*/
if (memspeed > 198) { if (memspeed > 198) {
msr = rdmsr(MC_CF1017_DATA); msr = rdmsr(MC_CF1017_DATA);
msr.lo &= ~(0x7 << CF1017_LOWER_WR_TO_RD_SHIFT); msr.lo &= ~(0x7 << CF1017_LOWER_WR_TO_RD_SHIFT);
@ -496,28 +502,30 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/** /**
* Set the registers for drive, namely drive and fet strength. * Set the registers for drive, namely drive and fet strength.
* @param dimm0 dimm0 SMBus address *
* @param dimm1 dimm1 SMBus address * @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*/ */
static void set_extended_mode_registers(u8 dimm0, u8 dimm1) static void set_extended_mode_registers(u8 dimm0, u8 dimm1)
{ {
u8 spd_byte0, spd_byte1; u8 spd_byte0, spd_byte1;
struct msr msr; struct msr msr;
spd_byte0 = smbus_read_byte(dimm0, SPD_DEVICE_ATTRIBUTES_GENERAL); spd_byte0 = smbus_read_byte(dimm0, SPD_DEVICE_ATTRIBUTES_GENERAL);
if (spd_byte0 == 0xFF) { if (spd_byte0 == 0xFF)
spd_byte0 = 0; spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_DEVICE_ATTRIBUTES_GENERAL); spd_byte1 = smbus_read_byte(dimm1, SPD_DEVICE_ATTRIBUTES_GENERAL);
if (spd_byte1 == 0xFF) { if (spd_byte1 == 0xFF)
spd_byte1 = 0; spd_byte1 = 0;
}
spd_byte1 &= spd_byte0; spd_byte1 &= spd_byte0;
msr = rdmsr(MC_CF07_DATA); msr = rdmsr(MC_CF07_DATA);
if (spd_byte1 & 1) { /* Drive Strength Control */ if (spd_byte1 & 1) {
/* Drive Strength Control */
msr.lo |= CF07_LOWER_EMR_DRV_SET; msr.lo |= CF07_LOWER_EMR_DRV_SET;
} }
if (spd_byte1 & 2) { /* FET Control */ if (spd_byte1 & 2) {
/* FET Control */
msr.lo |= CF07_LOWER_EMR_QFC_SET; msr.lo |= CF07_LOWER_EMR_QFC_SET;
} }
wrmsr(MC_CF07_DATA, msr); wrmsr(MC_CF07_DATA, msr);
@ -531,7 +539,7 @@ static void EnableMTest(void)
struct msr msr; struct msr msr;
msr = rdmsr(GLCP_DELAY_CONTROLS); msr = rdmsr(GLCP_DELAY_CONTROLS);
msr.hi &= ~(7 << 20); /* clear bits 54:52 */ msr.hi &= ~(7 << 20); /* Clear bits 54:52. */
if (geode_link_speed() < 200) { if (geode_link_speed() < 200) {
msr.hi |= 2 << 20; msr.hi |= 2 << 20;
} }
@ -547,8 +555,9 @@ static void EnableMTest(void)
printk(BIOS_DEBUG, "Enabled MTest for TLA debug\n"); printk(BIOS_DEBUG, "Enabled MTest for TLA debug\n");
} }
/** Set SDRAM registers that need to be set independent of SPD or even presence or absence of DIMMs /**
* in a slot. Parameters are ignored. * Set SDRAM registers that need to be set independent of SPD or even
* presence or absence of DIMMs in a slot. Parameters are ignored.
*/ */
void sdram_set_registers(void) void sdram_set_registers(void)
{ {
@ -570,19 +579,23 @@ void sdram_set_registers(void)
msrnum = MC_CF07_DATA; msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo &= ~0xF0; msr.lo &= ~0xF0;
msr.lo |= 0x40; /* set refresh to 4SDRAM clocks */ msr.lo |= 0x40; /* Set refresh to 4 SDRAM clocks. */
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Memory Interleave: Set HOI here otherwise default is LOI */ /* Memory Interleave: Set HOI here otherwise default is LOI. */
/* msrnum = MC_CF8F_DATA; #if 0
msrnum = MC_CF8F_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.hi |= CF8F_UPPER_HOI_LOI_SET; msr.hi |= CF8F_UPPER_HOI_LOI_SET;
wrmsr(msrnum, msr); */ wrmsr(msrnum, msr);
#endif
} }
/** Set SDRAM registers that need to are determined by SPD. /**
* @param dimm0 dimm0 SMBus address * Set SDRAM registers that need to be determined by SPD.
* @param dimm1 dimm1 SMBus address *
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*/ */
void sdram_set_spd_registers(u8 dimm0, u8 dimm1) void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
{ {
@ -591,15 +604,16 @@ void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
post_code(POST_MEM_SETUP); post_code(POST_MEM_SETUP);
spd_byte = smbus_read_byte(dimm0, SPD_MODULE_ATTRIBUTES); spd_byte = smbus_read_byte(dimm0, SPD_MODULE_ATTRIBUTES);
/* Check DIMM is not Register and not Buffered DIMMs. */
/* Check DIMM is not Registered and not Buffered DIMMs. */
if ((spd_byte != 0xFF) && (spd_byte & 3)) { if ((spd_byte != 0xFF) && (spd_byte & 3)) {
printk(BIOS_EMERG, "dimm0 NOT COMPATIBLE\n"); printk(BIOS_EMERG, "DIMM 0 NOT COMPATIBLE!\n");
post_code(ERROR_UNSUPPORTED_DIMM); post_code(ERROR_UNSUPPORTED_DIMM);
hlt(); hlt();
} }
spd_byte = smbus_read_byte(dimm1, SPD_MODULE_ATTRIBUTES); spd_byte = smbus_read_byte(dimm1, SPD_MODULE_ATTRIBUTES);
if ((spd_byte != 0xFF) && (spd_byte & 3)) { if ((spd_byte != 0xFF) && (spd_byte & 3)) {
printk(BIOS_EMERG, "dimm1 NOT COMPATIBLE\n"); printk(BIOS_EMERG, "DIMM 1 NOT COMPATIBLE!\n");
post_code(ERROR_UNSUPPORTED_DIMM); post_code(ERROR_UNSUPPORTED_DIMM);
hlt(); hlt();
} }
@ -609,37 +623,39 @@ void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
/* Check that the memory is not overclocked. */ /* Check that the memory is not overclocked. */
check_ddr_max(dimm0, dimm1); check_ddr_max(dimm0, dimm1);
/* Size the DIMMS */ /* Size the DIMMS.
/* this is gross. It is an artifact of our move to parametes instead of #defines. FIX ME */ * This is gross. It is an artifact of our move to parametes instead of
/* the fix is trivial but I want to see it work first. */ * #defines. FIXME! The fix is trivial but I want to see it work first.
*/
post_code(POST_MEM_SETUP3); post_code(POST_MEM_SETUP3);
auto_size_dimm(dimm0, dimm0, dimm1); auto_size_dimm(dimm0, dimm0, dimm1);
post_code(POST_MEM_SETUP4); post_code(POST_MEM_SETUP4);
auto_size_dimm(dimm1, dimm0, dimm1); auto_size_dimm(dimm1, dimm0, dimm1);
/* Set CAS latency */ /* Set CAS latency. */
post_code(POST_MEM_SETUP5); post_code(POST_MEM_SETUP5);
set_cas(dimm0, dimm1); set_cas(dimm0, dimm1);
/* Set all the other latencies here (tRAS, tRP....) */ /* Set all the other latencies here (tRAS, tRP...). */
set_latencies(dimm0, dimm1); set_latencies(dimm0, dimm1);
/* Set Extended Mode Registers */ /* Set Extended Mode Registers. */
set_extended_mode_registers(dimm0, dimm1); set_extended_mode_registers(dimm0, dimm1);
/* Set Memory Refresh Rate */ /* Set Memory Refresh Rate. */
set_refresh_rate(dimm0, dimm1); set_refresh_rate(dimm0, dimm1);
} }
/** /**
* enable the DRAMs. * Enable the DRAMs.
*
* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence * Section 6.1.3, LX processor databooks, BIOS Initialization Sequence
* Section 4.1.4, GX/CS5535 GeodeROM Porting guide * Section 4.1.4, GX/CS5535 GeodeROM Porting guide
* Turn on MC/DIMM interface per JEDEC *
* Turn on MC/DIMM interface per JEDEC:
* 1) Clock stabilizes > 200us * 1) Clock stabilizes > 200us
* 2) Assert CKE * 2) Assert CKE
* 3) Precharge All to put all banks into an idles state * 3) Precharge All to put all banks into an idle state
* 4) EMRS to enable DLL * 4) EMRS to enable DLL
* 6) MRS w/ memory config & reset DLL set * 6) MRS w/ memory config & reset DLL set
* 7) Wait 200 clocks (2us) * 7) Wait 200 clocks (2us)
@ -647,41 +663,45 @@ void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
* 9) MRS w/ memory config & reset DLL clear * 9) MRS w/ memory config & reset DLL clear
* 8) DDR SDRAM ready for normal operation * 8) DDR SDRAM ready for normal operation
* *
* @param dimm0 dimm0 SMBus address * @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
* @param dimm1 dimm1 SMBus address * @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
*/ */
void sdram_enable(u8 dimm0, u8 dimm1) void sdram_enable(u8 dimm0, u8 dimm1)
{ {
u32 i, msrnum; u32 i, msrnum;
struct msr msr; struct msr msr;
post_code(POST_MEM_ENABLE); // post_76h post_code(POST_MEM_ENABLE);
/* Only enable MTest for TLA memory debug */ /* Only enable MTest for TLA memory debug. */
/* EnableMTest(); */ /* EnableMTest(); */
/* If both Page Size = "Not Installed" we have a problems and should halt. */ /* If both Page Size = "Not Installed" we have a problem and
* should halt.
*/
msr = rdmsr(MC_CF07_DATA); msr = rdmsr(MC_CF07_DATA);
if ((msr.hi & ((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) == if ((msr.hi & ((7 << CF07_UPPER_D1_PSZ_SHIFT) |
((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) { (7 << CF07_UPPER_D0_PSZ_SHIFT))) ==
((7 << CF07_UPPER_D1_PSZ_SHIFT) |
(7 << CF07_UPPER_D0_PSZ_SHIFT))) {
printk(BIOS_EMERG, "No memory in the system\n"); printk(BIOS_EMERG, "No memory in the system\n");
post_code(ERROR_NO_DIMMS); post_code(ERROR_NO_DIMMS);
hlt(); hlt();
} }
/* Set CKEs */ /* Set CKEs. */
msrnum = MC_CFCLK_DBUG; msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo &= ~(CFCLK_LOWER_MASK_CKE_SET0 | CFCLK_LOWER_MASK_CKE_SET1); msr.lo &= ~(CFCLK_LOWER_MASK_CKE_SET0 | CFCLK_LOWER_MASK_CKE_SET1);
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Force Precharge All on next command, EMRS */ /* Force Precharge All on next command, EMRS. */
msrnum = MC_CFCLK_DBUG; msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET; msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* EMRS to enable DLL (pre-setup done in setExtendedModeRegisters) */ /* EMRS to enable DLL (pre-setup done in setExtendedModeRegisters). */
msrnum = MC_CF07_DATA; msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET; msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET;
@ -689,13 +709,13 @@ void sdram_enable(u8 dimm0, u8 dimm1)
msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET); msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET);
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Clear Force Precharge All */ /* Clear Force Precharge All. */
msrnum = MC_CFCLK_DBUG; msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET; msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* MRS Reset DLL - set */ /* MRS Reset DLL - set. */
msrnum = MC_CF07_DATA; msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET; msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET;
@ -703,23 +723,23 @@ void sdram_enable(u8 dimm0, u8 dimm1)
msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET); msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET);
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* 2us delay (200 clocks @ 200Mhz). We probably really don't /* 2us delay (200 clocks @ 200Mhz). We probably really don't need
* need this but.... better safe. * this but... better safe.
*
* Wait two 'port 61 ticks' (between 15us and 30us).
* This would be endless if the timer is stuck.
*/ */
/* Wait 2 PORT61 ticks. between 15us and 30us */ while ((inb(0x61))); /* Find the first edge. */
/* This would be endless if the timer is stuck. */
while ((inb(0x61))) ; /* find the first edge */
while (!(~inb(0x61))); while (!(~inb(0x61)));
/* Force Precharge All on the next command, auto-refresh */ /* Force Precharge All on the next command, auto-refresh. */
msrnum = MC_CFCLK_DBUG; msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET; msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Manually AUTO refresh #1 */ /* Manually AUTO refresh #1. If auto refresh was not enabled above we
/* If auto refresh was not enabled above we would need to do 8 * would need to do 8 refreshes to prime the pump before these 2.
* refreshes to prime the pump before these 2.
*/ */
msrnum = MC_CF07_DATA; msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
@ -728,14 +748,15 @@ void sdram_enable(u8 dimm0, u8 dimm1)
msr.lo &= ~CF07_LOWER_REF_TEST_SET; msr.lo &= ~CF07_LOWER_REF_TEST_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Clear Force Precharge All */ /* Clear Force Precharge All. */
msrnum = MC_CFCLK_DBUG; msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET; msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Manually AUTO refresh */ /* Manually AUTO refresh.
/* The MC should insert the right delay between the refreshes */ * The MC should insert the right delay between the refreshes.
*/
msrnum = MC_CF07_DATA; msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= CF07_LOWER_REF_TEST_SET; msr.lo |= CF07_LOWER_REF_TEST_SET;
@ -743,7 +764,7 @@ void sdram_enable(u8 dimm0, u8 dimm1)
msr.lo &= ~CF07_LOWER_REF_TEST_SET; msr.lo &= ~CF07_LOWER_REF_TEST_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* MRS Reset DLL - clear */ /* MRS Reset DLL - clear. */
msrnum = MC_CF07_DATA; msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= CF07_LOWER_PROG_DRAM_SET; msr.lo |= CF07_LOWER_PROG_DRAM_SET;
@ -751,13 +772,13 @@ void sdram_enable(u8 dimm0, u8 dimm1)
msr.lo &= ~CF07_LOWER_PROG_DRAM_SET; msr.lo &= ~CF07_LOWER_PROG_DRAM_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Allow MC to tristate during idle cycles with MTEST OFF */ /* Allow MC to tristate during idle cycles with MTEST OFF. */
msrnum = MC_CFCLK_DBUG; msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo &= ~CFCLK_LOWER_TRISTATE_DIS_SET; msr.lo &= ~CFCLK_LOWER_TRISTATE_DIS_SET;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
/* Disable SDCLK dimm1 slot if no DIMM installed to save power. */ /* Disable SDCLK DIMM 1 slot if no DIMM installed (to save power). */
msr = rdmsr(MC_CF07_DATA); msr = rdmsr(MC_CF07_DATA);
if ((msr.hi & (7 << CF07_UPPER_D1_PSZ_SHIFT)) == if ((msr.hi & (7 << CF07_UPPER_D1_PSZ_SHIFT)) ==
(7 << CF07_UPPER_D1_PSZ_SHIFT)) { (7 << CF07_UPPER_D1_PSZ_SHIFT)) {
@ -767,53 +788,54 @@ void sdram_enable(u8 dimm0, u8 dimm1)
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
} }
/* Set PMode0 Sensitivity Counter */ /* Set PMode0 Sensitivity Counter. */
msr.lo = 0; /* pmode 0=0 most aggressive */ msr.lo = 0; /* pmode 0=0 most aggressive */
msr.hi = 0x200; /* pmode 1=200h */ msr.hi = 0x200; /* pmode 1=200h */
wrmsr(MC_CF_PMCTR, msr); wrmsr(MC_CF_PMCTR, msr);
/* Set PMode1 Up delay enable */ /* Set PMode1 Up delay enable. */
msrnum = MC_CF1017_DATA; msrnum = MC_CF1017_DATA;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= (209 << 8); /* bits[15:8] = 209 */ msr.lo |= (209 << 8); /* bits[15:8] = 209 */
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
printk(BIOS_DEBUG, "DRAM controller init done.\n"); printk(BIOS_DEBUG, "DRAM controller init done.\n");
post_code(POST_MEM_SETUP_GOOD); //0x7E post_code(POST_MEM_SETUP_GOOD);
/* make sure there is nothing stale in the cache */ /* Make sure there is nothing stale in the cache. */
/* CAR stack is in the cache __asm__ __volatile__("wbinvd\n"); */ /* CAR stack is in the cache __asm__ __volatile__("wbinvd\n"); */
/* The RAM dll needs a write to lock on so generate a few dummy writes */ /* The RAM dll needs a write to lock on so generate a few dummy
/* Note: The descriptor needs to be enabled to point at memory */ * writes. Note: The descriptor needs to be enabled to point at memory.
*/
volatile unsigned long *ptr; volatile unsigned long *ptr;
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
ptr = (void *)i; ptr = (void *)i;
*ptr = (unsigned long)i; *ptr = (unsigned long)i;
} }
/* SWAPSiF for PBZ 4112 (Errata 34) */
/* check for failed DLL settings now that we have done a memory write. */ /* SWAPSiF for PBZ 4112 (Errata 34)
* Check for failed DLL settings now that we have done a
* memory write.
*/
msrnum = GLCP_DELAY_CONTROLS; msrnum = GLCP_DELAY_CONTROLS;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
if ((msr.lo & 0x7FF) == 0x104) { if ((msr.lo & 0x7FF) == 0x104) {
/* If you had it you would need to clear out the fail boot
/* If you had it you would need to clear out the fail * count flag (depending on where it counts from etc).
* boot count flag (depending on where it counts from
* etc).
*/ */
/* The we are about to perform clears the PM_SSC /* The we are about to perform clears the PM_SSC
* register in the 5536 so will need to store the S3 * register in the CS5536 so will need to store the S3
* resume *flag in NVRAM otherwise it would do a * resume flag in NVRAM otherwise it would do a normal boot.
* normal boot
*/ */
/* Reset the system */ /* Reset the system. */
msrnum = MDD_SOFT_RESET; msrnum = MDD_SOFT_RESET;
msr = rdmsr(msrnum); msr = rdmsr(msrnum);
msr.lo |= 1; msr.lo |= 1;
wrmsr(msrnum, msr); wrmsr(msrnum, msr);
} }
printk(BIOS_DEBUG, "RAM DLL lock\n");
printk(BIOS_DEBUG, "RAM DLL lock\n");
} }