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 <io.h>
|
||||||
#include <amd_geodelx.h>
|
#include <amd_geodelx.h>
|
||||||
|
|
||||||
/* here is programming for the various MSRs.*/
|
/* Here is programming for the various MSRs. */
|
||||||
#define IM_QWAIT 0x100000
|
#define IM_QWAIT 0x100000
|
||||||
|
|
||||||
/* set in high nibl */
|
/* Set in high nibble. */
|
||||||
#define DMCF_WRITE_SERIALIZE_REQUEST (2<<12) /* 2 outstanding */
|
#define DMCF_WRITE_SERIALIZE_REQUEST (2 << 12) /* 2 outstanding */
|
||||||
|
|
||||||
#define DMCF_SERIAL_LOAD_MISSES (2) /* enabled */
|
#define DMCF_SERIAL_LOAD_MISSES 2 /* Enabled */
|
||||||
|
|
||||||
/* these are the 8-bit attributes for controlling RCONF registers
|
/* These are the 8-bit attributes for controlling RCONF registers.
|
||||||
* RCONF is Region CONFiguraiton, and controls caching and other
|
*
|
||||||
* attributes of a region. Just like MTRRs, only different.
|
* RCONF is Region CONFiguration, and controls caching and other
|
||||||
*/
|
* attributes of a region. Just like MTRRs, only different.
|
||||||
#define CACHE_DISABLE (1<<0)
|
*/
|
||||||
#define WRITE_ALLOCATE (1<<1)
|
#define CACHE_DISABLE (1 << 0)
|
||||||
#define WRITE_PROTECT (1<<2)
|
#define WRITE_ALLOCATE (1 << 1)
|
||||||
#define WRITE_THROUGH (1<<3)
|
#define WRITE_PROTECT (1 << 2)
|
||||||
#define WRITE_COMBINE (1<<4)
|
#define WRITE_THROUGH (1 << 3)
|
||||||
#define WRITE_SERIALIZE (1<<5)
|
#define WRITE_COMBINE (1 << 4)
|
||||||
|
#define WRITE_SERIALIZE (1 << 5)
|
||||||
|
|
||||||
/* ram has none of this stuff */
|
/* RAM has none of this stuff. */
|
||||||
#define RAM_PROPERTIES (0)
|
#define RAM_PROPERTIES 0
|
||||||
#define DEVICE_PROPERTIES (WRITE_SERIALIZE|CACHE_DISABLE)
|
#define DEVICE_PROPERTIES (WRITE_SERIALIZE|CACHE_DISABLE)
|
||||||
#define ROM_PROPERTIES (WRITE_SERIALIZE|WRITE_PROTECT|CACHE_DISABLE)
|
#define ROM_PROPERTIES (WRITE_SERIALIZE|WRITE_PROTECT|CACHE_DISABLE)
|
||||||
#define MSR_WS_CD_DEFAULT (0x21212121)
|
#define MSR_WS_CD_DEFAULT 0x21212121
|
||||||
|
|
||||||
/* RCONF registers 1810-1817 give you 8 registers with which to
|
/* RCONF registers 1810-1817 give you 8 registers with which to
|
||||||
* program protection regions the are region configuration range
|
* program protection regions the are region configuration range
|
||||||
* registers, or RRCF in msr terms, the are a straight base, top
|
* registers, or RRCF in msr terms, the are a straight base, top
|
||||||
* address assign, since they are 4k aligned.
|
* address assign, since they are 4k aligned.
|
||||||
*/
|
*/
|
||||||
/* so no left-shift needed for top or base */
|
/* So no left-shift needed for top or base. */
|
||||||
#define RRCF_LOW(base,properties) (base|(1<<8)|properties)
|
#define RRCF_LOW(base, properties) (base | (1 << 8) | properties)
|
||||||
#define RRCF_LOW_CD(base) RRCF_LOW(base, CACHE_DISABLE)
|
#define RRCF_LOW_CD(base) RRCF_LOW(base, CACHE_DISABLE)
|
||||||
|
|
||||||
/* build initializer for P2D MSR */
|
/* Build initializer for P2D MSR.
|
||||||
/* this is complex enough that you are going to need to RTFM if you
|
*
|
||||||
* really want to understand it.
|
* This is complex enough that you are going to need to RTFM if you
|
||||||
|
* really want to understand it.
|
||||||
*/
|
*/
|
||||||
#define P2D_BM(msr, pdid1, bizarro, pbase, pmask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(pbase>>24), .lo=(pbase<<8)|pmask}}
|
#define P2D_BM(msr, pdid1, bizarro, pbase, pmask) \
|
||||||
#define P2D_BMO(msr, pdid1, bizarro, poffset, pbase, pmask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(poffset<<8)|(pbase>>24), .lo=(pbase<<8)|pmask}}
|
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (pbase >> 24), \
|
||||||
#define P2D_R(msr, pdid1, bizarro, pmax, pmin) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(pmax>>12), .lo=(pmax<<20)|pmin}}
|
.lo = (pbase << 8) | pmask}}
|
||||||
#define P2D_RO(msr, pdid1, bizarro, poffset, pmax, pmin) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(poffset<<8)|(pmax>>12), .lo=(pmax<<20)|pmin}}
|
#define P2D_BMO(msr, pdid1, bizarro, poffset, pbase, pmask) \
|
||||||
#define P2D_SC(msr, pdid1, bizarro, wen, ren,pscbase) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(wen), .lo=(ren<<16)|(pscbase>>18)}}
|
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | \
|
||||||
#define IOD_BM(msr, pdid1, bizarro, ibase, imask) {msr, {.hi=(pdid1<<29)|(bizarro<<28)|(ibase>>12), .lo=(ibase<<20)|imask}}
|
(poffset << 8) | (pbase >> 24), \
|
||||||
#define IOD_SC(msr, pdid1, bizarro, en, wen, ren, ibase) {msr, {.hi=(pdid1<<29)|(bizarro<<28), .lo=(en<<24)|(wen<<21)|(ren<<20)|(ibase<<3)}}
|
.lo = (pbase << 8) | pmask}}
|
||||||
|
#define P2D_R(msr, pdid1, bizarro, pmax, pmin) \
|
||||||
|
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (pmax >> 12), \
|
||||||
|
.lo = (pmax << 20) | pmin}}
|
||||||
|
#define P2D_RO(msr, pdid1, bizarro, poffset, pmax, pmin) \
|
||||||
|
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | \
|
||||||
|
(poffset << 8) | (pmax >> 12), \
|
||||||
|
.lo = (pmax << 20) | pmin}}
|
||||||
|
#define P2D_SC(msr, pdid1, bizarro, wen, ren,pscbase) \
|
||||||
|
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (wen), \
|
||||||
|
.lo = (ren << 16) | (pscbase >> 18)}}
|
||||||
|
#define IOD_BM(msr, pdid1, bizarro, ibase, imask) \
|
||||||
|
{msr, {.hi = (pdid1 << 29) | (bizarro << 28) | (ibase >> 12), \
|
||||||
|
.lo = (ibase << 20) | imask}}
|
||||||
|
#define IOD_SC(msr, pdid1, bizarro, en, wen, ren, ibase) \
|
||||||
|
{msr, {.hi = (pdid1 << 29) | (bizarro << 28), \
|
||||||
|
.lo = (en << 24) | (wen << 21) | \
|
||||||
|
(ren << 20) | (ibase << 3)}}
|
||||||
|
|
||||||
#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
|
#define BRIDGE_IO_MASK (IORESOURCE_IO | IORESOURCE_MEM)
|
||||||
|
|
||||||
|
/* TODO: Should be in some header file? */
|
||||||
extern void graphics_init(void);
|
extern void graphics_init(void);
|
||||||
extern void cpu_bug(void);
|
extern void cpu_bug(void);
|
||||||
extern void chipsetinit(void);
|
extern void chipsetinit(void);
|
||||||
|
@ -90,195 +110,213 @@ void do_vsmbios(void);
|
||||||
|
|
||||||
struct msr_defaults {
|
struct msr_defaults {
|
||||||
int msr_no;
|
int msr_no;
|
||||||
struct msr msr;
|
struct msr msr;
|
||||||
} msr_defaults[] = {
|
} msr_defaults[] = {
|
||||||
{0x1700, {.hi = 0,.lo = IM_QWAIT}},
|
{ 0x1700, {.hi = 0,.lo = IM_QWAIT}},
|
||||||
{0x1800, {.hi = DMCF_WRITE_SERIALIZE_REQUEST,
|
{ 0x1800, {.hi = DMCF_WRITE_SERIALIZE_REQUEST,
|
||||||
.lo = DMCF_SERIAL_LOAD_MISSES}},
|
.lo = DMCF_SERIAL_LOAD_MISSES}},
|
||||||
|
|
||||||
/* 1808 will be done down below, so we have to do 180a->1817
|
/* 1808 will be done down below, so we have to do 180a->1817
|
||||||
* (well, 1813 really)
|
* (well, 1813 really).
|
||||||
*/
|
*/
|
||||||
/* for 180a, for now, we assume VSM will configure it */
|
/* For 180a, for now, we assume VSM will configure it. */
|
||||||
/* 180b is left at reset value,a0000-bffff is non-cacheable */
|
/* 180b is left at reset value, a0000-bffff is non-cacheable. */
|
||||||
/* 180c, c0000-dffff is set to write serialize and non-cachable */
|
/* 180c, c0000-dffff is set to write serialize and non-cachable. */
|
||||||
/* oops, 180c will be set by cpu bug handling in cpubug.c */
|
/* Oops, 180c will be set by CPU bug handling in cpubug.c. */
|
||||||
//{0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}},
|
/* TODO: There's no cpubug.c. */
|
||||||
/* 180d is left at default, e0000-fffff is non-cached */
|
// {0x180c, {.hi = MSR_WS_CD_DEFAULT, .lo = MSR_WS_CD_DEFAULT}},
|
||||||
/* we will assume 180e, the ssm region configuration, is left
|
/* 180d is left at default, e0000-fffff is non-cached. */
|
||||||
* at default or set by VSM */
|
/* We will assume 180e, the ssm region configuration, is left
|
||||||
/* we will not set 0x180f, the DMM,yet
|
* at default or set by VSM.
|
||||||
*/
|
*/
|
||||||
//{0x1810, {.hi=0xee7ff000, .lo=RRCF_LOW(0xee000000, WRITE_COMBINE|CACHE_DISABLE)}},
|
/* We will not set 0x180f, the DMM, yet. */
|
||||||
//{0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
|
|
||||||
//{0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}},
|
// {0x1810, {.hi = 0xee7ff000,
|
||||||
//{0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}},
|
// .lo = RRCF_LOW(0xee000000, WRITE_COMBINE|CACHE_DISABLE)}},
|
||||||
/* now for GLPCI routing */
|
// {0x1811, {.hi = 0xefffb000, .lo = RRCF_LOW_CD(0xefff8000)}},
|
||||||
|
// {0x1812, {.hi = 0xefff7000, .lo = RRCF_LOW_CD(0xefff4000)}},
|
||||||
|
// {0x1813, {.hi = 0xefff3000, .lo = RRCF_LOW_CD(0xefff0000)}},
|
||||||
|
|
||||||
|
/* Now for GLPCI routing. */
|
||||||
|
|
||||||
/* GLIU0 */
|
/* GLIU0 */
|
||||||
P2D_BM(MSR_GLIU0_BASE1, 0x1, 0x0, 0x0, 0xfff80),
|
P2D_BM(MSR_GLIU0_BASE1, 0x1, 0x0, 0x0, 0xfff80),
|
||||||
P2D_BM(MSR_GLIU0_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
|
P2D_BM(MSR_GLIU0_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
|
||||||
P2D_SC(MSR_GLIU0_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
|
P2D_SC(MSR_GLIU0_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
|
||||||
|
|
||||||
/* GLIU1 */
|
/* GLIU1 */
|
||||||
P2D_BM(MSR_GLIU1_BASE1, 0x1, 0x0, 0x0, 0xfff80),
|
P2D_BM(MSR_GLIU1_BASE1, 0x1, 0x0, 0x0, 0xfff80),
|
||||||
P2D_BM(MSR_GLIU1_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
|
P2D_BM(MSR_GLIU1_BASE2, 0x1, 0x0, 0x80000, 0xfffe0),
|
||||||
P2D_SC(MSR_GLIU1_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
|
P2D_SC(MSR_GLIU1_SHADOW, 0x1, 0x0, 0x0, 0xff03, 0xC0000),
|
||||||
{0}
|
|
||||||
|
{0},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size up ram. All we need to here is read the MSR for DRAM and grab
|
* Size up ram.
|
||||||
* out the sizing bits. Note that this code depends on initram
|
*
|
||||||
* having run. It uses the MSRs, not the SPDs, and the MSRs of course
|
* All we need to do here is read the MSR for DRAM and grab out the sizing
|
||||||
* are set up by initram.
|
* bits. Note that this code depends on initram having run. It uses the MSRs,
|
||||||
*/
|
* not the SPDs, and the MSRs of course are set up by initram.
|
||||||
|
*
|
||||||
|
* @return TODO
|
||||||
|
*/
|
||||||
int sizeram(void)
|
int sizeram(void)
|
||||||
{
|
{
|
||||||
struct msr msr;
|
struct msr msr;
|
||||||
int sizem = 0;
|
int sizem = 0;
|
||||||
unsigned short dimm;
|
unsigned short dimm;
|
||||||
|
|
||||||
/* Get the RAM size from the memory controller as calculated
|
/* Get the RAM size from the memory controller as calculated
|
||||||
* and set by auto_size_dimm()
|
* and set by auto_size_dimm().
|
||||||
*/
|
*/
|
||||||
msr = rdmsr(MC_CF07_DATA);
|
msr = rdmsr(MC_CF07_DATA);
|
||||||
printk(BIOS_DEBUG,"sizeram: _MSR MC_CF07_DATA: %08x:%08x\n", msr.hi, msr.lo);
|
printk(BIOS_DEBUG, "sizeram: _MSR MC_CF07_DATA: %08x:%08x\n", msr.hi,
|
||||||
|
msr.lo);
|
||||||
/* dimm 0 */
|
|
||||||
|
/* DIMM 0 */
|
||||||
dimm = msr.hi;
|
dimm = msr.hi;
|
||||||
/* installed? */
|
/* Installed? */
|
||||||
if ((dimm & 7) != 7) {
|
if ((dimm & 7) != 7) {
|
||||||
/* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */
|
/* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */
|
||||||
sizem = 4 << ((dimm >> 12) & 0x0F); }
|
sizem = 4 << ((dimm >> 12) & 0x0F);
|
||||||
|
}
|
||||||
/* dimm 1 */
|
|
||||||
|
/* DIMM 1 */
|
||||||
dimm = msr.hi >> 16;
|
dimm = msr.hi >> 16;
|
||||||
/* installed? */
|
/* Installed? */
|
||||||
if ((dimm & 7) != 7) {
|
if ((dimm & 7) != 7) {
|
||||||
/* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */
|
/* 1:8MB, 2:16MB, 3:32MB, 4:64MB, ... 7:512MB, 8:1GB */
|
||||||
sizem += 4 << ((dimm >> 12) & 0x0F);
|
sizem += 4 << ((dimm >> 12) & 0x0F);
|
||||||
}
|
}
|
||||||
|
|
||||||
printk(BIOS_DEBUG,"sizeram: sizem 0x%xMB\n", sizem);
|
printk(BIOS_DEBUG, "sizeram: sizem 0x%xMB\n", sizem);
|
||||||
|
|
||||||
return sizem;
|
return sizem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enable_shadow. Currently not set up.
|
* Currently not set up.
|
||||||
* @param dev The nortbridge device.
|
*
|
||||||
*/
|
* @param dev The nortbridge device.
|
||||||
static void enable_shadow(struct device * dev)
|
*/
|
||||||
|
static void enable_shadow(struct device *dev)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* init the northbridge pci device. Right now this a no op. We leave
|
* Initialize the northbridge PCI device.
|
||||||
* it here as a hook for later use.
|
* Right now this a no op. We leave it here as a hook for later use.
|
||||||
* @param dev The nortbridge device.
|
*
|
||||||
*/
|
* @param dev The nortbridge device.
|
||||||
static void geodelx_northbridge_init(struct device * dev)
|
*/
|
||||||
|
static void geodelx_northbridge_init(struct device *dev)
|
||||||
{
|
{
|
||||||
//struct msr msr;
|
/* struct msr msr; */
|
||||||
|
|
||||||
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__);
|
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
|
||||||
|
|
||||||
enable_shadow(dev);
|
enable_shadow(dev);
|
||||||
/*
|
|
||||||
* Swiss cheese
|
|
||||||
*/
|
|
||||||
//msr = rdmsr(MSR_GLIU0_SHADOW);
|
|
||||||
|
|
||||||
//msr.hi |= 0x3;
|
#if 0
|
||||||
//msr.lo |= 0x30000;
|
/* Swiss cheese */
|
||||||
|
msr = rdmsr(MSR_GLIU0_SHADOW);
|
||||||
|
|
||||||
//printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU0_SHADOW, msr.hi, msr.lo);
|
msr.hi |= 0x3;
|
||||||
//printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU1_SHADOW, msr.hi, msr.lo);
|
msr.lo |= 0x30000;
|
||||||
|
|
||||||
|
printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU0_SHADOW, msr.hi, msr.lo);
|
||||||
|
printk(BIOS_DEBUG,"MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU1_SHADOW, msr.hi, msr.lo);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set resources for the PCI northbridge device. This function is
|
* Set resources for the PCI northbridge device.
|
||||||
* required due to VSA interactions.
|
* This function is required due to VSA interactions.
|
||||||
* @param dev The nortbridge device.
|
*
|
||||||
*/
|
* @param dev The nortbridge device.
|
||||||
|
*/
|
||||||
void geodelx_northbridge_set_resources(struct device *dev)
|
void geodelx_northbridge_set_resources(struct device *dev)
|
||||||
{
|
{
|
||||||
struct resource *resource, *last;
|
struct resource *resource, *last;
|
||||||
unsigned link;
|
unsigned int link;
|
||||||
u8 line;
|
u8 line;
|
||||||
|
|
||||||
last = &dev->resource[dev->resources];
|
last = &dev->resource[dev->resources];
|
||||||
|
|
||||||
for (resource = &dev->resource[0]; resource < last; resource++) {
|
for (resource = &dev->resource[0]; resource < last; resource++) {
|
||||||
|
/* From AMD: do not change the base address, it will
|
||||||
/*
|
* make the VSA virtual registers unusable.
|
||||||
* from AMD: do not change the base address, it will
|
|
||||||
* make the VSA virtual registers unusable
|
|
||||||
*/
|
*/
|
||||||
//pci_set_resource(dev, resource);
|
// pci_set_resource(dev, resource);
|
||||||
// FIXME: static allocation may conflict with dynamic mappings!
|
// FIXME: Static allocation may conflict with dynamic mappings!
|
||||||
}
|
}
|
||||||
|
|
||||||
for (link = 0; link < dev->links; link++) {
|
for (link = 0; link < dev->links; link++) {
|
||||||
struct bus *bus;
|
struct bus *bus;
|
||||||
bus = &dev->link[link];
|
bus = &dev->link[link];
|
||||||
if (bus->children) {
|
if (bus->children) {
|
||||||
printk(BIOS_DEBUG,
|
printk(BIOS_DEBUG,
|
||||||
"my_dev_set_resources: phase4_assign_resources %d\n", bus);
|
"my_dev_set_resources: phase4_assign_resources %d\n",
|
||||||
|
bus);
|
||||||
phase4_assign_resources(bus);
|
phase4_assign_resources(bus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* set a default latency timer */
|
/* Set a default latency timer. */
|
||||||
pci_write_config8(dev, PCI_LATENCY_TIMER, 0x40);
|
pci_write_config8(dev, PCI_LATENCY_TIMER, 0x40);
|
||||||
|
|
||||||
/* set a default secondary latency timer */
|
/* Set a default secondary latency timer. */
|
||||||
if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
|
if ((dev->hdr_type & 0x7f) == PCI_HEADER_TYPE_BRIDGE)
|
||||||
pci_write_config8(dev, PCI_SEC_LATENCY_TIMER, 0x40);
|
pci_write_config8(dev, PCI_SEC_LATENCY_TIMER, 0x40);
|
||||||
}
|
|
||||||
|
|
||||||
/* zero the irq settings */
|
/* Zero the IRQ settings. */
|
||||||
line = pci_read_config8(dev, PCI_INTERRUPT_PIN);
|
line = pci_read_config8(dev, PCI_INTERRUPT_PIN);
|
||||||
if (line) {
|
if (line)
|
||||||
pci_write_config8(dev, PCI_INTERRUPT_LINE, 0);
|
pci_write_config8(dev, PCI_INTERRUPT_LINE, 0);
|
||||||
}
|
|
||||||
|
|
||||||
/* set the cache line size, so far 64 bytes is good for everyone */
|
/* Set the cache line size, so far 64 bytes is good for everyone. */
|
||||||
pci_write_config8(dev, PCI_CACHE_LINE_SIZE, 64 >> 2);
|
pci_write_config8(dev, PCI_CACHE_LINE_SIZE, 64 >> 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set resources for the PCI domain.
|
||||||
/**
|
*
|
||||||
* Set resources for the PCI domain. Just set up basic global ranges
|
* Just set up basic global ranges for I/O and memory. Allocation of
|
||||||
* for IO and memory Allocation of sub-resources draws on these
|
* sub-resources draws on these top-level resources in the usual
|
||||||
* top-level resources in the usual hierarchical manner.
|
* hierarchical manner.
|
||||||
* @param dev The nortbridge device.
|
*
|
||||||
*/
|
* @param dev The nortbridge device.
|
||||||
static void geodelx_pci_domain_read_resources(struct device * dev)
|
*/
|
||||||
|
static void geodelx_pci_domain_read_resources(struct device *dev)
|
||||||
{
|
{
|
||||||
struct resource *resource;
|
struct resource *resource;
|
||||||
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__);
|
|
||||||
|
|
||||||
/* Initialize the system wide io space constraints */
|
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
|
||||||
|
|
||||||
|
/* Initialize the system wide I/O space constraints. */
|
||||||
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
|
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0, 0));
|
||||||
resource->limit = 0xffffUL;
|
resource->limit = 0xffffUL;
|
||||||
resource->flags =
|
resource->flags =
|
||||||
IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
|
IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
|
||||||
|
|
||||||
/* Initialize the system wide memory resources constraints */
|
/* Initialize the system wide memory resources constraints. */
|
||||||
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
|
resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1, 0));
|
||||||
resource->limit = 0xffffffffULL;
|
resource->limit = 0xffffffffULL;
|
||||||
resource->flags =
|
resource->flags =
|
||||||
IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
|
IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ram resource, by taking the passed-in size and createing
|
* Create a RAM resource, by taking the passed-in size and creating
|
||||||
* a resource record.
|
* a resource record.
|
||||||
* @param dev the device
|
*
|
||||||
* @param index a resource index
|
* @param dev The device.
|
||||||
* @param basek base memory address in k
|
* @param index A resource index.
|
||||||
* @param sizek size of memory in k
|
* @param basek Base memory address in KB.
|
||||||
*/
|
* @param sizek Size of memory in KB.
|
||||||
static void ram_resource(struct device * dev, unsigned long index,
|
*/
|
||||||
|
static void ram_resource(struct device *dev, unsigned long index,
|
||||||
unsigned long basek, unsigned long sizek)
|
unsigned long basek, unsigned long sizek)
|
||||||
{
|
{
|
||||||
struct resource *resource;
|
struct resource *resource;
|
||||||
|
@ -290,159 +328,169 @@ static void ram_resource(struct device * dev, unsigned long index,
|
||||||
resource->base = ((resource_t) basek) << 10;
|
resource->base = ((resource_t) basek) << 10;
|
||||||
resource->size = ((resource_t) sizek) << 10;
|
resource->size = ((resource_t) sizek) << 10;
|
||||||
resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE |
|
resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE |
|
||||||
IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
|
IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set resources in the pci domain. Also, as a side effect, create a
|
* Set resources in the PCI domain.
|
||||||
* ram resource in the child which, interestingly enough, is the
|
*
|
||||||
* north bridge pci device, for later allocation of address space.
|
* Also, as a side effect, create a RAM resource in the child which,
|
||||||
* @param dev the device
|
* interestingly enough, is the northbridge PCI device, for later
|
||||||
*/
|
* allocation of address space.
|
||||||
static void geodelx_pci_domain_set_resources(struct device * dev)
|
*
|
||||||
|
* @param dev The device.
|
||||||
|
*/
|
||||||
|
static void geodelx_pci_domain_set_resources(struct device *dev)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
struct device * mc_dev;
|
struct device *mc_dev;
|
||||||
|
|
||||||
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__);
|
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
|
||||||
|
|
||||||
mc_dev = dev->link[0].children;
|
mc_dev = dev->link[0].children;
|
||||||
if (mc_dev) {
|
if (mc_dev) {
|
||||||
/* Report the memory regions */
|
/* Report the memory regions. */
|
||||||
idx = 10;
|
idx = 10;
|
||||||
|
/* 0 .. 640 KB */
|
||||||
ram_resource(dev, idx++, 0, 640);
|
ram_resource(dev, idx++, 0, 640);
|
||||||
/* Systop - 1 MB -> KB*/
|
/* 1 MB .. (Systop - 1 MB) (converted to KB) */
|
||||||
ram_resource(dev, idx++, 1024, (get_systop() - 0x100000) / 1024);
|
ram_resource(dev, idx++, 1024,
|
||||||
|
(get_systop() - (1 * 1024 * 1024)) / 1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
phase4_assign_resources(&dev->link[0]);
|
phase4_assign_resources(&dev->link[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enable the pci domain. A littly tricky on this chipset due to the
|
* Enable the PCI domain.
|
||||||
* VSA interactions. This must happen before any PCI scans happen.
|
*
|
||||||
* we do early northbridge init to make sure pci scans will work, but
|
* A littly tricky on this chipset due to the VSA interactions. This must
|
||||||
* the weird part is we actually have to run some code in x86 mode to
|
* happen before any PCI scans happen. We do early northbridge init to make
|
||||||
* get the VSM installed, since the VSM actually handles some PCI bus
|
* sure PCI scans will work, but the weird part is we actually have to run
|
||||||
* scan tasks via the System Management Interrupt. Yes, it gets
|
* some code in x86 mode to get the VSM installed, since the VSM actually
|
||||||
* tricky ...
|
* handles some PCI bus scan tasks via the System Management Interrupt.
|
||||||
* @param dev the device
|
* Yes, it gets tricky...
|
||||||
*/
|
*
|
||||||
static void geodelx_pci_domain_phase2(struct device * dev)
|
* @param dev The device.
|
||||||
|
*/
|
||||||
|
static void geodelx_pci_domain_phase2(struct device *dev)
|
||||||
{
|
{
|
||||||
|
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
|
||||||
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__);
|
|
||||||
|
|
||||||
northbridge_init_early();
|
northbridge_init_early();
|
||||||
#warning cpu bug has been moved to initram stage
|
#warning cpu bug has been moved to initram stage
|
||||||
// cpu_bug();
|
/* cpu_bug(); */
|
||||||
chipsetinit();
|
chipsetinit();
|
||||||
|
|
||||||
setup_realmode_idt();
|
setup_realmode_idt();
|
||||||
|
|
||||||
printk(BIOS_DEBUG,"Before VSA:\n");
|
printk(BIOS_DEBUG, "Before VSA:\n");
|
||||||
// print_conf();
|
/* print_conf(); */
|
||||||
#warning Not doing vsm bios -- linux will fail.
|
#warning Not doing vsm bios -- linux will fail.
|
||||||
// do_vsmbios(); // do the magic stuff here, so prepare your tambourine ;)
|
/* Do the magic stuff here, so prepare your tambourine ;) */
|
||||||
|
/* do_vsmbios(); */
|
||||||
|
printk(BIOS_DEBUG, "After VSA:\n");
|
||||||
|
/* print_conf(); */
|
||||||
|
|
||||||
printk(BIOS_DEBUG,"After VSA:\n");
|
#warning graphics_init is disabled.
|
||||||
// print_conf();
|
/* graphics_init(); */
|
||||||
|
|
||||||
#warning graphics_init is disabled.
|
|
||||||
// graphics_init();
|
|
||||||
pci_set_method(dev);
|
pci_set_method(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for scan bus from the "tippy top" -- i.e. the pci domain,
|
* Support for scan bus from the "tippy top" -- i.e. the PCI domain,
|
||||||
* not the 0:0.0 device.
|
* not the 0:0.0 device.
|
||||||
* @param dev The pci domain device
|
*
|
||||||
* @param max max number of devices to scan.
|
* @param dev The PCI domain device.
|
||||||
*/
|
* @param max Maximum number of devices to scan.
|
||||||
static unsigned int geodelx_pci_domain_scan_bus(struct device * dev, unsigned int max)
|
*/
|
||||||
|
static unsigned int geodelx_pci_domain_scan_bus(struct device *dev,
|
||||||
|
unsigned int max)
|
||||||
{
|
{
|
||||||
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__);
|
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
|
||||||
|
|
||||||
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
|
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0, 0), 0xff, max);
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for APIC cluster init.
|
||||||
|
*
|
||||||
|
* TODO: Should we do this in phase 2? It is now done in phase 6.
|
||||||
|
*
|
||||||
|
* @param dev The PCI domain device.
|
||||||
|
*/
|
||||||
|
static void cpu_bus_init(struct device *dev)
|
||||||
|
{
|
||||||
|
printk(BIOS_SPEW, ">> Entering northbridge.c: %s\n", __FUNCTION__);
|
||||||
|
printk(BIOS_SPEW, ">> Exiting northbridge.c: %s\n", __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cpu_bus_noop(struct device *dev)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The same hardware, being multifunction, has several roles. In this case,
|
||||||
|
* the northbridge is a PCI domain controller, APIC cluster, and the
|
||||||
|
* traditional 0:0.0 device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Operations for when the northbridge is running a PCI domain. */
|
||||||
|
struct device_operations geodelx_pcidomainops = {
|
||||||
|
.constructor = default_device_constructor,
|
||||||
|
.phase2_setup_scan_bus = geodelx_pci_domain_phase2,
|
||||||
|
.phase3_scan = geodelx_pci_domain_scan_bus,
|
||||||
|
.phase4_read_resources = geodelx_pci_domain_read_resources,
|
||||||
|
.phase4_set_resources = geodelx_pci_domain_set_resources,
|
||||||
|
.phase5_enable_resources = enable_childrens_resources,
|
||||||
|
.phase6_init = 0,
|
||||||
|
.ops_pci_bus = &pci_cf8_conf1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Operations for when the northbridge is running an APIC cluster. */
|
||||||
|
struct device_operations geodelx_apicops = {
|
||||||
|
.constructor = default_device_constructor,
|
||||||
|
.phase3_scan = 0,
|
||||||
|
.phase4_read_resources = cpu_bus_noop,
|
||||||
|
.phase4_set_resources = cpu_bus_noop,
|
||||||
|
.phase5_enable_resources = cpu_bus_noop,
|
||||||
|
.phase6_init = cpu_bus_init,
|
||||||
|
.ops_pci_bus = &pci_cf8_conf1,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Operations for when the northbridge is running a PCI device. */
|
||||||
|
struct device_operations geodelx_pci_ops = {
|
||||||
|
.constructor = default_device_constructor,
|
||||||
|
.phase3_scan = geodelx_pci_domain_scan_bus,
|
||||||
|
.phase4_read_resources = geodelx_pci_domain_read_resources,
|
||||||
|
.phase4_set_resources = geodelx_northbridge_set_resources,
|
||||||
|
.phase5_enable_resources = enable_childrens_resources,
|
||||||
|
.phase6_init = geodelx_northbridge_init,
|
||||||
|
.ops_pci_bus = &pci_cf8_conf1,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for apic cluster init. TODO should we do this in phase 2?
|
* The constructor for the device.
|
||||||
* It is now done in phase 6
|
* Domain ops and APIC cluster ops and PCI device ops are different.
|
||||||
* @param dev The pci domain device
|
|
||||||
*/
|
|
||||||
static void cpu_bus_init(struct device * dev)
|
|
||||||
{
|
|
||||||
printk(BIOS_SPEW,">> Entering northbridge.c: %s\n", __FUNCTION__);
|
|
||||||
printk(BIOS_SPEW,">> Exiting northbridge.c: %s\n", __FUNCTION__);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cpu_bus_noop(struct device * dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/* the same hardware, being multifunction, has several roles. In this
|
|
||||||
* case, the north is a pci domain controller, apic cluster, and the
|
|
||||||
* traditional 0:0.0 device
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Here are the operations for when the northbridge is running a PCI
|
|
||||||
* domain.
|
|
||||||
*/
|
*/
|
||||||
struct device_operations geodelx_pcidomainops = {
|
|
||||||
.constructor = default_device_constructor,
|
|
||||||
.phase2_setup_scan_bus = geodelx_pci_domain_phase2,
|
|
||||||
.phase3_scan = geodelx_pci_domain_scan_bus,
|
|
||||||
.phase4_read_resources = geodelx_pci_domain_read_resources,
|
|
||||||
.phase4_set_resources = geodelx_pci_domain_set_resources,
|
|
||||||
.phase5_enable_resources = enable_childrens_resources,
|
|
||||||
.phase6_init = 0,
|
|
||||||
.ops_pci_bus = &pci_cf8_conf1,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Here are the operations for when the northbridge is running an APIC
|
|
||||||
* cluster.
|
|
||||||
*/
|
|
||||||
struct device_operations geodelx_apicops = {
|
|
||||||
.constructor = default_device_constructor,
|
|
||||||
.phase3_scan = 0,
|
|
||||||
.phase4_read_resources = cpu_bus_noop,
|
|
||||||
.phase4_set_resources = cpu_bus_noop,
|
|
||||||
.phase5_enable_resources = cpu_bus_noop,
|
|
||||||
.phase6_init = cpu_bus_init,
|
|
||||||
.ops_pci_bus = &pci_cf8_conf1,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Here are the operations for when the northbridge is running a PCI
|
|
||||||
* device.
|
|
||||||
*/
|
|
||||||
struct device_operations geodelx_pci_ops = {
|
|
||||||
.constructor = default_device_constructor,
|
|
||||||
.phase3_scan = geodelx_pci_domain_scan_bus,
|
|
||||||
.phase4_read_resources = geodelx_pci_domain_read_resources,
|
|
||||||
.phase4_set_resources = geodelx_northbridge_set_resources,
|
|
||||||
.phase5_enable_resources = enable_childrens_resources,
|
|
||||||
.phase6_init = geodelx_northbridge_init,
|
|
||||||
.ops_pci_bus = &pci_cf8_conf1,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/* The constructor for the device. */
|
|
||||||
/* Domain ops and apic cluster ops and pci device ops are different */
|
|
||||||
struct constructor geodelx_north_constructors[] = {
|
struct constructor geodelx_north_constructors[] = {
|
||||||
{.id = {.type = DEVICE_ID_PCI_DOMAIN,
|
/* Northbridge running a PCI domain. */
|
||||||
.u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
|
{.id = {.type = DEVICE_ID_PCI_DOMAIN,
|
||||||
&geodelx_pcidomainops},
|
.u = {.pci_domain = {.vendor = PCI_VENDOR_ID_AMD,
|
||||||
{.id = {.type = DEVICE_ID_APIC_CLUSTER,
|
.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
|
||||||
.u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
|
.ops = &geodelx_pcidomainops},
|
||||||
&geodelx_apicops},
|
|
||||||
{.id = {.type = DEVICE_ID_PCI,
|
/* Northbridge running an APIC cluster. */
|
||||||
.u = {.pci = {.vendor = PCI_VENDOR_ID_AMD,.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
|
{.id = {.type = DEVICE_ID_APIC_CLUSTER,
|
||||||
&geodelx_pci_ops},
|
.u = {.apic_cluster = {.vendor = PCI_VENDOR_ID_AMD,
|
||||||
{.ops = 0},
|
.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
|
||||||
|
.ops = &geodelx_apicops},
|
||||||
|
|
||||||
|
/* Northbridge running a PCI device. */
|
||||||
|
{.id = {.type = DEVICE_ID_PCI,
|
||||||
|
.u = {.pci = {.vendor = PCI_VENDOR_ID_AMD,
|
||||||
|
.device = PCI_DEVICE_ID_AMD_LXBRIDGE}}},
|
||||||
|
.ops = &geodelx_pci_ops},
|
||||||
|
|
||||||
|
{.ops = 0},
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -32,16 +32,19 @@
|
||||||
#include <amd_geodelx.h>
|
#include <amd_geodelx.h>
|
||||||
#include <southbridge/amd/cs5536/cs5536.h>
|
#include <southbridge/amd/cs5536/cs5536.h>
|
||||||
|
|
||||||
static const u8 num_col_addr[] = {
|
static const u8 num_col_addr[] = {
|
||||||
0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x07,
|
0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Auto-detect, using SPD, the DIMM size. It's the usual magic, with
|
* Auto-detect, using SPD, the DIMM size. It's the usual magic, with
|
||||||
* all the usual failiure points that can happen.
|
* all the usual failure points that can happen.
|
||||||
* @param dimm -- The SMBus address of the DIMM
|
*
|
||||||
*/
|
* @param dimm TODO
|
||||||
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
|
*/
|
||||||
static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
|
static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u32 dimm_setting;
|
u32 dimm_setting;
|
||||||
|
@ -51,13 +54,10 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
|
||||||
|
|
||||||
dimm_setting = 0;
|
dimm_setting = 0;
|
||||||
|
|
||||||
/* Check that we have a dimm */
|
/* Check that we have a DIMM. */
|
||||||
if (smbus_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF) {
|
if (smbus_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* Field: Module Banks per DIMM */
|
|
||||||
/* EEPROM byte usage: (5) Number of DIMM Banks */
|
|
||||||
spd_byte = smbus_read_byte(dimm, SPD_NUM_DIMM_BANKS);
|
spd_byte = smbus_read_byte(dimm, SPD_NUM_DIMM_BANKS);
|
||||||
if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)) {
|
if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)) {
|
||||||
printk(BIOS_EMERG, "Number of module banks not compatible\n");
|
printk(BIOS_EMERG, "Number of module banks not compatible\n");
|
||||||
|
@ -66,8 +66,6 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
|
||||||
}
|
}
|
||||||
dimm_setting |= (spd_byte >> 1) << CF07_UPPER_D0_MB_SHIFT;
|
dimm_setting |= (spd_byte >> 1) << CF07_UPPER_D0_MB_SHIFT;
|
||||||
|
|
||||||
/* Field: Banks per SDRAM device */
|
|
||||||
/* EEPROM byte usage: (17) Number of Banks on SDRAM Device */
|
|
||||||
spd_byte = smbus_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM);
|
spd_byte = smbus_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM);
|
||||||
if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)) {
|
if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)) {
|
||||||
printk(BIOS_EMERG, "Number of device banks not compatible\n");
|
printk(BIOS_EMERG, "Number of device banks not compatible\n");
|
||||||
|
@ -76,59 +74,58 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
|
||||||
}
|
}
|
||||||
dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT;
|
dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT;
|
||||||
|
|
||||||
/* Field: DIMM size
|
|
||||||
*; EEPROM byte usage: (3) Number or Row Addresses
|
|
||||||
*; (4) Number of Column Addresses
|
|
||||||
*; (5) Number of DIMM Banks
|
|
||||||
*; (31) Module Bank Density
|
|
||||||
*; Size = Module Density * Module Banks
|
|
||||||
*/
|
|
||||||
if ((smbus_read_byte(dimm, SPD_NUM_ROWS) & 0xF0)
|
if ((smbus_read_byte(dimm, SPD_NUM_ROWS) & 0xF0)
|
||||||
|| (smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) {
|
|| (smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) {
|
||||||
printk(BIOS_EMERG, "Assymetirc DIMM not compatible\n");
|
printk(BIOS_EMERG, "Asymmetric DIMM not compatible\n");
|
||||||
post_code(ERROR_UNSUPPORTED_DIMM);
|
post_code(ERROR_UNSUPPORTED_DIMM);
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Size = Module Density * Module Banks */
|
||||||
dimm_size = smbus_read_byte(dimm, SPD_BANK_DENSITY);
|
dimm_size = smbus_read_byte(dimm, SPD_BANK_DENSITY);
|
||||||
/* align so 1GB(bit0) is bit 8, this is a little weird to get gcc to not optimize this out */
|
/* Align so 1 GB (bit 0) is bit 8. This is a little weird to get gcc
|
||||||
|
* to not optimize this out.
|
||||||
|
*/
|
||||||
dimm_size |= (dimm_size << 8);
|
dimm_size |= (dimm_size << 8);
|
||||||
/* and off 2GB DIMM size : not supported and the 1GB size we just moved up to bit 8 as well as all the extra on top */
|
/* And off 2 GB DIMM size: not supported and the 1 GB size we just
|
||||||
|
* moved up to bit 8 as well as all the extra on top.
|
||||||
|
*/
|
||||||
dimm_size &= 0x01FC;
|
dimm_size &= 0x01FC;
|
||||||
/* Module Density * Module Banks */
|
/* Module Density * Module Banks */
|
||||||
/* shift to multiply by # DIMM banks */
|
/* Shift to multiply by the number of DIMM banks. */
|
||||||
dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1;
|
dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1;
|
||||||
dimm_size = __builtin_ctz(dimm_size);
|
dimm_size = __builtin_ctz(dimm_size);
|
||||||
if (dimm_size > 8) { /* 8 is 1GB only support 1GB per DIMM */
|
if (dimm_size > 8) { /* 8 is 1 GB only support 1 GB per DIMM */
|
||||||
printk(BIOS_EMERG, "Only support up to 1 GB per DIMM\n");
|
printk(BIOS_EMERG, "Only support up to 1 GB per DIMM\n");
|
||||||
post_code(ERROR_DENSITY_DIMM);
|
post_code(ERROR_DENSITY_DIMM);
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT;
|
dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT;
|
||||||
|
|
||||||
/* Field: PAGE size
|
/* PageSize = 2 ^ (number of column addresses) * data width in bytes
|
||||||
* EEPROM byte usage: (4) Number of Column Addresses
|
* (should be 8 bytes for a normal DIMM)
|
||||||
* PageSize = 2^# Column Addresses * Data width in bytes (should be 8bytes for a normal DIMM)
|
*
|
||||||
*
|
* If ma[12:0] is the memory address pins, and pa[12:0] is the
|
||||||
* But this really works by magic.
|
* physical column address that the memory controller (MC) generates,
|
||||||
*If ma[12:0] is the memory address pins, and pa[12:0] is the physical column address
|
* here is how the MC assigns the pa onto the ma pins:
|
||||||
*that MC generates, here is how the MC assigns the pa onto the ma pins:
|
*
|
||||||
*
|
* ma 12 11 10 09 08 07 06 05 04 03 02 01 00
|
||||||
*ma 12 11 10 09 08 07 06 05 04 03 02 01 00
|
* -------------------------------------------
|
||||||
*-------------------------------------------
|
* pa 09 08 07 06 05 04 03 (7 col addr bits = 1K page size)
|
||||||
*pa 09 08 07 06 05 04 03 (7 col addr bits = 1K page size)
|
* pa 10 09 08 07 06 05 04 03 (8 col addr bits = 2K page size)
|
||||||
*pa 10 09 08 07 06 05 04 03 (8 col addr bits = 2K page size)
|
* pa 11 10 09 08 07 06 05 04 03 (9 col addr bits = 4K page size)
|
||||||
*pa 11 10 09 08 07 06 05 04 03 (9 col addr bits = 4K page size)
|
* pa 12 11 10 09 08 07 06 05 04 03 (10 col addr bits = 8K page size)
|
||||||
*pa 12 11 10 09 08 07 06 05 04 03 (10 col addr bits = 8K page size)
|
* pa 13 AP 12 11 10 09 08 07 06 05 04 03 (11 col addr bits = 16K page size)
|
||||||
*pa 13 AP 12 11 10 09 08 07 06 05 04 03 (11 col addr bits = 16K page size)
|
* pa 14 13 AP 12 11 10 09 08 07 06 05 04 03 (12 col addr bits = 32K page size)
|
||||||
*pa 14 13 AP 12 11 10 09 08 07 06 05 04 03 (12 col addr bits = 32K page size)
|
*
|
||||||
* *AP=autoprecharge bit
|
* (AP = autoprecharge bit)
|
||||||
*
|
*
|
||||||
*Remember that pa[2:0] are zeroed out since it's a 64-bit data bus (8 bytes),
|
* Remember that pa[2:0] are zeroed out since it's a 64-bit data bus
|
||||||
*so lower 3 address bits are dont_cares.So from the table above,
|
* (8 bytes), so lower 3 address bits are dont_cares. So from the
|
||||||
*it's easier to see what the old code is doing: if for example,#col_addr_bits=7(06h),
|
* table above, it's easier to see what the old code is doing: if for
|
||||||
*it adds 3 to get 10, then does 2^10=1K. Get it?
|
* example, #col_addr_bits = 7 (06h), it adds 3 to get 10, then does
|
||||||
*/
|
* 2^10=1K. Get it?
|
||||||
|
*/
|
||||||
|
|
||||||
spd_byte = num_col_addr[smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF];
|
spd_byte = num_col_addr[smbus_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF];
|
||||||
if (spd_byte > MAX_COL_ADDR) {
|
if (spd_byte > MAX_COL_ADDR) {
|
||||||
|
@ -137,10 +134,12 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
spd_byte -= 7;
|
spd_byte -= 7;
|
||||||
if (spd_byte > 5) { /* if the value is above 6 it means >12 address lines */
|
/* If the value is above 6 it means >12 address lines... */
|
||||||
spd_byte = 7; /* which means >32k so set to disabled */
|
if (spd_byte > 5) {
|
||||||
|
spd_byte = 7; /* ...which means >32k so set to disabled. */
|
||||||
}
|
}
|
||||||
dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT; /* 0=1k,1=2k,2=4k,etc */
|
/* 0 = 1k, 1 = 2k, 2 = 4k, etc. */
|
||||||
|
dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT;
|
||||||
|
|
||||||
msr = rdmsr(MC_CF07_DATA);
|
msr = rdmsr(MC_CF07_DATA);
|
||||||
if (dimm == dimm0) {
|
if (dimm == dimm0) {
|
||||||
|
@ -153,11 +152,15 @@ static void auto_size_dimm(unsigned int dimm, u8 dimm0, u8 dimm1)
|
||||||
wrmsr(MC_CF07_DATA, msr);
|
wrmsr(MC_CF07_DATA, msr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Try to compute the max DDR clock rate. The only bad news here is that if you have got a geode link
|
/**
|
||||||
* speed that is too fast, you are going to pay for it: the system will hlt!
|
* Try to compute the max. DDR clock rate.
|
||||||
* @param dimm0 dimm0 SMBus address
|
*
|
||||||
* @param dimm1 dimm1 SMBus address
|
* The only bad news here is that if you have got a GeodeLink speed that is
|
||||||
*/
|
* too fast, you are going to pay for it: the system will hlt!
|
||||||
|
*
|
||||||
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
|
*/
|
||||||
static void check_ddr_max(u8 dimm0, u8 dimm1)
|
static void check_ddr_max(u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u8 spd_byte0, spd_byte1;
|
u8 spd_byte0, spd_byte1;
|
||||||
|
@ -165,32 +168,32 @@ static void check_ddr_max(u8 dimm0, u8 dimm1)
|
||||||
|
|
||||||
/* PC133 identifier */
|
/* PC133 identifier */
|
||||||
spd_byte0 = smbus_read_byte(dimm0, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
|
spd_byte0 = smbus_read_byte(dimm0, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
|
||||||
if (spd_byte0 == 0xFF) {
|
if (spd_byte0 == 0xFF)
|
||||||
spd_byte0 = 0;
|
spd_byte0 = 0;
|
||||||
}
|
|
||||||
spd_byte1 = smbus_read_byte(dimm1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
|
spd_byte1 = smbus_read_byte(dimm1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
|
||||||
if (spd_byte1 == 0xFF) {
|
if (spd_byte1 == 0xFF)
|
||||||
spd_byte1 = 0;
|
spd_byte1 = 0;
|
||||||
|
|
||||||
|
/* I don't think you need this check. */
|
||||||
|
#if 0
|
||||||
|
if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0) {
|
||||||
|
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink speed\n");
|
||||||
|
post_code(POST_PLL_MEM_FAIL);
|
||||||
|
hlt();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* I don't think you need this check.
|
/* Use the slowest DIMM. */
|
||||||
if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0){
|
|
||||||
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink Speed\n");
|
|
||||||
post_code(POST_PLL_MEM_FAIL);
|
|
||||||
hlt();
|
|
||||||
} */
|
|
||||||
|
|
||||||
/* Use the slowest DIMM */
|
|
||||||
if (spd_byte0 < spd_byte1) {
|
if (spd_byte0 < spd_byte1) {
|
||||||
spd_byte0 = spd_byte1;
|
spd_byte0 = spd_byte1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */
|
/* Turn SPD ns time into MHz. Check what the asm does to this math. */
|
||||||
speed = 2 * ((10000 / (((spd_byte0 >> 4) * 10) + (spd_byte0 & 0x0F))));
|
speed = 2 * ((10000 / (((spd_byte0 >> 4) * 10) + (spd_byte0 & 0x0F))));
|
||||||
|
|
||||||
/* current speed > max speed? */
|
/* Current speed > max speed? */
|
||||||
if (geode_link_speed() > speed) {
|
if (geode_link_speed() > speed) {
|
||||||
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink Speed\n");
|
printk(BIOS_EMERG, "DIMM overclocked. Check GeodeLink speed\n");
|
||||||
post_code(POST_PLL_MEM_FAIL);
|
post_code(POST_PLL_MEM_FAIL);
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
|
@ -198,11 +201,14 @@ static void check_ddr_max(u8 dimm0, u8 dimm1)
|
||||||
|
|
||||||
const u16 REFRESH_RATE[] = { 15, 3, 7, 31, 62, 125 }; /* ns */
|
const u16 REFRESH_RATE[] = { 15, 3, 7, 31, 62, 125 }; /* ns */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* compute a refresh rate. You have to read both dimms and take the one that requires a faster rate.
|
* Compute a refresh rate.
|
||||||
* @param dimm0 dimm0 SMBus address
|
*
|
||||||
* @param dimm1 dimm1 SMBus address
|
* You have to read both DIMMs and take the one that requires a faster rate.
|
||||||
*/
|
*
|
||||||
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
|
*/
|
||||||
static void set_refresh_rate(u8 dimm0, u8 dimm1)
|
static void set_refresh_rate(u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u8 spd_byte0, spd_byte1;
|
u8 spd_byte0, spd_byte1;
|
||||||
|
@ -223,40 +229,41 @@ static void set_refresh_rate(u8 dimm0, u8 dimm1)
|
||||||
}
|
}
|
||||||
rate1 = REFRESH_RATE[spd_byte1];
|
rate1 = REFRESH_RATE[spd_byte1];
|
||||||
|
|
||||||
/* Use the faster rate (lowest number) */
|
/* Use the faster rate (lowest number). */
|
||||||
if (rate0 > rate1) {
|
if (rate0 > rate1) {
|
||||||
rate0 = rate1;
|
rate0 = rate1;
|
||||||
}
|
}
|
||||||
|
|
||||||
msr = rdmsr(MC_CF07_DATA);
|
msr = rdmsr(MC_CF07_DATA);
|
||||||
msr.lo |= ((rate0 * (geode_link_speed() / 2)) / 16)
|
msr.lo |= ((rate0 * (geode_link_speed() / 2)) / 16)
|
||||||
<< CF07_LOWER_REF_INT_SHIFT;
|
<< CF07_LOWER_REF_INT_SHIFT;
|
||||||
wrmsr(MC_CF07_DATA, msr);
|
wrmsr(MC_CF07_DATA, msr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 CASDDR[] = { 5, 5, 2, 6, 3, 7, 4, 0 }; /* 1(1.5), 1.5, 2, 2.5, 3, 3.5, 4, 0 */
|
/* 1(1.5), 1.5, 2, 2.5, 3, 3.5, 4, 0 */
|
||||||
|
const u8 CASDDR[] = { 5, 5, 2, 6, 3, 7, 4, 0 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the CAS rate.
|
* Compute the CAS rate.
|
||||||
* EEPROM byte usage: (18) SDRAM device attributes - CAS latency
|
*
|
||||||
* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5
|
* The CAS setting is based on the information provided in each DIMMs SPD.
|
||||||
* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1
|
*
|
||||||
*
|
* The speed at which a DIMM can run is described relative to the slowest
|
||||||
* The CAS setting is based on the information provided in each DIMMs SPD.
|
* CAS the DIMM supports. Each speed for the relative CAS settings is
|
||||||
* The speed at which a DIMM can run is described relative to the slowest
|
* checked that it is within the GeodeLink speed. If it isn't within the
|
||||||
* CAS the DIMM supports. Each speed for the relative CAS settings is
|
* GeodeLink speed, the CAS setting is removed from the list of good settings
|
||||||
* checked that it is within the GeodeLink speed. If it isn't within the GeodeLink
|
* for the DIMM.
|
||||||
* speed, the CAS setting is removed from the list of good settings for
|
*
|
||||||
* the DIMM. This is done for both DIMMs and the lists are compared to
|
* This is done for both DIMMs and the lists are compared to find the lowest
|
||||||
* find the lowest common CAS latency setting. If there are no CAS settings
|
* common CAS latency setting. If there are no CAS settings
|
||||||
* in common we out a ERROR_DIFF_DIMMS (78h) to port 80h and halt.
|
* in common we output a ERROR_DIFF_DIMMS (0x78) POST code and halt.
|
||||||
* Result is that we will set fastest CAS Latency based on GeodeLink speed
|
*
|
||||||
* and SPD information.
|
* Result is that we will set fastest CAS latency based on GeodeLink speed
|
||||||
*
|
* and SPD information.
|
||||||
* @param dimm0 dimm0 SMBus address
|
*
|
||||||
* @param dimm1 dimm1 SMBus address
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
*
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
*/
|
*/
|
||||||
static void set_cas(u8 dimm0, u8 dimm1)
|
static void set_cas(u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u16 glspeed, dimm_speed;
|
u16 glspeed, dimm_speed;
|
||||||
|
@ -265,72 +272,78 @@ static void set_cas(u8 dimm0, u8 dimm1)
|
||||||
|
|
||||||
glspeed = geode_link_speed();
|
glspeed = geode_link_speed();
|
||||||
|
|
||||||
/************************** dimm0 **********************************/
|
/* DIMM 0 */
|
||||||
casmap0 = smbus_read_byte(dimm0, SPD_ACCEPTABLE_CAS_LATENCIES);
|
casmap0 = smbus_read_byte(dimm0, SPD_ACCEPTABLE_CAS_LATENCIES);
|
||||||
if (casmap0 != 0xFF) {
|
if (casmap0 != 0xFF) {
|
||||||
/* IF -.5 timing is supported, check -.5 timing > GeodeLink */
|
/* If -.5 timing is supported, check -.5 timing > GeodeLink. */
|
||||||
|
/* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5 */
|
||||||
spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_2ND);
|
spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_2ND);
|
||||||
if (spd_byte != 0) {
|
if (spd_byte != 0) {
|
||||||
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */
|
/* Turn SPD ns time into MHz. Check what the asm does
|
||||||
|
* to this math.
|
||||||
|
*/
|
||||||
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) +
|
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) +
|
||||||
(spd_byte & 0x0F)));
|
(spd_byte & 0x0F)));
|
||||||
if (dimm_speed >= glspeed) {
|
if (dimm_speed >= glspeed) {
|
||||||
/* IF -1 timing is supported, check -1 timing > GeodeLink */
|
/* If -1 timing is supported, check -1 timing > GeodeLink. */
|
||||||
|
/* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1 */
|
||||||
spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_3RD);
|
spd_byte = smbus_read_byte(dimm0, SPD_SDRAM_CYCLE_TIME_3RD);
|
||||||
if (spd_byte != 0) {
|
if (spd_byte != 0) {
|
||||||
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */
|
/* Turn SPD ns time into MHz. Check what the asm does to this math. */
|
||||||
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
|
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
|
||||||
if (dimm_speed <= glspeed) {
|
if (dimm_speed <= glspeed) {
|
||||||
/* set we can use -.5 timing but not -1 */
|
/* Set we can use -.5 timing but not -1. */
|
||||||
spd_byte = 31 - __builtin_clz((u32) casmap0);
|
spd_byte = 31 - __builtin_clz((u32) casmap0);
|
||||||
/* just want bits in the lower byte since we have to cast to a 32 */
|
/* Just want bits in the lower byte since we have to cast to a 32. */
|
||||||
casmap0 &= 0xFF << (--spd_byte);
|
casmap0 &= 0xFF << (--spd_byte);
|
||||||
}
|
}
|
||||||
} /*MIN_CYCLE_10 !=0 */
|
} /* MIN_CYCLE_10 != 0 */
|
||||||
} else {
|
} else {
|
||||||
/* Timing_05 < GLspeed, can't use -.5 or -1 timing */
|
/* Timing_05 < GLspeed, can't use -.5 or -1 timing. */
|
||||||
spd_byte = 31 - __builtin_clz((u32) casmap0);
|
spd_byte = 31 - __builtin_clz((u32) casmap0);
|
||||||
/* just want bits in the lower byte since we have to cast to a 32 */
|
/* Just want bits in the lower byte since we have to cast to a 32. */
|
||||||
casmap0 &= 0xFF << (spd_byte);
|
casmap0 &= 0xFF << (spd_byte);
|
||||||
}
|
}
|
||||||
} /*MIN_CYCLE_05 !=0 */
|
} /* MIN_CYCLE_05 != 0 */
|
||||||
} else { /* No DIMM */
|
} else { /* No DIMM */
|
||||||
casmap0 = 0;
|
casmap0 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** dimm1 **********************************/
|
/* DIMM 1 */
|
||||||
casmap1 = smbus_read_byte(dimm1, SPD_ACCEPTABLE_CAS_LATENCIES);
|
casmap1 = smbus_read_byte(dimm1, SPD_ACCEPTABLE_CAS_LATENCIES);
|
||||||
if (casmap1 != 0xFF) {
|
if (casmap1 != 0xFF) {
|
||||||
/* IF -.5 timing is supported, check -.5 timing > GeodeLink */
|
/* If -.5 timing is supported, check -.5 timing > GeodeLink. */
|
||||||
|
/* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5 */
|
||||||
spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_2ND);
|
spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_2ND);
|
||||||
if (spd_byte != 0) {
|
if (spd_byte != 0) {
|
||||||
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */
|
/* Turn SPD ns time into MHz. Check what the asm does to this math. */
|
||||||
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
|
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
|
||||||
if (dimm_speed >= glspeed) {
|
if (dimm_speed >= glspeed) {
|
||||||
/* IF -1 timing is supported, check -1 timing > GeodeLink */
|
/* If -1 timing is supported, check -1 timing > GeodeLink. */
|
||||||
|
/* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1 */
|
||||||
spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_3RD);
|
spd_byte = smbus_read_byte(dimm1, SPD_SDRAM_CYCLE_TIME_3RD);
|
||||||
if (spd_byte != 0) {
|
if (spd_byte != 0) {
|
||||||
/* Turn SPD ns time into MHZ. Check what the asm does to this math. */
|
/* Turn SPD ns time into MHz. Check what the asm does to this math. */
|
||||||
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
|
dimm_speed = 2 * (10000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F)));
|
||||||
if (dimm_speed <= glspeed) {
|
if (dimm_speed <= glspeed) {
|
||||||
/* set we can use -.5 timing but not -1 */
|
/* Set we can use -.5 timing but not -1. */
|
||||||
spd_byte = 31 - __builtin_clz((u32) casmap1);
|
spd_byte = 31 - __builtin_clz((u32) casmap1);
|
||||||
/* just want bits in the lower byte since we have to cast to a 32 */
|
/* Just want bits in the lower byte since we have to cast to a 32. */
|
||||||
casmap1 &= 0xFF << (--spd_byte);
|
casmap1 &= 0xFF << (--spd_byte);
|
||||||
}
|
}
|
||||||
} /*MIN_CYCLE_10 !=0 */
|
} /* MIN_CYCLE_10 != 0 */
|
||||||
} else {
|
} else {
|
||||||
/* Timing_05 < GLspeed, can't use -.5 or -1 timing */
|
/* Timing_05 < GLspeed, can't use -.5 or -1 timing. */
|
||||||
spd_byte = 31 - __builtin_clz((u32) casmap1);
|
spd_byte = 31 - __builtin_clz((u32) casmap1);
|
||||||
/* just want bits in the lower byte since we have to cast to a 32 */
|
/* Just want bits in the lower byte since we have to cast to a 32. */
|
||||||
casmap1 &= 0xFF << (spd_byte);
|
casmap1 &= 0xFF << (spd_byte);
|
||||||
}
|
}
|
||||||
} /*MIN_CYCLE_05 !=0 */
|
} /* MIN_CYCLE_05 != 0 */
|
||||||
} else { /* No DIMM */
|
} else { /* No DIMM */
|
||||||
casmap1 = 0;
|
casmap1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************* CAS_LAT MAP COMPARE ***************************/
|
/* Compare CAS latencies. */
|
||||||
if (casmap0 == 0) {
|
if (casmap0 == 0) {
|
||||||
spd_byte = CASDDR[__builtin_ctz((u32) casmap1)];
|
spd_byte = CASDDR[__builtin_ctz((u32) casmap1)];
|
||||||
} else if (casmap1 == 0) {
|
} else if (casmap1 == 0) {
|
||||||
|
@ -338,7 +351,7 @@ static void set_cas(u8 dimm0, u8 dimm1)
|
||||||
} else if ((casmap0 &= casmap1)) {
|
} else if ((casmap0 &= casmap1)) {
|
||||||
spd_byte = CASDDR[__builtin_ctz((u32) casmap0)];
|
spd_byte = CASDDR[__builtin_ctz((u32) casmap0)];
|
||||||
} else {
|
} else {
|
||||||
printk(BIOS_EMERG, "DIMM CAS Latencies not compatible\n");
|
printk(BIOS_EMERG, "DIMM CAS latencies not compatible\n");
|
||||||
post_code(ERROR_DIFF_DIMMS);
|
post_code(ERROR_DIFF_DIMMS);
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
|
@ -349,12 +362,15 @@ static void set_cas(u8 dimm0, u8 dimm1)
|
||||||
wrmsr(MC_CF8F_DATA, msr);
|
wrmsr(MC_CF8F_DATA, msr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set latencies for DRAM. These are the famed ras and cas latencies.
|
* Set latencies for DRAM.
|
||||||
* Take the one with the tightest requirements, and use that for both.
|
*
|
||||||
* @param dimm0 dimm0 SMBus address
|
* These are the famed RAS and CAS latencies. Take the one with the tightest
|
||||||
* @param dimm1 dimm1 SMBus address
|
* requirements, and use that for both.
|
||||||
*/
|
*
|
||||||
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
|
*/
|
||||||
static void set_latencies(u8 dimm0, u8 dimm1)
|
static void set_latencies(u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u32 memspeed, dimm_setting;
|
u32 memspeed, dimm_setting;
|
||||||
|
@ -367,36 +383,29 @@ static void set_latencies(u8 dimm0, u8 dimm1)
|
||||||
/* MC_CF8F setup */
|
/* MC_CF8F setup */
|
||||||
/* tRAS */
|
/* tRAS */
|
||||||
spd_byte0 = smbus_read_byte(dimm0, SPD_tRAS);
|
spd_byte0 = smbus_read_byte(dimm0, SPD_tRAS);
|
||||||
if (spd_byte0 == 0xFF) {
|
if (spd_byte0 == 0xFF)
|
||||||
spd_byte0 = 0;
|
spd_byte0 = 0;
|
||||||
}
|
|
||||||
spd_byte1 = smbus_read_byte(dimm1, SPD_tRAS);
|
spd_byte1 = smbus_read_byte(dimm1, SPD_tRAS);
|
||||||
if (spd_byte1 == 0xFF) {
|
if (spd_byte1 == 0xFF)
|
||||||
spd_byte1 = 0;
|
spd_byte1 = 0;
|
||||||
}
|
if (spd_byte0 < spd_byte1)
|
||||||
if (spd_byte0 < spd_byte1) {
|
|
||||||
spd_byte0 = spd_byte1;
|
spd_byte0 = spd_byte1;
|
||||||
}
|
|
||||||
|
|
||||||
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
||||||
spd_byte1 = (spd_byte0 * memspeed) / 1000;
|
spd_byte1 = (spd_byte0 * memspeed) / 1000;
|
||||||
if (((spd_byte0 * memspeed) % 1000)) {
|
if (((spd_byte0 * memspeed) % 1000))
|
||||||
++spd_byte1;
|
++spd_byte1;
|
||||||
}
|
|
||||||
dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT;
|
dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT;
|
||||||
|
|
||||||
/* tRP */
|
/* tRP */
|
||||||
spd_byte0 = smbus_read_byte(dimm0, SPD_tRP);
|
spd_byte0 = smbus_read_byte(dimm0, SPD_tRP);
|
||||||
if (spd_byte0 == 0xFF) {
|
if (spd_byte0 == 0xFF)
|
||||||
spd_byte0 = 0;
|
spd_byte0 = 0;
|
||||||
}
|
|
||||||
spd_byte1 = smbus_read_byte(dimm1, SPD_tRP);
|
spd_byte1 = smbus_read_byte(dimm1, SPD_tRP);
|
||||||
if (spd_byte1 == 0xFF) {
|
if (spd_byte1 == 0xFF)
|
||||||
spd_byte1 = 0;
|
spd_byte1 = 0;
|
||||||
}
|
if (spd_byte0 < spd_byte1)
|
||||||
if (spd_byte0 < spd_byte1) {
|
|
||||||
spd_byte0 = spd_byte1;
|
spd_byte0 = spd_byte1;
|
||||||
}
|
|
||||||
|
|
||||||
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
||||||
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
|
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
|
||||||
|
@ -407,16 +416,13 @@ static void set_latencies(u8 dimm0, u8 dimm1)
|
||||||
|
|
||||||
/* tRCD */
|
/* tRCD */
|
||||||
spd_byte0 = smbus_read_byte(dimm0, SPD_tRCD);
|
spd_byte0 = smbus_read_byte(dimm0, SPD_tRCD);
|
||||||
if (spd_byte0 == 0xFF) {
|
if (spd_byte0 == 0xFF)
|
||||||
spd_byte0 = 0;
|
spd_byte0 = 0;
|
||||||
}
|
|
||||||
spd_byte1 = smbus_read_byte(dimm1, SPD_tRCD);
|
spd_byte1 = smbus_read_byte(dimm1, SPD_tRCD);
|
||||||
if (spd_byte1 == 0xFF) {
|
if (spd_byte1 == 0xFF)
|
||||||
spd_byte1 = 0;
|
spd_byte1 = 0;
|
||||||
}
|
if (spd_byte0 < spd_byte1)
|
||||||
if (spd_byte0 < spd_byte1) {
|
|
||||||
spd_byte0 = spd_byte1;
|
spd_byte0 = spd_byte1;
|
||||||
}
|
|
||||||
|
|
||||||
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
||||||
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
|
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
|
||||||
|
@ -427,16 +433,13 @@ static void set_latencies(u8 dimm0, u8 dimm1)
|
||||||
|
|
||||||
/* tRRD */
|
/* tRRD */
|
||||||
spd_byte0 = smbus_read_byte(dimm0, SPD_tRRD);
|
spd_byte0 = smbus_read_byte(dimm0, SPD_tRRD);
|
||||||
if (spd_byte0 == 0xFF) {
|
if (spd_byte0 == 0xFF)
|
||||||
spd_byte0 = 0;
|
spd_byte0 = 0;
|
||||||
}
|
|
||||||
spd_byte1 = smbus_read_byte(dimm1, SPD_tRRD);
|
spd_byte1 = smbus_read_byte(dimm1, SPD_tRRD);
|
||||||
if (spd_byte1 == 0xFF) {
|
if (spd_byte1 == 0xFF)
|
||||||
spd_byte1 = 0;
|
spd_byte1 = 0;
|
||||||
}
|
if (spd_byte0 < spd_byte1)
|
||||||
if (spd_byte0 < spd_byte1) {
|
|
||||||
spd_byte0 = spd_byte1;
|
spd_byte0 = spd_byte1;
|
||||||
}
|
|
||||||
|
|
||||||
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
||||||
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
|
spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
|
||||||
|
@ -447,8 +450,8 @@ static void set_latencies(u8 dimm0, u8 dimm1)
|
||||||
|
|
||||||
/* tRC = tRP + tRAS */
|
/* tRC = tRP + tRAS */
|
||||||
dimm_setting |= (((dimm_setting >> CF8F_LOWER_ACT2PRE_SHIFT) & 0x0F) +
|
dimm_setting |= (((dimm_setting >> CF8F_LOWER_ACT2PRE_SHIFT) & 0x0F) +
|
||||||
((dimm_setting >> CF8F_LOWER_PRE2ACT_SHIFT) & 0x07))
|
((dimm_setting >> CF8F_LOWER_PRE2ACT_SHIFT) & 0x07))
|
||||||
<< CF8F_LOWER_ACT2ACTREF_SHIFT;
|
<< CF8F_LOWER_ACT2ACTREF_SHIFT;
|
||||||
|
|
||||||
msr = rdmsr(MC_CF8F_DATA);
|
msr = rdmsr(MC_CF8F_DATA);
|
||||||
msr.lo &= 0xF00000FF;
|
msr.lo &= 0xF00000FF;
|
||||||
|
@ -459,33 +462,36 @@ static void set_latencies(u8 dimm0, u8 dimm1)
|
||||||
/* MC_CF1017 setup */
|
/* MC_CF1017 setup */
|
||||||
/* tRFC */
|
/* tRFC */
|
||||||
spd_byte0 = smbus_read_byte(dimm0, SPD_tRFC);
|
spd_byte0 = smbus_read_byte(dimm0, SPD_tRFC);
|
||||||
if (spd_byte0 == 0xFF) {
|
if (spd_byte0 == 0xFF)
|
||||||
spd_byte0 = 0;
|
spd_byte0 = 0;
|
||||||
}
|
|
||||||
spd_byte1 = smbus_read_byte(dimm1, SPD_tRFC);
|
spd_byte1 = smbus_read_byte(dimm1, SPD_tRFC);
|
||||||
if (spd_byte1 == 0xFF) {
|
if (spd_byte1 == 0xFF)
|
||||||
spd_byte1 = 0;
|
spd_byte1 = 0;
|
||||||
}
|
if (spd_byte0 < spd_byte1)
|
||||||
if (spd_byte0 < spd_byte1) {
|
|
||||||
spd_byte0 = spd_byte1;
|
spd_byte0 = spd_byte1;
|
||||||
}
|
|
||||||
|
|
||||||
if (spd_byte0) {
|
if (spd_byte0) {
|
||||||
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
/* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
|
||||||
spd_byte1 = (spd_byte0 * memspeed) / 1000;
|
spd_byte1 = (spd_byte0 * memspeed) / 1000;
|
||||||
if (((spd_byte0 * memspeed) % 1000)) {
|
if (((spd_byte0 * memspeed) % 1000))
|
||||||
++spd_byte1;
|
++spd_byte1;
|
||||||
}
|
} else {
|
||||||
} else { /* Not all SPDs have tRFC setting. Use this formula tRFC = tRC + 1 clk */
|
/* Not all SPDs have tRFC setting.
|
||||||
|
* Use this formula: tRFC = tRC + 1 clk.
|
||||||
|
*/
|
||||||
spd_byte1 = ((dimm_setting >> CF8F_LOWER_ACT2ACTREF_SHIFT) & 0x0F) + 1;
|
spd_byte1 = ((dimm_setting >> CF8F_LOWER_ACT2ACTREF_SHIFT) & 0x0F) + 1;
|
||||||
}
|
}
|
||||||
dimm_setting = spd_byte1 << CF1017_LOWER_REF2ACT_SHIFT; /* note this clears the cf8f dimm setting */
|
|
||||||
|
/* Note: This clears the cf8f DIMM setting. */
|
||||||
|
dimm_setting = spd_byte1 << CF1017_LOWER_REF2ACT_SHIFT;
|
||||||
msr = rdmsr(MC_CF1017_DATA);
|
msr = rdmsr(MC_CF1017_DATA);
|
||||||
msr.lo &= ~(0x1F << CF1017_LOWER_REF2ACT_SHIFT);
|
msr.lo &= ~(0x1F << CF1017_LOWER_REF2ACT_SHIFT);
|
||||||
msr.lo |= dimm_setting;
|
msr.lo |= dimm_setting;
|
||||||
wrmsr(MC_CF1017_DATA, msr);
|
wrmsr(MC_CF1017_DATA, msr);
|
||||||
|
|
||||||
/* tWTR: Set tWTR to 2 for 400MHz and above GLBUS (200Mhz mem) other wise it stay default(1) */
|
/* tWTR: Set tWTR to 2 for 400 MHz and above GLBUS (200 Mhz mem)
|
||||||
|
* otherwise it stay default (1).
|
||||||
|
*/
|
||||||
if (memspeed > 198) {
|
if (memspeed > 198) {
|
||||||
msr = rdmsr(MC_CF1017_DATA);
|
msr = rdmsr(MC_CF1017_DATA);
|
||||||
msr.lo &= ~(0x7 << CF1017_LOWER_WR_TO_RD_SHIFT);
|
msr.lo &= ~(0x7 << CF1017_LOWER_WR_TO_RD_SHIFT);
|
||||||
|
@ -494,44 +500,46 @@ static void set_latencies(u8 dimm0, u8 dimm1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the registers for drive, namely drive and fet strength.
|
* Set the registers for drive, namely drive and fet strength.
|
||||||
* @param dimm0 dimm0 SMBus address
|
*
|
||||||
* @param dimm1 dimm1 SMBus address
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
*/
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
|
*/
|
||||||
static void set_extended_mode_registers(u8 dimm0, u8 dimm1)
|
static void set_extended_mode_registers(u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u8 spd_byte0, spd_byte1;
|
u8 spd_byte0, spd_byte1;
|
||||||
struct msr msr;
|
struct msr msr;
|
||||||
|
|
||||||
spd_byte0 = smbus_read_byte(dimm0, SPD_DEVICE_ATTRIBUTES_GENERAL);
|
spd_byte0 = smbus_read_byte(dimm0, SPD_DEVICE_ATTRIBUTES_GENERAL);
|
||||||
if (spd_byte0 == 0xFF) {
|
if (spd_byte0 == 0xFF)
|
||||||
spd_byte0 = 0;
|
spd_byte0 = 0;
|
||||||
}
|
|
||||||
spd_byte1 = smbus_read_byte(dimm1, SPD_DEVICE_ATTRIBUTES_GENERAL);
|
spd_byte1 = smbus_read_byte(dimm1, SPD_DEVICE_ATTRIBUTES_GENERAL);
|
||||||
if (spd_byte1 == 0xFF) {
|
if (spd_byte1 == 0xFF)
|
||||||
spd_byte1 = 0;
|
spd_byte1 = 0;
|
||||||
}
|
|
||||||
spd_byte1 &= spd_byte0;
|
spd_byte1 &= spd_byte0;
|
||||||
|
|
||||||
msr = rdmsr(MC_CF07_DATA);
|
msr = rdmsr(MC_CF07_DATA);
|
||||||
if (spd_byte1 & 1) { /* Drive Strength Control */
|
if (spd_byte1 & 1) {
|
||||||
|
/* Drive Strength Control */
|
||||||
msr.lo |= CF07_LOWER_EMR_DRV_SET;
|
msr.lo |= CF07_LOWER_EMR_DRV_SET;
|
||||||
}
|
}
|
||||||
if (spd_byte1 & 2) { /* FET Control */
|
if (spd_byte1 & 2) {
|
||||||
|
/* FET Control */
|
||||||
msr.lo |= CF07_LOWER_EMR_QFC_SET;
|
msr.lo |= CF07_LOWER_EMR_QFC_SET;
|
||||||
}
|
}
|
||||||
wrmsr(MC_CF07_DATA, msr);
|
wrmsr(MC_CF07_DATA, msr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug function. Only used when test hardware is connected.
|
* Debug function. Only used when test hardware is connected.
|
||||||
*/
|
*/
|
||||||
static void EnableMTest(void)
|
static void EnableMTest(void)
|
||||||
{
|
{
|
||||||
struct msr msr;
|
struct msr msr;
|
||||||
|
|
||||||
msr = rdmsr(GLCP_DELAY_CONTROLS);
|
msr = rdmsr(GLCP_DELAY_CONTROLS);
|
||||||
msr.hi &= ~(7 << 20); /* clear bits 54:52 */
|
msr.hi &= ~(7 << 20); /* Clear bits 54:52. */
|
||||||
if (geode_link_speed() < 200) {
|
if (geode_link_speed() < 200) {
|
||||||
msr.hi |= 2 << 20;
|
msr.hi |= 2 << 20;
|
||||||
}
|
}
|
||||||
|
@ -547,9 +555,10 @@ static void EnableMTest(void)
|
||||||
printk(BIOS_DEBUG, "Enabled MTest for TLA debug\n");
|
printk(BIOS_DEBUG, "Enabled MTest for TLA debug\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set SDRAM registers that need to be set independent of SPD or even presence or absence of DIMMs
|
/**
|
||||||
* in a slot. Parameters are ignored.
|
* Set SDRAM registers that need to be set independent of SPD or even
|
||||||
*/
|
* presence or absence of DIMMs in a slot. Parameters are ignored.
|
||||||
|
*/
|
||||||
void sdram_set_registers(void)
|
void sdram_set_registers(void)
|
||||||
{
|
{
|
||||||
struct msr msr;
|
struct msr msr;
|
||||||
|
@ -570,20 +579,24 @@ void sdram_set_registers(void)
|
||||||
msrnum = MC_CF07_DATA;
|
msrnum = MC_CF07_DATA;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo &= ~0xF0;
|
msr.lo &= ~0xF0;
|
||||||
msr.lo |= 0x40; /* set refresh to 4SDRAM clocks */
|
msr.lo |= 0x40; /* Set refresh to 4 SDRAM clocks. */
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Memory Interleave: Set HOI here otherwise default is LOI */
|
/* Memory Interleave: Set HOI here otherwise default is LOI. */
|
||||||
/* msrnum = MC_CF8F_DATA;
|
#if 0
|
||||||
msr = rdmsr(msrnum);
|
msrnum = MC_CF8F_DATA;
|
||||||
msr.hi |= CF8F_UPPER_HOI_LOI_SET;
|
msr = rdmsr(msrnum);
|
||||||
wrmsr(msrnum, msr); */
|
msr.hi |= CF8F_UPPER_HOI_LOI_SET;
|
||||||
|
wrmsr(msrnum, msr);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set SDRAM registers that need to are determined by SPD.
|
/**
|
||||||
* @param dimm0 dimm0 SMBus address
|
* Set SDRAM registers that need to be determined by SPD.
|
||||||
* @param dimm1 dimm1 SMBus address
|
*
|
||||||
*/
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
|
*/
|
||||||
void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
|
void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u8 spd_byte;
|
u8 spd_byte;
|
||||||
|
@ -591,15 +604,16 @@ void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
|
||||||
post_code(POST_MEM_SETUP);
|
post_code(POST_MEM_SETUP);
|
||||||
|
|
||||||
spd_byte = smbus_read_byte(dimm0, SPD_MODULE_ATTRIBUTES);
|
spd_byte = smbus_read_byte(dimm0, SPD_MODULE_ATTRIBUTES);
|
||||||
/* Check DIMM is not Register and not Buffered DIMMs. */
|
|
||||||
|
/* Check DIMM is not Registered and not Buffered DIMMs. */
|
||||||
if ((spd_byte != 0xFF) && (spd_byte & 3)) {
|
if ((spd_byte != 0xFF) && (spd_byte & 3)) {
|
||||||
printk(BIOS_EMERG, "dimm0 NOT COMPATIBLE\n");
|
printk(BIOS_EMERG, "DIMM 0 NOT COMPATIBLE!\n");
|
||||||
post_code(ERROR_UNSUPPORTED_DIMM);
|
post_code(ERROR_UNSUPPORTED_DIMM);
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
spd_byte = smbus_read_byte(dimm1, SPD_MODULE_ATTRIBUTES);
|
spd_byte = smbus_read_byte(dimm1, SPD_MODULE_ATTRIBUTES);
|
||||||
if ((spd_byte != 0xFF) && (spd_byte & 3)) {
|
if ((spd_byte != 0xFF) && (spd_byte & 3)) {
|
||||||
printk(BIOS_EMERG, "dimm1 NOT COMPATIBLE\n");
|
printk(BIOS_EMERG, "DIMM 1 NOT COMPATIBLE!\n");
|
||||||
post_code(ERROR_UNSUPPORTED_DIMM);
|
post_code(ERROR_UNSUPPORTED_DIMM);
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
|
@ -609,79 +623,85 @@ void sdram_set_spd_registers(u8 dimm0, u8 dimm1)
|
||||||
/* Check that the memory is not overclocked. */
|
/* Check that the memory is not overclocked. */
|
||||||
check_ddr_max(dimm0, dimm1);
|
check_ddr_max(dimm0, dimm1);
|
||||||
|
|
||||||
/* Size the DIMMS */
|
/* Size the DIMMS.
|
||||||
/* this is gross. It is an artifact of our move to parametes instead of #defines. FIX ME */
|
* This is gross. It is an artifact of our move to parametes instead of
|
||||||
/* the fix is trivial but I want to see it work first. */
|
* #defines. FIXME! The fix is trivial but I want to see it work first.
|
||||||
|
*/
|
||||||
post_code(POST_MEM_SETUP3);
|
post_code(POST_MEM_SETUP3);
|
||||||
auto_size_dimm(dimm0, dimm0, dimm1);
|
auto_size_dimm(dimm0, dimm0, dimm1);
|
||||||
post_code(POST_MEM_SETUP4);
|
post_code(POST_MEM_SETUP4);
|
||||||
auto_size_dimm(dimm1, dimm0, dimm1);
|
auto_size_dimm(dimm1, dimm0, dimm1);
|
||||||
|
|
||||||
/* Set CAS latency */
|
/* Set CAS latency. */
|
||||||
post_code(POST_MEM_SETUP5);
|
post_code(POST_MEM_SETUP5);
|
||||||
set_cas(dimm0, dimm1);
|
set_cas(dimm0, dimm1);
|
||||||
|
|
||||||
/* Set all the other latencies here (tRAS, tRP....) */
|
/* Set all the other latencies here (tRAS, tRP...). */
|
||||||
set_latencies(dimm0, dimm1);
|
set_latencies(dimm0, dimm1);
|
||||||
|
|
||||||
/* Set Extended Mode Registers */
|
/* Set Extended Mode Registers. */
|
||||||
set_extended_mode_registers(dimm0, dimm1);
|
set_extended_mode_registers(dimm0, dimm1);
|
||||||
|
|
||||||
/* Set Memory Refresh Rate */
|
/* Set Memory Refresh Rate. */
|
||||||
set_refresh_rate(dimm0, dimm1);
|
set_refresh_rate(dimm0, dimm1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enable the DRAMs.
|
* Enable the DRAMs.
|
||||||
* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence
|
*
|
||||||
* Section 4.1.4, GX/CS5535 GeodeROM Porting guide
|
* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence
|
||||||
* Turn on MC/DIMM interface per JEDEC
|
* Section 4.1.4, GX/CS5535 GeodeROM Porting guide
|
||||||
* 1) Clock stabilizes > 200us
|
*
|
||||||
* 2) Assert CKE
|
* Turn on MC/DIMM interface per JEDEC:
|
||||||
* 3) Precharge All to put all banks into an idles state
|
* 1) Clock stabilizes > 200us
|
||||||
* 4) EMRS to enable DLL
|
* 2) Assert CKE
|
||||||
* 6) MRS w/ memory config & reset DLL set
|
* 3) Precharge All to put all banks into an idle state
|
||||||
* 7) Wait 200 clocks (2us)
|
* 4) EMRS to enable DLL
|
||||||
* 8) Precharge All and 2 Auto refresh
|
* 6) MRS w/ memory config & reset DLL set
|
||||||
* 9) MRS w/ memory config & reset DLL clear
|
* 7) Wait 200 clocks (2us)
|
||||||
* 8) DDR SDRAM ready for normal operation
|
* 8) Precharge All and 2 Auto refresh
|
||||||
*
|
* 9) MRS w/ memory config & reset DLL clear
|
||||||
* @param dimm0 dimm0 SMBus address
|
* 8) DDR SDRAM ready for normal operation
|
||||||
* @param dimm1 dimm1 SMBus address
|
*
|
||||||
*/
|
* @param dimm0 The SMBus address of DIMM 0 (mainboard-dependent).
|
||||||
|
* @param dimm1 The SMBus address of DIMM 1 (mainboard-dependent).
|
||||||
|
*/
|
||||||
void sdram_enable(u8 dimm0, u8 dimm1)
|
void sdram_enable(u8 dimm0, u8 dimm1)
|
||||||
{
|
{
|
||||||
u32 i, msrnum;
|
u32 i, msrnum;
|
||||||
struct msr msr;
|
struct msr msr;
|
||||||
|
|
||||||
post_code(POST_MEM_ENABLE); // post_76h
|
post_code(POST_MEM_ENABLE);
|
||||||
|
|
||||||
/* Only enable MTest for TLA memory debug */
|
/* Only enable MTest for TLA memory debug. */
|
||||||
/*EnableMTest(); */
|
/* EnableMTest(); */
|
||||||
|
|
||||||
/* If both Page Size = "Not Installed" we have a problems and should halt. */
|
/* If both Page Size = "Not Installed" we have a problem and
|
||||||
|
* should halt.
|
||||||
|
*/
|
||||||
msr = rdmsr(MC_CF07_DATA);
|
msr = rdmsr(MC_CF07_DATA);
|
||||||
if ((msr.hi & ((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) ==
|
if ((msr.hi & ((7 << CF07_UPPER_D1_PSZ_SHIFT) |
|
||||||
((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) {
|
(7 << CF07_UPPER_D0_PSZ_SHIFT))) ==
|
||||||
|
((7 << CF07_UPPER_D1_PSZ_SHIFT) |
|
||||||
|
(7 << CF07_UPPER_D0_PSZ_SHIFT))) {
|
||||||
printk(BIOS_EMERG, "No memory in the system\n");
|
printk(BIOS_EMERG, "No memory in the system\n");
|
||||||
post_code(ERROR_NO_DIMMS);
|
post_code(ERROR_NO_DIMMS);
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set CKEs */
|
/* Set CKEs. */
|
||||||
msrnum = MC_CFCLK_DBUG;
|
msrnum = MC_CFCLK_DBUG;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo &= ~(CFCLK_LOWER_MASK_CKE_SET0 | CFCLK_LOWER_MASK_CKE_SET1);
|
msr.lo &= ~(CFCLK_LOWER_MASK_CKE_SET0 | CFCLK_LOWER_MASK_CKE_SET1);
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Force Precharge All on next command, EMRS */
|
/* Force Precharge All on next command, EMRS. */
|
||||||
msrnum = MC_CFCLK_DBUG;
|
msrnum = MC_CFCLK_DBUG;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
|
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* EMRS to enable DLL (pre-setup done in setExtendedModeRegisters) */
|
/* EMRS to enable DLL (pre-setup done in setExtendedModeRegisters). */
|
||||||
msrnum = MC_CF07_DATA;
|
msrnum = MC_CF07_DATA;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET;
|
msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET;
|
||||||
|
@ -689,13 +709,13 @@ void sdram_enable(u8 dimm0, u8 dimm1)
|
||||||
msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET);
|
msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET);
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Clear Force Precharge All */
|
/* Clear Force Precharge All. */
|
||||||
msrnum = MC_CFCLK_DBUG;
|
msrnum = MC_CFCLK_DBUG;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
|
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* MRS Reset DLL - set */
|
/* MRS Reset DLL - set. */
|
||||||
msrnum = MC_CF07_DATA;
|
msrnum = MC_CF07_DATA;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET;
|
msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET;
|
||||||
|
@ -703,23 +723,23 @@ void sdram_enable(u8 dimm0, u8 dimm1)
|
||||||
msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET);
|
msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET);
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* 2us delay (200 clocks @ 200Mhz). We probably really don't
|
/* 2us delay (200 clocks @ 200Mhz). We probably really don't need
|
||||||
* need this but.... better safe.
|
* this but... better safe.
|
||||||
|
*
|
||||||
|
* Wait two 'port 61 ticks' (between 15us and 30us).
|
||||||
|
* This would be endless if the timer is stuck.
|
||||||
*/
|
*/
|
||||||
/* Wait 2 PORT61 ticks. between 15us and 30us */
|
while ((inb(0x61))); /* Find the first edge. */
|
||||||
/* This would be endless if the timer is stuck. */
|
while (!(~inb(0x61)));
|
||||||
while ((inb(0x61))) ; /* find the first edge */
|
|
||||||
while (!(~inb(0x61))) ;
|
|
||||||
|
|
||||||
/* Force Precharge All on the next command, auto-refresh */
|
/* Force Precharge All on the next command, auto-refresh. */
|
||||||
msrnum = MC_CFCLK_DBUG;
|
msrnum = MC_CFCLK_DBUG;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
|
msr.lo |= CFCLK_LOWER_FORCE_PRE_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Manually AUTO refresh #1 */
|
/* Manually AUTO refresh #1. If auto refresh was not enabled above we
|
||||||
/* If auto refresh was not enabled above we would need to do 8
|
* would need to do 8 refreshes to prime the pump before these 2.
|
||||||
* refreshes to prime the pump before these 2.
|
|
||||||
*/
|
*/
|
||||||
msrnum = MC_CF07_DATA;
|
msrnum = MC_CF07_DATA;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
|
@ -728,14 +748,15 @@ void sdram_enable(u8 dimm0, u8 dimm1)
|
||||||
msr.lo &= ~CF07_LOWER_REF_TEST_SET;
|
msr.lo &= ~CF07_LOWER_REF_TEST_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Clear Force Precharge All */
|
/* Clear Force Precharge All. */
|
||||||
msrnum = MC_CFCLK_DBUG;
|
msrnum = MC_CFCLK_DBUG;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
|
msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Manually AUTO refresh */
|
/* Manually AUTO refresh.
|
||||||
/* The MC should insert the right delay between the refreshes */
|
* The MC should insert the right delay between the refreshes.
|
||||||
|
*/
|
||||||
msrnum = MC_CF07_DATA;
|
msrnum = MC_CF07_DATA;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= CF07_LOWER_REF_TEST_SET;
|
msr.lo |= CF07_LOWER_REF_TEST_SET;
|
||||||
|
@ -743,7 +764,7 @@ void sdram_enable(u8 dimm0, u8 dimm1)
|
||||||
msr.lo &= ~CF07_LOWER_REF_TEST_SET;
|
msr.lo &= ~CF07_LOWER_REF_TEST_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* MRS Reset DLL - clear */
|
/* MRS Reset DLL - clear. */
|
||||||
msrnum = MC_CF07_DATA;
|
msrnum = MC_CF07_DATA;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= CF07_LOWER_PROG_DRAM_SET;
|
msr.lo |= CF07_LOWER_PROG_DRAM_SET;
|
||||||
|
@ -751,13 +772,13 @@ void sdram_enable(u8 dimm0, u8 dimm1)
|
||||||
msr.lo &= ~CF07_LOWER_PROG_DRAM_SET;
|
msr.lo &= ~CF07_LOWER_PROG_DRAM_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Allow MC to tristate during idle cycles with MTEST OFF */
|
/* Allow MC to tristate during idle cycles with MTEST OFF. */
|
||||||
msrnum = MC_CFCLK_DBUG;
|
msrnum = MC_CFCLK_DBUG;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo &= ~CFCLK_LOWER_TRISTATE_DIS_SET;
|
msr.lo &= ~CFCLK_LOWER_TRISTATE_DIS_SET;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
/* Disable SDCLK dimm1 slot if no DIMM installed to save power. */
|
/* Disable SDCLK DIMM 1 slot if no DIMM installed (to save power). */
|
||||||
msr = rdmsr(MC_CF07_DATA);
|
msr = rdmsr(MC_CF07_DATA);
|
||||||
if ((msr.hi & (7 << CF07_UPPER_D1_PSZ_SHIFT)) ==
|
if ((msr.hi & (7 << CF07_UPPER_D1_PSZ_SHIFT)) ==
|
||||||
(7 << CF07_UPPER_D1_PSZ_SHIFT)) {
|
(7 << CF07_UPPER_D1_PSZ_SHIFT)) {
|
||||||
|
@ -767,53 +788,54 @@ void sdram_enable(u8 dimm0, u8 dimm1)
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set PMode0 Sensitivity Counter */
|
/* Set PMode0 Sensitivity Counter. */
|
||||||
msr.lo = 0; /* pmode 0=0 most aggressive */
|
msr.lo = 0; /* pmode 0=0 most aggressive */
|
||||||
msr.hi = 0x200; /* pmode 1=200h */
|
msr.hi = 0x200; /* pmode 1=200h */
|
||||||
wrmsr(MC_CF_PMCTR, msr);
|
wrmsr(MC_CF_PMCTR, msr);
|
||||||
|
|
||||||
/* Set PMode1 Up delay enable */
|
/* Set PMode1 Up delay enable. */
|
||||||
msrnum = MC_CF1017_DATA;
|
msrnum = MC_CF1017_DATA;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= (209 << 8); /* bits[15:8] = 209 */
|
msr.lo |= (209 << 8); /* bits[15:8] = 209 */
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "DRAM controller init done.\n");
|
printk(BIOS_DEBUG, "DRAM controller init done.\n");
|
||||||
post_code(POST_MEM_SETUP_GOOD); //0x7E
|
post_code(POST_MEM_SETUP_GOOD);
|
||||||
|
|
||||||
/* make sure there is nothing stale in the cache */
|
/* Make sure there is nothing stale in the cache. */
|
||||||
/* CAR stack is in the cache __asm__ __volatile__("wbinvd\n"); */
|
/* CAR stack is in the cache __asm__ __volatile__("wbinvd\n"); */
|
||||||
|
|
||||||
/* The RAM dll needs a write to lock on so generate a few dummy writes */
|
/* The RAM dll needs a write to lock on so generate a few dummy
|
||||||
/* Note: The descriptor needs to be enabled to point at memory */
|
* writes. Note: The descriptor needs to be enabled to point at memory.
|
||||||
|
*/
|
||||||
volatile unsigned long *ptr;
|
volatile unsigned long *ptr;
|
||||||
for (i = 0; i < 5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
ptr = (void *)i;
|
ptr = (void *)i;
|
||||||
*ptr = (unsigned long)i;
|
*ptr = (unsigned long)i;
|
||||||
}
|
}
|
||||||
/* SWAPSiF for PBZ 4112 (Errata 34) */
|
|
||||||
/* check for failed DLL settings now that we have done a memory write. */
|
/* SWAPSiF for PBZ 4112 (Errata 34)
|
||||||
|
* Check for failed DLL settings now that we have done a
|
||||||
|
* memory write.
|
||||||
|
*/
|
||||||
msrnum = GLCP_DELAY_CONTROLS;
|
msrnum = GLCP_DELAY_CONTROLS;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
if ((msr.lo & 0x7FF) == 0x104) {
|
if ((msr.lo & 0x7FF) == 0x104) {
|
||||||
|
/* If you had it you would need to clear out the fail boot
|
||||||
/* If you had it you would need to clear out the fail
|
* count flag (depending on where it counts from etc).
|
||||||
* boot count flag (depending on where it counts from
|
|
||||||
* etc).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The we are about to perform clears the PM_SSC
|
|
||||||
* register in the 5536 so will need to store the S3
|
|
||||||
* resume *flag in NVRAM otherwise it would do a
|
|
||||||
* normal boot
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Reset the system */
|
/* The we are about to perform clears the PM_SSC
|
||||||
|
* register in the CS5536 so will need to store the S3
|
||||||
|
* resume flag in NVRAM otherwise it would do a normal boot.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Reset the system. */
|
||||||
msrnum = MDD_SOFT_RESET;
|
msrnum = MDD_SOFT_RESET;
|
||||||
msr = rdmsr(msrnum);
|
msr = rdmsr(msrnum);
|
||||||
msr.lo |= 1;
|
msr.lo |= 1;
|
||||||
wrmsr(msrnum, msr);
|
wrmsr(msrnum, msr);
|
||||||
}
|
}
|
||||||
printk(BIOS_DEBUG, "RAM DLL lock\n");
|
|
||||||
|
|
||||||
|
printk(BIOS_DEBUG, "RAM DLL lock\n");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue