#include <cpu/k8/mtrr.h>
#include "raminit.h"
+#include "amdk8.h"
-#define ENABLE_IOMMU 1
-
-/* Function 2 */
-#define DRAM_CSBASE 0x40
-#define DRAM_CSMASK 0x60
-#define DRAM_BANK_ADDR_MAP 0x80
-#define DRAM_TIMING_LOW 0x88
-#define DTL_TCL_SHIFT 0
-#define DTL_TCL_MASK 0x7
-#define DTL_CL_2 1
-#define DTL_CL_3 2
-#define DTL_CL_2_5 5
-#define DTL_TRC_SHIFT 4
-#define DTL_TRC_MASK 0xf
-#define DTL_TRC_BASE 7
-#define DTL_TRC_MIN 7
-#define DTL_TRC_MAX 22
-#define DTL_TRFC_SHIFT 8
-#define DTL_TRFC_MASK 0xf
-#define DTL_TRFC_BASE 9
-#define DTL_TRFC_MIN 9
-#define DTL_TRFC_MAX 24
-#define DTL_TRCD_SHIFT 12
-#define DTL_TRCD_MASK 0x7
-#define DTL_TRCD_BASE 0
-#define DTL_TRCD_MIN 2
-#define DTL_TRCD_MAX 6
-#define DTL_TRRD_SHIFT 16
-#define DTL_TRRD_MASK 0x7
-#define DTL_TRRD_BASE 0
-#define DTL_TRRD_MIN 2
-#define DTL_TRRD_MAX 4
-#define DTL_TRAS_SHIFT 20
-#define DTL_TRAS_MASK 0xf
-#define DTL_TRAS_BASE 0
-#define DTL_TRAS_MIN 5
-#define DTL_TRAS_MAX 15
-#define DTL_TRP_SHIFT 24
-#define DTL_TRP_MASK 0x7
-#define DTL_TRP_BASE 0
-#define DTL_TRP_MIN 2
-#define DTL_TRP_MAX 6
-#define DTL_TWR_SHIFT 28
-#define DTL_TWR_MASK 0x1
-#define DTL_TWR_BASE 2
-#define DTL_TWR_MIN 2
-#define DTL_TWR_MAX 3
-#define DRAM_TIMING_HIGH 0x8c
-#define DTH_TWTR_SHIFT 0
-#define DTH_TWTR_MASK 0x1
-#define DTH_TWTR_BASE 1
-#define DTH_TWTR_MIN 1
-#define DTH_TWTR_MAX 2
-#define DTH_TRWT_SHIFT 4
-#define DTH_TRWT_MASK 0x7
-#define DTH_TRWT_BASE 1
-#define DTH_TRWT_MIN 1
-#define DTH_TRWT_MAX 6
-#define DTH_TREF_SHIFT 8
-#define DTH_TREF_MASK 0x1f
-#define DTH_TREF_100MHZ_4K 0x00
-#define DTH_TREF_133MHZ_4K 0x01
-#define DTH_TREF_166MHZ_4K 0x02
-#define DTH_TREF_200MHZ_4K 0x03
-#define DTH_TREF_100MHZ_8K 0x08
-#define DTH_TREF_133MHZ_8K 0x09
-#define DTH_TREF_166MHZ_8K 0x0A
-#define DTH_TREF_200MHZ_8K 0x0B
-#define DTH_TWCL_SHIFT 20
-#define DTH_TWCL_MASK 0x7
-#define DTH_TWCL_BASE 1
-#define DTH_TWCL_MIN 1
-#define DTH_TWCL_MAX 2
-#define DRAM_CONFIG_LOW 0x90
-#define DCL_DLL_Disable (1<<0)
-#define DCL_D_DRV (1<<1)
-#define DCL_QFC_EN (1<<2)
-#define DCL_DisDqsHys (1<<3)
-#define DCL_DramInit (1<<8)
-#define DCL_DramEnable (1<<10)
-#define DCL_MemClrStatus (1<<11)
-#define DCL_ESR (1<<12)
-#define DCL_SRS (1<<13)
-#define DCL_128BitEn (1<<16)
-#define DCL_DimmEccEn (1<<17)
-#define DCL_UnBufDimm (1<<18)
-#define DCL_32ByteEn (1<<19)
-#define DCL_x4DIMM_SHIFT 20
-#define DRAM_CONFIG_HIGH 0x94
-#define DCH_ASYNC_LAT_SHIFT 0
-#define DCH_ASYNC_LAT_MASK 0xf
-#define DCH_ASYNC_LAT_BASE 0
-#define DCH_ASYNC_LAT_MIN 0
-#define DCH_ASYNC_LAT_MAX 15
-#define DCH_RDPREAMBLE_SHIFT 8
-#define DCH_RDPREAMBLE_MASK 0xf
-#define DCH_RDPREAMBLE_BASE ((2<<1)+0) /* 2.0 ns */
-#define DCH_RDPREAMBLE_MIN ((2<<1)+0) /* 2.0 ns */
-#define DCH_RDPREAMBLE_MAX ((9<<1)+1) /* 9.5 ns */
-#define DCH_IDLE_LIMIT_SHIFT 16
-#define DCH_IDLE_LIMIT_MASK 0x7
-#define DCH_IDLE_LIMIT_0 0
-#define DCH_IDLE_LIMIT_4 1
-#define DCH_IDLE_LIMIT_8 2
-#define DCH_IDLE_LIMIT_16 3
-#define DCH_IDLE_LIMIT_32 4
-#define DCH_IDLE_LIMIT_64 5
-#define DCH_IDLE_LIMIT_128 6
-#define DCH_IDLE_LIMIT_256 7
-#define DCH_DYN_IDLE_CTR_EN (1 << 19)
-#define DCH_MEMCLK_SHIFT 20
-#define DCH_MEMCLK_MASK 0x7
-#define DCH_MEMCLK_100MHZ 0
-#define DCH_MEMCLK_133MHZ 2
-#define DCH_MEMCLK_166MHZ 5
-#define DCH_MEMCLK_200MHZ 7
-#define DCH_MEMCLK_VALID (1 << 25)
-#define DCH_MEMCLK_EN0 (1 << 26)
-#define DCH_MEMCLK_EN1 (1 << 27)
-#define DCH_MEMCLK_EN2 (1 << 28)
-#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
-#define SCRUB_80ns 2
-#define SCRUB_160ns 3
-#define SCRUB_320ns 4
-#define SCRUB_640ns 5
-#define SCRUB_1_28us 6
-#define SCRUB_2_56us 7
-#define SCRUB_5_12us 8
-#define SCRUB_10_2us 9
-#define SCRUB_20_5us 10
-#define SCRUB_41_0us 11
-#define SCRUB_81_9us 12
-#define SCRUB_163_8us 13
-#define SCRUB_327_7us 14
-#define SCRUB_655_4us 15
-#define SCRUB_1_31ms 16
-#define SCRUB_2_62ms 17
-#define SCRUB_5_24ms 18
-#define SCRUB_10_49ms 19
-#define SCRUB_20_97ms 20
-#define SCRUB_42ms 21
-#define SCRUB_84ms 22
-#define SC_DRAM_SCRUB_RATE_SHFIT 0
-#define SC_DRAM_SCRUB_RATE_MASK 0x1f
-#define SC_L2_SCRUB_RATE_SHIFT 8
-#define SC_L2_SCRUB_RATE_MASK 0x1f
-#define SC_L1D_SCRUB_RATE_SHIFT 16
-#define SC_L1D_SCRUB_RATE_MASK 0x1f
-#define SCRUB_ADDR_LOW 0x5C
-#define SCRUB_ADDR_HIGH 0x60
-#define NORTHBRIDGE_CAP 0xE8
-#define NBCAP_128Bit 0x0001
-#define NBCAP_MP 0x0002
-#define NBCAP_BIG_MP 0x0004
-#define NBCAP_ECC 0x0004
-#define NBCAP_CHIPKILL_ECC 0x0010
-#define NBCAP_MEMCLK_SHIFT 5
-#define NBCAP_MEMCLK_MASK 3
-#define NBCAP_MEMCLK_100MHZ 3
-#define NBCAP_MEMCLK_133MHZ 2
-#define NBCAP_MEMCLK_166MHZ 1
-#define NBCAP_MEMCLK_200MHZ 0
-#define NBCAP_MEMCTRL 0x0100
-
-
+#if (CONFIG_LB_MEM_TOPK & (CONFIG_LB_MEM_TOPK -1)) != 0
+# error "CONFIG_LB_MEM_TOPK must be a power of 2"
+#endif
static void setup_resource_map(const unsigned int *register_values, int max)
{
int i;
-
- unsigned int amd8111_link_nr;
-
- print_debug("setting up resource map....\r\n");
- /*
- * determine the HT link number the southbridge is connected to
- * bits 8-9 of the Unit ID register
- */
- amd8111_link_nr = (pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64) & 0x00000300) >> 8;
- print_debug(" AMD8111 southbridge is connected to HT link ");
- print_debug_hex32(amd8111_link_nr);
- print_debug("\r\n");
-
-
- print_debug("setting up resource map....\r\n");
+ print_debug("setting up resource map....");
+#if 0
+ print_debug("\r\n");
+#endif
for(i = 0; i < max; i += 3) {
device_t dev;
unsigned where;
unsigned long reg;
-
#if 0
print_debug_hex32(register_values[i]);
print_debug(" <-");
reg = pci_read_config32(dev, where);
reg &= register_values[i+1];
reg |= register_values[i+2];
-
- /*
- * set correct HT link to the southbridge
- * otherwise we cut of the acces to the flash we are from
- *
- */
- if (where == 0xBC)
- reg |= amd8111_link_nr << 4;
- if (where == 0xC4)
- reg |= amd8111_link_nr << 4;
- if (where == 0xE0)
- reg |= amd8111_link_nr << 8;
-
pci_write_config32(dev, where, reg);
#if 0
reg = pci_read_config32(register_values[i]);
* [31: 8] Reserved
*/
PCI_ADDR(0, 0x18, 3, 0x60), 0xffffff00, 0x00000000,
-
-#if ENABLE_IOMMU != 0
- /* BY LYH add IOMMU 64M APERTURE */
- PCI_ADDR(0, 0x18, 3, 0x94), 0xffff8000, 0x00000f70,
- PCI_ADDR(0, 0x18, 3, 0x90), 0xffffff80, 0x00000002,
- PCI_ADDR(0, 0x18, 3, 0x98), 0x0000000f, 0x00068300,
-#endif
};
int i;
int max;
- print_debug("setting up CPU");
- print_debug_hex8(ctrl->node_id);
- print_debug(" northbridge registers\r\n");
+ print_spew("setting up CPU");
+ print_spew_hex8(ctrl->node_id);
+ print_spew(" northbridge registers\r\n");
max = sizeof(register_values)/sizeof(register_values[0]);
for(i = 0; i < max; i += 3) {
device_t dev;
unsigned where;
unsigned long reg;
#if 0
- print_debug_hex32(register_values[i]);
- print_debug(" <-");
- print_debug_hex32(register_values[i+2]);
- print_debug("\r\n");
+ print_spew_hex32(register_values[i]);
+ print_spew(" <-");
+ print_spew_hex32(register_values[i+2]);
+ print_spew("\r\n");
#endif
dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x18, 0) + ctrl->f0;
where = register_values[i] & 0xff;
pci_write_config32(register_values[i], reg);
#endif
}
- print_debug("done.\r\n");
+ print_spew("done.\r\n");
}
+static void hw_enable_ecc(const struct mem_controller *ctrl)
+{
+ uint32_t dcl, nbcap;
+ nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
+ dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+ dcl &= ~DCL_DimmEccEn;
+ if (nbcap & NBCAP_ECC) {
+ dcl |= DCL_DimmEccEn;
+ }
+ if (read_option(CMOS_VSTART_ECC_memory, CMOS_VLEN_ECC_memory, 1) == 0) {
+ dcl &= ~DCL_DimmEccEn;
+ }
+ pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+
+}
+
static int is_dual_channel(const struct mem_controller *ctrl)
{
uint32_t dcl;
* sides of an assymetric dimm.
*/
value = spd_read_byte(device, 3); /* rows */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
sz.side1 += value & 0xf;
value = spd_read_byte(device, 4); /* columns */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
sz.side1 += value & 0xf;
value = spd_read_byte(device, 17); /* banks */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xff) == 0) goto val_err;
sz.side1 += log2(value & 0xff);
/* Get the module data width and convert it to a power of two */
value = spd_read_byte(device, 7); /* (high byte) */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
value &= 0xff;
value <<= 8;
low = spd_read_byte(device, 6); /* (low byte) */
- if (low < 0) goto out;
+ if (low < 0) goto hw_err;
value = value | (low & 0xff);
+ if ((value != 72) && (value &= 64)) goto val_err;
sz.side1 += log2(value);
/* side 2 */
value = spd_read_byte(device, 5); /* number of physical banks */
- if (value <= 1) goto out;
+ if (value < 0) goto hw_err;
+ if (value == 1) goto out;
+ if (value != 2) goto val_err;
/* Start with the symmetrical case */
sz.side2 = sz.side1;
value = spd_read_byte(device, 3); /* rows */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */
sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */
sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */
value = spd_read_byte(device, 4); /* columns */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xff) == 0) goto val_err;
sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */
sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */
+ goto out;
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ sz.side1 = 0;
+ sz.side2 = 0;
out:
return sz;
}
uint32_t base0, base1, map;
uint32_t dch;
-#if 0
- print_debug("set_dimm_size: (");
- print_debug_hex32(sz.side1);
- print_debug_char(',');
- print_debug_hex32(sz.side2);
- print_debug_char(',');
- print_debug_hex32(index);
- print_debug(")\r\n");
-#endif
if (sz.side1 != sz.side2) {
sz.side2 = 0;
}
}
}
-static void spd_set_ram_size(const struct mem_controller *ctrl)
+static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask)
{
int i;
- for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ for(i = 0; i < DIMM_SOCKETS; i++) {
struct dimm_size sz;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
sz = spd_get_dimm_size(ctrl->channel0[i]);
+ if (sz.side1 == 0) {
+ return -1; /* Report SPD error */
+ }
set_dimm_size(ctrl, sz, i);
}
+ return dimm_mask;
}
static void route_dram_accesses(const struct mem_controller *ctrl,
{
/* Error if I don't have memory */
if (!tom_k) {
- set_bios_reset();
- print_debug("No memory - reset");
- /* enable cf9 */
- pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1);
- /* reset */
- outb(0x0e, 0x0cf9);
+ die("No memory?");
}
-#if 1
/* Report the amount of memory. */
- print_debug("RAM: 0x");
- print_debug_hex32(tom_k);
- print_debug(" KB\r\n");
-#endif
+ print_spew("RAM: 0x");
+ print_spew_hex32(tom_k);
+ print_spew(" KB\r\n");
/* Now set top of memory */
msr_t msr;
uint32_t csbase_inc;
int chip_selects, index;
int bits;
- int dual_channel;
unsigned common_size;
uint32_t csbase, csmask;
csbase += csbase_inc;
}
-#if 1
- print_debug("Interleaved\r\n");
-#endif
+ print_spew("Interleaved\r\n");
+
/* Return the memory size in K */
return common_size << (15 + bits);
}
/* Compute the memory mask */
csmask = ((size -1) << 21);
csmask |= 0xfe00; /* For now don't optimize */
-#warning "Don't forget to optimize the DIMM size"
/* Write the new base register */
pci_write_config32(ctrl->f2, DRAM_CSBASE + (canidate << 2), csbase);
return (tom & ~0xff000000) << 15;
}
-static void order_dimms(const struct mem_controller *ctrl)
+unsigned long memory_end_k(const struct mem_controller *ctrl, int max_node_id)
{
- 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++) {
+ unsigned end_k;
+ /* Find the last memory address used */
+ end_k = 0;
+ for(node_id = 0; node_id < max_node_id; node_id++) {
uint32_t limit, base;
unsigned index;
index = node_id << 3;
/* Only look at the limit if the base is enabled */
if ((base & 3) == 3) {
limit = pci_read_config32(ctrl->f1, 0x44 + index);
- base_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
+ end_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
}
}
+ return end_k;
+}
+
+static void order_dimms(const struct mem_controller *ctrl)
+{
+ unsigned long tom_k, base_k;
+
+ if (read_option(CMOS_VSTART_interleave_chip_selects, CMOS_VLEN_interleave_chip_selects, 1) != 0) {
+ tom_k = interleave_chip_selects(ctrl);
+ } else {
+ print_debug("Interleaving disabled\r\n");
+ tom_k = 0;
+ }
+ if (!tom_k) {
+ tom_k = order_chip_selects(ctrl);
+ }
+ /* Compute the memory base address */
+ base_k = memory_end_k(ctrl, ctrl->node_id);
tom_k += base_k;
-#if 0
- 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);
set_top_mem(tom_k);
}
-static void disable_dimm(const struct mem_controller *ctrl, unsigned index)
+static long disable_dimm(const struct mem_controller *ctrl, unsigned index, long dimm_mask)
{
print_debug("disabling dimm");
print_debug_hex8(index);
print_debug("\r\n");
pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), 0);
pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), 0);
+ dimm_mask &= ~(1 << index);
+ return dimm_mask;
}
-
-static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl)
+static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl, long dimm_mask)
{
int i;
int registered;
uint32_t dcl;
unbuffered = 0;
registered = 0;
- for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ for(i = 0; (i < DIMM_SOCKETS); i++) {
int value;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
value = spd_read_byte(ctrl->channel0[i], 21);
if (value < 0) {
- disable_dimm(ctrl, i);
- continue;
+ return -1;
}
/* Registered dimm ? */
if (value & (1 << 1)) {
print_debug("Unbuffered\r\n");
}
#endif
+ return dimm_mask;
}
-static void spd_enable_2channels(const struct mem_controller *ctrl)
+static unsigned int spd_detect_dimms(const struct mem_controller *ctrl)
+{
+ unsigned dimm_mask;
+ int i;
+ dimm_mask = 0;
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ int byte;
+ unsigned device;
+ device = ctrl->channel0[i];
+ if (device) {
+ byte = spd_read_byte(ctrl->channel0[i], 2); /* Type */
+ if (byte == 7) {
+ dimm_mask |= (1 << i);
+ }
+ }
+ device = ctrl->channel1[i];
+ if (device) {
+ byte = spd_read_byte(ctrl->channel1[i], 2);
+ if (byte == 7) {
+ dimm_mask |= (1 << (i + DIMM_SOCKETS));
+ }
+ }
+ }
+ return dimm_mask;
+}
+
+static long spd_enable_2channels(const struct mem_controller *ctrl, long dimm_mask)
{
int i;
uint32_t nbcap;
/* SPD addresses to verify are identical */
-#warning "FINISHME review and see if these are the bytes I need"
- /* FINISHME review and see if these are the bytes I need */
static const unsigned addresses[] = {
2, /* Type should be DDR SDRAM */
3, /* *Row addresses */
41, /* *Minimum Active to Active/Auto Refresh Time(Trc) */
42, /* *Minimum Auto Refresh Command Time(Trfc) */
};
+ /* If the dimms are not in pairs do not do dual channels */
+ if ((dimm_mask & ((1 << DIMM_SOCKETS) - 1)) !=
+ ((dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) {
+ goto single_channel;
+ }
+ /* If the cpu is not capable of doing dual channels don't do dual channels */
nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
if (!(nbcap & NBCAP_128Bit)) {
- return;
+ goto single_channel;
}
for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
unsigned device0, device1;
int value0, value1;
int j;
+ /* If I don't have a dimm skip this one */
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
device0 = ctrl->channel0[i];
device1 = ctrl->channel1[i];
- if (!device1)
- return;
for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) {
unsigned addr;
addr = addresses[j];
value0 = spd_read_byte(device0, addr);
if (value0 < 0) {
- break;
+ return -1;
}
value1 = spd_read_byte(device1, addr);
if (value1 < 0) {
- return;
+ return -1;
}
if (value0 != value1) {
- return;
+ goto single_channel;
}
}
}
- print_debug("Enabling dual channel memory\r\n");
+ print_spew("Enabling dual channel memory\r\n");
uint32_t dcl;
dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
dcl &= ~DCL_32ByteEn;
dcl |= DCL_128BitEn;
pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+ return dimm_mask;
+ single_channel:
+ dimm_mask &= ~((1 << (DIMM_SOCKETS *2)) - (1 << DIMM_SOCKETS));
+ return dimm_mask;
}
struct mem_param {
if (!param->cycle_time) {
die("min_cycle_time to low");
}
-#if 1
+ print_spew(param->name);
+#ifdef DRAM_MIN_CYCLE_TIME
print_debug(param->name);
#endif
return param;
}
-static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
+struct spd_set_memclk_result {
+ const struct mem_param *param;
+ long dimm_mask;
+};
+static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, long dimm_mask)
{
/* Compute the minimum cycle time for these dimms */
- const struct mem_param *param;
- unsigned min_cycle_time, min_latency;
+ struct spd_set_memclk_result result;
+ unsigned min_cycle_time, min_latency, bios_cycle_time;
int i;
uint32_t value;
value = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK];
+ bios_cycle_time = min_cycle_times[
+ read_option(CMOS_VSTART_max_mem_clock, CMOS_VLEN_max_mem_clock, 0)];
+ if (bios_cycle_time > min_cycle_time) {
+ min_cycle_time = bios_cycle_time;
+ }
min_latency = 2;
-#if 0
- print_debug("min_cycle_time: ");
- print_debug_hex8(min_cycle_time);
- print_debug(" min_latency: ");
- print_debug_hex8(min_latency);
- print_debug("\r\n");
-#endif
-
/* Compute the least latency with the fastest clock supported
* by both the memory controller and the dimms.
*/
- for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ for(i = 0; i < DIMM_SOCKETS; i++) {
int new_cycle_time, new_latency;
int index;
int latencies;
int latency;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+
/* First find the supported CAS latencies
* Byte 18 for DDR SDRAM is interpreted:
* bit 0 == CAS Latency = 1.0
}
value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
if (value < 0) {
- continue;
+ goto hw_error;
}
/* Only increase the latency if we decreas the clock */
if (new_latency > min_latency) {
min_latency = new_latency;
}
-#if 0
- print_debug("i: ");
- print_debug_hex8(i);
- print_debug(" min_cycle_time: ");
- print_debug_hex8(min_cycle_time);
- print_debug(" min_latency: ");
- print_debug_hex8(min_latency);
- print_debug("\r\n");
-#endif
}
/* Make a second pass through the dimms and disable
* any that cannot support the selected memclk and cas latency.
int latency;
int index;
int value;
- int dimm;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
latencies = spd_read_byte(ctrl->channel0[i], 18);
- if (latencies <= 0) {
+ if (latencies < 0) goto hw_error;
+ if (latencies == 0) {
goto dimm_err;
}
/* Read the min_cycle_time for this latency */
value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
+ if (value < 0) goto hw_error;
/* All is good if the selected clock speed
* is what I need or slower.
}
/* Otherwise I have an error, disable the dimm */
dimm_err:
- disable_dimm(ctrl, i);
+ dimm_mask = disable_dimm(ctrl, i, dimm_mask);
}
-#if 0
- print_debug("min_cycle_time: ");
- print_debug_hex8(min_cycle_time);
- print_debug(" min_latency: ");
- print_debug_hex8(min_latency);
- print_debug("\r\n");
-#endif
/* Now that I know the minimum cycle time lookup the memory parameters */
- param = get_mem_param(min_cycle_time);
+ result.param = get_mem_param(min_cycle_time);
/* Update DRAM Config High with our selected memory speed */
value = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH);
value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT);
- value |= param->dch_memclk;
+ value |= result.param->dch_memclk;
pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, value);
static const unsigned latencies[] = { DTL_CL_2, DTL_CL_2_5, DTL_CL_3 };
value |= latencies[min_latency - 2] << DTL_TCL_SHIFT;
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value);
- return param;
+ result.dimm_mask = dimm_mask;
+ return result;
+ hw_error:
+ result.param = (const struct mem_param *)0;
+ result.dimm_mask = -1;
+ return result;
}
clocks = DTL_TRC_MIN;
}
if (clocks > DTL_TRC_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
dtl &= ~(DTL_TRC_MASK << DTL_TRC_SHIFT);
dtl |= ((clocks - DTL_TRC_BASE) << DTL_TRC_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
clocks = DTL_TRFC_MIN;
}
if (clocks > DTL_TRFC_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRFC_SHIFT) & DTL_TRFC_MASK) + DTL_TRFC_BASE;
dtl &= ~(DTL_TRFC_MASK << DTL_TRFC_SHIFT);
dtl |= ((clocks - DTL_TRFC_BASE) << DTL_TRFC_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
int value;
value = spd_read_byte(ctrl->channel0[i], 29);
if (value < 0) return -1;
-#if 0
clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1);
-#else
- clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
-#endif
if (clocks < DTL_TRCD_MIN) {
clocks = DTL_TRCD_MIN;
}
if (clocks > DTL_TRCD_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRCD_SHIFT) & DTL_TRCD_MASK) + DTL_TRCD_BASE;
dtl &= ~(DTL_TRCD_MASK << DTL_TRCD_SHIFT);
dtl |= ((clocks - DTL_TRCD_BASE) << DTL_TRCD_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
int value;
value = spd_read_byte(ctrl->channel0[i], 28);
if (value < 0) return -1;
- clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
+ clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1);
if (clocks < DTL_TRRD_MIN) {
clocks = DTL_TRRD_MIN;
}
if (clocks > DTL_TRRD_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRRD_SHIFT) & DTL_TRRD_MASK) + DTL_TRRD_BASE;
dtl &= ~(DTL_TRRD_MASK << DTL_TRRD_SHIFT);
dtl |= ((clocks - DTL_TRRD_BASE) << DTL_TRRD_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i)
clocks = DTL_TRAS_MIN;
}
if (clocks > DTL_TRAS_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE;
dtl &= ~(DTL_TRAS_MASK << DTL_TRAS_SHIFT);
dtl |= ((clocks - DTL_TRAS_BASE) << DTL_TRAS_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i)
int value;
value = spd_read_byte(ctrl->channel0[i], 27);
if (value < 0) return -1;
-#if 0
clocks = (value + (param->divisor << 1) - 1)/(param->divisor << 1);
-#else
- clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1);
-#endif
-#if 0
- print_debug("Trp: ");
- print_debug_hex8(clocks);
- print_debug(" spd value: ");
- print_debug_hex8(value);
- print_debug(" divisor: ");
- print_debug_hex8(param->divisor);
- print_debug("\r\n");
-#endif
if (clocks < DTL_TRP_MIN) {
clocks = DTL_TRP_MIN;
}
if (clocks > DTL_TRP_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRP_SHIFT) & DTL_TRP_MASK) + DTL_TRP_BASE;
dtl &= ~(DTL_TRP_MASK << DTL_TRP_SHIFT);
dtl |= ((clocks - DTL_TRP_BASE) << DTL_TRP_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param)
dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT);
dth |= (tref << DTH_TREF_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth);
- return 0;
+ return 1;
}
dcl |= (1 << dimm);
}
pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
- return 0;
+ return 1;
}
static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
dcl &= ~DCL_DimmEccEn;
pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
}
- return 0;
+ return 1;
}
static int count_dimms(const struct mem_controller *ctrl)
dimms = 0;
for(index = 0; index < 8; index += 2) {
uint32_t csbase;
- csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + index << 2));
+ csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + (index << 2)));
if (csbase & 1) {
dimms += 1;
}
}
}
if ((clocks < DTH_TRWT_MIN) || (clocks > DTH_TRWT_MAX)) {
- die("Unknown Trwt");
+ die("Unknown Trwt\r\n");
}
dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH);
static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param)
{
uint32_t dch;
- int i;
unsigned async_lat;
int dimms;
pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch);
}
-static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param)
+static long spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param, long dimm_mask)
{
- int dimms;
int i;
- int rc;
init_Tref(ctrl, param);
- for(i = 0; (i < 4) && ctrl->channel0[i]; i++) {
+ for(i = 0; i < DIMM_SOCKETS; i++) {
int rc;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
/* DRAM Timing Low Register */
- if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err;
+ if ((rc = update_dimm_Trc (ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trfc(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trcd(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trrd(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Tras(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trp (ctrl, param, i)) <= 0) goto dimm_err;
/* DRAM Timing High Register */
- if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err;
+ if ((rc = update_dimm_Tref(ctrl, param, i)) <= 0) goto dimm_err;
+
/* DRAM Config Low */
- if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err;
+ if ((rc = update_dimm_x4 (ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_ecc(ctrl, param, i)) <= 0) goto dimm_err;
continue;
dimm_err:
- disable_dimm(ctrl, i);
-
+ if (rc < 0) {
+ return -1;
+ }
+ dimm_mask = disable_dimm(ctrl, i, dimm_mask);
}
/* DRAM Timing Low Register */
set_Twr(ctrl, param);
set_read_preamble(ctrl, param);
set_max_async_latency(ctrl, param);
set_idle_cycle_limit(ctrl, param);
+ return dimm_mask;
}
static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
+ struct spd_set_memclk_result result;
const struct mem_param *param;
+ long dimm_mask;
+ hw_enable_ecc(ctrl);
activate_spd_rom(ctrl);
- spd_enable_2channels(ctrl);
- spd_set_ram_size(ctrl);
- spd_handle_unbuffered_dimms(ctrl);
- param = spd_set_memclk(ctrl);
- spd_set_dram_timing(ctrl, param);
+ dimm_mask = spd_detect_dimms(ctrl);
+ if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
+ print_debug("No memory for this cpu\r\n");
+ return;
+ }
+ dimm_mask = spd_enable_2channels(ctrl, dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_set_ram_size(ctrl , dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_handle_unbuffered_dimms(ctrl, dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ result = spd_set_memclk(ctrl, dimm_mask);
+ param = result.param;
+ dimm_mask = result.dimm_mask;
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_set_dram_timing(ctrl, param , dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
order_dimms(ctrl);
+ return;
+ hw_spd_err:
+ /* Unrecoverable error reading SPD data */
+ print_err("SPD error - reset\r\n");
+ hard_reset();
+ return;
}
#define TIMEOUT_LOOPS 300000
{
int i;
+ /* Error if I don't have memory */
+ if (memory_end_k(ctrl, controllers) == 0) {
+ die("No memory\r\n");
+ }
+
/* Before enabling memory start the memory clocks */
for(i = 0; i < controllers; i++) {
uint32_t dch;
dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
- dch |= DCH_MEMCLK_VALID;
- pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch);
+ if (dch & (DCH_MEMCLK_EN0|DCH_MEMCLK_EN1|DCH_MEMCLK_EN2|DCH_MEMCLK_EN3)) {
+ dch |= DCH_MEMCLK_VALID;
+ pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch);
+ }
+ else {
+ /* Disable dram receivers */
+ uint32_t dcl;
+ dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
+ dcl |= DCL_DisInRcvrs;
+ pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+ }
}
/* And if necessary toggle the the reset on the dimms by hand */
memreset(controllers, ctrl);
for(i = 0; i < controllers; i++) {
- uint32_t dcl;
+ uint32_t dcl, dch;
+ /* Skip everything if I don't have any memory on this controller */
+ dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
+ if (!(dch & DCH_MEMCLK_VALID)) {
+ continue;
+ }
+
/* Toggle DisDqsHys to get it working */
dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
-#if 0
- print_debug("dcl: ");
- print_debug_hex32(dcl);
- print_debug("\r\n");
-#endif
if (dcl & DCL_DimmEccEn) {
uint32_t mnc;
- print_debug("ECC enabled\r\n");
+ print_spew("ECC enabled\r\n");
mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG);
mnc |= MNC_ECC_EN;
if (dcl & DCL_128BitEn) {
}
for(i = 0; i < controllers; i++) {
- uint32_t dcl;
+ uint32_t dcl, dch;
+ /* Skip everything if I don't have any memory on this controller */
+ dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
+ if (!(dch & DCH_MEMCLK_VALID)) {
+ continue;
+ }
+
print_debug("Initializing memory: ");
int loops = 0;
do {
} while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS));
if (loops >= TIMEOUT_LOOPS) {
print_debug(" failed\r\n");
- } else {
- print_debug(" done\r\n");
+ continue;
}
- if (dcl & DCL_DimmEccEn) {
- print_debug("Clearing memory: ");
- 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
-
- /* 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)
- );
- }
-
- /* 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");
+ if (!is_cpu_pre_c0()) {
+ /* Wait until it is safe to touch memory */
+ 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) );
}
+ print_debug(" done\r\n");
}
+
+ /* Make certain the first 1M of memory is intialized */
+ msr_t msr, msr_201;
+ uint32_t cnt;
+
+ /* Save the value of msr_201 */
+ msr_201 = rdmsr(0x201);
+
+ print_debug("Clearing LinuxBIOS memory: ");
+
+ /* disable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* Disable fixed mtrrs */
+ msr = rdmsr(MTRRdefType_MSR);
+ msr.lo &= ~(1<<10);
+ wrmsr(MTRRdefType_MSR, msr);
+
+
+ /* Set the variable mtrrs to write combine */
+ msr.hi = 0;
+ msr.lo = 0 | MTRR_TYPE_WRCOMB;
+ wrmsr(0x200, msr);
+
+ /* Set the limit to 1M of ram */
+ msr.hi = 0x000000ff;
+ msr.lo = (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800;
+ wrmsr(0x201, msr);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* clear memory 1meg */
+ __asm__ volatile(
+ "1: \n\t"
+ "movl %0, %%fs:(%1)\n\t"
+ "addl $4,%1\n\t"
+ "subl $4,%2\n\t"
+ "jnz 1b\n\t"
+ :
+ : "a" (0), "D" (0), "c" (1024*1024)
+ );
+
+ /* 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.hi = 0;
+ msr.lo = MTRR_TYPE_WRBACK;
+ wrmsr(0x200, msr);
+ wrmsr(0x201, msr_201);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ print_debug(" done\r\n");
}