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,54 +30,74 @@
#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 *
* attributes of a region. Just like MTRRs, only different. * RCONF is Region CONFiguration, and controls caching and other
*/ * attributes of a region. Just like MTRRs, only different.
#define CACHE_DISABLE (1<<0) */
#define WRITE_ALLOCATE (1<<1) #define CACHE_DISABLE (1 << 0)
#define WRITE_PROTECT (1<<2) #define WRITE_ALLOCATE (1 << 1)
#define WRITE_THROUGH (1<<3) #define WRITE_PROTECT (1 << 2)
#define WRITE_COMBINE (1<<4) #define WRITE_THROUGH (1 << 3)
#define WRITE_SERIALIZE (1<<5) #define WRITE_COMBINE (1 << 4)
#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 *
* really want to understand it. * This is complex enough that you are going to need to RTFM if you
* 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);
@ -90,195 +110,213 @@ void do_vsmbios(void);
struct msr_defaults { struct msr_defaults {
int msr_no; int msr_no;
struct msr msr; struct msr msr;
} msr_defaults[] = { } 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. */
//{0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}}, /* TODO: There's no cpubug.c. */
/* 180d is left at default, e0000-fffff is non-cached */ // {0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}},
/* we will assume 180e, the ssm region configuration, is left /* 180d is left at default, e0000-fffff is non-cached. */
* at default or set by VSM */ /* We will assume 180e, the ssm region configuration, is left
/* we will not set 0x180f, the DMM,yet * at default or set by VSM.
*/ */
//{0x1810, {.hi=0xee7ff000, .lo=RRCF_LOW(0xee000000, WRITE_COMBINE|CACHE_DISABLE)}}, /* We will not set 0x180f, the DMM, yet. */
//{0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
//{0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}}, // {0x1810, {.hi = 0xee7ff000,
//{0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}}, // .lo = RRCF_LOW(0xee000000, WRITE_COMBINE|CACHE_DISABLE)}},
/* now for GLPCI routing */ // {0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
// {0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}},
// {0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}},
/* Now for GLPCI routing. */
/* GLIU0 */ /* 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)
{ {
struct msr msr; struct msr msr;
int sizem = 0; int sizem = 0;
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)
{ {
} }
/** /**
* 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++) {
struct bus *bus; struct bus *bus;
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.
/** *
* Set resources for the PCI domain. Just set up basic global ranges * Just set up basic global ranges for I/O and memory. Allocation of
* for IO and memory Allocation of sub-resources draws on these * sub-resources draws on these top-level resources in the usual
* top-level resources in the usual hierarchical manner. * 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__);
/* Initialize the system wide io space constraints */ printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
/* 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 =
IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED; IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
} }
/** /**
* 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)
{ {
struct resource *resource; struct resource *resource;
@ -290,159 +328,169 @@ static void ram_resource(struct device * dev, unsigned long index,
resource->base = ((resource_t) basek) << 10; resource->base = ((resource_t) basek) << 10;
resource->size = ((resource_t) sizek) << 10; resource->size = ((resource_t) sizek) << 10;
resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE |
IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
} }
/** /**
* 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.
static void geodelx_pci_domain_set_resources(struct device * dev) *
* @param dev The device.
*/
static void geodelx_pci_domain_set_resources(struct device *dev)
{ {
int idx; int idx;
struct device * mc_dev; struct device *mc_dev;
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__); printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
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...
*/ *
static void geodelx_pci_domain_phase2(struct device * dev) * @param dev The device.
*/
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");
/* print_conf(); */
printk(BIOS_DEBUG,"After VSA:\n"); #warning graphics_init is disabled.
// print_conf(); /* graphics_init(); */
#warning graphics_init is disabled.
// 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__);
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max); max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
return max; return max;
} }
/**
* Support for APIC cluster init.
*
* 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)
{
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
printk(BIOS_SPEW, ">> Exiting northbridge.c: %s\n", __FUNCTION__);
}
static void cpu_bus_noop(struct device *dev)
{
}
/* The same hardware, being multifunction, has several roles. In this case,
* the northbridge is a PCI domain controller, APIC cluster, and the
* traditional 0:0.0 device.
*/
/** Operations for when the northbridge is running a PCI domain. */
struct device_operations geodelx_pcidomainops = {
.constructor = default_device_constructor,
.phase2_setup_scan_bus = geodelx_pci_domain_phase2,
.phase3_scan = geodelx_pci_domain_scan_bus,
.phase4_read_resources = geodelx_pci_domain_read_resources,
.phase4_set_resources = geodelx_pci_domain_set_resources,
.phase5_enable_resources = enable_childrens_resources,
.phase6_init = 0,
.ops_pci_bus = &pci_cf8_conf1,
};
/** Operations for when the northbridge is running an APIC cluster. */
struct device_operations geodelx_apicops = {
.constructor = default_device_constructor,
.phase3_scan = 0,
.phase4_read_resources = cpu_bus_noop,
.phase4_set_resources = cpu_bus_noop,
.phase5_enable_resources = cpu_bus_noop,
.phase6_init = cpu_bus_init,
.ops_pci_bus = &pci_cf8_conf1,
};
/** Operations for when the northbridge is running a PCI device. */
struct device_operations geodelx_pci_ops = {
.constructor = default_device_constructor,
.phase3_scan = geodelx_pci_domain_scan_bus,
.phase4_read_resources = geodelx_pci_domain_read_resources,
.phase4_set_resources = geodelx_northbridge_set_resources,
.phase5_enable_resources = enable_childrens_resources,
.phase6_init = geodelx_northbridge_init,
.ops_pci_bus = &pci_cf8_conf1,
};
/** /**
* Support for apic cluster init. TODO should we do this in phase 2? * The constructor for the device.
* It is now done in phase 6 * Domain ops and APIC cluster ops and PCI device ops are different.
* @param dev The pci domain device
*/
static void cpu_bus_init(struct device * dev)
{
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__);
printk(BIOS_SPEW,">> Exiting northbridge.c: %s\n", __FUNCTION__);
}
static void cpu_bus_noop(struct device * dev)
{
}
/* the same hardware, being multifunction, has several roles. In this
* case, the north is a pci domain controller, apic cluster, and the
* traditional 0:0.0 device
*/
/* Here are the operations for when the northbridge is running a PCI
* domain.
*/ */
struct device_operations geodelx_pcidomainops = {
.constructor = default_device_constructor,
.phase2_setup_scan_bus = geodelx_pci_domain_phase2,
.phase3_scan = geodelx_pci_domain_scan_bus,
.phase4_read_resources = geodelx_pci_domain_read_resources,
.phase4_set_resources = geodelx_pci_domain_set_resources,
.phase5_enable_resources = enable_childrens_resources,
.phase6_init = 0,
.ops_pci_bus = &pci_cf8_conf1,
};
/* Here are the operations for when the northbridge is running an APIC
* cluster.
*/
struct device_operations geodelx_apicops = {
.constructor = default_device_constructor,
.phase3_scan = 0,
.phase4_read_resources = cpu_bus_noop,
.phase4_set_resources = cpu_bus_noop,
.phase5_enable_resources = cpu_bus_noop,
.phase6_init = cpu_bus_init,
.ops_pci_bus = &pci_cf8_conf1,
};
/* Here are the operations for when the northbridge is running a PCI
* device.
*/
struct device_operations geodelx_pci_ops = {
.constructor = default_device_constructor,
.phase3_scan = geodelx_pci_domain_scan_bus,
.phase4_read_resources = geodelx_pci_domain_read_resources,
.phase4_set_resources = geodelx_northbridge_set_resources,
.phase5_enable_resources = enable_childrens_resources,
.phase6_init = geodelx_northbridge_init,
.ops_pci_bus = &pci_cf8_conf1,
};
/* The constructor for the device. */
/* Domain ops and apic cluster ops and pci device ops are different */
struct constructor geodelx_north_constructors[] = { struct constructor geodelx_north_constructors[] = {
{.id = {.type = DEVICE_ID_PCI_DOMAIN, /* Northbridge running a PCI domain. */
.u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}}, {.id = {.type = DEVICE_ID_PCI_DOMAIN,
&geodelx_pcidomainops}, .u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,
{.id = {.type = DEVICE_ID_APIC_CLUSTER, .device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}}, .ops = &geodelx_pcidomainops},
&geodelx_apicops},
{.id = {.type = DEVICE_ID_PCI, /* Northbridge running an APIC cluster. */
.u = {.pci = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}}, {.id = {.type = DEVICE_ID_APIC_CLUSTER,
&geodelx_pci_ops}, .u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,
{.ops = 0}, .device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.ops = &geodelx_apicops},
/* Northbridge running a PCI device. */
{.id = {.type = DEVICE_ID_PCI,
.u = {.pci = {.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.ops = &geodelx_pci_ops},
{.ops = 0},
}; };

File diff suppressed because it is too large Load diff

View file

@ -32,16 +32,19 @@
#include <amd_geodelx.h> #include <amd_geodelx.h>
#include <southbridge/amd/cs5536/cs5536.h> #include <southbridge/amd/cs5536/cs5536.h>
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)
{ {
u32 dimm_setting; u32 dimm_setting;
@ -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,59 +74,58 @@ 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 1GB only support 1GB per DIMM */ if (dimm_size > 8) { /* 8 is 1 GB only support 1 GB per DIMM */
printk(BIOS_EMERG, "Only support up to 1 GB per DIMM\n"); printk(BIOS_EMERG, "Only support up to 1 GB per DIMM\n");
post_code(ERROR_DENSITY_DIMM); post_code(ERROR_DENSITY_DIMM);
hlt(); hlt();
} }
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) *
* * If ma[12:0] is the memory address pins, and pa[12:0] is the
* But this really works by magic. * physical column address that the memory controller (MC) generates,
*If ma[12:0] is the memory address pins, and pa[12:0] is the physical column address * here is how the MC assigns the pa onto the ma pins:
*that MC generates, 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 * -------------------------------------------
*------------------------------------------- * pa 09 08 07 06 05 04 03 (7 col addr bits = 1K page size)
*pa 09 08 07 06 05 04 03 (7 col addr bits = 1K page size) * pa 10 09 08 07 06 05 04 03 (8 col addr bits = 2K page size)
*pa 10 09 08 07 06 05 04 03 (8 col addr bits = 2K page size) * pa 11 10 09 08 07 06 05 04 03 (9 col addr bits = 4K page size)
*pa 11 10 09 08 07 06 05 04 03 (9 col addr bits = 4K page size) * 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 * (AP = autoprecharge bit)
* *
*Remember that pa[2:0] are zeroed out since it's a 64-bit data bus (8 bytes), * Remember that pa[2:0] are zeroed out since it's a 64-bit data bus
*so lower 3 address bits are dont_cares.So from the table above, * (8 bytes), so lower 3 address bits are dont_cares. So from the
*it's easier to see what the old code is doing: if for example,#col_addr_bits=7(06h), * table above, it's easier to see what the old code is doing: if for
*it adds 3 to get 10, then does 2^10=1K. Get it? * 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];
if (spd_byte > MAX_COL_ADDR) { if (spd_byte > MAX_COL_ADDR) {
@ -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,11 +152,15 @@ 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)
{ {
u8 spd_byte0, spd_byte1; u8 spd_byte0, spd_byte1;
@ -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. */
#if 0
if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0) {
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink speed\n");
post_code(POST_PLL_MEM_FAIL);
hlt();
} }
#endif
/* I don't think you need this check. /* Use the slowest DIMM. */
if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0){
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink Speed\n");
post_code(POST_PLL_MEM_FAIL);
hlt();
} */
/* 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();
} }
@ -198,11 +201,14 @@ 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)
{ {
u8 spd_byte0, spd_byte1; u8 spd_byte0, spd_byte1;
@ -223,40 +229,41 @@ 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;
} }
msr = rdmsr(MC_CF07_DATA); msr = rdmsr(MC_CF07_DATA);
msr.lo |= ((rate0 * (geode_link_speed() / 2)) / 16) msr.lo |= ((rate0 * (geode_link_speed() / 2)) / 16)
<< CF07_LOWER_REF_INT_SHIFT; << CF07_LOWER_REF_INT_SHIFT;
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 * The CAS setting is based on the information provided in each DIMMs SPD.
* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1 *
* * The speed at which a DIMM can run is described relative to the slowest
* The CAS setting is based on the information provided in each DIMMs SPD. * CAS the DIMM supports. Each speed for the relative CAS settings is
* The speed at which a DIMM can run is described relative to the slowest * checked that it is within the GeodeLink speed. If it isn't within the
* CAS the DIMM supports. Each speed for the relative CAS settings is * GeodeLink speed, the CAS setting is removed from the list of good settings
* checked that it is within the GeodeLink speed. If it isn't within the GeodeLink * for the DIMM.
* speed, the CAS setting is removed from the list of good settings for *
* the DIMM. This is done for both DIMMs and the lists are compared to * This is done for both DIMMs and the lists are compared to find the lowest
* find the lowest common CAS latency setting. If there are no CAS settings * common CAS latency setting. If there are no CAS settings
* in common we out a ERROR_DIFF_DIMMS (78h) to port 80h and halt. * 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. * Result is that we will set fastest CAS latency based on GeodeLink speed
* * and SPD information.
* @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_cas(u8 dimm0, u8 dimm1) static void set_cas(u8 dimm0, u8 dimm1)
{ {
u16 glspeed, dimm_speed; u16 glspeed, dimm_speed;
@ -265,72 +272,78 @@ 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 */
} else { /* No DIMM */ } else { /* No DIMM */
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 */
} else { /* No DIMM */ } else { /* No DIMM */
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();
} }
@ -349,12 +362,15 @@ static void set_cas(u8 dimm0, u8 dimm1)
wrmsr(MC_CF8F_DATA, msr); wrmsr(MC_CF8F_DATA, msr);
} }
/** /**
* 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)
{ {
u32 memspeed, dimm_setting; u32 memspeed, dimm_setting;
@ -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;
@ -447,8 +450,8 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* tRC = tRP + tRAS */ /* tRC = tRP + tRAS */
dimm_setting |= (((dimm_setting >> CF8F_LOWER_ACT2PRE_SHIFT) & 0x0F) + dimm_setting |= (((dimm_setting >> CF8F_LOWER_ACT2PRE_SHIFT) & 0x0F) +
((dimm_setting >> CF8F_LOWER_PRE2ACT_SHIFT) & 0x07)) ((dimm_setting >> CF8F_LOWER_PRE2ACT_SHIFT) & 0x07))
<< CF8F_LOWER_ACT2ACTREF_SHIFT; << CF8F_LOWER_ACT2ACTREF_SHIFT;
msr = rdmsr(MC_CF8F_DATA); msr = rdmsr(MC_CF8F_DATA);
msr.lo &= 0xF00000FF; msr.lo &= 0xF00000FF;
@ -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);
@ -494,44 +500,46 @@ 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);
} }
/** /**
* Debug function. Only used when test hardware is connected. * Debug function. Only used when test hardware is connected.
*/ */
static void EnableMTest(void) 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,9 +555,10 @@ 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)
{ {
struct msr msr; struct msr msr;
@ -570,20 +579,24 @@ 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
msr = rdmsr(msrnum); msrnum = MC_CF8F_DATA;
msr.hi |= CF8F_UPPER_HOI_LOI_SET; msr = rdmsr(msrnum);
wrmsr(msrnum, msr); */ msr.hi |= CF8F_UPPER_HOI_LOI_SET;
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)
{ {
u8 spd_byte; u8 spd_byte;
@ -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,79 +623,85 @@ 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 4.1.4, GX/CS5535 GeodeROM Porting guide * Section 6.1.3, LX processor databooks, BIOS Initialization Sequence
* Turn on MC/DIMM interface per JEDEC * Section 4.1.4, GX/CS5535 GeodeROM Porting guide
* 1) Clock stabilizes > 200us *
* 2) Assert CKE * Turn on MC/DIMM interface per JEDEC:
* 3) Precharge All to put all banks into an idles state * 1) Clock stabilizes > 200us
* 4) EMRS to enable DLL * 2) Assert CKE
* 6) MRS w/ memory config & reset DLL set * 3) Precharge All to put all banks into an idle state
* 7) Wait 200 clocks (2us) * 4) EMRS to enable DLL
* 8) Precharge All and 2 Auto refresh * 6) MRS w/ memory config & reset DLL set
* 9) MRS w/ memory config & reset DLL clear * 7) Wait 200 clocks (2us)
* 8) DDR SDRAM ready for normal operation * 8) Precharge All and 2 Auto refresh
* * 9) MRS w/ memory config & reset DLL clear
* @param dimm0 dimm0 SMBus address * 8) DDR SDRAM ready for normal operation
* @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_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)));
while ((inb(0x61))) ; /* find the first edge */
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
* register in the 5536 so will need to store the S3
* resume *flag in NVRAM otherwise it would do a
* normal boot
*/ */
/* Reset the system */ /* The we are about to perform clears the PM_SSC
* register in the CS5536 so will need to store the S3
* resume flag in NVRAM otherwise it would do a normal boot.
*/
/* 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");
} }