mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
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:
parent
203bffe9e7
commit
7f484d348f
3 changed files with 888 additions and 807 deletions
|
@ -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},
|
||||
};
|
||||
|
|
|
@ -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__);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue