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 <amd_geodelx.h>
/* here is programming for the various MSRs.*/
/* Here is programming for the various MSRs. */
#define IM_QWAIT 0x100000
/* set in high nibl */
#define DMCF_WRITE_SERIALIZE_REQUEST (2<<12) /* 2 outstanding */
/* Set in high nibble. */
#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
* RCONF is Region CONFiguraiton, and controls caching and other
/* These are the 8-bit attributes for controlling RCONF registers.
*
* 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 WRITE_PROTECT (1<<2)
#define WRITE_THROUGH (1<<3)
#define WRITE_COMBINE (1<<4)
#define WRITE_SERIALIZE (1<<5)
#define CACHE_DISABLE (1 << 0)
#define WRITE_ALLOCATE (1 << 1)
#define WRITE_PROTECT (1 << 2)
#define WRITE_THROUGH (1 << 3)
#define WRITE_COMBINE (1 << 4)
#define WRITE_SERIALIZE (1 << 5)
/* ram has none of this stuff */
#define RAM_PROPERTIES (0)
/* RAM has none of this stuff. */
#define RAM_PROPERTIES 0
#define DEVICE_PROPERTIES (WRITE_SERIALIZE|CACHE_DISABLE)
#define ROM_PROPERTIES (WRITE_SERIALIZE|WRITE_PROTECT|CACHE_DISABLE)
#define MSR_WS_CD_DEFAULT (0x21212121)
#define MSR_WS_CD_DEFAULT 0x21212121
/* RCONF registers 1810-1817 give you 8 registers with which to
* program protection regions the are region configuration range
* registers, or RRCF in msr terms, the are a straight base, top
* address assign, since they are 4k aligned.
*/
/* so no left-shift needed for top or base */
#define RRCF_LOW(base,properties) (base|(1<<8)|properties)
/* So no left-shift needed for top or base. */
#define RRCF_LOW(base, properties) (base | (1 << 8) | properties)
#define RRCF_LOW_CD(base) RRCF_LOW(base, CACHE_DISABLE)
/* build initializer for P2D MSR */
/* this is complex enough that you are going to need to RTFM if you
/* Build initializer for P2D MSR.
*
* 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_BMO(msr, pdid1, bizarro, poffset, pbase, pmask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(poffset<<8)|(pbase>>24), .lo=(pbase<<8)|pmask}}
#define P2D_R(msr, pdid1, bizarro, pmax, pmin) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(pmax>>12), .lo=(pmax<<20)|pmin}}
#define P2D_RO(msr, pdid1, bizarro, poffset, pmax, pmin) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(poffset<<8)|(pmax>>12), .lo=(pmax<<20)|pmin}}
#define P2D_SC(msr, pdid1, bizarro, wen, ren,pscbase) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(wen), .lo=(ren<<16)|(pscbase>>18)}}
#define IOD_BM(msr, pdid1, bizarro, ibase, imask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(ibase>>12), .lo=(ibase<<20)|imask}}
#define IOD_SC(msr, pdid1, bizarro, en, wen, ren, ibase) {msr, {.hi=(pdid1<<29)|(bizarro<<28), .lo=(en<<24)|(wen<<21)|(ren<<20)|(ibase<<3)}}
#define P2D_BM(msr, pdid1, bizarro, pbase, pmask) \
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (pbase >> 24), \
.lo = (pbase << 8) | pmask}}
#define P2D_BMO(msr, pdid1, bizarro, poffset, pbase, pmask) \
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | \
(poffset << 8) | (pbase >> 24), \
.lo = (pbase << 8) | pmask}}
#define P2D_R(msr, pdid1, bizarro, pmax, pmin) \
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (pmax >> 12), \
.lo = (pmax << 20) | pmin}}
#define P2D_RO(msr, pdid1, bizarro, poffset, pmax, pmin) \
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | \
(poffset << 8) | (pmax >> 12), \
.lo = (pmax << 20) | pmin}}
#define P2D_SC(msr, pdid1, bizarro, wen, ren,pscbase) \
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (wen), \
.lo = (ren << 16) | (pscbase >> 18)}}
#define IOD_BM(msr, pdid1, bizarro, ibase, imask) \
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (ibase >> 12), \
.lo = (ibase << 20) | imask}}
#define IOD_SC(msr, pdid1, bizarro, en, wen, ren, ibase) \
{msr, {.hi = (pdid1 << 29) | (bizarro << 28), \
.lo = (en << 24) | (wen << 21) | \
(ren << 20) | (ibase << 3)}}
#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
/* TODO: Should be in some header file? */
extern void graphics_init(void);
extern void cpu_bug(void);
extern void chipsetinit(void);
@ -92,43 +112,54 @@ struct msr_defaults {
int msr_no;
struct msr msr;
} msr_defaults[] = {
{0x1700, {.hi = 0,.lo = IM_QWAIT}},
{0x1800, {.hi = DMCF_WRITE_SERIALIZE_REQUEST,
{ 0x1700, {.hi = 0,.lo = IM_QWAIT}},
{ 0x1800, {.hi = DMCF_WRITE_SERIALIZE_REQUEST,
.lo = DMCF_SERIAL_LOAD_MISSES}},
/* 1808 will be done down below, so we have to do 180a->1817
* (well, 1813 really)
* (well, 1813 really).
*/
/* for 180a, for now, we assume VSM will configure it */
/* 180b is left at reset value,a0000-bffff is non-cacheable */
/* 180c, c0000-dffff is set to write serialize and non-cachable */
/* oops, 180c will be set by cpu bug handling in cpubug.c */
//{0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}},
/* 180d is left at default, e0000-fffff is non-cached */
/* we will assume 180e, the ssm region configuration, is left
* at default or set by VSM */
/* we will not set 0x180f, the DMM,yet
/* For 180a, for now, we assume VSM will configure it. */
/* 180b is left at reset value, a0000-bffff is non-cacheable. */
/* 180c, c0000-dffff is set to write serialize and non-cachable. */
/* Oops, 180c will be set by CPU bug handling in cpubug.c. */
/* TODO: There's no cpubug.c. */
// {0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}},
/* 180d is left at default, e0000-fffff is non-cached. */
/* We will assume 180e, the ssm region configuration, is left
* at default or set by VSM.
*/
//{0x1810, {.hi=0xee7ff000, .lo=RRCF_LOW(0xee000000, WRITE_COMBINE|CACHE_DISABLE)}},
//{0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
//{0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}},
//{0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}},
/* now for GLPCI routing */
/* We will not set 0x180f, the DMM, yet. */
// {0x1810, {.hi = 0xee7ff000,
// .lo = RRCF_LOW(0xee000000, WRITE_COMBINE|CACHE_DISABLE)}},
// {0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
// {0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}},
// {0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}},
/* Now for GLPCI routing. */
/* GLIU0 */
P2D_BM(MSR_GLIU0_BASE1, 0x1, 0x0, 0x0, 0xfff80),
P2D_BM(MSR_GLIU0_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
P2D_SC(MSR_GLIU0_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
/* GLIU1 */
P2D_BM(MSR_GLIU1_BASE1, 0x1, 0x0, 0x0, 0xfff80),
P2D_BM(MSR_GLIU1_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
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
* 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
* are set up by initram.
* Size up ram.
*
* All we need to do here is read the MSR for DRAM and grab 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 are set up by initram.
*
* @return TODO
*/
int sizeram(void)
{
@ -137,83 +168,88 @@ int sizeram(void)
unsigned short dimm;
/* 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);
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;
/* installed? */
/* Installed? */
if ((dimm & 7) != 7) {
/* 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;
/* installed? */
/* Installed? */
if ((dimm & 7) != 7) {
/* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */
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;
}
/**
* enable_shadow. Currently not set up.
* Currently not set up.
*
* @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
* it here as a hook for later use.
* Initialize the northbridge PCI device.
* Right now this a no op. We leave it here as a hook for later use.
*
* @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);
/*
* Swiss cheese
*/
//msr = rdmsr(MSR_GLIU0_SHADOW);
//msr.hi |= 0x3;
//msr.lo |= 0x30000;
#if 0
/* 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);
//printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU1_SHADOW, msr.hi, msr.lo);
msr.hi |= 0x3;
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
* required due to VSA interactions.
* Set resources for the PCI northbridge device.
* This function is required due to VSA interactions.
*
* @param dev The nortbridge device.
*/
void geodelx_northbridge_set_resources(struct device *dev)
{
struct resource *resource, *last;
unsigned link;
unsigned int link;
u8 line;
last = &dev->resource[dev->resources];
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);
// FIXME: static allocation may conflict with dynamic mappings!
// pci_set_resource(dev, resource);
// FIXME: Static allocation may conflict with dynamic mappings!
}
for (link = 0; link < dev->links; link++) {
@ -221,49 +257,50 @@ void geodelx_northbridge_set_resources(struct device *dev)
bus = &dev->link[link];
if (bus->children) {
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);
}
}
/* set a default latency timer */
/* Set a default latency timer. */
pci_write_config8(dev, PCI_LATENCY_TIMER, 0x40);
/* set a default secondary latency timer */
if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
/* Set a default secondary latency timer. */
if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE)
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);
if (line) {
if (line)
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);
}
/**
* Set resources for the PCI domain. Just set up basic global ranges
* for IO and memory Allocation of sub-resources draws on these
* top-level resources in the usual hierarchical manner.
* Set resources for the PCI domain.
*
* 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.
*/
static void geodelx_pci_domain_read_resources(struct device * dev)
static void geodelx_pci_domain_read_resources(struct device *dev)
{
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->limit = 0xffffUL;
resource->flags =
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->limit = 0xffffffffULL;
resource->flags =
@ -271,14 +308,15 @@ 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.
* @param dev the device
* @param index a resource index
* @param basek base memory address in k
* @param sizek size of memory in k
*
* @param dev The device.
* @param index A resource index.
* @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)
{
struct resource *resource;
@ -294,104 +332,110 @@ static void ram_resource(struct device * dev, unsigned long index,
}
/**
* Set resources in the pci domain. Also, as a side effect, create a
* ram resource in the child which, interestingly enough, is the
* north bridge pci device, for later allocation of address space.
* @param dev the device
* Set resources in the PCI domain.
*
* Also, as a side effect, create a RAM resource in the child which,
* 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)
{
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;
if (mc_dev) {
/* Report the memory regions */
/* Report the memory regions. */
idx = 10;
/* 0 .. 640 KB */
ram_resource(dev, idx++, 0, 640);
/* Systop - 1 MB -> KB*/
ram_resource(dev, idx++, 1024, (get_systop() - 0x100000) / 1024);
/* 1 MB .. (Systop - 1 MB) (converted to KB) */
ram_resource(dev, idx++, 1024,
(get_systop() - (1 * 1024 * 1024)) / 1024);
}
phase4_assign_resources(&dev->link[0]);
}
/**
* enable the pci domain. A littly tricky on this chipset due to the
* VSA interactions. This must happen before any PCI scans happen.
* we do early northbridge init to make sure pci scans will work, but
* the weird part is we actually have to run some code in x86 mode to
* get the VSM installed, since the VSM actually handles some PCI bus
* scan tasks via the System Management Interrupt. Yes, it gets
* tricky ...
* @param dev the device
* Enable the PCI domain.
*
* A littly tricky on this chipset due to the VSA interactions. This must
* happen before any PCI scans happen. We do early northbridge init to make
* sure PCI scans will work, but the weird part is we actually have to run
* some code in x86 mode to get the VSM installed, since the VSM actually
* handles some PCI bus scan tasks via the System Management Interrupt.
* 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();
#warning cpu bug has been moved to initram stage
// cpu_bug();
/* cpu_bug(); */
chipsetinit();
setup_realmode_idt();
printk(BIOS_DEBUG,"Before VSA:\n");
// print_conf();
printk(BIOS_DEBUG, "Before VSA:\n");
/* print_conf(); */
#warning Not doing vsm bios -- linux will fail.
// do_vsmbios(); // do the magic stuff here, so prepare your tambourine ;)
printk(BIOS_DEBUG,"After VSA:\n");
// print_conf();
/* Do the magic stuff here, so prepare your tambourine ;) */
/* do_vsmbios(); */
printk(BIOS_DEBUG, "After VSA:\n");
/* print_conf(); */
#warning graphics_init is disabled.
// graphics_init();
/* graphics_init(); */
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.
* @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);
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
* 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)
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__);
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)
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
/* 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.
*/
/* Here are the operations for when the northbridge is running a PCI
* domain.
*/
/** 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,
@ -401,12 +445,9 @@ struct device_operations geodelx_pcidomainops = {
.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.
*/
/** Operations for when the northbridge is running an APIC cluster. */
struct device_operations geodelx_apicops = {
.constructor = default_device_constructor,
.phase3_scan = 0,
@ -417,9 +458,7 @@ struct device_operations geodelx_apicops = {
.ops_pci_bus = &pci_cf8_conf1,
};
/* Here are the operations for when the northbridge is running a PCI
* device.
*/
/** 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,
@ -428,21 +467,30 @@ struct device_operations geodelx_pci_ops = {
.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 */
/**
* The constructor for the device.
* Domain ops and APIC cluster ops and PCI device ops are different.
*/
struct constructor geodelx_north_constructors[] = {
/* Northbridge running a PCI domain. */
{.id = {.type = DEVICE_ID_PCI_DOMAIN,
.u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
&geodelx_pcidomainops},
.u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.ops = &geodelx_pcidomainops},
/* Northbridge running an APIC cluster. */
{.id = {.type = DEVICE_ID_APIC_CLUSTER,
.u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
&geodelx_apicops},
.u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,
.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}}},
&geodelx_pci_ops},
.u = {.pci = {.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
.ops = &geodelx_pci_ops},
{.ops = 0},
};

View file

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

View file

@ -34,13 +34,16 @@
static const u8 num_col_addr[] = {
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
* all the usual failiure points that can happen.
* @param dimm -- The SMBus address of the DIMM
* all the usual failure points that can happen.
*
* @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)
{
@ -51,13 +54,10 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
dimm_setting = 0;
/* Check that we have a dimm */
if (smbus_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF) {
/* Check that we have a DIMM. */
if (smbus_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF)
return;
}
/* Field: Module Banks per DIMM */
/* EEPROM byte usage: (5) Number of DIMM Banks */
spd_byte = smbus_read_byte(dimm, SPD_NUM_DIMM_BANKS);
if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)) {
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;
/* 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);
if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)) {
printk(BIOS_EMERG, "Number of device banks not compatible\n");
@ -76,58 +74,57 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
}
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)
|| (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);
hlt();
}
/* Size = Module Density * Module Banks */
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);
/* 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;
/* 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 = __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");
post_code(ERROR_DENSITY_DIMM);
hlt();
}
dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT;
/* Field: PAGE size
* EEPROM byte usage: (4) Number of Column Addresses
* PageSize = 2^# Column Addresses * Data width in bytes (should be 8bytes for a normal DIMM)
/* PageSize = 2 ^ (number of column addresses) * data width in bytes
* (should be 8 bytes 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 physical column address
*that MC generates, here is how the MC assigns the pa onto the ma pins:
* If ma[12:0] is the memory address pins, and pa[12:0] is the
* physical column address that the memory controller (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
*-------------------------------------------
*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 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 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)
* *AP=autoprecharge bit
* 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 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 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 14 13 AP 12 11 10 09 08 07 06 05 04 03 (12 col addr bits = 32K page size)
*
*Remember that pa[2:0] are zeroed out since it's a 64-bit data bus (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?
* (AP = autoprecharge bit)
*
* Remember that pa[2:0] are zeroed out since it's a 64-bit data bus
* (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];
@ -137,10 +134,12 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
hlt();
}
spd_byte -= 7;
if (spd_byte > 5) { /* if the value is above 6 it means >12 address lines */
spd_byte = 7; /* which means >32k so set to disabled */
/* If the value is above 6 it means >12 address lines... */
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);
if (dimm == dimm0) {
@ -153,10 +152,14 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
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!
* @param dimm0 dimm0 SMBus address
* @param dimm1 dimm1 SMBus address
/**
* Try to compute the max. DDR clock rate.
*
* 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)
{
@ -165,32 +168,32 @@ static void check_ddr_max(u8 dimm0, u8 dimm1)
/* PC133 identifier */
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_byte1 = smbus_read_byte(dimm1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
if (spd_byte1 == 0xFF) {
if (spd_byte1 == 0xFF)
spd_byte1 = 0;
}
/* I don't think you need this check.
if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0){
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink Speed\n");
/* 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
/* Use the slowest DIMM */
/* Use the slowest DIMM. */
if (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))));
/* current speed > max speed? */
/* Current speed > max 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);
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 */
/**
* compute a refresh rate. You have to read both dimms and take the one that requires a faster rate.
* @param dimm0 dimm0 SMBus address
* @param dimm1 dimm1 SMBus address
* Compute a refresh rate.
*
* 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)
{
@ -223,7 +229,7 @@ static void set_refresh_rate(u8 dimm0, u8 dimm1)
}
rate1 = REFRESH_RATE[spd_byte1];
/* Use the faster rate (lowest number) */
/* Use the faster rate (lowest number). */
if (rate0 > rate1) {
rate0 = rate1;
}
@ -234,28 +240,29 @@ static void set_refresh_rate(u8 dimm0, u8 dimm1)
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.
* 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 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
* checked that it is within the GeodeLink speed. If it isn't within the GeodeLink
* 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
* 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.
* Result is that we will set fastest CAS Latency based on GeodeLink speed
* checked that it is within the GeodeLink speed. If it isn't within the
* GeodeLink 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 find the lowest
* 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.
*
* @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)
{
@ -265,72 +272,78 @@ static void set_cas(u8 dimm0, u8 dimm1)
glspeed = geode_link_speed();
/************************** dimm0 **********************************/
/* DIMM 0 */
casmap0 = smbus_read_byte(dimm0, SPD_ACCEPTABLE_CAS_LATENCIES);
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);
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)));
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);
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)));
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);
/* 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);
}
} /*MIN_CYCLE_10 !=0 */
} /* MIN_CYCLE_10 != 0 */
} 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);
/* 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);
}
} /*MIN_CYCLE_05 !=0 */
} /* MIN_CYCLE_05 != 0 */
} else { /* No DIMM */
casmap0 = 0;
}
/************************** dimm1 **********************************/
/* DIMM 1 */
casmap1 = smbus_read_byte(dimm1, SPD_ACCEPTABLE_CAS_LATENCIES);
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);
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)));
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);
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)));
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);
/* 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);
}
} /*MIN_CYCLE_10 !=0 */
} /* MIN_CYCLE_10 != 0 */
} 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);
/* 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);
}
} /*MIN_CYCLE_05 !=0 */
} /* MIN_CYCLE_05 != 0 */
} else { /* No DIMM */
casmap1 = 0;
}
/********************* CAS_LAT MAP COMPARE ***************************/
/* Compare CAS latencies. */
if (casmap0 == 0) {
spd_byte = CASDDR[__builtin_ctz((u32) casmap1)];
} else if (casmap1 == 0) {
@ -338,7 +351,7 @@ static void set_cas(u8 dimm0, u8 dimm1)
} else if ((casmap0 &= casmap1)) {
spd_byte = CASDDR[__builtin_ctz((u32) casmap0)];
} else {
printk(BIOS_EMERG, "DIMM CAS Latencies not compatible\n");
printk(BIOS_EMERG, "DIMM CAS latencies not compatible\n");
post_code(ERROR_DIFF_DIMMS);
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.
* Take the one with the tightest requirements, and use that for both.
* @param dimm0 dimm0 SMBus address
* @param dimm1 dimm1 SMBus address
* Set latencies for DRAM.
*
* These are the famed RAS and CAS latencies. Take the one with the tightest
* 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)
{
@ -367,36 +383,29 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* MC_CF8F setup */
/* tRAS */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRAS);
if (spd_byte0 == 0xFF) {
if (spd_byte0 == 0xFF)
spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRAS);
if (spd_byte1 == 0xFF) {
if (spd_byte1 == 0xFF)
spd_byte1 = 0;
}
if (spd_byte0 < spd_byte1) {
if (spd_byte0 < spd_byte1)
spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = (spd_byte0 * memspeed) / 1000;
if (((spd_byte0 * memspeed) % 1000)) {
if (((spd_byte0 * memspeed) % 1000))
++spd_byte1;
}
dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT;
/* tRP */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRP);
if (spd_byte0 == 0xFF) {
if (spd_byte0 == 0xFF)
spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRP);
if (spd_byte1 == 0xFF) {
if (spd_byte1 == 0xFF)
spd_byte1 = 0;
}
if (spd_byte0 < spd_byte1) {
if (spd_byte0 < spd_byte1)
spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
@ -407,16 +416,13 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* tRCD */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRCD);
if (spd_byte0 == 0xFF) {
if (spd_byte0 == 0xFF)
spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRCD);
if (spd_byte1 == 0xFF) {
if (spd_byte1 == 0xFF)
spd_byte1 = 0;
}
if (spd_byte0 < spd_byte1) {
if (spd_byte0 < spd_byte1)
spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
@ -427,16 +433,13 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* tRRD */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRRD);
if (spd_byte0 == 0xFF) {
if (spd_byte0 == 0xFF)
spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRRD);
if (spd_byte1 == 0xFF) {
if (spd_byte1 == 0xFF)
spd_byte1 = 0;
}
if (spd_byte0 < spd_byte1) {
if (spd_byte0 < spd_byte1)
spd_byte0 = spd_byte1;
}
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
@ -459,33 +462,36 @@ static void set_latencies(u8 dimm0, u8 dimm1)
/* MC_CF1017 setup */
/* tRFC */
spd_byte0 = smbus_read_byte(dimm0, SPD_tRFC);
if (spd_byte0 == 0xFF) {
if (spd_byte0 == 0xFF)
spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_tRFC);
if (spd_byte1 == 0xFF) {
if (spd_byte1 == 0xFF)
spd_byte1 = 0;
}
if (spd_byte0 < spd_byte1) {
if (spd_byte0 < spd_byte1)
spd_byte0 = spd_byte1;
}
if (spd_byte0) {
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
spd_byte1 = (spd_byte0 * memspeed) / 1000;
if (((spd_byte0 * memspeed) % 1000)) {
if (((spd_byte0 * memspeed) % 1000))
++spd_byte1;
}
} else { /* Not all SPDs have tRFC setting. Use this formula tRFC = tRC + 1 clk */
} else {
/* Not all SPDs have tRFC setting.
* Use this formula: tRFC = tRC + 1 clk.
*/
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.lo &= ~(0x1F << CF1017_LOWER_REF2ACT_SHIFT);
msr.lo |= dimm_setting;
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) {
msr = rdmsr(MC_CF1017_DATA);
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.
* @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)
{
u8 spd_byte0, spd_byte1;
struct msr msr;
spd_byte0 = smbus_read_byte(dimm0, SPD_DEVICE_ATTRIBUTES_GENERAL);
if (spd_byte0 == 0xFF) {
if (spd_byte0 == 0xFF)
spd_byte0 = 0;
}
spd_byte1 = smbus_read_byte(dimm1, SPD_DEVICE_ATTRIBUTES_GENERAL);
if (spd_byte1 == 0xFF) {
if (spd_byte1 == 0xFF)
spd_byte1 = 0;
}
spd_byte1 &= spd_byte0;
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;
}
if (spd_byte1 & 2) { /* FET Control */
if (spd_byte1 & 2) {
/* FET Control */
msr.lo |= CF07_LOWER_EMR_QFC_SET;
}
wrmsr(MC_CF07_DATA, msr);
@ -531,7 +539,7 @@ static void EnableMTest(void)
struct msr msr;
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) {
msr.hi |= 2 << 20;
}
@ -547,8 +555,9 @@ static void EnableMTest(void)
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)
{
@ -570,19 +579,23 @@ void sdram_set_registers(void)
msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum);
msr.lo &= ~0xF0;
msr.lo |= 0x40; /* set refresh to 4SDRAM clocks */
msr.lo |= 0x40; /* Set refresh to 4 SDRAM clocks. */
wrmsr(msrnum, msr);
/* Memory Interleave: Set HOI here otherwise default is LOI */
/* msrnum = MC_CF8F_DATA;
/* Memory Interleave: Set HOI here otherwise default is LOI. */
#if 0
msrnum = MC_CF8F_DATA;
msr = rdmsr(msrnum);
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
* @param dimm1 dimm1 SMBus address
/**
* Set SDRAM registers that need to be determined by SPD.
*
* @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)
{
@ -591,15 +604,16 @@ void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
post_code(POST_MEM_SETUP);
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)) {
printk(BIOS_EMERG, "dimm0 NOT COMPATIBLE\n");
printk(BIOS_EMERG, "DIMM 0 NOT COMPATIBLE!\n");
post_code(ERROR_UNSUPPORTED_DIMM);
hlt();
}
spd_byte = smbus_read_byte(dimm1, SPD_MODULE_ATTRIBUTES);
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);
hlt();
}
@ -609,37 +623,39 @@ void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
/* Check that the memory is not overclocked. */
check_ddr_max(dimm0, dimm1);
/* Size the DIMMS */
/* this is gross. It is an artifact of our move to parametes instead of #defines. FIX ME */
/* the fix is trivial but I want to see it work first. */
/* Size the DIMMS.
* This is gross. It is an artifact of our move to parametes instead of
* #defines. FIXME! The fix is trivial but I want to see it work first.
*/
post_code(POST_MEM_SETUP3);
auto_size_dimm(dimm0, dimm0, dimm1);
post_code(POST_MEM_SETUP4);
auto_size_dimm(dimm1, dimm0, dimm1);
/* Set CAS latency */
/* Set CAS latency. */
post_code(POST_MEM_SETUP5);
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 Extended Mode Registers */
/* Set Extended Mode Registers. */
set_extended_mode_registers(dimm0, dimm1);
/* Set Memory Refresh Rate */
/* Set Memory Refresh Rate. */
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
* Turn on MC/DIMM interface per JEDEC
*
* Turn on MC/DIMM interface per JEDEC:
* 1) Clock stabilizes > 200us
* 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
* 6) MRS w/ memory config & reset DLL set
* 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
* 8) DDR SDRAM ready for normal operation
*
* @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).
*/
void sdram_enable(u8 dimm0, u8 dimm1)
{
u32 i, msrnum;
struct msr msr;
post_code(POST_MEM_ENABLE); // post_76h
post_code(POST_MEM_ENABLE);
/* Only enable MTest for TLA memory debug */
/*EnableMTest(); */
/* Only enable MTest for TLA memory debug. */
/* 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);
if ((msr.hi & ((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) ==
((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) {
if ((msr.hi & ((7 << CF07_UPPER_D1_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");
post_code(ERROR_NO_DIMMS);
hlt();
}
/* Set CKEs */
/* Set CKEs. */
msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum);
msr.lo &= ~(CFCLK_LOWER_MASK_CKE_SET0 | CFCLK_LOWER_MASK_CKE_SET1);
wrmsr(msrnum, msr);
/* Force Precharge All on next command, EMRS */
/* Force Precharge All on next command, EMRS. */
msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum);
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
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;
msr = rdmsr(msrnum);
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);
wrmsr(msrnum, msr);
/* Clear Force Precharge All */
/* Clear Force Precharge All. */
msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum);
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
wrmsr(msrnum, msr);
/* MRS Reset DLL - set */
/* MRS Reset DLL - set. */
msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum);
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);
wrmsr(msrnum, msr);
/* 2us delay (200 clocks @ 200Mhz). We probably really don't
* need this but.... better safe.
/* 2us delay (200 clocks @ 200Mhz). We probably really don't need
* 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 */
/* This would be endless if the timer is stuck. */
while ((inb(0x61))) ; /* find the first edge */
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;
msr = rdmsr(msrnum);
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
wrmsr(msrnum, msr);
/* Manually AUTO refresh #1 */
/* If auto refresh was not enabled above we would need to do 8
* refreshes to prime the pump before these 2.
/* Manually AUTO refresh #1. If auto refresh was not enabled above we
* would need to do 8 refreshes to prime the pump before these 2.
*/
msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum);
@ -728,14 +748,15 @@ void sdram_enable(u8 dimm0, u8 dimm1)
msr.lo &= ~CF07_LOWER_REF_TEST_SET;
wrmsr(msrnum, msr);
/* Clear Force Precharge All */
/* Clear Force Precharge All. */
msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum);
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
wrmsr(msrnum, msr);
/* Manually AUTO refresh */
/* The MC should insert the right delay between the refreshes */
/* Manually AUTO refresh.
* The MC should insert the right delay between the refreshes.
*/
msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum);
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;
wrmsr(msrnum, msr);
/* MRS Reset DLL - clear */
/* MRS Reset DLL - clear. */
msrnum = MC_CF07_DATA;
msr = rdmsr(msrnum);
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;
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;
msr = rdmsr(msrnum);
msr.lo &= ~CFCLK_LOWER_TRISTATE_DIS_SET;
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);
if ((msr.hi & (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);
}
/* Set PMode0 Sensitivity Counter */
/* Set PMode0 Sensitivity Counter. */
msr.lo = 0; /* pmode 0=0 most aggressive */
msr.hi = 0x200; /* pmode 1=200h */
wrmsr(MC_CF_PMCTR, msr);
/* Set PMode1 Up delay enable */
/* Set PMode1 Up delay enable. */
msrnum = MC_CF1017_DATA;
msr = rdmsr(msrnum);
msr.lo |= (209 << 8); /* bits[15:8] = 209 */
wrmsr(msrnum, msr);
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"); */
/* The RAM dll needs a write to lock on so generate a few dummy writes */
/* Note: The descriptor needs to be enabled to point at memory */
/* The RAM dll needs a write to lock on so generate a few dummy
* writes. Note: The descriptor needs to be enabled to point at memory.
*/
volatile unsigned long *ptr;
for (i = 0; i < 5; i++) {
ptr = (void *)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;
msr = rdmsr(msrnum);
if ((msr.lo & 0x7FF) == 0x104) {
/* If you had it you would need to clear out the fail
* boot count flag (depending on where it counts from
* etc).
/* If you had it you would need to clear out the fail 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
* 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 */
/* Reset the system. */
msrnum = MDD_SOFT_RESET;
msr = rdmsr(msrnum);
msr.lo |= 1;
wrmsr(msrnum, msr);
}
printk(BIOS_DEBUG, "RAM DLL lock\n");
printk(BIOS_DEBUG, "RAM DLL lock\n");
}