summaryrefslogtreecommitdiff
path: root/src/northbridge/amd
diff options
context:
space:
mode:
authorEric Biederman <ebiederm@xmission.com>2003-10-11 06:20:25 +0000
committerEric Biederman <ebiederm@xmission.com>2003-10-11 06:20:25 +0000
commit83b991afff40e12a8b6756af06a472842edb1a66 (patch)
treea441ff0d88afcb0a07cf22dc3653db3e07a05c98 /src/northbridge/amd
parent080038bfbd8fdf08bac12476a3789495e6f705ca (diff)
- O2, enums, and switch statements work in romcc
- Support for compiling romcc on non x86 platforms - new romc options -msse and -mmmx for specifying extra registers to use - Bug fixes to device the device disable/enable framework and an amd8111 implementation - Move the link specification to the chip specification instead of the path - Allow specifying devices with internal bridges. - Initial via epia support - Opteron errata fixes git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1200 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/amd')
-rw-r--r--src/northbridge/amd/amdk8/Config.lb1
-rw-r--r--src/northbridge/amd/amdk8/coherent_ht.c124
-rw-r--r--src/northbridge/amd/amdk8/cpu_rev.c25
-rw-r--r--src/northbridge/amd/amdk8/misc_control.c42
-rw-r--r--src/northbridge/amd/amdk8/northbridge.c2
-rw-r--r--src/northbridge/amd/amdk8/raminit.c320
6 files changed, 400 insertions, 114 deletions
diff --git a/src/northbridge/amd/amdk8/Config.lb b/src/northbridge/amd/amdk8/Config.lb
index 6112ed18c8..0110e218ce 100644
--- a/src/northbridge/amd/amdk8/Config.lb
+++ b/src/northbridge/amd/amdk8/Config.lb
@@ -1,3 +1,4 @@
config chip.h
object northbridge.o
driver misc_control.o
+driver mcf0_control.o
diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c
index b2839159c7..f05ee3d22d 100644
--- a/src/northbridge/amd/amdk8/coherent_ht.c
+++ b/src/northbridge/amd/amdk8/coherent_ht.c
@@ -100,43 +100,6 @@ static void disable_probes(void)
print_debug("done.\r\n");
}
-//BY LYH
-#define WAIT_TIMES 1000
-static void wait_ap_stop(u8 node)
-{
- unsigned long reg;
- unsigned long i;
- for(i=0;i<WAIT_TIMES;i++) {
- unsigned long regx;
- regx = pci_read_config32(NODE_HT(node),0x6c);
- if((regx & (1<<4))==1) break;
- }
- reg = pci_read_config32(NODE_HT(node),0x6c);
- reg &= ~(1<<4); // clear it
- pci_write_config32(NODE_HT(node), 0x6c, reg);
-
-}
-static void notify_bsp_ap_is_stopped(void)
-{
- unsigned long reg;
- unsigned long apic_id;
- apic_id = *((volatile unsigned long *)(APIC_DEFAULT_BASE+APIC_ID));
- apic_id >>= 24;
-#if 0
- print_debug("applicaton cpu apic_id: ");
- print_debug_hex32(apic_id);
- print_debug("\r\n");
-#endif
- /* AP apic_id == node_id ? */
- if(apic_id != 0) {
- /* set the ColdResetbit to notify BSP that AP is stopped */
- reg = pci_read_config32(NODE_HT(apic_id), 0x6C);
- reg |= 1<<4;
- pci_write_config32(NODE_HT(apic_id), 0x6C, reg);
- }
-
-}
-//BY LYH END
static void enable_routing(u8 node)
{
@@ -169,15 +132,8 @@ static void enable_routing(u8 node)
print_debug_hex32(node);
val=pci_read_config32(NODE_HT(node), 0x6c);
- val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
- pci_write_config32(NODE_HT(node), 0x6c, val);
-//BY LYH
-#if 1
- if(node!=0) {
- wait_ap_stop(node);
- }
-#endif
-//BY LYH END
+ val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
+ pci_write_config32(NODE_HT(node), 0x6c, val);
print_debug(" done.\r\n");
}
@@ -225,6 +181,62 @@ static bool check_connection(u8 src, u8 dest, u8 link)
return 1;
}
+static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2)
+{
+ static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
+ static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
+ uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask;
+ uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2;
+ uint8_t freq;
+ /* Set link width and frequency */
+
+ /* Get the frequency capabilities */
+ freq_cap1 = pci_read_config16(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ_CAP);
+ freq_cap2 = pci_read_config16(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ_CAP);
+
+ /* Calculate the highest possible frequency */
+#if 1
+ /* FIXME!!!!!!!
+ * This method of computing the fastes frequency is broken.
+ * Because the frequencies (i.e. 100Mhz) are not ordered.
+ */
+ freq = log2(freq_cap1 & freq_cap2 & 0xff);
+#else
+ /* Only allow supported frequencies 800Mhz and below */
+ freq = log2(freq_cap1 & freq_cap2 & 0x3f);
+#endif
+
+ /* Set the Calulcated link frequency */
+ pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ, freq);
+ pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ, freq);
+
+ /* Get the width capabilities */
+ width_cap1 = pci_read_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH);
+ width_cap2 = pci_read_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH);
+
+ /* Calculate node1's input width */
+ ln_width1 = link_width_to_pow2[width_cap1 & 7];
+ ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7];
+ if (ln_width1 > ln_width2) {
+ ln_width1 = ln_width2;
+ }
+ width = pow2_to_link_width[ln_width1];
+ /* Calculate node1's output width */
+ ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7];
+ ln_width2 = link_width_to_pow2[width_cap2 & 7];
+ if (ln_width1 > ln_width2) {
+ ln_width1 = ln_width2;
+ }
+ width |= pow2_to_link_width[ln_width1] << 4;
+
+ /* Set node1's widths */
+ pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+
+ /* Set node2's widths */
+ width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
+ pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+}
+
static void fill_row(u8 node, u8 row, u32 value)
{
#if 0
@@ -346,6 +358,7 @@ static u8 setup_smp(void)
}
/* We found 2 nodes so far */
+ optimize_connection(0, ACROSS, 7, ACROSS);
setup_node(0, cpus); /* Node 1 is there. Setup Node 0 correctly */
setup_remote_node(1, cpus); /* Setup the routes on the remote node */
rename_temp_node(1); /* Rename Node 7 to Node 1 */
@@ -444,17 +457,6 @@ static unsigned detect_mp_capabilities(unsigned cpus)
#endif
-/* this is a shrunken cpuid. */
-
-static unsigned int cpuid(unsigned int op)
-{
- unsigned int ret;
-
- asm volatile ( "cpuid" : "=a" (ret) : "a" (op));
-
- return ret;
-}
-
static void coherent_ht_finalize(unsigned cpus)
{
int node;
@@ -469,7 +471,7 @@ static void coherent_ht_finalize(unsigned cpus)
#if 1
print_debug("coherent_ht_finalize\r\n");
#endif
- rev_a0=((cpuid(1)&0xffff)==0x0f10);
+ rev_a0= is_cpu_rev_a0();
for (node=0; node<cpus; node++) {
u32 val;
@@ -479,7 +481,11 @@ static void coherent_ht_finalize(unsigned cpus)
pci_write_config32(NODE_HT(node),0x60,val);
val=pci_read_config32(NODE_HT(node), 0x68);
+#if 1
+ val |= 0x00008000;
+#else
val |= 0x0f00c800; // 0x00008000->0f00c800 BY LYH
+#endif
pci_write_config32(NODE_HT(node),0x68,val);
if (rev_a0) {
@@ -508,7 +514,7 @@ static int setup_coherent_ht_domain(void)
#endif
coherent_ht_finalize(cpus);
- /* this should probably go away again. */
+ /* FIXME this should probably go away again. */
coherent_ht_mainboard(cpus);
return reset_needed;
}
diff --git a/src/northbridge/amd/amdk8/cpu_rev.c b/src/northbridge/amd/amdk8/cpu_rev.c
new file mode 100644
index 0000000000..51f235905e
--- /dev/null
+++ b/src/northbridge/amd/amdk8/cpu_rev.c
@@ -0,0 +1,25 @@
+/* this is a shrunken cpuid. */
+
+static unsigned int cpuid(unsigned int op)
+{
+ unsigned int ret;
+ unsigned dummy2,dummy3,dummy4;
+
+ asm volatile (
+ "cpuid"
+ : "=a" (ret), "=b" (dummy2), "=c" (dummy3), "=d" (dummy4)
+ : "a" (op)
+ );
+
+ return ret;
+}
+
+static int is_cpu_rev_a0(void)
+{
+ return (cpuid(1) & 0xffff) == 0x0f10;
+}
+
+static int is_cpu_pre_c0(void)
+{
+ return (cpuid(1) & 0xffef) < 0x0f48;
+}
diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c
index 639e34fbaf..045f5cef06 100644
--- a/src/northbridge/amd/amdk8/misc_control.c
+++ b/src/northbridge/amd/amdk8/misc_control.c
@@ -8,6 +8,7 @@
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
+#include "./cpu_rev.c"
static void misc_control_init(struct device *dev)
{
@@ -17,7 +18,48 @@ static void misc_control_init(struct device *dev)
cmd = pci_read_config32(dev, 0x44);
cmd |= (1<<6) | (1<<25);
pci_write_config32(dev, 0x44, cmd );
+ if (is_cpu_pre_c0()) {
+ /* errata 58 */
+ cmd = pci_read_config32(dev, 0x80);
+ cmd &= ~(1<<0);
+ pci_write_config32(dev, 0x80, cmd );
+ cmd = pci_read_config32(dev, 0x84);
+ cmd &= ~(1<<24);
+ cmd &= ~(1<<8);
+ pci_write_config32(dev, 0x84, cmd );
+ /* errata 66 */
+ cmd = pci_read_config32(dev, 0x70);
+ cmd &= ~(1<<0);
+ cmd |= (1<<1);
+ pci_write_config32(dev, 0x70, cmd );
+ cmd = pci_read_config32(dev, 0x7c);
+ cmd &= ~(3<<4);
+ pci_write_config32(dev, 0x7c, cmd );
+ }
+ else {
+ /* errata 98 */
+#if 0
+ cmd = pci_read_config32(dev, 0xd4);
+ if(cmd != 0x04e20707) {
+ cmd = 0x04e20707;
+ pci_write_config32(dev, 0xd4, cmd );
+ hard_reset();
+ }
+#endif
+ cmd = 0x04e20707;
+ pci_write_config32(dev, 0xd4, cmd );
+ }
+#if 1
+ cmd = pci_read_config32(dev, 0xdc);
+ if((cmd & 0x0000ff00) != 0x02500) {
+ cmd &= 0xffff00ff;
+ cmd |= 0x00002500;
+ pci_write_config32(dev, 0xdc, cmd );
+ printk_debug("resetting cpu\n");
+ hard_reset();
+ }
+#endif
printk_debug("done.\n");
}
diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c
index 7bcb1567ba..13845c5a70 100644
--- a/src/northbridge/amd/amdk8/northbridge.c
+++ b/src/northbridge/amd/amdk8/northbridge.c
@@ -475,6 +475,6 @@ static void enumerate(struct chip *chip)
}
struct chip_control northbridge_amd_amdk8_control = {
- .enumerate = enumerate,
.name = "AMD K8 Northbridge",
+ .enumerate = enumerate,
};
diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c
index 802e4318b4..437ef2655d 100644
--- a/src/northbridge/amd/amdk8/raminit.c
+++ b/src/northbridge/amd/amdk8/raminit.c
@@ -124,6 +124,9 @@
#define DCH_MEMCLK_EN3 (1 << 29)
/* Function 3 */
+#define MCA_NB_CONFIG 0x44
+#define MNC_ECC_EN (1 << 22)
+#define MNC_CHIPKILL_EN (1 << 23)
#define SCRUB_CONTROL 0x58
#define SCRUB_NONE 0
#define SCRUB_40ns 1
@@ -1127,23 +1130,6 @@ static void spd_set_ram_size(const struct mem_controller *ctrl)
}
}
-//BY LYH //Fill next base reg with right value
-static void fill_last(unsigned long node_id,unsigned long base)
-{
- unsigned i;
- unsigned base_reg;
- base &=0xffff0000;
- device_t device;
- for(device = PCI_DEV(0, 0x18, 1); device <= PCI_DEV(0, 0x1f, 1); device
-+= PCI_DEV(0, 1, 0)) {
- for(i=node_id+1;i<=7;i++) {
- base_reg=0x40+(i<<3);
- pci_write_config32(device,base_reg,base);
- }
- }
-}
-//BY LYH END
-
static void route_dram_accesses(const struct mem_controller *ctrl,
unsigned long base_k, unsigned long limit_k)
{
@@ -1177,7 +1163,12 @@ static void set_top_mem(unsigned tom_k)
{
/* Error if I don't have memory */
if (!tom_k) {
- die("No memory");
+ set_bios_reset();
+ print_debug("No memory - reset");
+ /* enable cf9 */
+ pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1);
+ /* reset */
+ outb(0x0e, 0x0cf9);
}
#if 1
@@ -1204,15 +1195,102 @@ static void set_top_mem(unsigned tom_k)
wrmsr(TOP_MEM, msr);
}
-static void order_dimms(const struct mem_controller *ctrl)
+static unsigned long interleave_chip_selects(const struct mem_controller *ctrl)
{
- unsigned long tom, tom_k, base_k;
- unsigned node_id;
+ /* 35 - 25 */
+ static const uint32_t csbase_low[] = {
+ /* 32MB */ (1 << (13 - 4)),
+ /* 64MB */ (1 << (14 - 4)),
+ /* 128MB */ (1 << (14 - 4)),
+ /* 256MB */ (1 << (15 - 4)),
+ /* 512MB */ (1 << (15 - 4)),
+ /* 1GB */ (1 << (16 - 4)),
+ /* 2GB */ (1 << (16 - 4)),
+ };
+ uint32_t csbase_inc;
+ int chip_selects, index;
+ int bits;
+ int dual_channel;
+ unsigned common_size;
+ uint32_t csbase, csmask;
+
+ /* See if all of the memory chip selects are the same size
+ * and if so count them.
+ */
+ chip_selects = 0;
+ common_size = 0;
+ for(index = 0; index < 8; index++) {
+ unsigned size;
+ uint32_t value;
+
+ value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2));
+
+ /* Is it enabled? */
+ if (!(value & 1)) {
+ continue;
+ }
+ chip_selects++;
+ size = value >> 21;
+ if (common_size == 0) {
+ common_size = size;
+ }
+ /* The size differed fail */
+ if (common_size != size) {
+ return 0;
+ }
+ }
+ /* Chip selects can only be interleaved when there is
+ * more than one and their is a power of two of them.
+ */
+ bits = log2(chip_selects);
+ if (((1 << bits) != chip_selects) || (bits < 1) || (bits > 3)) {
+ return 0;
+
+ }
+ /* Also we run out of address mask bits if we try and interleave 8 4GB dimms */
+ if ((bits == 3) && (common_size == (1 << (32 - 3)))) {
+ print_debug("8 4GB chip selects cannot be interleaved\r\n");
+ return 0;
+ }
+ /* Find the bits of csbase that we need to interleave on */
+ if (is_dual_channel(ctrl)) {
+ csbase_inc = csbase_low[log2(common_size) - 1] << 1;
+ } else {
+ csbase_inc = csbase_low[log2(common_size)];
+ }
+ /* Compute the initial values for csbase and csbask.
+ * In csbase just set the enable bit and the base to zero.
+ * In csmask set the mask bits for the size and page level interleave.
+ */
+ csbase = 0 | 1;
+ csmask = (((common_size << bits) - 1) << 21);
+ csmask |= 0xfe00 & ~((csbase_inc << bits) - csbase_inc);
+ for(index = 0; index < 8; index++) {
+ uint32_t value;
+
+ value = pci_read_config32(ctrl->f2, DRAM_CSBASE + (index << 2));
+ /* Is it enabled? */
+ if (!(value & 1)) {
+ continue;
+ }
+ pci_write_config32(ctrl->f2, DRAM_CSBASE + (index << 2), csbase);
+ pci_write_config32(ctrl->f2, DRAM_CSMASK + (index << 2), csmask);
+ csbase += csbase_inc;
+ }
+
+#if 1
+ print_debug("Interleaved\r\n");
+#endif
+ /* Return the memory size in K */
+ return common_size << (15 + bits);
+}
- /* Compute the memory base address address */
- base_k = 0;
+static unsigned long order_chip_selects(const struct mem_controller *ctrl)
+{
+ unsigned long tom;
+
/* Remember which registers we have used in the high 8 bits of tom */
- tom = base_k >> 15;
+ tom = 0;
for(;;) {
/* Find the largest remaining canidate */
unsigned index, canidate;
@@ -1270,8 +1348,19 @@ static void order_dimms(const struct mem_controller *ctrl)
pci_write_config32(ctrl->f2, DRAM_CSMASK + (canidate << 2), csmask);
}
- tom_k = (tom & ~0xff000000) << 15;
+ /* Return the memory size in K */
+ return (tom & ~0xff000000) << 15;
+}
+
+static void order_dimms(const struct mem_controller *ctrl)
+{
+ unsigned long tom, tom_k, base_k;
+ unsigned node_id;
+ tom_k = interleave_chip_selects(ctrl);
+ if (!tom_k) {
+ tom_k = order_chip_selects(ctrl);
+ }
/* Compute the memory base address */
base_k = 0;
for(node_id = 0; node_id < ctrl->node_id; node_id++) {
@@ -1287,18 +1376,13 @@ static void order_dimms(const struct mem_controller *ctrl)
}
tom_k += base_k;
#if 0
- print_debug("tom: ");
- print_debug_hex32(tom);
- print_debug(" base_k: ");
+ print_debug("base_k: ");
print_debug_hex32(base_k);
print_debug(" tom_k: ");
print_debug_hex32(tom_k);
print_debug("\r\n");
#endif
route_dram_accesses(ctrl, base_k, tom_k);
-//BY LYH
- fill_last(ctrl->node_id, tom_k<<2);
-//BY LYH END
set_top_mem(tom_k);
}
@@ -2063,6 +2147,10 @@ static void set_read_preamble(const struct mem_controller *ctrl, const struct me
/* 166Mhz, 7.5ns */
rdpreamble = ((7 << 1)+1);
}
+ else if (divisor == ((5 << 1)+0)) {
+ /* 200Mhz, 7ns */
+ rdpreamble = ((7 << 1)+0);
+ }
}
else {
int slots;
@@ -2175,6 +2263,8 @@ static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct
{
int dimms;
int i;
+ int rc;
+
init_Tref(ctrl, param);
for(i = 0; (i < 4) && ctrl->channel0[i]; i++) {
int rc;
@@ -2247,13 +2337,16 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
print_debug_hex32(dcl);
print_debug("\r\n");
#endif
-#warning "FIXME set the ECC type to perform"
-#warning "FIXME initialize the scrub registers"
-#if 1
if (dcl & DCL_DimmEccEn) {
+ uint32_t mnc;
print_debug("ECC enabled\r\n");
+ mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG);
+ mnc |= MNC_ECC_EN;
+ if (dcl & DCL_128BitEn) {
+ mnc |= MNC_CHIPKILL_EN;
+ }
+ pci_write_config32(ctrl[i].f3, MCA_NB_CONFIG, mnc);
}
-#endif
dcl |= DCL_DisDqsHys;
pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
dcl &= ~DCL_DisDqsHys;
@@ -2280,29 +2373,148 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
} else {
print_debug(" done\r\n");
}
-#if 0
if (dcl & DCL_DimmEccEn) {
print_debug("Clearing memory: ");
- loops = 0;
- dcl &= ~DCL_MemClrStatus;
- pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+ if (!is_cpu_pre_c0()) {
+ /* Wait until the automatic ram scrubber is finished */
+ dcl &= ~(DCL_MemClrStatus | DCL_DramEnable);
+ pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+ do {
+ dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
+ } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) );
+ }
+ uint32_t base, last_scrub_k, scrub_k;
+ uint32_t cnt,zstart,zend;
+ msr_t msr,msr_201;
+
+ /* First make certain the scrubber is disabled */
+ pci_write_config32(ctrl[i].f3, SCRUB_CONTROL,
+ (SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0));
+
+ /* load the start and end for the memory block to clear */
+ msr_201 = rdmsr(0x201);
+ zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8));
+ zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8));
+ zstart >>= 16;
+ zend >>=16;
+#if 1
+ print_debug("addr ");
+ print_debug_hex32(zstart);
+ print_debug("-");
+ print_debug_hex32(zend);
+ print_debug("\r\n");
+#endif
- do {
- dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
- loops += 1;
- if ((loops & 1023) == 0) {
- print_debug(" ");
- print_debug_hex32(loops);
- }
- } while(((dcl & DCL_MemClrStatus) == 0) && (loops < TIMEOUT_LOOPS));
- if (loops >= TIMEOUT_LOOPS) {
- print_debug("failed\r\n");
- } else {
- print_debug("done\r\n");
+ /* Disable fixed mtrrs */
+ msr = rdmsr(MTRRdefType_MSR);
+ msr.lo &= ~(1<<10);
+ wrmsr(MTRRdefType_MSR, msr);
+
+ /* turn on the wrap 32 disable */
+ msr = rdmsr(0xc0010015);
+ msr.lo |= (1<<17);
+ wrmsr(0xc0010015,msr);
+
+ for(;zstart<zend;zstart+=4) {
+
+ /* test for the last 64 meg of 4 gig space */
+ if(zstart == 0x0fc)
+ continue;
+
+ /* disable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* Set the variable mtrrs to write combine */
+ msr.lo = 1 + ((zstart&0x0ff)<<24);
+ msr.hi = (zstart&0x0ff00)>>8;
+ wrmsr(0x200,msr);
+
+ /* Set the limit to 64 meg of ram */
+ msr.hi = 0x000000ff;
+ msr.lo = 0xfc000800;
+ wrmsr(0x201,msr);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+ /* Set fs base address */
+ msr.lo = (zstart&0xff) << 24;
+ msr.hi = (zstart&0xff00) >> 8;
+ wrmsr(0xc0000100,msr);
+
+ print_debug_char((zstart > 0x0ff)?'+':'-');
+
+ /* clear memory 64meg */
+ __asm__ volatile(
+ "1: \n\t"
+ "movl %0, %%fs:(%1)\n\t"
+ "addl $4,%1\n\t"
+ "subl $1,%2\n\t"
+ "jnz 1b\n\t"
+ :
+ : "a" (0), "D" (0), "c" (0x01000000)
+ );
}
- pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, 0);
- pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, 0);
+
+ /* disable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* restore msr registers */
+ msr = rdmsr(MTRRdefType_MSR);
+ msr.lo |= 0x0400;
+ wrmsr(MTRRdefType_MSR, msr);
+
+ /* Restore the variable mtrrs */
+ msr.lo = 6;
+ msr.hi = 0;
+ wrmsr(0x200,msr);
+ wrmsr(0x201,msr_201);
+
+ /* Set fs base to 0 */
+ msr.lo = 0;
+ msr.hi = 0;
+ wrmsr(0xc0000100,msr);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* turn off the wrap 32 disable */
+ msr = rdmsr(0xc0010015);
+ msr.lo &= ~(1<<17);
+ wrmsr(0xc0010015,msr);
+
+ /* Find the Srub base address for this cpu */
+ base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3));
+ base &= 0xffff0000;
+
+ /* Set the scrub base address registers */
+ pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, base << 8);
+ pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, base >> 24);
+
+ /* Enable scrubbing at the lowest possible rate */
+ pci_write_config32(ctrl[i].f3, SCRUB_CONTROL,
+ (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0));
+
+ print_debug("done\r\n");
}
-#endif
}
}