summaryrefslogtreecommitdiff
path: root/src/northbridge
diff options
context:
space:
mode:
authorYinghai Lu <yinghailu@gmail.com>2005-07-08 02:49:49 +0000
committerYinghai Lu <yinghailu@gmail.com>2005-07-08 02:49:49 +0000
commit13f1c2af8be2cd7f7e99a678f5d428a65b771811 (patch)
tree27cad5581f1fa150f573149d48e82f70ba1b1d9f /src/northbridge
parent14cde9e96a777f9d75016a13b23fab0480515f58 (diff)
downloadcoreboot-13f1c2af8be2cd7f7e99a678f5d428a65b771811.tar.xz
eric patch
1. x86_setup_mtrr take address bit. 2. generic ht, pcix, pcie beidge... 3. scan bus and reset_bus 4. ht read ctrl to decide if the ht chain is ready 5. Intel e7520 and e7525 support 6. new ich5r support 7. intel sb 6300 support. yhlu patch 1. split x86_setup_mtrrs to fixed and var 2. if (resource->flags & IORESOURCE_FIXED ) return; in device.c pick_largest_resource 3. in_conherent.c K8_SCAN_PCI_BUS git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1982 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge')
-rw-r--r--src/northbridge/amd/amdk8/coherent_ht.c114
-rw-r--r--src/northbridge/amd/amdk8/debug.c32
-rw-r--r--src/northbridge/amd/amdk8/early_ht.c31
-rw-r--r--src/northbridge/amd/amdk8/incoherent_ht.c334
-rw-r--r--src/northbridge/amd/amdk8/misc_control.c5
-rw-r--r--src/northbridge/amd/amdk8/northbridge.c260
-rw-r--r--src/northbridge/amd/amdk8/setup_resource_map.c149
-rw-r--r--src/northbridge/intel/E7520/Config.lb12
-rw-r--r--src/northbridge/intel/E7520/chip.h7
-rw-r--r--src/northbridge/intel/E7520/e7520.h44
-rw-r--r--src/northbridge/intel/E7520/memory_initialized.c13
-rw-r--r--src/northbridge/intel/E7520/northbridge.c270
-rw-r--r--src/northbridge/intel/E7520/northbridge.h8
-rw-r--r--src/northbridge/intel/E7520/pciexp_porta.c62
-rw-r--r--src/northbridge/intel/E7520/pciexp_porta1.c41
-rw-r--r--src/northbridge/intel/E7520/pciexp_portb.c42
-rw-r--r--src/northbridge/intel/E7520/pciexp_portc.c41
-rw-r--r--src/northbridge/intel/E7520/raminit.c1333
-rw-r--r--src/northbridge/intel/E7520/raminit.h12
-rw-r--r--src/northbridge/intel/E7520/raminit_test.c442
-rw-r--r--src/northbridge/intel/E7525/Config.lb12
-rw-r--r--src/northbridge/intel/E7525/chip.h7
-rw-r--r--src/northbridge/intel/E7525/e7525.h44
-rw-r--r--src/northbridge/intel/E7525/memory_initialized.c9
-rw-r--r--src/northbridge/intel/E7525/northbridge.c270
-rw-r--r--src/northbridge/intel/E7525/northbridge.h8
-rw-r--r--src/northbridge/intel/E7525/pciexp_porta.c41
-rw-r--r--src/northbridge/intel/E7525/pciexp_porta1.c41
-rw-r--r--src/northbridge/intel/E7525/pciexp_portb.c41
-rw-r--r--src/northbridge/intel/E7525/pciexp_portc.c41
-rw-r--r--src/northbridge/intel/E7525/raminit.c1300
-rw-r--r--src/northbridge/intel/E7525/raminit.h12
-rw-r--r--src/northbridge/intel/E7525/raminit_test.c393
33 files changed, 5172 insertions, 299 deletions
diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c
index d7be557d37..c79a432ab5 100644
--- a/src/northbridge/amd/amdk8/coherent_ht.c
+++ b/src/northbridge/amd/amdk8/coherent_ht.c
@@ -145,15 +145,16 @@ static void disable_probes(void)
print_spew("Disabling read/write/fill probes for UP... ");
- val=pci_read_config32(NODE_HT(0), 0x68);
- val |= (1<<10)|(1<<9)|(1<<8)|(1<<4)|(1<<3)|(1<<2)|(1<<1)|(1 << 0);
- pci_write_config32(NODE_HT(0), 0x68, val);
+ val=pci_read_config32(NODE_HT(0), HT_TRANSACTION_CONTROL);
+ val |= HTTC_DIS_FILL_P | HTTC_DIS_RMT_MEM_C | HTTC_DIS_P_MEM_C |
+ HTTC_DIS_MTS | HTTC_DIS_WR_DW_P | HTTC_DIS_WR_B_P |
+ HTTC_DIS_RD_DW_P | HTTC_DIS_RD_B_P;
+ pci_write_config32(NODE_HT(0), HT_TRANSACTION_CONTROL, val);
print_spew("done.\r\n");
}
-
#ifndef ENABLE_APIC_EXT_ID
#define ENABLE_APIC_EXT_ID 0
#endif
@@ -163,7 +164,7 @@ static void enable_apic_ext_id(u8 node)
#if ENABLE_APIC_EXT_ID==1
#warning "FIXME Is the right place to enable apic ext id here?"
- u32 val;
+ u32 val;
val = pci_read_config32(NODE_HT(node), 0x68);
val |= (HTTC_APIC_EXT_SPUR | HTTC_APIC_EXT_ID | HTTC_APIC_EXT_BRD_CST);
@@ -171,8 +172,6 @@ static void enable_apic_ext_id(u8 node)
#endif
}
-
-
static void enable_routing(u8 node)
{
u32 val;
@@ -277,11 +276,11 @@ static void wait_ht_stable(uint8_t node)
}
#endif
-static int check_connection(u8 dest)
+static int verify_connection(u8 dest)
{
/* See if we have a valid connection to dest */
u32 val;
-
+
/* Verify that the coherent hypertransport link is
* established and actually working by reading the
* remode node's vendor/device id
@@ -289,10 +288,6 @@ static int check_connection(u8 dest)
val = pci_read_config32(NODE_HT(dest),0);
if(val != 0x11001022)
return 0;
-// needed?
-#if K8_HT_CHECK_PENDING_LINK == 1
- wait_ht_stable(dest);
-#endif
return 1;
}
@@ -306,11 +301,11 @@ static uint16_t read_freq_cap(device_t dev, uint8_t pos)
freq_cap = pci_read_config16(dev, pos);
freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */
-
- #if K8_HT_FREQ_1G_SUPPORT == 1
- if (!is_cpu_pre_e0())
+#if K8_HT_FREQ_1G_SUPPORT == 1
+ if (!is_cpu_pre_e0()) {
return freq_cap;
- #endif
+ }
+#endif
id = pci_read_config32(dev, 0);
@@ -726,8 +721,8 @@ static struct setup_smp_result setup_smp2(void)
print_linkn("(0,1) link=", byte);
setup_row_direct(0,1, byte);
setup_temp_row(0, 1);
-
- check_connection(7);
+
+ verify_connection(7);
/* We found 2 nodes so far */
val = pci_read_config32(NODE_HT(7), 0x6c);
@@ -751,8 +746,8 @@ static struct setup_smp_result setup_smp2(void)
print_linkn("\t-->(0,1) link=", byte);
setup_row_direct(0,1, byte);
setup_temp_row(0, 1);
-
- check_connection(7);
+
+ verify_connection(7);
/* We found 2 nodes so far */
val = pci_read_config32(NODE_HT(7), 0x6c);
@@ -832,7 +827,7 @@ static struct setup_smp_result setup_smp4(int needs_reset)
setup_row_indirect_group(conn4_1, sizeof(conn4_1)/sizeof(conn4_1[0]));
setup_temp_row(0,2);
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 0*/
print_linkn("(2,0) link=", byte);
@@ -846,7 +841,7 @@ static struct setup_smp_result setup_smp4(int needs_reset)
setup_temp_row(0,1);
setup_temp_row(1,3);
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 1*/
@@ -865,7 +860,7 @@ static struct setup_smp_result setup_smp4(int needs_reset)
setup_row_direct(2,3, byte & 0x3);
setup_temp_row(0,2);
setup_temp_row(2,3);
- check_connection(7); /* to 3*/
+ verify_connection(7); /* to 3*/
#if (CONFIG_MAX_PHYSICAL_CPUS > 4) || (CONFIG_MAX_PHYSICAL_CPUS_4_BUT_MORE_INSTALLED == 1)
/* We need to find out which link is to node3 */
@@ -878,7 +873,7 @@ static struct setup_smp_result setup_smp4(int needs_reset)
print_linkn("\t-->(2,3) link=", byte);
setup_row_direct(2,3,byte);
setup_temp_row(2,3);
- check_connection(7); /* to 3*/
+ verify_connection(7); /* to 3*/
}
}
#endif
@@ -1016,7 +1011,7 @@ static struct setup_smp_result setup_smp6(int needs_reset)
for(byte=0; byte<4; byte+=2) {
setup_temp_row(byte,byte+2);
}
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /*get default link on 7 to 2*/
print_linkn("(4,2) link=", byte);
@@ -1044,7 +1039,7 @@ static struct setup_smp_result setup_smp6(int needs_reset)
for(byte=0; byte<4; byte+=2) {
setup_temp_row(byte+1,byte+3);
}
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 3*/
@@ -1064,7 +1059,7 @@ static struct setup_smp_result setup_smp6(int needs_reset)
setup_temp_row(0,2);
setup_temp_row(2,4);
setup_temp_row(4,5);
- check_connection(7); /* to 5*/
+ verify_connection(7); /* to 5*/
#if CONFIG_MAX_PHYSICAL_CPUS > 6
/* We need to find out which link is to node5 */
@@ -1078,7 +1073,7 @@ static struct setup_smp_result setup_smp6(int needs_reset)
print_linkn("\t-->(4,5) link=", byte);
setup_row_direct(4,5,byte);
setup_temp_row(4,5);
- check_connection(7); /* to 5*/
+ verify_connection(7); /* to 5*/
}
}
#endif
@@ -1254,7 +1249,7 @@ static struct setup_smp_result setup_smp8(int needs_reset)
for(byte=0; byte<6; byte+=2) {
setup_temp_row(byte,byte+2);
}
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 4*/
print_linkn("(6,4) link=", byte);
@@ -1294,7 +1289,7 @@ static struct setup_smp_result setup_smp8(int needs_reset)
}
setup_temp_row(5,6);
- check_connection(7);
+ verify_connection(7);
val = get_row(7,6); // to chect it if it is node6 before renaming
if( (val>>16) == 1) { // it is real node 7 so swap it
@@ -1316,7 +1311,7 @@ static struct setup_smp_result setup_smp8(int needs_reset)
#endif
setup_temp_row(5,6);
- check_connection(7);
+ verify_connection(7);
}
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 5*/
@@ -1334,7 +1329,7 @@ static struct setup_smp_result setup_smp8(int needs_reset)
setup_temp_row(byte+1,byte+3);
}
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 5*/
@@ -1354,7 +1349,7 @@ static struct setup_smp_result setup_smp8(int needs_reset)
setup_temp_row(byte,byte+2);
}
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 4*/
@@ -1379,7 +1374,7 @@ static struct setup_smp_result setup_smp8(int needs_reset)
setup_temp_row(byte+1,byte+3);
}
- check_connection(7);
+ verify_connection(7);
val = pci_read_config32(NODE_HT(7), 0x6c);
byte = (val>>2) & 0x3; /* get default link on 7 to 5*/
@@ -1568,7 +1563,6 @@ static struct setup_smp_result setup_smp(void)
#endif
return result;
-
}
static unsigned verify_mp_capabilities(unsigned nodes)
@@ -1663,10 +1657,10 @@ static void coherent_ht_finalize(unsigned nodes)
#endif
/* set up cpu count and node count and enable Limit
- * Config Space Range for all available CPUs.
- * Also clear non coherent hypertransport bus range
- * registers on Hammer A0 revision.
- */
+ * Config Space Range for all available CPUs.
+ * Also clear non coherent hypertransport bus range
+ * registers on Hammer A0 revision.
+ */
print_spew("coherent_ht_finalize\r\n");
rev_a0 = is_cpu_rev_a0();
@@ -1686,21 +1680,19 @@ static void coherent_ht_finalize(unsigned nodes)
pci_write_config32(dev, 0x60, val);
/* Only respond to real cpu pci configuration cycles
- * and optimize the HT settings
- */
- val=pci_read_config32(dev, 0x68);
+ * and optimize the HT settings
+ */
+ val=pci_read_config32(dev, HT_TRANSACTION_CONTROL);
val &= ~((HTTC_BUF_REL_PRI_MASK << HTTC_BUF_REL_PRI_SHIFT) |
(HTTC_MED_PRI_BYP_CNT_MASK << HTTC_MED_PRI_BYP_CNT_SHIFT) |
(HTTC_HI_PRI_BYP_CNT_MASK << HTTC_HI_PRI_BYP_CNT_SHIFT));
val |= HTTC_LIMIT_CLDT_CFG |
(HTTC_BUF_REL_PRI_8 << HTTC_BUF_REL_PRI_SHIFT) |
- HTTC_RSP_PASS_PW |
(3 << HTTC_MED_PRI_BYP_CNT_SHIFT) |
(3 << HTTC_HI_PRI_BYP_CNT_SHIFT);
- pci_write_config32(dev, 0x68, val);
+ pci_write_config32(dev, HT_TRANSACTION_CONTROL, val);
if (rev_a0) {
- print_spew("shit it is an old cup\n");
pci_write_config32(dev, 0x94, 0);
pci_write_config32(dev, 0xb4, 0);
pci_write_config32(dev, 0xd4, 0);
@@ -1720,8 +1712,8 @@ static int apply_cpu_errata_fixes(unsigned nodes, int needs_reset)
if (is_cpu_pre_c0()) {
/* Errata 66
- * Limit the number of downstream posted requests to 1
- */
+ * Limit the number of downstream posted requests to 1
+ */
cmd = pci_read_config32(dev, 0x70);
if ((cmd & (3 << 0)) != 2) {
cmd &= ~(3<<0);
@@ -1745,12 +1737,12 @@ static int apply_cpu_errata_fixes(unsigned nodes, int needs_reset)
}
}
- else if(is_cpu_pre_d0()) { // d0 later don't need it
+ else if (is_cpu_pre_d0()) { // d0 later don't need it
uint32_t cmd_ref;
/* Errata 98
- * Set Clk Ramp Hystersis to 7
- * Clock Power/Timing Low
- */
+ * Set Clk Ramp Hystersis to 7
+ * Clock Power/Timing Low
+ */
cmd_ref = 0x04e20707; /* Registered */
cmd = pci_read_config32(dev, 0xd4);
if(cmd != cmd_ref) {
@@ -1778,7 +1770,10 @@ static int optimize_link_read_pointers(unsigned nodes, int needs_reset)
/* This works on an Athlon64 because unimplemented links return 0 */
reg = 0x98 + (link * 0x20);
link_type = pci_read_config32(f0_dev, reg);
- if ((link_type & 7) == 3) { /* only handle coherent link here*/
+ /* Only handle coherent links */
+ if ((link_type & (LinkConnected | InitComplete|NonCoherent)) ==
+ (LinkConnected|InitComplete))
+ {
cmd &= ~(0xff << (link *8));
cmd |= 0x25 << (link *8);
}
@@ -1794,6 +1789,8 @@ static int optimize_link_read_pointers(unsigned nodes, int needs_reset)
static int setup_coherent_ht_domain(void)
{
struct setup_smp_result result;
+ result.nodes = 1;
+ result.needs_reset = 0;
#if K8_HT_CHECK_PENDING_LINK == 1
//needed?
@@ -1802,17 +1799,14 @@ static int setup_coherent_ht_domain(void)
enable_bsp_routing();
#if CONFIG_MAX_PHYSICAL_CPUS > 1
- result = setup_smp();
- result.nodes = verify_mp_capabilities(result.nodes);
- clear_dead_routes(result.nodes);
-#else
- result.nodes = 1;
- result.needs_reset = 0;
+ result = setup_smp();
+ result.nodes = verify_mp_capabilities(result.nodes);
+ clear_dead_routes(result.nodes);
#endif
if (result.nodes == 1) {
setup_uniprocessor();
- }
+ }
coherent_ht_finalize(result.nodes);
result.needs_reset = apply_cpu_errata_fixes(result.nodes, result.needs_reset);
result.needs_reset = optimize_link_read_pointers(result.nodes, result.needs_reset);
diff --git a/src/northbridge/amd/amdk8/debug.c b/src/northbridge/amd/amdk8/debug.c
index 861ad8c38a..d0841e878e 100644
--- a/src/northbridge/amd/amdk8/debug.c
+++ b/src/northbridge/amd/amdk8/debug.c
@@ -5,12 +5,16 @@
#if 1
static void print_debug_pci_dev(unsigned dev)
{
+#if CONFIG_USE_INIT
+ printk_debug("PCI: %02x:%02x.%02x", (dev>>16) & 0xff, (dev>>11) & 0x1f, (dev>>8) & 0x7);
+#else
print_debug("PCI: ");
print_debug_hex8((dev >> 16) & 0xff);
print_debug_char(':');
print_debug_hex8((dev >> 11) & 0x1f);
print_debug_char('.');
print_debug_hex8((dev >> 8) & 7);
+#endif
}
static void print_pci_devices(void)
@@ -27,7 +31,19 @@ static void print_pci_devices(void)
continue;
}
print_debug_pci_dev(dev);
+#if CONFIG_USE_INIT
+ printk_debug(" %04x:%04x\r\n", (id & 0xffff), (id>>16));
+#else
+ print_debug_hex32(id);
print_debug("\r\n");
+#endif
+ if(((dev>>8) & 0x07) == 0) {
+ uint8_t hdr_type;
+ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+ if((hdr_type & 0x80) != 0x80) {
+ dev += PCI_DEV(0,0,7);
+ }
+ }
}
}
@@ -72,6 +88,14 @@ static void dump_pci_devices(void)
continue;
}
dump_pci_device(dev);
+
+ if(((dev>>8) & 0x07) == 0) {
+ uint8_t hdr_type;
+ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+ if((hdr_type & 0x80) != 0x80) {
+ dev += PCI_DEV(0,0,7);
+ }
+ }
}
}
@@ -89,6 +113,14 @@ static void dump_pci_devices_on_bus(unsigned busn)
continue;
}
dump_pci_device(dev);
+
+ if(((dev>>8) & 0x07) == 0) {
+ uint8_t hdr_type;
+ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+ if((hdr_type & 0x80) != 0x80) {
+ dev += PCI_DEV(0,0,7);
+ }
+ }
}
}
diff --git a/src/northbridge/amd/amdk8/early_ht.c b/src/northbridge/amd/amdk8/early_ht.c
index ab9d4592dd..2711657455 100644
--- a/src/northbridge/amd/amdk8/early_ht.c
+++ b/src/northbridge/amd/amdk8/early_ht.c
@@ -17,8 +17,9 @@ static int enumerate_ht_chain(void)
id = pci_read_config32(PCI_DEV(0,0,0), PCI_VENDOR_ID);
/* If the chain is enumerated quit */
if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0x0000)) {
+ (((id >> 16) & 0xffff) == 0xffff) ||
+ (((id >> 16) & 0xffff) == 0x0000))
+ {
break;
}
@@ -35,7 +36,8 @@ static int enumerate_ht_chain(void)
hdr_type &= 0x7f;
if ((hdr_type == PCI_HEADER_TYPE_NORMAL) ||
- (hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
+ (hdr_type == PCI_HEADER_TYPE_BRIDGE))
+ {
pos = pci_read_config8(PCI_DEV(0,0,0), PCI_CAPABILITY_LIST);
}
while(pos != 0) {
@@ -43,24 +45,39 @@ static int enumerate_ht_chain(void)
cap = pci_read_config8(PCI_DEV(0,0,0), pos + PCI_CAP_LIST_ID);
if (cap == PCI_CAP_ID_HT) {
uint16_t flags;
+ /* Read and write and reread flags so the link
+ * direction bit is valid.
+ */
+ flags = pci_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS);
+ pci_write_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS, flags);
flags = pci_read_config16(PCI_DEV(0,0,0), pos + PCI_CAP_FLAGS);
if ((flags >> 13) == 0) {
unsigned count;
+ unsigned ctrl, ctrl_off;
flags &= ~0x1f;
flags |= next_unitid & 0x1f;
count = (flags >> 5) & 0x1f;
+ next_unitid += count;
+
+ /* Test for end of chain */
+ ctrl_off = ((flags >> 10) & 1)?
+ PCI_HT_CAP_SLAVE_CTRL1 : PCI_HT_CAP_SLAVE_CTRL0;
+ ctrl = pci_read_config16(PCI_DEV(0,0,0), pos + ctrl_off);
+ /* Is this the end of the hypertransport chain.
+ * or has the link failed?
+ */
+ if (ctrl & ((1 << 6)|(1 << 4))) {
+ next_unitid = 0x20;
+ }
pci_write_config16(PCI_DEV(0, 0, 0), pos + PCI_CAP_FLAGS, flags);
-
- next_unitid += count;
break;
}
}
pos = pci_read_config8(PCI_DEV(0, 0, 0), pos + PCI_CAP_LIST_NEXT);
}
- } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
-
+ } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
return reset_needed;
}
diff --git a/src/northbridge/amd/amdk8/incoherent_ht.c b/src/northbridge/amd/amdk8/incoherent_ht.c
index 7bb315d687..d4271efbda 100644
--- a/src/northbridge/amd/amdk8/incoherent_ht.c
+++ b/src/northbridge/amd/amdk8/incoherent_ht.c
@@ -10,6 +10,10 @@
#define K8_HT_FREQ_1G_SUPPORT 0
#endif
+#ifndef K8_SCAN_PCI_BUS
+ #define K8_SCAN_PCI_BUS 0
+#endif
+
static inline void print_linkn_in (const char *strval, uint8_t byteval)
{
#if 1
@@ -21,7 +25,7 @@ static inline void print_linkn_in (const char *strval, uint8_t byteval)
#endif
}
-static uint8_t ht_lookup_slave_capability(device_t dev)
+static uint8_t ht_lookup_capability(device_t dev, uint16_t val)
{
uint8_t pos;
uint8_t hdr_type;
@@ -44,8 +48,8 @@ static uint8_t ht_lookup_slave_capability(device_t dev)
uint16_t flags;
flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
- if ((flags >> 13) == 0) {
- /* Entry is a Slave secondary, success... */
+ if ((flags >> 13) == val) {
+ /* Entry is a slave or host , success... */
break;
}
}
@@ -54,6 +58,16 @@ static uint8_t ht_lookup_slave_capability(device_t dev)
return pos;
}
+static uint8_t ht_lookup_slave_capability(device_t dev)
+{
+ return ht_lookup_capability(dev, 0); // Slave/Primary Interface Block Format
+}
+
+static uint8_t ht_lookup_host_capability(device_t dev)
+{
+ return ht_lookup_capability(dev, 1); // Host/Secondary Interface Block Format
+}
+
static void ht_collapse_previous_enumeration(uint8_t bus)
{
device_t dev;
@@ -135,25 +149,28 @@ static uint16_t ht_read_freq_cap(device_t dev, uint8_t pos)
return freq_cap;
}
+#define LINK_OFFS(CTRL, WIDTH,FREQ,FREQ_CAP) \
+ (((CTRL & 0xff) << 24) | ((WIDTH & 0xff) << 16) | ((FREQ & 0xff) << 8) | (FREQ_CAP & 0xFF))
-#define LINK_OFFS(WIDTH,FREQ,FREQ_CAP) \
- (((WIDTH & 0xff) << 16) | ((FREQ & 0xff) << 8) | (FREQ_CAP & 0xFF))
-
+#define LINK_CTRL(OFFS) ((OFFS >> 24) & 0xFF)
#define LINK_WIDTH(OFFS) ((OFFS >> 16) & 0xFF)
#define LINK_FREQ(OFFS) ((OFFS >> 8) & 0xFF)
#define LINK_FREQ_CAP(OFFS) ((OFFS) & 0xFF)
#define PCI_HT_HOST_OFFS LINK_OFFS( \
+ PCI_HT_CAP_HOST_CTRL, \
PCI_HT_CAP_HOST_WIDTH, \
PCI_HT_CAP_HOST_FREQ, \
PCI_HT_CAP_HOST_FREQ_CAP)
#define PCI_HT_SLAVE0_OFFS LINK_OFFS( \
+ PCI_HT_CAP_SLAVE_CTRL0, \
PCI_HT_CAP_SLAVE_WIDTH0, \
PCI_HT_CAP_SLAVE_FREQ0, \
PCI_HT_CAP_SLAVE_FREQ_CAP0)
#define PCI_HT_SLAVE1_OFFS LINK_OFFS( \
+ PCI_HT_CAP_SLAVE_CTRL1, \
PCI_HT_CAP_SLAVE_WIDTH1, \
PCI_HT_CAP_SLAVE_FREQ1, \
PCI_HT_CAP_SLAVE_FREQ_CAP1)
@@ -164,8 +181,8 @@ static int ht_optimize_link(
{
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, old_width, ln_width1, ln_width2;
+ uint16_t freq_cap1, freq_cap2;
+ uint8_t width_cap1, width_cap2, width, old_width, ln_width1, ln_width2;
uint8_t freq, old_freq;
int needs_reset;
/* Set link width and frequency */
@@ -228,94 +245,123 @@ static int ht_optimize_link(
return needs_reset;
}
-static int ht_setup_chain(device_t udev, uint8_t upos)
+#if (USE_DCACHE_RAM == 1) && (K8_SCAN_PCI_BUS == 1)
+static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus);
+static int scan_pci_bus( unsigned bus)
{
- /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
- * On most boards this just happens. If a cpu has multiple
- * non Coherent links the appropriate bus registers for the
- * links needs to be programed to point at bus 0.
- */
- uint8_t next_unitid, last_unitid;
- int reset_needed;
- unsigned uoffs;
-
- /* Make certain the HT bus is not enumerated */
- ht_collapse_previous_enumeration(0);
+ /*
+ here we already can access PCI_DEV(bus, 0, 0) to PCI_DEV(bus, 0x1f, 0x7)
+ So We can scan these devices to find out if they are bridge
+ If it is pci bridge, We need to set busn in bridge, and go on
+ For ht bridge, We need to set the busn in bridge and ht_setup_chainx, and the scan_pci_bus
+ */
+ unsigned int devfn;
+ unsigned new_bus;
+ unsigned max_bus;
+
+ new_bus = (bus & 0xff); // mask out the reset_needed
+
+ if(new_bus<0x40) {
+ max_bus = 0x3f;
+ } else if (new_bus<0x80) {
+ max_bus = 0x7f;
+ } else if (new_bus<0xc0) {
+ max_bus = 0xbf;
+ } else {
+ max_bus = 0xff;
+ }
- reset_needed = 0;
- uoffs = PCI_HT_HOST_OFFS;
- next_unitid = 1;
- do {
- uint32_t id;
- uint8_t pos;
- uint16_t flags;
- uint8_t count;
- unsigned offs;
+ new_bus = bus;
- device_t dev = PCI_DEV(0, 0, 0);
- last_unitid = next_unitid;
+#if 0
+#if CONFIG_USE_INIT == 1
+ printk_debug("bus_num=%02x\r\n", bus);
+#endif
+#endif
- id = pci_read_config32(dev, PCI_VENDOR_ID);
- /* If the chain is enumerated quit */
- if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0x0000)) {
- break;
- }
+ for (devfn = 0; devfn <= 0xff; devfn++) {
+ uint8_t hdr_type;
+ uint16_t class;
+ uint32_t buses;
+ device_t dev;
+ uint16_t cr;
+ dev = PCI_DEV((bus & 0xff), ((devfn>>3) & 0x1f), (devfn & 0x7));
+ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+ class = pci_read_config16(dev, PCI_CLASS_DEVICE);
- pos = ht_lookup_slave_capability(dev);
- if (!pos) {
- print_err("HT link capability not found\r\n");
- break;
+#if 0
+#if CONFIG_USE_INIT == 1
+ if(hdr_type !=0xff ) {
+ printk_debug("dev=%02x fn=%02x hdr_type=%02x class=%04x\r\n",
+ (devfn>>3)& 0x1f, (devfn & 0x7), hdr_type, class);
}
-#if CK804_DEVN_BASE==0
- //CK804 workaround:
- // CK804 UnitID changes not use
- id = pci_read_config32(dev, PCI_VENDOR_ID);
- if(id != 0x005e10de) {
#endif
-
- /* Update the Unitid of the current device */
- flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
- flags &= ~0x1f; /* mask out the bse Unit ID */
- flags |= next_unitid & 0x1f;
- pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
-
- dev = PCI_DEV(0, next_unitid, 0);
-#if CK804_DEVN_BASE==0
- }
- else {
- dev = PCI_DEV(0, 0, 0);
- }
#endif
-
- /* Compute the number of unitids consumed */
- count = (flags >> 5) & 0x1f;
- next_unitid += count;
-
- /* get ht direction */
- flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); // double read ??
-
- offs = ((flags>>10) & 1) ? PCI_HT_SLAVE1_OFFS : PCI_HT_SLAVE0_OFFS;
-
- /* Setup the Hypertransport link */
- reset_needed |= ht_optimize_link(udev, upos, uoffs, dev, pos, offs);
-
-#if CK804_DEVN_BASE==0
- if(id == 0x005e10de) {
- break;
+ switch(hdr_type & 0x7f) { /* header type */
+ case PCI_HEADER_TYPE_BRIDGE:
+ if (class != PCI_CLASS_BRIDGE_PCI) goto bad;
+ /* set the bus range dev */
+
+ /* Clear all status bits and turn off memory, I/O and master enables. */
+ cr = pci_read_config16(dev, PCI_COMMAND);
+ pci_write_config16(dev, PCI_COMMAND, 0x0000);
+ pci_write_config16(dev, PCI_STATUS, 0xffff);
+
+ buses = pci_read_config32(dev, PCI_PRIMARY_BUS);
+
+ buses &= 0xff000000;
+ new_bus++;
+ buses |= (((unsigned int) (bus & 0xff) << 0) |
+ ((unsigned int) (new_bus & 0xff) << 8) |
+ ((unsigned int) max_bus << 16));
+ pci_write_config32(dev, PCI_PRIMARY_BUS, buses);
+
+ {
+ /* here we need to figure out if dev is a ht bridge
+ if it is ht bridge, we need to call ht_setup_chainx at first
+ Not verified --- yhlu
+ */
+ uint8_t upos;
+ upos = ht_lookup_host_capability(dev); // one func one ht sub
+ if (upos) { // sub ht chain
+ uint8_t busn;
+ busn = (new_bus & 0xff);
+ /* Make certain the HT bus is not enumerated */
+ ht_collapse_previous_enumeration(busn);
+ /* scan the ht chain */
+ new_bus |= (ht_setup_chainx(dev,upos,busn)<<16); // store reset_needed to upword
+ }
+ }
+
+ new_bus = scan_pci_bus(new_bus);
+ /* set real max bus num in that */
+
+ buses = (buses & 0xff00ffff) |
+ ((unsigned int) (new_bus & 0xff) << 16);
+ pci_write_config32(dev, PCI_PRIMARY_BUS, buses);
+
+ pci_write_config16(dev, PCI_COMMAND, cr);
+
+ break;
+ default:
+ bad:
+ ;
+ }
+
+ /* if this is not a multi function device,
+ * or the device is not present don't waste
+ * time probing another function.
+ * Skip to next device.
+ */
+ if ( ((devfn & 0x07) == 0x00) && ((hdr_type & 0x80) != 0x80))
+ {
+ devfn += 0x07;
}
-#endif
-
- /* Remeber the location of the last device */
- udev = dev;
- upos = pos;
- uoffs = (offs != PCI_HT_SLAVE0_OFFS) ? PCI_HT_SLAVE0_OFFS : PCI_HT_SLAVE1_OFFS;
-
- } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
- return reset_needed;
+ }
+
+ return new_bus;
}
-
+#endif
static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
{
uint8_t next_unitid, last_unitid;
@@ -328,25 +374,38 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
do {
uint32_t id;
uint8_t pos;
- uint16_t flags;
+ uint16_t flags, ctrl;
uint8_t count;
unsigned offs;
-
+
+ /* Wait until the link initialization is complete */
+ do {
+ ctrl = pci_read_config16(udev, upos + LINK_CTRL(uoffs));
+ /* Is this the end of the hypertransport chain? */
+ if (ctrl & (1 << 6)) {
+ break;
+ }
+ /* Has the link failed */
+ if (ctrl & (1 << 4)) {
+ break;
+ }
+ } while((ctrl & (1 << 5)) == 0);
+
device_t dev = PCI_DEV(bus, 0, 0);
last_unitid = next_unitid;
id = pci_read_config32(dev, PCI_VENDOR_ID);
/* If the chain is enumerated quit */
- if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0x0000)) {
+ if ( (id == 0xffffffff) || (id == 0x00000000) ||
+ (id == 0x0000ffff) || (id == 0xffff0000))
+ {
break;
}
pos = ht_lookup_slave_capability(dev);
if (!pos) {
- print_err(" HT link capability not found\r\n");
+ print_err("HT link capability not found\r\n");
break;
}
@@ -363,6 +422,7 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
flags |= next_unitid & 0x1f;
pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
+ /* Note the change in device number */
dev = PCI_DEV(bus, next_unitid, 0);
#if CK804_DEVN_BASE==0
}
@@ -375,9 +435,11 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
count = (flags >> 5) & 0x1f;
next_unitid += count;
- /* get ht direction */
- flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS); // double read ??
-
+ /* Find which side of the ht link we are on,
+ * by reading which direction our last write to PCI_CAP_FLAGS
+ * came from.
+ */
+ flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
offs = ((flags>>10) & 1) ? PCI_HT_SLAVE1_OFFS : PCI_HT_SLAVE0_OFFS;
/* Setup the Hypertransport link */
@@ -395,9 +457,23 @@ static int ht_setup_chainx(device_t udev, uint8_t upos, uint8_t bus)
uoffs = ( offs != PCI_HT_SLAVE0_OFFS ) ? PCI_HT_SLAVE0_OFFS : PCI_HT_SLAVE1_OFFS;
} while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
+
return reset_needed;
}
+static int ht_setup_chain(device_t udev, unsigned upos)
+{
+ /* Assumption the HT chain that is bus 0 has the HT I/O Hub on it.
+ * On most boards this just happens. If a cpu has multiple
+ * non Coherent links the appropriate bus registers for the
+ * links needs to be programed to point at bus 0.
+ */
+
+ /* Make certain the HT bus is not enumerated */
+ ht_collapse_previous_enumeration(0);
+
+ return ht_setup_chainx(udev, upos, 0);
+}
static int optimize_link_read_pointer(uint8_t node, uint8_t linkn, uint8_t linkt, uint8_t val)
{
uint32_t dword, dword_old;
@@ -444,7 +520,7 @@ static int optimize_link_in_coherent(uint8_t ht_c_num)
reg = pci_read_config32( PCI_DEV(busn, 1, 0), PCI_VENDOR_ID);
if ( (reg & 0xffff) == PCI_VENDOR_ID_AMD) {
val = 0x25;
- } else if ( (reg & 0xffff) == 0x10de ) {
+ } else if ( (reg & 0xffff) == PCI_VENDOR_ID_NVIDIA ) {
val = 0x25;//???
} else {
continue;
@@ -477,6 +553,9 @@ static int ht_setup_chains(uint8_t ht_c_num)
unsigned regpos;
uint32_t dword;
uint8_t busn;
+ #if (USE_DCACHE_RAM == 1) && (K8_SCAN_PCI_BUS == 1)
+ unsigned bus;
+ #endif
reg = pci_read_config32(PCI_DEV(0,0x18,1), 0xe0 + i * 4);
@@ -498,7 +577,11 @@ static int ht_setup_chains(uint8_t ht_c_num)
reset_needed |= ht_setup_chainx(udev,upos,busn);
-
+ #if (USE_DCACHE_RAM == 1) && (K8_SCAN_PCI_BUS == 1)
+ /* You can use use this in romcc, because there is function call in romcc, recursive will kill you */
+ bus = busn; // we need 32 bit
+ reset_needed |= (scan_pci_bus(bus)>>16); // take out reset_needed that stored in upword
+ #endif
}
reset_needed |= optimize_link_in_coherent(ht_c_num);
@@ -506,6 +589,10 @@ static int ht_setup_chains(uint8_t ht_c_num)
return reset_needed;
}
+#ifndef K8_ALLOCATE_IO_RANGE
+ #define K8_ALLOCATE_IO_RANGE 0
+#endif
+
static int ht_setup_chains_x(void)
{
uint8_t nodeid;
@@ -514,18 +601,34 @@ static int ht_setup_chains_x(void)
uint8_t next_busn;
uint8_t ht_c_num;
uint8_t nodes;
+#if K8_ALLOCATE_IO_RANGE == 1
+ unsigned next_io_base;
+#endif
/* read PCI_DEV(0,0x18,0) 0x64 bit [8:9] to find out SbLink m */
reg = pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64);
- /* update PCI_DEV(0, 0x18, 1) 0xe0 to 0x05000m03, and next_busn=5+1 */
+ /* update PCI_DEV(0, 0x18, 1) 0xe0 to 0x05000m03, and next_busn=0x3f+1 */
print_linkn_in("SBLink=", ((reg>>8) & 3) );
- tempreg = 3 | ( 0<<4) | (((reg>>8) & 3)<<8) | (0<<16)| (5<<24);
+ tempreg = 3 | ( 0<<4) | (((reg>>8) & 3)<<8) | (0<<16)| (0x3f<<24);
pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0, tempreg);
- next_busn=5+1; /* 0 will be used ht chain with SB we need to keep SB in bus0 in auto stage*/
+ next_busn=0x3f+1; /* 0 will be used ht chain with SB we need to keep SB in bus0 in auto stage*/
+
+#if K8_ALLOCATE_IO_RANGE == 1
+ /* io range allocation */
+ tempreg = 0 | (((reg>>8) & 0x3) << 4 )| (0x3<<12); //limit
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC4, tempreg);
+ tempreg = 3 | ( 3<<4) | (0<<12); //base
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC0, tempreg);
+ next_io_base = 0x3+0x1;
+#endif
+
/* clean others */
for(ht_c_num=1;ht_c_num<4; ht_c_num++) {
pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4, 0);
+ /* io range allocation */
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xc4 + ht_c_num * 8, 0);
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xc0 + ht_c_num * 8, 0);
}
nodes = ((pci_read_config32(PCI_DEV(0, 0x18, 0), 0x60)>>4) & 7) + 1;
@@ -548,13 +651,23 @@ static int ht_setup_chains_x(void)
break;
}
}
- if(ht_c_num == 4) break; /*used up onle 4 non conherent allowed*/
+ if(ht_c_num == 4) break; /*used up only 4 non conherent allowed*/
/*update to 0xe0...*/
if((reg & 0xf) == 3) continue; /*SbLink so don't touch it */
print_linkn_in("\tbusn=", next_busn);
- tempreg |= (next_busn<<16)|((next_busn+5)<<24);
+ tempreg |= (next_busn<<16)|((next_busn+0x3f)<<24);
pci_write_config32(PCI_DEV(0, 0x18, 1), 0xe0 + ht_c_num * 4, tempreg);
- next_busn+=5+1;
+ next_busn+=0x3f+1;
+
+#if K8_ALLOCATE_IO_RANGE == 1
+ /* io range allocation */
+ tempreg = nodeid | (linkn<<4) | ((next_io_base+0x3)<<12); //limit
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC4 + ht_c_num * 8, tempreg);
+ tempreg = 3 | ( 3<<4) | (next_io_base<<12); //base
+ pci_write_config32(PCI_DEV(0, 0x18, 1), 0xC0 + ht_c_num * 8, tempreg);
+ next_io_base += 0x3+0x1;
+#endif
+
}
}
/*update 0xe0, 0xe4, 0xe8, 0xec from PCI_DEV(0, 0x18,1) to PCI_DEV(0, 0x19,1) to PCI_DEV(0, 0x1f,1);*/
@@ -568,8 +681,23 @@ static int ht_setup_chains_x(void)
regpos = 0xe0 + i * 4;
reg = pci_read_config32(PCI_DEV(0, 0x18, 1), regpos);
pci_write_config32(dev, regpos, reg);
+ }
+#if K8_ALLOCATE_IO_RANGE == 1
+ /* io range allocation */
+ for(i = 0; i< 4; i++) {
+ unsigned regpos;
+ regpos = 0xc4 + i * 8;
+ reg = pci_read_config32(PCI_DEV(0, 0x18, 1), regpos);
+ pci_write_config32(dev, regpos, reg);
}
+ for(i = 0; i< 4; i++) {
+ unsigned regpos;
+ regpos = 0xc0 + i * 8;
+ reg = pci_read_config32(PCI_DEV(0, 0x18, 1), regpos);
+ pci_write_config32(dev, regpos, reg);
+ }
+#endif
}
/* recount ht_c_num*/
diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c
index 4ac6ef473d..4cd3d0d42d 100644
--- a/src/northbridge/amd/amdk8/misc_control.c
+++ b/src/northbridge/amd/amdk8/misc_control.c
@@ -187,7 +187,10 @@ static void misc_control_init(struct device *dev)
/* This works on an Athlon64 because unimplemented links return 0 */
reg = 0x98 + (link * 0x20);
link_type = pci_read_config32(f0_dev, reg);
- if ((link_type & 7) == 3) { /* Only handle coherent link here */
+ /* Only handle coherent link here please */
+ if ((link_type & (LinkConnected|InitComplete|NonCoherent))
+ == (LinkConnected|InitComplete))
+ {
cmd &= ~(0xff << (link *8));
/* FIXME this assumes the device on the other side is an AMD device */
cmd |= 0x25 << (link *8);
diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c
index 89602f37a6..e45aff8242 100644
--- a/src/northbridge/amd/amdk8/northbridge.c
+++ b/src/northbridge/amd/amdk8/northbridge.c
@@ -40,7 +40,7 @@ static device_t __f1_dev[FX_DEVS];
static void debug_fx_devs(void)
{
int i;
- for (i = 0; i < FX_DEVS; i++) {
+ for(i = 0; i < FX_DEVS; i++) {
device_t dev;
dev = __f0_dev[i];
if (dev) {
@@ -62,7 +62,7 @@ static void get_fx_devs(void)
if (__f1_dev[0]) {
return;
}
- for (i = 0; i < FX_DEVS; i++) {
+ for(i = 0; i < FX_DEVS; i++) {
__f0_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 0));
__f1_dev[i] = dev_find_slot(0, PCI_DEVFN(0x18 + i, 1));
}
@@ -81,7 +81,7 @@ static void f1_write_config32(unsigned reg, uint32_t value)
{
int i;
get_fx_devs();
- for (i = 0; i < FX_DEVS; i++) {
+ for(i = 0; i < FX_DEVS; i++) {
device_t dev;
dev = __f1_dev[i];
if (dev && dev->enabled) {
@@ -102,9 +102,9 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
nodeid = amdk8_nodeid(dev);
#if 0
printk_debug("%s amdk8_scan_chains max: %d starting...\n",
- dev_path(dev), max);
+ dev_path(dev), max);
#endif
- for (link = 0; link < dev->links; link++) {
+ for(link = 0; link < dev->links; link++) {
uint32_t link_type;
uint32_t busses, config_busses;
unsigned free_reg, config_reg;
@@ -122,9 +122,10 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
continue;
}
/* See if there is an available configuration space mapping
- * register in function 1. */
+ * register in function 1.
+ */
free_reg = 0;
- for (config_reg = 0xe0; config_reg <= 0xec; config_reg += 4) {
+ for(config_reg = 0xe0; config_reg <= 0xec; config_reg += 4) {
uint32_t config;
config = f1_read_config32(config_reg);
if (!free_reg && ((config & 3) == 0)) {
@@ -132,8 +133,8 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
continue;
}
if (((config & 3) == 3) &&
- (((config >> 4) & 7) == nodeid) &&
- (((config >> 8) & 3) == link)) {
+ (((config >> 4) & 7) == nodeid) &&
+ (((config >> 8) & 3) == link)) {
break;
}
}
@@ -141,7 +142,8 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
config_reg = free_reg;
}
/* If we can't find an available configuration space mapping
- * register skip this bus */
+ * register skip this bus
+ */
if (config_reg > 0xec) {
continue;
}
@@ -158,15 +160,15 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
*/
busses = pci_read_config32(dev, dev->link[link].cap + 0x14);
config_busses = f1_read_config32(config_reg);
-
+
/* Configure the bus numbers for this bridge: the configuration
* transactions will not be propagates by the bridge if it is
* not correctly configured
*/
busses &= 0xff000000;
busses |= (((unsigned int)(dev->bus->secondary) << 0) |
- ((unsigned int)(dev->link[link].secondary) << 8) |
- ((unsigned int)(dev->link[link].subordinate) << 16));
+ ((unsigned int)(dev->link[link].secondary) << 8) |
+ ((unsigned int)(dev->link[link].subordinate) << 16));
pci_write_config32(dev, dev->link[link].cap + 0x14, busses);
config_busses &= 0x000fc88;
@@ -183,13 +185,14 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
dev_path(dev), link, max);
#endif
/* Now we can scan all of the subordinate busses i.e. the
- * chain on the hypertranport link */
- max = hypertransport_scan_chain(&dev->link[link], max);
+ * chain on the hypertranport link
+ */
+ max = hypertransport_scan_chain(&dev->link[link], 0, 0xbf, max);
#if 0
printk_debug("%s Hyper transport scan link: %d new max: %d\n",
dev_path(dev), link, max);
-#endif
+#endif
/* We know the number of busses behind this bridge. Set the
* subordinate bus number to it's real value
@@ -202,6 +205,7 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
config_busses = (config_busses & 0x00ffffff) |
(dev->link[link].subordinate << 24);
f1_write_config32(config_reg, config_busses);
+
#if 0
printk_debug("%s Hypertransport scan link: %d done\n",
dev_path(dev), link);
@@ -214,32 +218,34 @@ static unsigned int amdk8_scan_chains(device_t dev, unsigned int max)
return max;
}
-static int reg_useable(unsigned reg, device_t goal_dev, unsigned goal_nodeid,
- unsigned goal_link)
+static int reg_useable(unsigned reg,
+ device_t goal_dev, unsigned goal_nodeid, unsigned goal_link)
{
struct resource *res;
unsigned nodeid, link;
int result;
res = 0;
- for (nodeid = 0; !res && (nodeid < 8); nodeid++) {
+ for(nodeid = 0; !res && (nodeid < 8); nodeid++) {
device_t dev;
dev = __f0_dev[nodeid];
- for (link = 0; !res && (link < 3); link++) {
+ for(link = 0; !res && (link < 3); link++) {
res = probe_resource(dev, 0x100 + (reg | link));
}
}
result = 2;
if (res) {
result = 0;
- if ((goal_link == (link - 1)) &&
- (goal_nodeid == (nodeid - 1)) &&
- (res->flags <= 1)) {
+ if ( (goal_link == (link - 1)) &&
+ (goal_nodeid == (nodeid - 1)) &&
+ (res->flags <= 1)) {
result = 1;
}
}
#if 0
printk_debug("reg: %02x result: %d gnodeid: %u glink: %u nodeid: %u link: %u\n",
- reg, result, goal_nodeid, goal_link, nodeid, link);
+ reg, result,
+ goal_nodeid, goal_link,
+ nodeid, link);
#endif
return result;
}
@@ -250,7 +256,7 @@ static struct resource *amdk8_find_iopair(device_t dev, unsigned nodeid, unsigne
unsigned free_reg, reg;
resource = 0;
free_reg = 0;
- for (reg = 0xc0; reg <= 0xd8; reg += 0x8) {
+ for(reg = 0xc0; reg <= 0xd8; reg += 0x8) {
int result;
result = reg_useable(reg, dev, nodeid, link);
if (result == 1) {
@@ -277,7 +283,7 @@ static struct resource *amdk8_find_mempair(device_t dev, unsigned nodeid, unsign
unsigned free_reg, reg;
resource = 0;
free_reg = 0;
- for (reg = 0x80; reg <= 0xb8; reg += 0x8) {
+ for(reg = 0x80; reg <= 0xb8; reg += 0x8) {
int result;
result = reg_useable(reg, dev, nodeid, link);
if (result == 1) {
@@ -348,7 +354,7 @@ static void amdk8_read_resources(device_t dev)
{
unsigned nodeid, link;
nodeid = amdk8_nodeid(dev);
- for (link = 0; link < dev->links; link++) {
+ for(link = 0; link < dev->links; link++) {
if (dev->link[link].children) {
amdk8_link_read_bases(dev, nodeid, link);
}
@@ -499,11 +505,11 @@ static void amdk8_set_resources(device_t dev)
amdk8_create_vga_resource(dev, nodeid);
/* Set each resource we have found */
- for (i = 0; i < dev->resources; i++) {
+ for(i = 0; i < dev->resources; i++) {
amdk8_set_resource(dev, &dev->resource[i], nodeid);
}
- for (link = 0; link < dev->links; link++) {
+ for(link = 0; link < dev->links; link++) {
struct bus *bus;
bus = &dev->link[link];
if (bus->children) {
@@ -520,26 +526,9 @@ static void amdk8_enable_resources(device_t dev)
static void mcf0_control_init(struct device *dev)
{
- uint32_t cmd;
-
#if 0
printk_debug("NB: Function 0 Misc Control.. ");
#endif
-#if 1
- /* improve latency and bandwith on HT */
- cmd = pci_read_config32(dev, 0x68);
- cmd &= 0xffff80ff;
- cmd |= 0x00004800;
- pci_write_config32(dev, 0x68, cmd );
-#endif
-
-#if 0
- /* over drive the ht port to 1000 Mhz */
- cmd = pci_read_config32(dev, 0xa8);
- cmd &= 0xfffff0ff;
- cmd |= 0x00000600;
- pci_write_config32(dev, 0xdc, cmd );
-#endif
#if 0
printk_debug("done.\n");
#endif
@@ -578,7 +567,7 @@ static void pci_domain_read_resources(device_t dev)
/* Find the already assigned resource pairs */
get_fx_devs();
- for (reg = 0x80; reg <= 0xd8; reg+= 0x08) {
+ for(reg = 0x80; reg <= 0xd8; reg+= 0x08) {
uint32_t base, limit;
base = f1_read_config32(reg);
limit = f1_read_config32(reg + 0x04);
@@ -612,8 +601,8 @@ static void pci_domain_read_resources(device_t dev)
resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
}
-static void ram_resource(device_t dev, unsigned long index,
- unsigned long basek, unsigned long sizek)
+static void ram_resource(device_t dev, unsigned long index,
+ unsigned long basek, unsigned long sizek)
{
struct resource *resource;
@@ -691,7 +680,7 @@ static void pci_domain_set_resources(device_t dev)
#endif
idx = 10;
- for (i = 0; i < 8; i++) {
+ for(i = 0; i < 8; i++) {
uint32_t base, limit;
unsigned basek, limitk, sizek;
base = f1_read_config32(0x40 + (i << 3));
@@ -737,11 +726,35 @@ static void pci_domain_set_resources(device_t dev)
static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
{
unsigned reg;
+ int i;
/* Unmap all of the HT chains */
- for (reg = 0xe0; reg <= 0xec; reg += 4) {
+ for(reg = 0xe0; reg <= 0xec; reg += 4) {
f1_write_config32(reg, 0);
}
max = pci_scan_bus(&dev->link[0], PCI_DEVFN(0x18, 0), 0xff, max);
+
+ /* Tune the hypertransport transaction for best performance.
+ * Including enabling relaxed ordering if it is safe.
+ */
+ get_fx_devs();
+ for(i = 0; i < FX_DEVS; i++) {
+ device_t f0_dev;
+ f0_dev = __f0_dev[i];
+ if (f0_dev && f0_dev->enabled) {
+ uint32_t httc;
+ int j;
+ httc = pci_read_config32(f0_dev, HT_TRANSACTION_CONTROL);
+ httc &= ~HTTC_RSP_PASS_PW;
+ if (!dev->link[0].disable_relaxed_ordering) {
+ httc |= HTTC_RSP_PASS_PW;
+ }
+ printk_spew("%s passpw: %s\n",
+ dev_path(dev),
+ (!dev->link[0].disable_relaxed_ordering)?
+ "enabled":"disabled");
+ pci_write_config32(f0_dev, HT_TRANSACTION_CONTROL, httc);
+ }
+ }
return max;
}
@@ -755,20 +768,34 @@ static struct device_operations pci_domain_ops = {
};
#define APIC_ID_OFFSET 0x10
+
static unsigned int cpu_bus_scan(device_t dev, unsigned int max)
{
struct bus *cpu_bus;
device_t dev_mc;
+ int bsp_apic_id;
+ int apic_id_offset;
int i,j;
- unsigned nb_cfg_54 = 0;
- unsigned siblings = 0;
- int enable_apic_ext_id = 0;
- int bsp_apic_id = lapicid(); // bsp apicid
- int apic_id_offset = bsp_apic_id;
+ unsigned nb_cfg_54;
+ int enable_apic_ext_id;
+ unsigned siblings;
+#if CONFIG_LOGICAL_CPUS == 1
+ int e0_later_single_core;
+ int disable_siblings;
+#endif
-#if CONFIG_LOGICAL_CPUS==1
- int e0_later_single_core;
- int disable_siblings = !CONFIG_LOGICAL_CPUS;
+ nb_cfg_54 = 0;
+ enable_apic_ext_id = 0;
+ siblings = 0;
+
+ /* Find the bootstrap processors apicid */
+ bsp_apic_id = lapicid();
+
+ /* See if I will enable extended ids' */
+ apic_id_offset = bsp_apic_id;
+
+#if CONFIG_LOGICAL_CPUS == 1
+ disable_siblings = !CONFIG_LOGICAL_CPUS;
get_option(&disable_siblings, "dual_core");
// for pre_e0, nb_cfg_54 can not be set, ( even set, when you read it still be 0)
@@ -776,45 +803,42 @@ static unsigned int cpu_bus_scan(device_t dev, unsigned int max)
nb_cfg_54 = read_nb_cfg_54();
#endif
-
dev_mc = dev_find_slot(0, PCI_DEVFN(0x18, 0));
- if(pci_read_config32(dev_mc, 0x68) & ( HTTC_APIC_EXT_ID | HTTC_APIC_EXT_BRD_CST)) {
+ if (!dev_mc) {
+ die("0:18.0 not found?");
+ }
+ if (pci_read_config32(dev_mc, 0x68) & (HTTC_APIC_EXT_ID|HTTC_APIC_EXT_BRD_CST))
+ {
enable_apic_ext_id = 1;
- if(apic_id_offset==0) { //bsp apic id is not changed
+ if (apic_id_offset == 0) {
+ /* bsp apic id is not changed */
apic_id_offset = APIC_ID_OFFSET;
}
}
-
/* Find which cpus are present */
cpu_bus = &dev->link[0];
- for (i = 0; i < 8; i++) {
+ for(i = 0; i < 8; i++) {
device_t dev, cpu;
struct device_path cpu_path;
- /* Find the cpu's memory controller */
+ /* Find the cpu's pci device */
dev = dev_find_slot(0, PCI_DEVFN(0x18 + i, 3));
- if(!dev) { // in case we move apic cluser before pci_domain and not set that for second CPU
- for(j=0; j<4; j++) {
- struct device dummy;
- uint32_t id;
- dummy.bus = dev_mc->bus;
- dummy.path.type = DEVICE_PATH_PCI;
- dummy.path.u.pci.devfn = PCI_DEVFN(0x18 + i, j);
- id = pci_read_config32(&dummy, PCI_VENDOR_ID);
- if (id != 0xffffffff && id != 0x00000000 &&
- id != 0x0000ffff && id != 0xffff0000) {
- //create that for it
- dev = alloc_dev(dev_mc->bus, &dummy.path);
- }
+ if (!dev) {
+ /* If I am probing things in a weird order
+ * ensure all of the cpu's pci devices are found.
+ */
+ int j;
+ for(j = 0; j <= 3; j++) {
+ dev = pci_probe_dev(NULL, dev_mc->bus,
+ PCI_DEVFN(0x18 + i, j));
}
}
-#if CONFIG_LOGICAL_CPUS==1
+#if CONFIG_LOGICAL_CPUS == 1
e0_later_single_core = 0;
- if((!disable_siblings) && dev && dev->enabled) {
- j = (pci_read_config32(dev, 0xe8) >> 12) & 3; //dev is func 3
-
+ if ((!disable_siblings) && dev && dev->enabled) {
+ j = (pci_read_config32(dev, 0xe8) >> 12) & 3; // dev is func 3
printk_debug(" %s siblings=%d\r\n", dev_path(dev), j);
if(nb_cfg_54) {
@@ -843,51 +867,49 @@ static unsigned int cpu_bus_scan(device_t dev, unsigned int max)
}
} else {
siblings = j;
- }
+ }
}
#endif
-
#if CONFIG_LOGICAL_CPUS==1
for (j = 0; j <= (e0_later_single_core?0:siblings); j++ ) {
#else
- for (j = 0; j <= siblings; j++ ) {
+ for (j = 0; j <= siblings; j++ ) {
#endif
- /* Build the cpu device path */
- cpu_path.type = DEVICE_PATH_APIC;
- cpu_path.u.apic.apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:8);
-
- /* See if I can find the cpu */
- cpu = find_dev_path(cpu_bus, &cpu_path);
-
- /* Enable the cpu if I have the processor */
- if (dev && dev->enabled) {
- if (!cpu) {
- cpu = alloc_dev(cpu_bus, &cpu_path);
- }
- if (cpu) {
- cpu->enabled = 1;
- }
- }
-
- /* Disable the cpu if I don't have the processor */
- if (cpu && (!dev || !dev->enabled)) {
- cpu->enabled = 0;
- }
-
- /* Report what I have done */
- if (cpu) {
- if(enable_apic_ext_id) {
- if(cpu->path.u.apic.apic_id<apic_id_offset) { //all add offset except bsp core0
- if( (cpu->path.u.apic.apic_id > siblings) || (bsp_apic_id!=0) )
- cpu->path.u.apic.apic_id += apic_id_offset;
- }
+ /* Build the cpu device path */
+ cpu_path.type = DEVICE_PATH_APIC;
+ cpu_path.u.apic.apic_id = i * (nb_cfg_54?(siblings+1):1) + j * (nb_cfg_54?1:8);
+
+ /* See if I can find the cpu */
+ cpu = find_dev_path(cpu_bus, &cpu_path);
+
+ /* Enable the cpu if I have the processor */
+ if (dev && dev->enabled) {
+ if (!cpu) {
+ cpu = alloc_dev(cpu_bus, &cpu_path);
}
- printk_debug("CPU: %s %s\n",
- dev_path(cpu), cpu->enabled?"enabled":"disabled");
- }
- } //j
+ if (cpu) {
+ cpu->enabled = 1;
+ }
+ }
+
+ /* Disable the cpu if I don't have the processor */
+ if (cpu && (!dev || !dev->enabled)) {
+ cpu->enabled = 0;
+ }
+
+ /* Report what I have done */
+ if (cpu) {
+ if(enable_apic_ext_id) {
+ if(cpu->path.u.apic.apic_id<apic_id_offset) { //all add offset except bsp core0
+ if( (cpu->path.u.apic.apic_id > siblings) || (bsp_apic_id!=0) )
+ cpu->path.u.apic.apic_id += apic_id_offset;
+ }
+ }
+ printk_debug("CPU: %s %s\n",
+ dev_path(cpu), cpu->enabled?"enabled":"disabled");
+ }
+ } //j
}
-
return max;
}
diff --git a/src/northbridge/amd/amdk8/setup_resource_map.c b/src/northbridge/amd/amdk8/setup_resource_map.c
index ebd1978a7c..27da719409 100644
--- a/src/northbridge/amd/amdk8/setup_resource_map.c
+++ b/src/northbridge/amd/amdk8/setup_resource_map.c
@@ -1,16 +1,53 @@
#define RES_DEBUG 0
+static void setup_resource_map_offset(const unsigned int *register_values, int max, unsigned offset_pci_dev, unsigned offset_io_base)
+{
+ int i;
+// print_debug("setting up resource map offset....");
+#if 0
+ print_debug("\r\n");
+#endif
+ for(i = 0; i < max; i += 3) {
+ device_t dev;
+ unsigned where;
+ unsigned long reg;
+#if 0
+ #if CONFIG_USE_INIT
+ prink_debug("%08x <- %08x\r\n", register_values[i] + offset_pci_dev, register_values[i+2]);
+ #else
+ print_debug_hex32(register_values[i] + offset_pci_dev);
+ print_debug(" <-");
+ print_debug_hex32(register_values[i+2]);
+ print_debug("\r\n");
+ #endif
+#endif
+ dev = (register_values[i] & ~0xff) + offset_pci_dev;
+ where = register_values[i] & 0xff;
+ reg = pci_read_config32(dev, where);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2] + offset_io_base;
+ pci_write_config32(dev, where, reg);
+#if 0
+ reg = pci_read_config32(register_values[i]);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2] & ~register_values[i+1];
+ pci_write_config32(register_values[i], reg);
+#endif
+ }
+// print_debug("done.\r\n");
+}
+
#define RES_PCI_IO 0x10
#define RES_PORT_IO_8 0x22
#define RES_PORT_IO_32 0x20
-#define RES_MEM_IO 0x30
+#define RES_MEM_IO 0x40
-static void setup_resource_map_x(const unsigned int *register_values, int max)
+static void setup_resource_map_x_offset(const unsigned int *register_values, int max, unsigned offset_pci_dev, unsigned offset_io_base)
{
int i;
#if RES_DEBUG
- print_debug("setting up resource map ex....");
+ print_debug("setting up resource map ex offset....");
#endif
@@ -21,17 +58,23 @@ static void setup_resource_map_x(const unsigned int *register_values, int max)
#if RES_DEBUG
#if CONFIG_USE_INIT
printk_debug("%04x: %02x %08x <- & %08x | %08x\r\n",
- i/4, register_values[i],register_values[i+1], register_values[i+2], register_values[i+3]);
+ i/4, register_values[i],
+ register_values[i+1] + ( (register_values[i]==RES_PCI_IO) ? offset_pci_dev : 0),
+ register_values[i+2],
+ register_values[i+3] + ( ( (register_values[i] & RES_PORT_IO_32) == RES_PORT_IO_32) ? offset_io_base : 0)
+ );
#else
print_debug_hex16(i/4);
print_debug(": ");
print_debug_hex8(register_values[i]);
print_debug(" ");
- print_debug_hex32(register_values[i+1]);
+ print_debug_hex32(register_values[i+1] + ( (register_values[i]==RES_PCI_IO) ? offset_pci_dev : 0) );
print_debug(" <- & ");
print_debug_hex32(register_values[i+2]);
print_debug(" | ");
- print_debug_hex32(register_values[i+3]);
+ print_debug_hex32(register_values[i+3] +
+ (((register_values[i] & RES_PORT_IO_32) == RES_PORT_IO_32) ? offset_io_base : 0)
+ );
print_debug("\r\n");
#endif
#endif
@@ -41,7 +84,7 @@ static void setup_resource_map_x(const unsigned int *register_values, int max)
device_t dev;
unsigned where;
unsigned long reg;
- dev = register_values[i+1] & ~0xff;
+ dev = (register_values[i+1] & ~0xff) + offset_pci_dev;
where = register_values[i+1] & 0xff;
reg = pci_read_config32(dev, where);
reg &= register_values[i+2];
@@ -53,7 +96,7 @@ static void setup_resource_map_x(const unsigned int *register_values, int max)
{
unsigned where;
unsigned reg;
- where = register_values[i+1];
+ where = register_values[i+1] + offset_io_base;
reg = inb(where);
reg &= register_values[i+2];
reg |= register_values[i+3];
@@ -64,7 +107,7 @@ static void setup_resource_map_x(const unsigned int *register_values, int max)
{
unsigned where;
unsigned long reg;
- where = register_values[i+1];
+ where = register_values[i+1] + offset_io_base;
reg = inl(where);
reg &= register_values[i+2];
reg |= register_values[i+3];
@@ -94,7 +137,95 @@ static void setup_resource_map_x(const unsigned int *register_values, int max)
print_debug("done.\r\n");
#endif
}
+static void setup_resource_map_x(const unsigned int *register_values, int max)
+{
+ int i;
+#if RES_DEBUG
+ print_debug("setting up resource map ex offset....");
+
+#endif
+
+#if RES_DEBUG
+ print_debug("\r\n");
+#endif
+ for(i = 0; i < max; i += 4) {
+#if RES_DEBUG
+ #if CONFIG_USE_INIT
+ printk_debug("%04x: %02x %08x <- & %08x | %08x\r\n",
+ i/4, register_values[i],register_values[i+1], register_values[i+2], register_values[i+3]);
+ #else
+ print_debug_hex16(i/4);
+ print_debug(": ");
+ print_debug_hex8(register_values[i]);
+ print_debug(" ");
+ print_debug_hex32(register_values[i+1]);
+ print_debug(" <- & ");
+ print_debug_hex32(register_values[i+2]);
+ print_debug(" | ");
+ print_debug_hex32(register_values[i+3]);
+ print_debug("\r\n");
+ #endif
+#endif
+ switch (register_values[i]) {
+ case RES_PCI_IO: //PCI
+ {
+ device_t dev;
+ unsigned where;
+ unsigned long reg;
+ dev = register_values[i+1] & ~0xff;
+ where = register_values[i+1] & 0xff;
+ reg = pci_read_config32(dev, where);
+ reg &= register_values[i+2];
+ reg |= register_values[i+3];
+ pci_write_config32(dev, where, reg);
+ }
+ break;
+ case RES_PORT_IO_8: // io 8
+ {
+ unsigned where;
+ unsigned reg;
+ where = register_values[i+1];
+ reg = inb(where);
+ reg &= register_values[i+2];
+ reg |= register_values[i+3];
+ outb(reg, where);
+ }
+ break;
+ case RES_PORT_IO_32: //io32
+ {
+ unsigned where;
+ unsigned long reg;
+ where = register_values[i+1];
+ reg = inl(where);
+ reg &= register_values[i+2];
+ reg |= register_values[i+3];
+ outl(reg, where);
+ }
+ break;
+#if 0
+ case RES_MEM_IO: //mem
+ {
+ unsigned where;
+ unsigned long reg;
+ where = register_values[i+1];
+ reg = read32(where);
+ reg &= register_values[i+2];
+ reg |= register_values[i+3];
+ write32( where, reg);
+ }
+ break;
+#endif
+
+ } // switch
+
+
+ }
+
+#if RES_DEBUG
+ print_debug("done.\r\n");
+#endif
+}
static void setup_iob_resource_map(const unsigned int *register_values, int max)
{
diff --git a/src/northbridge/intel/E7520/Config.lb b/src/northbridge/intel/E7520/Config.lb
new file mode 100644
index 0000000000..064c867618
--- /dev/null
+++ b/src/northbridge/intel/E7520/Config.lb
@@ -0,0 +1,12 @@
+config chip.h
+driver northbridge.o
+driver pciexp_porta.o
+driver pciexp_porta1.o
+driver pciexp_portb.o
+driver pciexp_portc.o
+
+makerule raminit_test
+ depends "$(TOP)/src/northbridge/intel/e7520/raminit_test.c"
+ depends "$(TOP)/src/northbridge/intel/e7520/raminit.c"
+ action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g $< -o $@"
+end
diff --git a/src/northbridge/intel/E7520/chip.h b/src/northbridge/intel/E7520/chip.h
new file mode 100644
index 0000000000..e9ee0a2e10
--- /dev/null
+++ b/src/northbridge/intel/E7520/chip.h
@@ -0,0 +1,7 @@
+struct northbridge_intel_E7520_config
+{
+ /* Interrupt line connect */
+ unsigned int intrline;
+};
+
+extern struct chip_operations northbridge_intel_E7520_ops;
diff --git a/src/northbridge/intel/E7520/e7520.h b/src/northbridge/intel/E7520/e7520.h
new file mode 100644
index 0000000000..be76303d4f
--- /dev/null
+++ b/src/northbridge/intel/E7520/e7520.h
@@ -0,0 +1,44 @@
+#define VID 0X00
+#define DID 0X02
+#define PCICMD 0X04
+#define PCISTS 0X06
+#define RID 0X08
+#define IURBASE 0X14
+#define MCHCFG0 0X50
+#define MCHSCRB 0X52
+#define FDHC 0X58
+#define PAM 0X59
+#define DRB 0X60
+#define DRA 0X70
+#define DRT 0X78
+#define DRC 0X7C
+#define DRM 0X80
+#define DRORC 0X82
+#define ECCDIAG 0X84
+#define SDRC 0X88
+#define CKDIS 0X8C
+#define CKEDIS 0X8D
+#define DDRCSR 0X9A
+#define DEVPRES 0X9C
+#define DEVPRES_D0F0 (1 << 0)
+#define DEVPRES_D1F0 (1 << 1)
+#define DEVPRES_D2F0 (1 << 2)
+#define DEVPRES_D3F0 (1 << 3)
+#define DEVPRES_D4F0 (1 << 4)
+#define DEVPRES_D5F0 (1 << 5)
+#define DEVPRES_D6F0 (1 << 6)
+#define DEVPRES_D7F0 (1 << 7)
+#define ESMRC 0X9D
+#define SMRC 0X9E
+#define EXSMRC 0X9F
+#define DDR2ODTC 0XB0
+#define TOLM 0XC4
+#define REMAPBASE 0XC6
+#define REMAPLIMIT 0XC8
+#define REMAPOFFSET 0XCA
+#define TOM 0XCC
+#define EXPECBASE 0XCE
+#define DEVPRES1 0XF4
+#define DEVPRES1_D0F1 (1 << 5)
+#define DEVPRES1_D8F0 (1 << 1)
+#define MSCFG 0XF6
diff --git a/src/northbridge/intel/E7520/memory_initialized.c b/src/northbridge/intel/E7520/memory_initialized.c
new file mode 100644
index 0000000000..3b9b696a21
--- /dev/null
+++ b/src/northbridge/intel/E7520/memory_initialized.c
@@ -0,0 +1,13 @@
+#include "e7520.h"
+#define NB_DEV PCI_DEV(0, 0, 0)
+
+static inline int memory_initialized(void)
+{
+ uint32_t drc;
+ drc = pci_read_config32(NB_DEV, DRC);
+ //print_debug("memory_initialized: DRC: ");
+ //print_debug_hex32(drc);
+ //print_debug("\r\n");
+
+ return (drc & (1<<29));
+}
diff --git a/src/northbridge/intel/E7520/northbridge.c b/src/northbridge/intel/E7520/northbridge.c
new file mode 100644
index 0000000000..44490861f8
--- /dev/null
+++ b/src/northbridge/intel/E7520/northbridge.c
@@ -0,0 +1,270 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/hypertransport.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bitops.h>
+#include <cpu/cpu.h>
+#include "chip.h"
+#include "northbridge.h"
+#include "e7520.h"
+
+
+static unsigned int max_bus;
+
+static void ram_resource(device_t dev, unsigned long index,
+ unsigned long basek, unsigned long sizek)
+{
+ struct resource *resource;
+
+ resource = new_resource(dev, index);
+ resource->base = ((resource_t)basek) << 10;
+ resource->size = ((resource_t)sizek) << 10;
+ resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
+ IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+}
+
+
+static void pci_domain_read_resources(device_t dev)
+{
+ struct resource *resource;
+
+ /* Initialize the system wide io space constraints */
+ resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0));
+ resource->base = 0;
+ resource->size = 0;
+ resource->align = 0;
+ resource->gran = 0;
+ resource->limit = 0xffffUL;
+ resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+
+ /* Initialize the system wide memory resources constraints */
+ resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0));
+ resource->base = 0;
+ resource->size = 0;
+ resource->align = 0;
+ resource->gran = 0;
+ resource->limit = 0xffffffffUL;
+ resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+}
+
+static void tolm_test(void *gp, struct device *dev, struct resource *new)
+{
+ struct resource **best_p = gp;
+ struct resource *best;
+ best = *best_p;
+ if (!best || (best->base > new->base)) {
+ best = new;
+ }
+ *best_p = best;
+}
+
+static uint32_t find_pci_tolm(struct bus *bus)
+{
+ struct resource *min;
+ uint32_t tolm;
+ min = 0;
+ search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
+ tolm = 0xffffffffUL;
+ if (min && tolm > min->base) {
+ tolm = min->base;
+ }
+ return tolm;
+}
+
+
+static void pci_domain_set_resources(device_t dev)
+{
+ device_t mc_dev;
+ uint32_t pci_tolm;
+
+ pci_tolm = find_pci_tolm(&dev->link[0]);
+
+#if 1
+ printk_debug("PCI mem marker = %x\n", pci_tolm);
+#endif
+ /* FIXME Me temporary hack */
+ if(pci_tolm > 0xe0000000)
+ pci_tolm = 0xe0000000;
+ /* Ensure pci_tolm is 128M aligned */
+ pci_tolm &= 0xf8000000;
+ mc_dev = dev->link[0].children;
+ if (mc_dev) {
+ /* Figure out which areas are/should be occupied by RAM.
+ * This is all computed in kilobytes and converted to/from
+ * the memory controller right at the edges.
+ * Having different variables in different units is
+ * too confusing to get right. Kilobytes are good up to
+ * 4 Terabytes of RAM...
+ */
+ uint16_t tolm_r, remapbase_r, remaplimit_r, remapoffset_r;
+ unsigned long tomk, tolmk;
+ unsigned long remapbasek, remaplimitk, remapoffsetk;
+
+ /* Get the Top of Memory address, units are 128M */
+ tomk = ((unsigned long)pci_read_config16(mc_dev, TOM)) << 17;
+ /* Compute the Top of Low Memory */
+ tolmk = (pci_tolm & 0xf8000000) >> 10;
+
+ if (tolmk >= tomk) {
+ /* The PCI hole does not overlap memory
+ * we won't use the remap window.
+ */
+ tolmk = tomk;
+ remapbasek = 0x3ff << 16;
+ remaplimitk = 0 << 16;
+ remapoffsetk = 0 << 16;
+ }
+ else {
+ /* The PCI memory hole overlaps memory
+ * setup the remap window.
+ */
+ /* Find the bottom of the remap window
+ * is it above 4G?
+ */
+ remapbasek = 4*1024*1024;
+ if (tomk > remapbasek) {
+ remapbasek = tomk;
+ }
+ /* Find the limit of the remap window */
+ remaplimitk = (remapbasek + (4*1024*1024 - tolmk) - (1 << 16));
+ /* Find the offset of the remap window from tolm */
+ remapoffsetk = remapbasek - tolmk;
+ }
+ /* Write the ram configruation registers,
+ * preserving the reserved bits.
+ */
+ tolm_r = pci_read_config16(mc_dev, 0xc4);
+ tolm_r = ((tolmk >> 17) << 11) | (tolm_r & 0x7ff);
+ pci_write_config16(mc_dev, 0xc4, tolm_r);
+
+ remapbase_r = pci_read_config16(mc_dev, 0xc6);
+ remapbase_r = (remapbasek >> 16) | (remapbase_r & 0xfc00);
+ pci_write_config16(mc_dev, 0xc6, remapbase_r);
+
+ remaplimit_r = pci_read_config16(mc_dev, 0xc8);
+ remaplimit_r = (remaplimitk >> 16) | (remaplimit_r & 0xfc00);
+ pci_write_config16(mc_dev, 0xc8, remaplimit_r);
+
+ remapoffset_r = pci_read_config16(mc_dev, 0xca);
+ remapoffset_r = (remapoffsetk >> 16) | (remapoffset_r & 0xfc00);
+ pci_write_config16(mc_dev, 0xca, remapoffset_r);
+
+ /* Report the memory regions */
+ ram_resource(dev, 3, 0, 640);
+ ram_resource(dev, 4, 768, (tolmk - 768));
+ if (tomk > 4*1024*1024) {
+ ram_resource(dev, 5, 4096*1024, tomk - 4*1024*1024);
+ }
+ if (remaplimitk >= remapbasek) {
+ ram_resource(dev, 6, remapbasek,
+ (remaplimitk + 64*1024) - remapbasek);
+ }
+ }
+ assign_resources(&dev->link[0]);
+}
+
+static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
+{
+ max = pci_scan_bus(&dev->link[0], 0, 0xff, max);
+ if (max > max_bus) {
+ max_bus = max;
+ }
+ return max;
+}
+
+static struct device_operations pci_domain_ops = {
+ .read_resources = pci_domain_read_resources,
+ .set_resources = pci_domain_set_resources,
+ .enable_resources = enable_childrens_resources,
+ .init = 0,
+ .scan_bus = pci_domain_scan_bus,
+ .ops_pci_bus = &pci_cf8_conf1, /* Do we want to use the memory mapped space here? */
+};
+
+static void mc_read_resources(device_t dev)
+{
+ struct resource *resource;
+
+ pci_dev_read_resources(dev);
+
+ resource = new_resource(dev, 0xcf);
+ resource->base = 0xe0000000;
+ resource->size = max_bus * 4096*256;
+ resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+}
+
+static void mc_set_resources(device_t dev)
+{
+ struct resource *resource, *last;
+
+ last = &dev->resource[dev->resources];
+ resource = find_resource(dev, 0xcf);
+ if (resource) {
+ report_resource_stored(dev, resource, "<mmconfig>");
+ }
+ pci_dev_set_resources(dev);
+}
+
+static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device)
+{
+ pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
+ ((device & 0xffff) << 16) | (vendor & 0xffff));
+}
+
+static struct pci_operations intel_pci_ops = {
+ .set_subsystem = intel_set_subsystem,
+};
+
+static struct device_operations mc_ops = {
+ .read_resources = mc_read_resources,
+ .set_resources = mc_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = 0,
+ .scan_bus = 0,
+ .ops_pci = &intel_pci_ops,
+};
+
+static struct pci_driver mc_driver __pci_driver = {
+ .ops = &mc_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x3590,
+};
+
+static void cpu_bus_init(device_t dev)
+{
+ initialize_cpus(&dev->link[0]);
+}
+
+static void cpu_bus_noop(device_t dev)
+{
+}
+
+static struct device_operations cpu_bus_ops = {
+ .read_resources = cpu_bus_noop,
+ .set_resources = cpu_bus_noop,
+ .enable_resources = cpu_bus_noop,
+ .init = cpu_bus_init,
+ .scan_bus = 0,
+};
+
+
+static void enable_dev(device_t dev)
+{
+ /* Set the operations if it is a special bus type */
+ if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
+ dev->ops = &pci_domain_ops;
+ }
+ else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
+ dev->ops = &cpu_bus_ops;
+ }
+}
+
+struct chip_operations northbridge_intel_E7520_ops = {
+ CHIP_NAME("Intel E7520 Northbridge")
+ .enable_dev = enable_dev,
+};
diff --git a/src/northbridge/intel/E7520/northbridge.h b/src/northbridge/intel/E7520/northbridge.h
new file mode 100644
index 0000000000..516834f23a
--- /dev/null
+++ b/src/northbridge/intel/E7520/northbridge.h
@@ -0,0 +1,8 @@
+#ifndef NORTHBRIDGE_INTEL_E7520_H
+#define NORTHBRIDGE_INTEL_E7520_H
+
+extern unsigned int e7520_scan_root_bus(device_t root, unsigned int max);
+
+
+#endif /* NORTHBRIDGE_INTEL_E7520_H */
+
diff --git a/src/northbridge/intel/E7520/pciexp_porta.c b/src/northbridge/intel/E7520/pciexp_porta.c
new file mode 100644
index 0000000000..5443d66174
--- /dev/null
+++ b/src/northbridge/intel/E7520/pciexp_porta.c
@@ -0,0 +1,62 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+#include <part/hard_reset.h>
+
+typedef struct northbridge_intel_E7520_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static unsigned int pcie_scan_bridge(struct device *dev, unsigned int max)
+{
+ uint16_t val;
+ uint16_t ctl;
+ int flag = 0;
+ do {
+ val = pci_read_config16(dev, 0x76);
+ printk_debug("pcie porta 0x76: %02x\n", val);
+ if((val & (1<<10) )&&(!flag)) { /* training error */
+ ctl = pci_read_config16(dev, 0x74);
+ pci_write_config16(dev, 0x74, (ctl | (1<<5)));
+ val = pci_read_config16(dev, 0x76);
+ printk_debug("pcie porta reset 0x76: %02x\n", val);
+ flag=1;
+ hard_reset();
+ }
+ } while ( val & (3<<10) );
+ return pciexp_scan_bridge(dev, max);
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pcie_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PA,
+};
+
+
diff --git a/src/northbridge/intel/E7520/pciexp_porta1.c b/src/northbridge/intel/E7520/pciexp_porta1.c
new file mode 100644
index 0000000000..b4dcb2fe15
--- /dev/null
+++ b/src/northbridge/intel/E7520/pciexp_porta1.c
@@ -0,0 +1,41 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+
+typedef struct northbridge_intel_E7520_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pciexp_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PA1,
+};
+
+
diff --git a/src/northbridge/intel/E7520/pciexp_portb.c b/src/northbridge/intel/E7520/pciexp_portb.c
new file mode 100644
index 0000000000..7f17925212
--- /dev/null
+++ b/src/northbridge/intel/E7520/pciexp_portb.c
@@ -0,0 +1,42 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+
+typedef struct northbridge_intel_E7520_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pciexp_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PB,
+};
+
+
diff --git a/src/northbridge/intel/E7520/pciexp_portc.c b/src/northbridge/intel/E7520/pciexp_portc.c
new file mode 100644
index 0000000000..c46610b069
--- /dev/null
+++ b/src/northbridge/intel/E7520/pciexp_portc.c
@@ -0,0 +1,41 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+
+typedef struct northbridge_intel_E7520_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pciexp_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PC,
+};
+
+
diff --git a/src/northbridge/intel/E7520/raminit.c b/src/northbridge/intel/E7520/raminit.c
new file mode 100644
index 0000000000..22ac115d6b
--- /dev/null
+++ b/src/northbridge/intel/E7520/raminit.c
@@ -0,0 +1,1333 @@
+#include <cpu/x86/mem.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/cache.h>
+#include "raminit.h"
+#include "e7520.h"
+
+#define BAR 0x40000000
+
+static void sdram_set_registers(const struct mem_controller *ctrl)
+{
+ static const unsigned int register_values[] = {
+
+ /* CKDIS 0x8c disable clocks */
+ PCI_ADDR(0, 0x00, 0, CKDIS), 0xffff0000, 0x0000ffff,
+
+ /* 0x9c Device present and extended RAM control
+ * DEVPRES is very touchy, hard code the initialization
+ * of PCI-E ports here.
+ */
+ PCI_ADDR(0, 0x00, 0, DEVPRES), 0x00000000, 0x07020801 | DEVPRES_CONFIG,
+
+ /* 0xc8 Remap RAM base and limit off */
+ PCI_ADDR(0, 0x00, 0, REMAPLIMIT), 0x00000000, 0x03df0000,
+
+ /* ??? */
+ PCI_ADDR(0, 0x00, 0, 0xd8), 0x00000000, 0xb5930000,
+ PCI_ADDR(0, 0x00, 0, 0xe8), 0x00000000, 0x00004a2a,
+
+ /* 0x50 scrub */
+ PCI_ADDR(0, 0x00, 0, MCHCFG0), 0xfce0ffff, 0x00006000, /* 6000 */
+
+ /* 0x58 0x5c PAM */
+ PCI_ADDR(0, 0x00, 0, PAM-1), 0xcccccc7f, 0x33333000,
+ PCI_ADDR(0, 0x00, 0, PAM+3), 0xcccccccc, 0x33333333,
+
+ /* 0xf4 */
+ PCI_ADDR(0, 0x00, 0, DEVPRES1), 0xffbffff, (1<<22)|(6<<2) | DEVPRES1_CONFIG,
+
+ /* 0x14 */
+ PCI_ADDR(0, 0x00, 0, IURBASE), 0x00000fff, BAR |0,
+ };
+ int i;
+ int max;
+
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ device_t dev;
+ unsigned where;
+ unsigned long reg;
+ dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x00, 0) + ctrl->f0;
+ where = register_values[i] & 0xff;
+ reg = pci_read_config32(dev, where);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2];
+ pci_write_config32(dev, where, reg);
+ }
+ print_spew("done.\r\n");
+}
+
+
+
+struct dimm_size {
+ unsigned long side1;
+ unsigned long side2;
+};
+
+static struct dimm_size spd_get_dimm_size(unsigned device)
+{
+ /* Calculate the log base 2 size of a DIMM in bits */
+ struct dimm_size sz;
+ int value, low, ddr2;
+ sz.side1 = 0;
+ sz.side2 = 0;
+
+ /* test for ddr2 */
+ ddr2=0;
+ value = spd_read_byte(device, 2); /* type */
+ if (value < 0) goto hw_err;
+ if (value == 8) ddr2 = 1;
+
+ /* Note it might be easier to use byte 31 here, it has the DIMM size as
+ * a multiple of 4MB. The way we do it now we can size both
+ * sides of an assymetric dimm.
+ */
+ value = spd_read_byte(device, 3); /* rows */
+ 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 hw_err;
+ if ((value & 0xf) == 0) goto val_err;
+ sz.side1 += value & 0xf;
+
+ value = spd_read_byte(device, 17); /* banks */
+ 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 hw_err;
+ value &= 0xff;
+ value <<= 8;
+
+ low = spd_read_byte(device, 6); /* (low byte) */
+ 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 < 0) goto hw_err;
+ value &= 7;
+ if(ddr2) value++;
+ 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 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 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;
+
+}
+
+static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask)
+{
+ int i;
+ int cum;
+
+ for(i = cum = 0; i < DIMM_SOCKETS; i++) {
+ struct dimm_size sz;
+ if (dimm_mask & (1 << i)) {
+ sz = spd_get_dimm_size(ctrl->channel0[i]);
+ if (sz.side1 < 29) {
+ return -1; /* Report SPD error */
+ }
+ /* convert bits to multiples of 64MB */
+ sz.side1 -= 29;
+ cum += (1 << sz.side1);
+ /* DRB = 0x60 */
+ pci_write_config8(ctrl->f0, DRB + (i*2), cum);
+ if( sz.side2 > 28) {
+ sz.side2 -= 29;
+ cum += (1 << sz.side2);
+ }
+ pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum);
+ }
+ else {
+ pci_write_config8(ctrl->f0, DRB + (i*2), cum);
+ pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum);
+ }
+ }
+ /* set TOM top of memory 0xcc */
+ pci_write_config16(ctrl->f0, TOM, cum);
+ /* set TOLM top of low memory */
+ if(cum > 0x18) {
+ cum = 0x18;
+ }
+ cum <<= 11;
+ /* 0xc4 TOLM */
+ pci_write_config16(ctrl->f0, TOLM, cum);
+ return 0;
+}
+
+
+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(device, 2); /* Type */
+ if ((byte == 7) || (byte == 8)) {
+ dimm_mask |= (1 << i);
+ }
+ }
+ device = ctrl->channel1[i];
+ if (device) {
+ byte = spd_read_byte(device, 2);
+ if ((byte == 7) || (byte == 8)) {
+ dimm_mask |= (1 << (i + DIMM_SOCKETS));
+ }
+ }
+ }
+ return dimm_mask;
+}
+
+
+static int spd_set_row_attributes(const struct mem_controller *ctrl,
+ long dimm_mask)
+{
+
+ int value;
+ int reg;
+ int dra;
+ int cnt;
+
+ dra = 0;
+ for(cnt=0; cnt < 4; cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ reg =0;
+ value = spd_read_byte(ctrl->channel0[cnt], 3); /* rows */
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
+ reg += value & 0xf;
+
+ value = spd_read_byte(ctrl->channel0[cnt], 4); /* columns */
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
+ reg += value & 0xf;
+
+ value = spd_read_byte(ctrl->channel0[cnt], 17); /* banks */
+ if (value < 0) goto hw_err;
+ if ((value & 0xff) == 0) goto val_err;
+ reg += log2(value & 0xff);
+
+ /* Get the device width and convert it to a power of two */
+ value = spd_read_byte(ctrl->channel0[cnt], 13);
+ if (value < 0) goto hw_err;
+ value = log2(value & 0xff);
+ reg += value;
+ if(reg < 27) goto hw_err;
+ reg -= 27;
+ reg += (value << 2);
+
+ dra += reg << (cnt*8);
+ value = spd_read_byte(ctrl->channel0[cnt], 5);
+ if (value & 2)
+ dra += reg << ((cnt*8)+4);
+ }
+
+ /* 0x70 DRA */
+ pci_write_config32(ctrl->f0, DRA, dra);
+ goto out;
+
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ dra = 0;
+ out:
+ return dra;
+
+}
+
+
+static int spd_set_drt_attributes(const struct mem_controller *ctrl,
+ long dimm_mask, uint32_t drc)
+{
+ int value;
+ int reg;
+ uint32_t drt;
+ int cnt;
+ int first_dimm;
+ int cas_latency=0;
+ int latency;
+ uint32_t index = 0;
+ uint32_t index2 = 0;
+ static const unsigned char cycle_time[3] = {0x75,0x60,0x50};
+ static const int latency_indicies[] = { 26, 23, 9 };
+
+ /* 0x78 DRT */
+ drt = pci_read_config32(ctrl->f0, DRT);
+ drt &= 3; /* save bits 1:0 */
+
+ for(first_dimm = 0; first_dimm < 4; first_dimm++) {
+ if (dimm_mask & (1 << first_dimm))
+ break;
+ }
+
+ /* get dimm type */
+ value = spd_read_byte(ctrl->channel0[first_dimm], 2);
+ if(value == 8) {
+ drt |= (3<<5); /* back to bark write turn around & cycle add */
+ }
+
+ drt |= (3<<18); /* Trasmax */
+
+ for(cnt=0; cnt < 4; cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 18); /* CAS Latency */
+ /* Compute the lowest cas latency supported */
+ latency = log2(reg) -2;
+
+ /* Loop through and find a fast clock with a low latency */
+ for(index = 0; index < 3; index++, latency++) {
+ if ((latency < 2) || (latency > 4) ||
+ (!(reg & (1 << latency)))) {
+ continue;
+ }
+ value = spd_read_byte(ctrl->channel0[cnt],
+ latency_indicies[index]);
+
+ if(value <= cycle_time[drc&3]) {
+ if( latency > cas_latency) {
+ cas_latency = latency;
+ }
+ break;
+ }
+ }
+ }
+ index = (cas_latency-2);
+ if((index)==0) cas_latency = 20;
+ else if((index)==1) cas_latency = 25;
+ else cas_latency = 30;
+
+ for(cnt=0;cnt<4;cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 27)&0x0ff;
+ if(((index>>8)&0x0ff)<reg) {
+ index &= ~(0x0ff << 8);
+ index |= (reg << 8);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 28)&0x0ff;
+ if(((index>>16)&0x0ff)<reg) {
+ index &= ~(0x0ff << 16);
+ index |= (reg<<16);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 29)&0x0ff;
+ if(((index2>>0)&0x0ff)<reg) {
+ index2 &= ~(0x0ff << 0);
+ index2 |= (reg<<0);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 41)&0x0ff;
+ if(((index2>>8)&0x0ff)<reg) {
+ index2 &= ~(0x0ff << 8);
+ index2 |= (reg<<8);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 42)&0x0ff;
+ if(((index2>>16)&0x0ff)<reg) {
+ index2 &= ~(0x0ff << 16);
+ index2 |= (reg<<16);
+ }
+ }
+
+ /* get dimm speed */
+ value = cycle_time[drc&3];
+ if(value <= 0x50) { /* 200 MHz */
+ if((index&7) > 2) {
+ drt |= (2<<2); /* CAS latency 4 */
+ cas_latency = 40;
+ } else {
+ drt |= (1<<2); /* CAS latency 3 */
+ cas_latency = 30;
+ }
+ if((index&0x0ff00)<=0x03c00) {
+ drt |= (1<<8); /* Trp RAS Precharg */
+ } else {
+ drt |= (2<<8); /* Trp RAS Precharg */
+ }
+
+ /* Trcd RAS to CAS delay */
+ if((index2&0x0ff)<=0x03c) {
+ drt |= (0<<10);
+ } else {
+ drt |= (1<<10);
+ }
+
+ /* Tdal Write auto precharge recovery delay */
+ drt |= (1<<12);
+
+ /* Trc TRS min */
+ if((index2&0x0ff00)<=0x03700)
+ drt |= (0<<14);
+ else if((index2&0xff00)<=0x03c00)
+ drt |= (1<<14);
+ else
+ drt |= (2<<14); /* spd 41 */
+
+ drt |= (2<<16); /* Twr not defined for DDR docs say use 2 */
+
+ /* Trrd Row Delay */
+ if((index&0x0ff0000)<=0x0140000) {
+ drt |= (0<<20);
+ } else if((index&0x0ff0000)<=0x0280000) {
+ drt |= (1<<20);
+ } else if((index&0x0ff0000)<=0x03c0000) {
+ drt |= (2<<20);
+ } else {
+ drt |= (3<<20);
+ }
+
+ /* Trfc Auto refresh cycle time */
+ if((index2&0x0ff0000)<=0x04b0000) {
+ drt |= (0<<22);
+ } else if((index2&0x0ff0000)<=0x0690000) {
+ drt |= (1<<22);
+ } else {
+ drt |= (2<<22);
+ }
+ /* Docs say use 55 for all 200Mhz */
+ drt |= (0x055<<24);
+ }
+ else if(value <= 0x60) { /* 167 Mhz */
+ /* according to new documentation CAS latency is 00
+ * for bits 3:2 for all 167 Mhz
+ drt |= ((index&3)<<2); */ /* set CAS latency */
+ if((index&0x0ff00)<=0x03000) {
+ drt |= (1<<8); /* Trp RAS Precharg */
+ } else {
+ drt |= (2<<8); /* Trp RAS Precharg */
+ }
+
+ /* Trcd RAS to CAS delay */
+ if((index2&0x0ff)<=0x030) {
+ drt |= (0<<10);
+ } else {
+ drt |= (1<<10);
+ }
+
+ /* Tdal Write auto precharge recovery delay */
+ drt |= (2<<12);
+
+ /* Trc TRS min */
+ drt |= (2<<14); /* spd 41, but only one choice */
+
+ drt |= (2<<16); /* Twr not defined for DDR docs say 2 */
+
+ /* Trrd Row Delay */
+ if((index&0x0ff0000)<=0x0180000) {
+ drt |= (0<<20);
+ } else if((index&0x0ff0000)<=0x0300000) {
+ drt |= (1<<20);
+ } else {
+ drt |= (2<<20);
+ }
+
+ /* Trfc Auto refresh cycle time */
+ if((index2&0x0ff0000)<=0x0480000) {
+ drt |= (0<<22);
+ } else if((index2&0x0ff0000)<=0x0780000) {
+ drt |= (2<<22);
+ } else {
+ drt |= (2<<22);
+ }
+ /* Docs state to use 99 for all 167 Mhz */
+ drt |= (0x099<<24);
+ }
+ else if(value <= 0x75) { /* 133 Mhz */
+ drt |= ((index&3)<<2); /* set CAS latency */
+ if((index&0x0ff00)<=0x03c00) {
+ drt |= (1<<8); /* Trp RAS Precharg */
+ } else {
+ drt |= (2<<8); /* Trp RAS Precharg */
+ }
+
+ /* Trcd RAS to CAS delay */
+ if((index2&0x0ff)<=0x03c) {
+ drt |= (0<<10);
+ } else {
+ drt |= (1<<10);
+ }
+
+ /* Tdal Write auto precharge recovery delay */
+ drt |= (1<<12);
+
+ /* Trc TRS min */
+ drt |= (2<<14); /* spd 41, but only one choice */
+
+ drt |= (1<<16); /* Twr not defined for DDR docs say 1 */
+
+ /* Trrd Row Delay */
+ if((index&0x0ff0000)<=0x01e0000) {
+ drt |= (0<<20);
+ } else if((index&0x0ff0000)<=0x03c0000) {
+ drt |= (1<<20);
+ } else {
+ drt |= (2<<20);
+ }
+
+ /* Trfc Auto refresh cycle time */
+ if((index2&0x0ff0000)<=0x04b0000) {
+ drt |= (0<<22);
+ } else if((index2&0x0ff0000)<=0x0780000) {
+ drt |= (2<<22);
+ } else {
+ drt |= (2<<22);
+ }
+
+ /* Based on CAS latency */
+ if(index&7)
+ drt |= (0x099<<24);
+ else
+ drt |= (0x055<<24);
+
+ }
+ else {
+ die("Invalid SPD 9 bus speed.\r\n");
+ }
+
+ /* 0x78 DRT */
+ pci_write_config32(ctrl->f0, DRT, drt);
+
+ return(cas_latency);
+}
+
+static int spd_set_dram_controller_mode(const struct mem_controller *ctrl,
+ long dimm_mask)
+{
+ int value;
+ int reg;
+ int drc;
+ int cnt;
+ msr_t msr;
+ unsigned char dram_type = 0xff;
+ unsigned char ecc = 0xff;
+ unsigned char rate = 62;
+ static const unsigned char spd_rates[6] = {15,3,7,7,62,62};
+ static const unsigned char drc_rates[5] = {0,15,7,62,3};
+ static const unsigned char fsb_conversion[4] = {3,1,3,2};
+
+ /* 0x7c DRC */
+ drc = pci_read_config32(ctrl->f0, DRC);
+ for(cnt=0; cnt < 4; cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ value = spd_read_byte(ctrl->channel0[cnt], 11); /* ECC */
+ reg = spd_read_byte(ctrl->channel0[cnt], 2); /* Type */
+ if (value == 2) { /* RAM is ECC capable */
+ if (reg == 8) {
+ if ( ecc == 0xff ) {
+ ecc = 2;
+ }
+ else if (ecc == 1) {
+ die("ERROR - Mixed DDR & DDR2 RAM\r\n");
+ }
+ }
+ else if ( reg == 7 ) {
+ if ( ecc == 0xff) {
+ ecc = 1;
+ }
+ else if ( ecc > 1 ) {
+ die("ERROR - Mixed DDR & DDR2 RAM\r\n");
+ }
+ }
+ else {
+ die("ERROR - RAM not DDR\r\n");
+ }
+ }
+ else {
+ die("ERROR - Non ECC memory dimm\r\n");
+ }
+
+ value = spd_read_byte(ctrl->channel0[cnt], 12); /*refresh rate*/
+ value &= 0x0f; /* clip self refresh bit */
+ if (value > 5) goto hw_err;
+ if (rate > spd_rates[value])
+ rate = spd_rates[value];
+
+ value = spd_read_byte(ctrl->channel0[cnt], 9); /* cycle time */
+ if (value > 0x75) goto hw_err;
+ if (value <= 0x50) {
+ if (dram_type >= 2) {
+ if (reg == 8) { /*speed is good, is this ddr2?*/
+ dram_type = 2;
+ } else { /* not ddr2 so use ddr333 */
+ dram_type = 1;
+ }
+ }
+ }
+ else if (value <= 0x60) {
+ if (dram_type >= 1) dram_type = 1;
+ }
+ else dram_type = 0; /* ddr266 */
+
+ }
+ ecc = 2;
+ if (read_option(CMOS_VSTART_ECC_memory,CMOS_VLEN_ECC_memory,1) == 0) {
+ ecc = 0; /* ECC off in CMOS so disable it */
+ print_debug("ECC off\r\n");
+ }
+ else {
+ print_debug("ECC on\r\n");
+ }
+ drc &= ~(3 << 20); /* clear the ecc bits */
+ drc |= (ecc << 20); /* or in the calculated ecc bits */
+ for ( cnt = 1; cnt < 5; cnt++)
+ if (drc_rates[cnt] == rate)
+ break;
+ if (cnt < 5) {
+ drc &= ~(7 << 8); /* clear the rate bits */
+ drc |= (cnt << 8);
+ }
+
+ if (reg == 8) { /* independant clocks */
+ drc |= (1 << 4);
+ }
+
+ drc |= (1 << 26); /* set the overlap bit - the factory BIOS does */
+ drc |= (1 << 27); /* set DED retry enable - the factory BIOS does */
+ /* front side bus */
+ msr = rdmsr(0x2c);
+ value = msr.lo >> 16;
+ value &= 0x03;
+ drc &= ~(3 << 2); /* set the front side bus */
+ drc |= (fsb_conversion[value] << 2);
+ drc &= ~(3 << 0); /* set the dram type */
+ drc |= (dram_type << 0);
+
+ goto out;
+
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ drc = 0;
+ out:
+ return drc;
+}
+
+static void sdram_set_spd_registers(const struct mem_controller *ctrl)
+{
+ long dimm_mask;
+
+ /* Test if we can read the spd and if ram is ddr or ddr2 */
+ dimm_mask = spd_detect_dimms(ctrl);
+ if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
+ print_err("No memory for this cpu\r\n");
+ return;
+ }
+ return;
+}
+
+static void do_delay(void)
+{
+ int i;
+ unsigned char b;
+ for(i=0;i<16;i++)
+ b=inb(0x80);
+}
+
+static void pll_setup(uint32_t drc)
+{
+ unsigned pins;
+ if(drc&3) { /* DDR 333 or DDR 400 */
+ if((drc&0x0c) == 0x0c) { /* FSB 200 */
+ pins = 2 | 1;
+ }
+ else if((drc&0x0c) == 0x08) { /* FSB 167 */
+ pins = 0 | 1;
+ }
+ else if(drc&1){ /* FSB 133 DDR 333 */
+ pins = 2 | 1;
+ }
+ else { /* FSB 133 DDR 400 */
+ pins = 0 | 1;
+ }
+ }
+ else { /* DDR 266 */
+ if((drc&0x08) == 0x08) { /* FSB 200 or 167 */
+ pins = 0 | 0;
+ }
+ else { /* FSB 133 */
+ pins = 0 | 1;
+ }
+ }
+ mainboard_set_e7520_pll(pins);
+ return;
+}
+
+#define TIMEOUT_LOOPS 300000
+
+#define DCALCSR 0x100
+#define DCALADDR 0x104
+#define DCALDATA 0x108
+
+static void set_on_dimm_termination_enable(const struct mem_controller *ctrl)
+{
+ unsigned char c1,c2;
+ unsigned int dimm,i;
+ unsigned int data32;
+ unsigned int t4;
+
+ /* Set up northbridge values */
+ /* ODT enable */
+ pci_write_config32(ctrl->f0, 0x88, 0xf0000180);
+ /* Figure out which slots are Empty, Single, or Double sided */
+ for(i=0,t4=0,c2=0;i<8;i+=2) {
+ c1 = pci_read_config8(ctrl->f0, DRB+i);
+ if(c1 == c2) continue;
+ c2 = pci_read_config8(ctrl->f0, DRB+1+i);
+ if(c1 == c2)
+ t4 |= (1 << (i*4));
+ else
+ t4 |= (2 << (i*4));
+ }
+ for(i=0;i<1;i++) {
+ if((t4&0x0f) == 1) {
+ if( ((t4>>8)&0x0f) == 0 ) {
+ data32 = 0x00000010; /* EEES */
+ break;
+ }
+ if ( ((t4>>16)&0x0f) == 0 ) {
+ data32 = 0x00003132; /* EESS */
+ break;
+ }
+ if ( ((t4>>24)&0x0f) == 0 ) {
+ data32 = 0x00335566; /* ESSS */
+ break;
+ }
+ data32 = 0x77bbddee; /* SSSS */
+ break;
+ }
+ if((t4&0x0f) == 2) {
+ if( ((t4>>8)&0x0f) == 0 ) {
+ data32 = 0x00003132; /* EEED */
+ break;
+ }
+ if ( ((t4>>8)&0x0f) == 2 ) {
+ data32 = 0xb373ecdc; /* EEDD */
+ break;
+ }
+ if ( ((t4>>16)&0x0f) == 0 ) {
+ data32 = 0x00b3a898; /* EESD */
+ break;
+ }
+ data32 = 0x777becdc; /* ESSD */
+ break;
+ }
+ die("Error - First dimm slot empty\r\n");
+ }
+
+ print_debug("ODT Value = ");
+ print_debug_hex32(data32);
+ print_debug("\r\n");
+
+ pci_write_config32(ctrl->f0, 0xb0, data32);
+
+ for(dimm=0;dimm<8;dimm+=1) {
+
+ write32(BAR+DCALADDR, 0x0b840001);
+ write32(BAR+DCALCSR, 0x83000003 | (dimm << 20));
+
+ for(i=0;i<1001;i++) {
+ data32 = read32(BAR+DCALCSR);
+ if(!(data32 & (1<<31)))
+ break;
+ }
+ }
+}
+static void set_receive_enable(const struct mem_controller *ctrl)
+{
+ unsigned int i;
+ unsigned int cnt;
+ uint32_t recena=0;
+ uint32_t recenb=0;
+
+ {
+ unsigned int dimm;
+ unsigned int edge;
+ int32_t data32;
+ uint32_t data32_dram;
+ uint32_t dcal_data32_0;
+ uint32_t dcal_data32_1;
+ uint32_t dcal_data32_2;
+ uint32_t dcal_data32_3;
+ uint32_t work32l;
+ uint32_t work32h;
+ uint32_t data32r;
+ int32_t recen;
+ for(dimm=0;dimm<8;dimm+=1) {
+
+ if(!(dimm&1)) {
+ write32(BAR+DCALDATA+(17*4), 0x04020000);
+ write32(BAR+DCALCSR, 0x83800004 | (dimm << 20));
+
+ for(i=0;i<1001;i++) {
+ data32 = read32(BAR+DCALCSR);
+ if(!(data32 & (1<<31)))
+ break;
+ }
+ if(i>=1000)
+ continue;
+
+ dcal_data32_0 = read32(BAR+DCALDATA + 0);
+ dcal_data32_1 = read32(BAR+DCALDATA + 4);
+ dcal_data32_2 = read32(BAR+DCALDATA + 8);
+ dcal_data32_3 = read32(BAR+DCALDATA + 12);
+ }
+ else {
+ dcal_data32_0 = read32(BAR+DCALDATA + 16);
+ dcal_data32_1 = read32(BAR+DCALDATA + 20);
+ dcal_data32_2 = read32(BAR+DCALDATA + 24);
+ dcal_data32_3 = read32(BAR+DCALDATA + 28);
+ }
+
+ /* check if bank is installed */
+ if((dcal_data32_0 == 0) && (dcal_data32_2 == 0))
+ continue;
+ /* Calculate the timing value */
+ {
+ unsigned int bit;
+ for(i=0,edge=0,bit=63,cnt=31,data32r=0,
+ work32l=dcal_data32_1,work32h=dcal_data32_3;
+ (i<4) && bit; i++) {
+ for(;;bit--,cnt--) {
+ if(work32l & (1<<cnt))
+ break;
+ if(!cnt) {
+ work32l = dcal_data32_0;
+ work32h = dcal_data32_2;
+ cnt = 32;
+ }
+ if(!bit) break;
+ }
+ for(;;bit--,cnt--) {
+ if(!(work32l & (1<<cnt)))
+ break;
+ if(!cnt) {
+ work32l = dcal_data32_0;
+ work32h = dcal_data32_2;
+ cnt = 32;
+ }
+ if(!bit) break;
+ }
+ if(!bit) {
+ break;
+ }
+ data32 = ((bit%8) << 1);
+ if(work32h & (1<<cnt))
+ data32 += 1;
+ if(data32 < 4) {
+ if(!edge) {
+ edge = 1;
+ }
+ else {
+ if(edge != 1) {
+ data32 = 0x0f;
+ }
+ }
+ }
+ if(data32 > 12) {
+ if(!edge) {
+ edge = 2;
+ }
+ else {
+ if(edge != 2) {
+ data32 = 0x00;
+ }
+ }
+ }
+ data32r += data32;
+ }
+ }
+ work32l = dcal_data32_0;
+ work32h = dcal_data32_2;
+ recen = data32r;
+ recen += 3;
+ recen = recen>>2;
+ for(cnt=5;cnt<24;) {
+ for(;;cnt++)
+ if(!(work32l & (1<<cnt)))
+ break;
+ for(;;cnt++) {
+ if(work32l & (1<<cnt))
+ break;
+ }
+ data32 = (((cnt-1)%8)<<1);
+ if(work32h & (1<<(cnt-1))) {
+ data32++;
+ }
+ /* test for frame edge cross overs */
+ if((edge == 1) && (data32 > 12) &&
+ (((recen+16)-data32) < 3)) {
+ data32 = 0;
+ cnt += 2;
+ }
+ if((edge == 2) && (data32 < 4) &&
+ ((recen - data32) > 12)) {
+ data32 = 0x0f;
+ cnt -= 2;
+ }
+ if(((recen+3) >= data32) && ((recen-3) <= data32))
+ break;
+ }
+ cnt--;
+ cnt /= 8;
+ cnt--;
+ if(recen&1)
+ recen+=2;
+ recen >>= 1;
+ recen += (cnt*8);
+ recen+=2; /* this is not in the spec, but matches
+ the factory output, and has less failure */
+ recen <<= (dimm/2) * 8;
+ if(!(dimm&1)) {
+ recena |= recen;
+ }
+ else {
+ recenb |= recen;
+ }
+ }
+ }
+ /* Check for Eratta problem */
+ for(i=cnt=0;i<32;i+=8) {
+ if (((recena>>i)&0x0f)>7) {
+ cnt+= 0x101;
+ }
+ else {
+ if((recena>>i)&0x0f) {
+ cnt++;
+ }
+ }
+ }
+ if(cnt&0x0f00) {
+ cnt = (cnt&0x0f) - (cnt>>16);
+ if(cnt>1) {
+ for(i=0;i<32;i+=8) {
+ if(((recena>>i)&0x0f)>7) {
+ recena &= ~(0x0f<<i);
+ recena |= (7<<i);
+ }
+ }
+ }
+ else {
+ for(i=0;i<32;i+=8) {
+ if(((recena>>i)&0x0f)<8) {
+ recena &= ~(0x0f<<i);
+ recena |= (8<<i);
+ }
+ }
+ }
+ }
+ for(i=cnt=0;i<32;i+=8) {
+ if (((recenb>>i)&0x0f)>7) {
+ cnt+= 0x101;
+ }
+ else {
+ if((recenb>>i)&0x0f) {
+ cnt++;
+ }
+ }
+ }
+ if(cnt & 0x0f00) {
+ cnt = (cnt&0x0f) - (cnt>>16);
+ if(cnt>1) {
+ for(i=0;i<32;i+=8) {
+ if(((recenb>>i)&0x0f)>7) {
+ recenb &= ~(0x0f<<i);
+ recenb |= (7<<i);
+ }
+ }
+ }
+ else {
+ for(i=0;i<32;i+=8) {
+ if(((recenb>>8)&0x0f)<8) {
+ recenb &= ~(0x0f<<i);
+ recenb |= (8<<i);
+ }
+ }
+ }
+ }
+
+ print_debug("Receive enable A = ");
+ print_debug_hex32(recena);
+ print_debug(", Receive enable B = ");
+ print_debug_hex32(recenb);
+ print_debug("\r\n");
+
+ /* clear out the calibration area */
+ write32(BAR+DCALDATA+(16*4), 0x00000000);
+ write32(BAR+DCALDATA+(17*4), 0x00000000);
+ write32(BAR+DCALDATA+(18*4), 0x00000000);
+ write32(BAR+DCALDATA+(19*4), 0x00000000);
+
+ /* No command */
+ write32(BAR+DCALCSR, 0x0000000f);
+
+ write32(BAR+0x150, recena);
+ write32(BAR+0x154, recenb);
+}
+
+
+static void sdram_enable(int controllers, const struct mem_controller *ctrl)
+{
+ int i;
+ int cs;
+ int cnt;
+ int cas_latency;
+ long mask;
+ uint32_t drc;
+ uint32_t data32;
+ uint32_t mode_reg;
+ uint32_t *iptr;
+ volatile unsigned long *iptrv;
+ msr_t msr;
+ uint32_t scratch;
+ uint8_t byte;
+ uint16_t data16;
+ static const struct {
+ uint32_t clkgr[4];
+ } gearing [] = {
+ /* FSB 133 DIMM 266 */
+ {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
+ /* FSB 133 DIMM 333 */
+ {{ 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+ /* FSB 133 DIMM 400 */
+ {{ 0x00000120, 0x00000000, 0x00000032, 0x00000010}},
+ /* FSB 167 DIMM 266 */
+ {{ 0x00005432, 0x00001000, 0x00004325, 0x00000000}},
+ /* FSB 167 DIMM 333 */
+ {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
+ /* FSB 167 DIMM 400 */
+ {{ 0x00154320, 0x00000000, 0x00065432, 0x00010000}},
+ /* FSB 200 DIMM 266 */
+ {{ 0x00000032, 0x00000010, 0x00000120, 0x00000000}},
+ /* FSB 200 DIMM 333 */
+ {{ 0x00065432, 0x00010000, 0x00154320, 0x00000000}},
+ /* FSB 200 DIMM 400 */
+ {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
+ };
+
+ static const uint32_t dqs_data[] = {
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff};
+
+ mask = spd_detect_dimms(ctrl);
+ print_debug("Starting SDRAM Enable\r\n");
+
+ /* 0x80 */
+#ifdef DIMM_MAP_LOGICAL
+ pci_write_config32(ctrl->f0, DRM,
+ 0x00210000 | DIMM_MAP_LOGICAL);
+#else
+ pci_write_config32(ctrl->f0, DRM, 0x00211248);
+#endif
+ /* set dram type and Front Side Bus freq. */
+ drc = spd_set_dram_controller_mode(ctrl, mask);
+ if( drc == 0) {
+ die("Error calculating DRC\r\n");
+ }
+ pll_setup(drc);
+ data32 = drc & ~(3 << 20); /* clear ECC mode */
+ data32 = data32 & ~(7 << 8); /* clear refresh rates */
+ data32 = data32 | (1 << 5); /* temp turn off of ODT */
+ /* Set gearing, then dram controller mode */
+ /* drc bits 1:0 = DIMM speed, bits 3:2 = FSB speed */
+ for(iptr = gearing[(drc&3)+((((drc>>2)&3)-1)*3)].clkgr,cnt=0;
+ cnt<4;cnt++) {
+ pci_write_config32(ctrl->f0, 0xa0+(cnt*4), iptr[cnt]);
+ }
+ /* 0x7c DRC */
+ pci_write_config32(ctrl->f0, DRC, data32);
+
+ /* turn the clocks on */
+ /* 0x8c CKDIS */
+ pci_write_config16(ctrl->f0, CKDIS, 0x0000);
+
+ /* 0x9a DDRCSR Take subsystem out of idle */
+ data16 = pci_read_config16(ctrl->f0, DDRCSR);
+ data16 &= ~(7 << 12);
+ data16 |= (3 << 12); /* use dual channel lock step */
+ pci_write_config16(ctrl->f0, DDRCSR, data16);
+
+ /* program row size DRB */
+ spd_set_ram_size(ctrl, mask);
+
+ /* program page size DRA */
+ spd_set_row_attributes(ctrl, mask);
+
+ /* program DRT timing values */
+ cas_latency = spd_set_drt_attributes(ctrl, mask, drc);
+
+ for(i=0;i<8;i++) { /* loop throught each dimm to test for row */
+ print_debug("DIMM ");
+ print_debug_hex8(i);
+ print_debug("\r\n");
+ /* Apply NOP */
+ do_delay();
+
+ write32(BAR + 0x100, (0x03000000 | (i<<20)));
+
+ write32(BAR+0x100, (0x83000000 | (i<<20)));
+
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+
+ }
+
+ /* Apply NOP */
+ do_delay();
+
+ for(cs=0;cs<8;cs++) {
+ write32(BAR + DCALCSR, (0x83000000 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Precharg all banks */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ if ((drc & 3) == 2) /* DDR2 */
+ write32(BAR+DCALADDR, 0x04000000);
+ else /* DDR1 */
+ write32(BAR+DCALADDR, 0x00000000);
+ write32(BAR+DCALCSR, (0x83000002 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* EMRS dll's enabled */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ if ((drc & 3) == 2) /* DDR2 */
+ /* fixme hard code AL additive latency */
+ write32(BAR+DCALADDR, 0x0b940001);
+ else /* DDR1 */
+ write32(BAR+DCALADDR, 0x00000001);
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ /* MRS reset dll's */
+ do_delay();
+ if ((drc & 3) == 2) { /* DDR2 */
+ if(cas_latency == 30)
+ mode_reg = 0x053a0000;
+ else
+ mode_reg = 0x054a0000;
+ }
+ else { /* DDR1 */
+ if(cas_latency == 20)
+ mode_reg = 0x012a0000;
+ else /* CAS Latency 2.5 */
+ mode_reg = 0x016a0000;
+ }
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALADDR, mode_reg);
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Precharg all banks */
+ do_delay();
+ do_delay();
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ if ((drc & 3) == 2) /* DDR2 */
+ write32(BAR+DCALADDR, 0x04000000);
+ else /* DDR1 */
+ write32(BAR+DCALADDR, 0x00000000);
+ write32(BAR+DCALCSR, (0x83000002 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Do 2 refreshes */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ do_delay();
+ /* for good luck do 6 more */
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ /* MRS reset dll's normal */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALADDR, (mode_reg & ~(1<<24)));
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Do only if DDR2 EMRS dll's enabled */
+ if ((drc & 3) == 2) { /* DDR2 */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALADDR, (0x0b940001));
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ }
+
+ do_delay();
+ /* No command */
+ write32(BAR+DCALCSR, 0x0000000f);
+
+ /* DDR1 This is test code to copy some codes in the factory setup */
+
+ write32(BAR, 0x00100000);
+
+ if ((drc & 3) == 2) { /* DDR2 */
+ /* enable on dimm termination */
+ set_on_dimm_termination_enable(ctrl);
+ }
+ else { /* ddr */
+ pci_write_config32(ctrl->f0, 0x88, 0xa0000000 );
+ }
+
+ /* receive enable calibration */
+ set_receive_enable(ctrl);
+
+ /* DQS */
+ pci_write_config32(ctrl->f0, 0x94, 0x3904a100 );
+ for(i = 0, cnt = (BAR+0x200); i < 24; i++, cnt+=4) {
+ write32(cnt, dqs_data[i]);
+ }
+ pci_write_config32(ctrl->f0, 0x94, 0x3904a100 );
+
+ /* Enable refresh */
+ /* 0x7c DRC */
+ data32 = drc & ~(3 << 20); /* clear ECC mode */
+ pci_write_config32(ctrl->f0, DRC, data32);
+ write32(BAR+DCALCSR, 0x0008000f);
+
+ /* clear memory and init ECC */
+ print_debug("Clearing memory\r\n");
+ for(i=0;i<64;i+=4) {
+ write32(BAR+DCALDATA+i, 0x00000000);
+ }
+
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x830831d8 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Bring memory subsystem on line */
+ data32 = pci_read_config32(ctrl->f0, 0x98);
+ data32 |= (1 << 31);
+ pci_write_config32(ctrl->f0, 0x98, data32);
+ /* wait for completion */
+ print_debug("Waiting for mem complete\r\n");
+ while(1) {
+ data32 = pci_read_config32(ctrl->f0, 0x98);
+ if( (data32 & (1<<31)) == 0)
+ break;
+ }
+ print_debug("Done\r\n");
+
+ /* Set initialization complete */
+ /* 0x7c DRC */
+ drc |= (1 << 29);
+ data32 = drc & ~(3 << 20); /* clear ECC mode */
+ pci_write_config32(ctrl->f0, DRC, data32);
+
+ /* Set the ecc mode */
+ pci_write_config32(ctrl->f0, DRC, drc);
+
+ /* Enable memory scrubbing */
+ /* 0x52 MCHSCRB */
+ data16 = pci_read_config16(ctrl->f0, MCHSCRB);
+ data16 &= ~0x0f;
+ data16 |= ((2 << 2) | (2 << 0));
+ pci_write_config16(ctrl->f0, MCHSCRB, data16);
+
+ /* The memory is now setup, use it */
+ cache_lbmem(MTRR_TYPE_WRBACK);
+}
diff --git a/src/northbridge/intel/E7520/raminit.h b/src/northbridge/intel/E7520/raminit.h
new file mode 100644
index 0000000000..183ace8385
--- /dev/null
+++ b/src/northbridge/intel/E7520/raminit.h
@@ -0,0 +1,12 @@
+#ifndef RAMINIT_H
+#define RAMINIT_H
+
+#define DIMM_SOCKETS 4
+struct mem_controller {
+ unsigned node_id;
+ device_t f0, f1, f2, f3;
+ uint16_t channel0[DIMM_SOCKETS];
+ uint16_t channel1[DIMM_SOCKETS];
+};
+
+#endif /* RAMINIT_H */
diff --git a/src/northbridge/intel/E7520/raminit_test.c b/src/northbridge/intel/E7520/raminit_test.c
new file mode 100644
index 0000000000..a69bafdac9
--- /dev/null
+++ b/src/northbridge/intel/E7520/raminit_test.c
@@ -0,0 +1,442 @@
+#include <unistd.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <setjmp.h>
+#include <device/pci_def.h>
+#include "e7520.h"
+
+jmp_buf end_buf;
+
+static int is_cpu_pre_c0(void)
+{
+ return 0;
+}
+
+#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \
+ (((BUS) & 0xFF) << 16) | \
+ (((DEV) & 0x1f) << 11) | \
+ (((FN) & 0x07) << 8) | \
+ ((WHERE) & 0xFF))
+
+#define PCI_DEV(BUS, DEV, FN) ( \
+ (((BUS) & 0xFF) << 16) | \
+ (((DEV) & 0x1f) << 11) | \
+ (((FN) & 0x7) << 8))
+
+#define PCI_ID(VENDOR_ID, DEVICE_ID) \
+ ((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF))
+
+typedef unsigned device_t;
+
+unsigned char pci_register[256*5*3*256];
+
+static uint8_t pci_read_config8(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = dev | where;
+ return pci_register[addr];
+}
+
+static uint16_t pci_read_config16(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = dev | where;
+ return pci_register[addr] | (pci_register[addr + 1] << 8);
+}
+
+static uint32_t pci_read_config32(device_t dev, unsigned where)
+{
+ unsigned addr;
+ uint32_t value;
+ addr = dev | where;
+ value = pci_register[addr] |
+ (pci_register[addr + 1] << 8) |
+ (pci_register[addr + 2] << 16) |
+ (pci_register[addr + 3] << 24);
+
+#if 0
+ print_debug("pcir32(");
+ print_debug_hex32(addr);
+ print_debug("):");
+ print_debug_hex32(value);
+ print_debug("\n");
+#endif
+ return value;
+
+}
+
+static void pci_write_config8(device_t dev, unsigned where, uint8_t value)
+{
+ unsigned addr;
+ addr = dev | where;
+ pci_register[addr] = value;
+}
+
+static void pci_write_config16(device_t dev, unsigned where, uint16_t value)
+{
+ unsigned addr;
+ addr = dev | where;
+ pci_register[addr] = value & 0xff;
+ pci_register[addr + 1] = (value >> 8) & 0xff;
+}
+
+static void pci_write_config32(device_t dev, unsigned where, uint32_t value)
+{
+ unsigned addr;
+ addr = dev | where;
+ pci_register[addr] = value & 0xff;
+ pci_register[addr + 1] = (value >> 8) & 0xff;
+ pci_register[addr + 2] = (value >> 16) & 0xff;
+ pci_register[addr + 3] = (value >> 24) & 0xff;
+
+#if 0
+ print_debug("pciw32(");
+ print_debug_hex32(addr);
+ print_debug(", ");
+ print_debug_hex32(value);
+ print_debug(")\n");
+#endif
+}
+
+#define PCI_DEV_INVALID (0xffffffffU)
+static device_t pci_locate_device(unsigned pci_id, device_t dev)
+{
+ for(; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0,0,1)) {
+ unsigned int id;
+ id = pci_read_config32(dev, 0);
+ if (id == pci_id) {
+ return dev;
+ }
+ }
+ return PCI_DEV_INVALID;
+}
+
+
+
+
+static void uart_tx_byte(unsigned char data)
+{
+ write(STDOUT_FILENO, &data, 1);
+}
+static void hlt(void)
+{
+ longjmp(end_buf, 2);
+}
+#include "../../../arch/i386/lib/console.c"
+
+unsigned long log2(unsigned long x)
+{
+ // assume 8 bits per byte.
+ unsigned long i = 1 << (sizeof(x)*8 - 1);
+ unsigned long pow = sizeof(x) * 8 - 1;
+
+ if (! x) {
+ static const char errmsg[] = " called with invalid parameter of 0\n";
+ write(STDERR_FILENO, __func__, sizeof(__func__) - 1);
+ write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1);
+ hlt();
+ }
+ for(; i > x; i >>= 1, pow--)
+ ;
+
+ return pow;
+}
+
+typedef struct msr_struct
+{
+ unsigned lo;
+ unsigned hi;
+} msr_t;
+
+static inline msr_t rdmsr(unsigned index)
+{
+ msr_t result;
+ result.lo = 0;
+ result.hi = 0;
+ return result;
+}
+
+static inline void wrmsr(unsigned index, msr_t msr)
+{
+}
+
+#include "raminit.h"
+
+#define SIO_BASE 0x2e
+
+static void hard_reset(void)
+{
+ /* FIXME implement the hard reset case... */
+ longjmp(end_buf, 3);
+}
+
+static void memreset_setup(void)
+{
+ /* Nothing to do */
+}
+
+static void memreset(int controllers, const struct mem_controller *ctrl)
+{
+ /* Nothing to do */
+}
+
+static inline void activate_spd_rom(const struct mem_controller *ctrl)
+{
+ /* nothing to do */
+}
+
+
+static uint8_t spd_mt4lsdt464a[256] =
+{
+ 0x80, 0x08, 0x04, 0x0C, 0x08, 0x01, 0x40, 0x00, 0x01, 0x70,
+ 0x54, 0x00, 0x80, 0x10, 0x00, 0x01, 0x8F, 0x04, 0x06, 0x01,
+ 0x01, 0x00, 0x0E, 0x75, 0x54, 0x00, 0x00, 0x0F, 0x0E, 0x0F,
+
+ 0x25, 0x08, 0x15, 0x08, 0x15, 0x08, 0x00, 0x12, 0x01, 0x4E,
+ 0x9C, 0xE4, 0xB7, 0x46, 0x2C, 0xFF, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x00,
+};
+
+static uint8_t spd_micron_512MB_DDR333[256] =
+{
+ 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x02, 0x48, 0x00, 0x04, 0x60,
+ 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01,
+ 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48,
+ 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x48, 0x30, 0x28, 0x50, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x6f, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x01, 0x33, 0x36, 0x56, 0x44, 0x44, 0x46, 0x31,
+ 0x32, 0x38, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43,
+ 0x33, 0x03, 0x00, 0x03, 0x23, 0x17, 0x07, 0x5a, 0xb2, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static uint8_t spd_micron_256MB_DDR333[256] =
+{
+ 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x01, 0x48, 0x00, 0x04, 0x60,
+ 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01,
+ 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48,
+ 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x48, 0x30, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x58, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x01, 0x31, 0x38, 0x56, 0x44, 0x44, 0x46, 0x36,
+ 0x34, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, 0x31,
+ 0x20, 0x01, 0x00, 0x03, 0x19, 0x17, 0x05, 0xb2, 0xf4, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+#define MAX_DIMMS 16
+static uint8_t spd_data[MAX_DIMMS*256];
+
+static unsigned spd_count, spd_fail_count;
+static int spd_read_byte(unsigned device, unsigned address)
+{
+ int result;
+ spd_count++;
+ if ((device < 0x50) || (device >= (0x50 +MAX_DIMMS))) {
+ result = -1;
+ }
+ else {
+ device -= 0x50;
+
+ if (address > 256) {
+ result = -1;
+ }
+ else if (spd_data[(device << 8) | 2] != 7) {
+ result = -1;
+ }
+ else {
+ result = spd_data[(device << 8) | address];
+ }
+ }
+#if 0
+ print_debug("spd_read_byte(");
+ print_debug_hex32(device);
+ print_debug(", ");
+ print_debug_hex32(address);
+ print_debug(") -> ");
+ print_debug_hex32(result);
+ print_debug("\n");
+#endif
+ if (spd_count >= spd_fail_count) {
+ result = -1;
+ }
+ return result;
+}
+
+/* no specific code here. this should go away completely */
+static void coherent_ht_mainboard(unsigned cpus)
+{
+}
+
+#include "raminit.c"
+#include "../../../sdram/generic_sdram.c"
+
+#define FIRST_CPU 1
+#define SECOND_CPU 1
+#define TOTAL_CPUS (FIRST_CPU + SECOND_CPU)
+static void raminit_main(void)
+{
+ /*
+ * GPIO28 of 8111 will control H0_MEMRESET_L
+ * GPIO29 of 8111 will control H1_MEMRESET_L
+ */
+ static const struct mem_controller cpu[] = {
+#if FIRST_CPU
+ {
+ .node_id = 0,
+ .f0 = PCI_DEV(0, 0x18, 0),
+ .f1 = PCI_DEV(0, 0x18, 1),
+ .f2 = PCI_DEV(0, 0x18, 2),
+ .f3 = PCI_DEV(0, 0x18, 3),
+ .channel0 = { 0x50+0, 0x50+2, 0x50+4, 0x50+6 },
+ .channel1 = { 0x50+1, 0x50+3, 0x50+5, 0x50+7 },
+ },
+#endif
+#if SECOND_CPU
+ {
+ .node_id = 1,
+ .f0 = PCI_DEV(0, 0x19, 0),
+ .f1 = PCI_DEV(0, 0x19, 1),
+ .f2 = PCI_DEV(0, 0x19, 2),
+ .f3 = PCI_DEV(0, 0x19, 3),
+ .channel0 = { 0x50+8, 0x50+10, 0x50+12, 0x50+14 },
+ .channel1 = { 0x50+9, 0x50+11, 0x50+13, 0x50+15 },
+ },
+#endif
+ };
+ console_init();
+ memreset_setup();
+ sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu);
+
+}
+
+static void reset_tests(void)
+{
+ /* Clear the results of any previous tests */
+ memset(pci_register, 0, sizeof(pci_register));
+ memset(spd_data, 0, sizeof(spd_data));
+ spd_count = 0;
+ spd_fail_count = UINT_MAX;
+
+ pci_write_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP,
+ NBCAP_128Bit |
+ NBCAP_MP| NBCAP_BIG_MP |
+ /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */
+ (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) |
+ NBCAP_MEMCTRL);
+
+ pci_write_config32(PCI_DEV(0, 0x19, 3), NORTHBRIDGE_CAP,
+ NBCAP_128Bit |
+ NBCAP_MP| NBCAP_BIG_MP |
+ /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */
+ (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) |
+ NBCAP_MEMCTRL);
+
+#if 0
+ pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP);
+#endif
+}
+
+static void test1(void)
+{
+ reset_tests();
+
+ memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256);
+#if 0
+ memcpy(&spd_data[2*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[3*256], spd_micron_512MB_DDR333, 256);
+
+ memcpy(&spd_data[8*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[9*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[10*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[11*256], spd_micron_512MB_DDR333, 256);
+#endif
+
+ raminit_main();
+
+#if 0
+ print_debug("spd_count: ");
+ print_debug_hex32(spd_count);
+ print_debug("\r\n");
+#endif
+
+}
+
+
+static void do_test2(int i)
+{
+ jmp_buf tmp_buf;
+ memcpy(&tmp_buf, &end_buf, sizeof(end_buf));
+ if (setjmp(end_buf) != 0) {
+ goto done;
+ }
+ reset_tests();
+ spd_fail_count = i;
+
+ print_debug("\r\nSPD will fail after: ");
+ print_debug_hex32(spd_fail_count);
+ print_debug(" accesses.\r\n");
+
+ memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256);
+
+ raminit_main();
+
+ done:
+ memcpy(&end_buf, &tmp_buf, sizeof(end_buf));
+}
+
+static void test2(void)
+{
+ int i;
+ for(i = 0; i < 0x48; i++) {
+ do_test2(i);
+ }
+
+}
+
+int main(int argc, char **argv)
+{
+ if (setjmp(end_buf) != 0) {
+ return -1;
+ }
+ test1();
+ test2();
+ return 0;
+}
diff --git a/src/northbridge/intel/E7525/Config.lb b/src/northbridge/intel/E7525/Config.lb
new file mode 100644
index 0000000000..919e0f8adf
--- /dev/null
+++ b/src/northbridge/intel/E7525/Config.lb
@@ -0,0 +1,12 @@
+config chip.h
+driver northbridge.o
+driver pciexp_porta.o
+driver pciexp_porta1.o
+driver pciexp_portb.o
+driver pciexp_portc.o
+
+makerule raminit_test
+ depends "$(TOP)/src/northbridge/intel/e7525/raminit_test.c"
+ depends "$(TOP)/src/northbridge/intel/e7525/raminit.c"
+ action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g $< -o $@"
+end
diff --git a/src/northbridge/intel/E7525/chip.h b/src/northbridge/intel/E7525/chip.h
new file mode 100644
index 0000000000..19d8c4e54c
--- /dev/null
+++ b/src/northbridge/intel/E7525/chip.h
@@ -0,0 +1,7 @@
+struct northbridge_intel_E7525_config
+{
+ /* Interrupt line connect */
+ unsigned int intrline;
+};
+
+extern struct chip_operations northbridge_intel_E7525_ops;
diff --git a/src/northbridge/intel/E7525/e7525.h b/src/northbridge/intel/E7525/e7525.h
new file mode 100644
index 0000000000..be76303d4f
--- /dev/null
+++ b/src/northbridge/intel/E7525/e7525.h
@@ -0,0 +1,44 @@
+#define VID 0X00
+#define DID 0X02
+#define PCICMD 0X04
+#define PCISTS 0X06
+#define RID 0X08
+#define IURBASE 0X14
+#define MCHCFG0 0X50
+#define MCHSCRB 0X52
+#define FDHC 0X58
+#define PAM 0X59
+#define DRB 0X60
+#define DRA 0X70
+#define DRT 0X78
+#define DRC 0X7C
+#define DRM 0X80
+#define DRORC 0X82
+#define ECCDIAG 0X84
+#define SDRC 0X88
+#define CKDIS 0X8C
+#define CKEDIS 0X8D
+#define DDRCSR 0X9A
+#define DEVPRES 0X9C
+#define DEVPRES_D0F0 (1 << 0)
+#define DEVPRES_D1F0 (1 << 1)
+#define DEVPRES_D2F0 (1 << 2)
+#define DEVPRES_D3F0 (1 << 3)
+#define DEVPRES_D4F0 (1 << 4)
+#define DEVPRES_D5F0 (1 << 5)
+#define DEVPRES_D6F0 (1 << 6)
+#define DEVPRES_D7F0 (1 << 7)
+#define ESMRC 0X9D
+#define SMRC 0X9E
+#define EXSMRC 0X9F
+#define DDR2ODTC 0XB0
+#define TOLM 0XC4
+#define REMAPBASE 0XC6
+#define REMAPLIMIT 0XC8
+#define REMAPOFFSET 0XCA
+#define TOM 0XCC
+#define EXPECBASE 0XCE
+#define DEVPRES1 0XF4
+#define DEVPRES1_D0F1 (1 << 5)
+#define DEVPRES1_D8F0 (1 << 1)
+#define MSCFG 0XF6
diff --git a/src/northbridge/intel/E7525/memory_initialized.c b/src/northbridge/intel/E7525/memory_initialized.c
new file mode 100644
index 0000000000..6eb31a8ca3
--- /dev/null
+++ b/src/northbridge/intel/E7525/memory_initialized.c
@@ -0,0 +1,9 @@
+#include "e7525.h"
+#define NB_DEV PCI_DEV(0, 0, 0)
+
+static inline int memory_initialized(void)
+{
+ uint32_t drc;
+ drc = pci_read_config32(NB_DEV, DRC);
+ return (drc & (1<<29));
+}
diff --git a/src/northbridge/intel/E7525/northbridge.c b/src/northbridge/intel/E7525/northbridge.c
new file mode 100644
index 0000000000..71f17224df
--- /dev/null
+++ b/src/northbridge/intel/E7525/northbridge.c
@@ -0,0 +1,270 @@
+#include <console/console.h>
+#include <arch/io.h>
+#include <stdint.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/hypertransport.h>
+#include <stdlib.h>
+#include <string.h>
+#include <bitops.h>
+#include <cpu/cpu.h>
+#include "chip.h"
+#include "northbridge.h"
+#include "e7525.h"
+
+
+static unsigned int max_bus;
+
+static void ram_resource(device_t dev, unsigned long index,
+ unsigned long basek, unsigned long sizek)
+{
+ struct resource *resource;
+
+ resource = new_resource(dev, index);
+ resource->base = ((resource_t)basek) << 10;
+ resource->size = ((resource_t)sizek) << 10;
+ resource->flags = IORESOURCE_MEM | IORESOURCE_CACHEABLE | \
+ IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+}
+
+
+static void pci_domain_read_resources(device_t dev)
+{
+ struct resource *resource;
+
+ /* Initialize the system wide io space constraints */
+ resource = new_resource(dev, IOINDEX_SUBTRACTIVE(0,0));
+ resource->base = 0;
+ resource->size = 0;
+ resource->align = 0;
+ resource->gran = 0;
+ resource->limit = 0xffffUL;
+ resource->flags = IORESOURCE_IO | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+
+ /* Initialize the system wide memory resources constraints */
+ resource = new_resource(dev, IOINDEX_SUBTRACTIVE(1,0));
+ resource->base = 0;
+ resource->size = 0;
+ resource->align = 0;
+ resource->gran = 0;
+ resource->limit = 0xffffffffUL;
+ resource->flags = IORESOURCE_MEM | IORESOURCE_SUBTRACTIVE | IORESOURCE_ASSIGNED;
+}
+
+static void tolm_test(void *gp, struct device *dev, struct resource *new)
+{
+ struct resource **best_p = gp;
+ struct resource *best;
+ best = *best_p;
+ if (!best || (best->base > new->base)) {
+ best = new;
+ }
+ *best_p = best;
+}
+
+static uint32_t find_pci_tolm(struct bus *bus)
+{
+ struct resource *min;
+ uint32_t tolm;
+ min = 0;
+ search_bus_resources(bus, IORESOURCE_MEM, IORESOURCE_MEM, tolm_test, &min);
+ tolm = 0xffffffffUL;
+ if (min && tolm > min->base) {
+ tolm = min->base;
+ }
+ return tolm;
+}
+
+
+static void pci_domain_set_resources(device_t dev)
+{
+ device_t mc_dev;
+ uint32_t pci_tolm;
+
+ pci_tolm = find_pci_tolm(&dev->link[0]);
+
+#if 1
+ printk_debug("PCI mem marker = %x\n", pci_tolm);
+#endif
+ /* FIXME Me temporary hack */
+ if(pci_tolm > 0xe0000000)
+ pci_tolm = 0xe0000000;
+ /* Ensure pci_tolm is 128M aligned */
+ pci_tolm &= 0xf8000000;
+ mc_dev = dev->link[0].children;
+ if (mc_dev) {
+ /* Figure out which areas are/should be occupied by RAM.
+ * This is all computed in kilobytes and converted to/from
+ * the memory controller right at the edges.
+ * Having different variables in different units is
+ * too confusing to get right. Kilobytes are good up to
+ * 4 Terabytes of RAM...
+ */
+ uint16_t tolm_r, remapbase_r, remaplimit_r, remapoffset_r;
+ unsigned long tomk, tolmk;
+ unsigned long remapbasek, remaplimitk, remapoffsetk;
+
+ /* Get the Top of Memory address, units are 128M */
+ tomk = ((unsigned long)pci_read_config16(mc_dev, TOM)) << 17;
+ /* Compute the Top of Low Memory */
+ tolmk = (pci_tolm & 0xf8000000) >> 10;
+
+ if (tolmk >= tomk) {
+ /* The PCI hole does not overlap memory
+ * we won't use the remap window.
+ */
+ tolmk = tomk;
+ remapbasek = 0x3ff << 16;
+ remaplimitk = 0 << 16;
+ remapoffsetk = 0 << 16;
+ }
+ else {
+ /* The PCI memory hole overlaps memory
+ * setup the remap window.
+ */
+ /* Find the bottom of the remap window
+ * is it above 4G?
+ */
+ remapbasek = 4*1024*1024;
+ if (tomk > remapbasek) {
+ remapbasek = tomk;
+ }
+ /* Find the limit of the remap window */
+ remaplimitk = (remapbasek + (4*1024*1024 - tolmk) - (1 << 16));
+ /* Find the offset of the remap window from tolm */
+ remapoffsetk = remapbasek - tolmk;
+ }
+ /* Write the ram configruation registers,
+ * preserving the reserved bits.
+ */
+ tolm_r = pci_read_config16(mc_dev, 0xc4);
+ tolm_r = ((tolmk >> 17) << 11) | (tolm_r & 0x7ff);
+ pci_write_config16(mc_dev, 0xc4, tolm_r);
+
+ remapbase_r = pci_read_config16(mc_dev, 0xc6);
+ remapbase_r = (remapbasek >> 16) | (remapbase_r & 0xfc00);
+ pci_write_config16(mc_dev, 0xc6, remapbase_r);
+
+ remaplimit_r = pci_read_config16(mc_dev, 0xc8);
+ remaplimit_r = (remaplimitk >> 16) | (remaplimit_r & 0xfc00);
+ pci_write_config16(mc_dev, 0xc8, remaplimit_r);
+
+ remapoffset_r = pci_read_config16(mc_dev, 0xca);
+ remapoffset_r = (remapoffsetk >> 16) | (remapoffset_r & 0xfc00);
+ pci_write_config16(mc_dev, 0xca, remapoffset_r);
+
+ /* Report the memory regions */
+ ram_resource(dev, 3, 0, 640);
+ ram_resource(dev, 4, 768, tolmk - 768);
+ if (tomk > 4*1024*1024) {
+ ram_resource(dev, 5, 4096*1024, tomk - 4*1024*1024);
+ }
+ if (remaplimitk >= remapbasek) {
+ ram_resource(dev, 6, remapbasek,
+ (remaplimitk + 64*1024) - remapbasek);
+ }
+ }
+ assign_resources(&dev->link[0]);
+}
+
+static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
+{
+ max = pci_scan_bus(&dev->link[0], 0, 0xff, max);
+ if (max > max_bus) {
+ max_bus = max;
+ }
+ return max;
+}
+
+static struct device_operations pci_domain_ops = {
+ .read_resources = pci_domain_read_resources,
+ .set_resources = pci_domain_set_resources,
+ .enable_resources = enable_childrens_resources,
+ .init = 0,
+ .scan_bus = pci_domain_scan_bus,
+ .ops_pci_bus = &pci_cf8_conf1, /* Do we want to use the memory mapped space here? */
+};
+
+static void mc_read_resources(device_t dev)
+{
+ struct resource *resource;
+
+ pci_dev_read_resources(dev);
+
+ resource = new_resource(dev, 0xcf);
+ resource->base = 0xe0000000;
+ resource->size = max_bus * 4096*256;
+ resource->flags = IORESOURCE_MEM | IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+}
+
+static void mc_set_resources(device_t dev)
+{
+ struct resource *resource, *last;
+
+ last = &dev->resource[dev->resources];
+ resource = find_resource(dev, 0xcf);
+ if (resource) {
+ report_resource_stored(dev, resource, "<mmconfig>");
+ }
+ pci_dev_set_resources(dev);
+}
+
+static void intel_set_subsystem(device_t dev, unsigned vendor, unsigned device)
+{
+ pci_write_config32(dev, PCI_SUBSYSTEM_VENDOR_ID,
+ ((device & 0xffff) << 16) | (vendor & 0xffff));
+}
+
+static struct pci_operations intel_pci_ops = {
+ .set_subsystem = intel_set_subsystem,
+};
+
+static struct device_operations mc_ops = {
+ .read_resources = mc_read_resources,
+ .set_resources = mc_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = 0,
+ .scan_bus = 0,
+ .ops_pci = &intel_pci_ops,
+};
+
+static struct pci_driver mc_driver __pci_driver = {
+ .ops = &mc_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = 0x359e,
+};
+
+static void cpu_bus_init(device_t dev)
+{
+ initialize_cpus(&dev->link[0]);
+}
+
+static void cpu_bus_noop(device_t dev)
+{
+}
+
+static struct device_operations cpu_bus_ops = {
+ .read_resources = cpu_bus_noop,
+ .set_resources = cpu_bus_noop,
+ .enable_resources = cpu_bus_noop,
+ .init = cpu_bus_init,
+ .scan_bus = 0,
+};
+
+
+static void enable_dev(device_t dev)
+{
+ /* Set the operations if it is a special bus type */
+ if (dev->path.type == DEVICE_PATH_PCI_DOMAIN) {
+ dev->ops = &pci_domain_ops;
+ }
+ else if (dev->path.type == DEVICE_PATH_APIC_CLUSTER) {
+ dev->ops = &cpu_bus_ops;
+ }
+}
+
+struct chip_operations northbridge_intel_E7525_ops = {
+ CHIP_NAME("Intel E7525 Northbridge")
+ .enable_dev = enable_dev,
+};
diff --git a/src/northbridge/intel/E7525/northbridge.h b/src/northbridge/intel/E7525/northbridge.h
new file mode 100644
index 0000000000..0ee533f011
--- /dev/null
+++ b/src/northbridge/intel/E7525/northbridge.h
@@ -0,0 +1,8 @@
+#ifndef NORTHBRIDGE_INTEL_E7525_H
+#define NORTHBRIDGE_INTEL_E7525_H
+
+extern unsigned int e7525_scan_root_bus(device_t root, unsigned int max);
+
+
+#endif /* NORTHBRIDGE_INTEL_E7525_H */
+
diff --git a/src/northbridge/intel/E7525/pciexp_porta.c b/src/northbridge/intel/E7525/pciexp_porta.c
new file mode 100644
index 0000000000..093edec38f
--- /dev/null
+++ b/src/northbridge/intel/E7525/pciexp_porta.c
@@ -0,0 +1,41 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+
+typedef struct northbridge_intel_E7525_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pciexp_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PA,
+};
+
+
diff --git a/src/northbridge/intel/E7525/pciexp_porta1.c b/src/northbridge/intel/E7525/pciexp_porta1.c
new file mode 100644
index 0000000000..7118caa72f
--- /dev/null
+++ b/src/northbridge/intel/E7525/pciexp_porta1.c
@@ -0,0 +1,41 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+
+typedef struct northbridge_intel_E7525_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pciexp_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PA1,
+};
+
+
diff --git a/src/northbridge/intel/E7525/pciexp_portb.c b/src/northbridge/intel/E7525/pciexp_portb.c
new file mode 100644
index 0000000000..f623a54416
--- /dev/null
+++ b/src/northbridge/intel/E7525/pciexp_portb.c
@@ -0,0 +1,41 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+
+typedef struct northbridge_intel_E7525_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pciexp_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PB,
+};
+
+
diff --git a/src/northbridge/intel/E7525/pciexp_portc.c b/src/northbridge/intel/E7525/pciexp_portc.c
new file mode 100644
index 0000000000..05e0b68863
--- /dev/null
+++ b/src/northbridge/intel/E7525/pciexp_portc.c
@@ -0,0 +1,41 @@
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <device/pciexp.h>
+#include <arch/io.h>
+#include "chip.h"
+
+typedef struct northbridge_intel_E7525_config config_t;
+
+static void pcie_init(struct device *dev)
+{
+ config_t *config;
+
+ /* Get the chip configuration */
+ config = dev->chip_info;
+
+ if(config->intrline) {
+ pci_write_config32(dev, 0x3c, config->intrline);
+ }
+
+}
+
+static struct device_operations pcie_ops = {
+ .read_resources = pci_bus_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_bus_enable_resources,
+ .init = pcie_init,
+ .scan_bus = pciexp_scan_bridge,
+ .reset_bus = pci_bus_reset,
+ .ops_pci = 0,
+};
+
+static struct pci_driver pci_driver __pci_driver = {
+ .ops = &pcie_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_PCIE_PC,
+};
+
+
diff --git a/src/northbridge/intel/E7525/raminit.c b/src/northbridge/intel/E7525/raminit.c
new file mode 100644
index 0000000000..c0e6b4291e
--- /dev/null
+++ b/src/northbridge/intel/E7525/raminit.c
@@ -0,0 +1,1300 @@
+#include <cpu/x86/mem.h>
+#include <cpu/x86/mtrr.h>
+#include <cpu/x86/cache.h>
+#include "raminit.h"
+#include "e7525.h"
+
+#define BAR 0x40000000
+
+static void sdram_set_registers(const struct mem_controller *ctrl)
+{
+ static const unsigned int register_values[] = {
+
+ /* CKDIS 0x8c disable clocks */
+ PCI_ADDR(0, 0x00, 0, CKDIS), 0xffff0000, 0x0000ffff,
+
+ /* 0x9c Device present and extended RAM control
+ * DEVPRES is very touchy, hard code the initialization
+ * of PCI-E ports here.
+ */
+ PCI_ADDR(0, 0x00, 0, DEVPRES), 0x00000000, 0x07020801 | DEVPRES_CONFIG,
+
+ /* 0xc8 Remap RAM base and limit off */
+ PCI_ADDR(0, 0x00, 0, REMAPLIMIT), 0x00000000, 0x03df0000,
+
+ /* ??? */
+ PCI_ADDR(0, 0x00, 0, 0xd8), 0x00000000, 0xb5930000,
+ PCI_ADDR(0, 0x00, 0, 0xe8), 0x00000000, 0x00004a2a,
+
+ /* 0x50 scrub */
+ PCI_ADDR(0, 0x00, 0, MCHCFG0), 0xfce0ffff, 0x00006000, /* 6000 */
+
+ /* 0x58 0x5c PAM */
+ PCI_ADDR(0, 0x00, 0, PAM-1), 0xcccccc7f, 0x33333000,
+ PCI_ADDR(0, 0x00, 0, PAM+3), 0xcccccccc, 0x33333333,
+
+ /* 0xf4 */
+ PCI_ADDR(0, 0x00, 0, DEVPRES1), 0xffbffff, (1<<22)|(6<<2) | DEVPRES1_CONFIG,
+
+ /* 0x14 */
+ PCI_ADDR(0, 0x00, 0, IURBASE), 0x00000fff, BAR |0,
+ };
+ int i;
+ int max;
+
+ max = sizeof(register_values)/sizeof(register_values[0]);
+ for(i = 0; i < max; i += 3) {
+ device_t dev;
+ unsigned where;
+ unsigned long reg;
+ dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x00, 0) + ctrl->f0;
+ where = register_values[i] & 0xff;
+ reg = pci_read_config32(dev, where);
+ reg &= register_values[i+1];
+ reg |= register_values[i+2];
+ pci_write_config32(dev, where, reg);
+ }
+ print_spew("done.\r\n");
+}
+
+
+
+struct dimm_size {
+ unsigned long side1;
+ unsigned long side2;
+};
+
+static struct dimm_size spd_get_dimm_size(unsigned device)
+{
+ /* Calculate the log base 2 size of a DIMM in bits */
+ struct dimm_size sz;
+ int value, low, ddr2;
+ sz.side1 = 0;
+ sz.side2 = 0;
+
+ /* test for ddr2 */
+ ddr2=0;
+ value = spd_read_byte(device, 2); /* type */
+ if (value < 0) goto hw_err;
+ if (value == 8) ddr2 = 1;
+
+ /* Note it might be easier to use byte 31 here, it has the DIMM size as
+ * a multiple of 4MB. The way we do it now we can size both
+ * sides of an assymetric dimm.
+ */
+ value = spd_read_byte(device, 3); /* rows */
+ 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 hw_err;
+ if ((value & 0xf) == 0) goto val_err;
+ sz.side1 += value & 0xf;
+
+ value = spd_read_byte(device, 17); /* banks */
+ 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 hw_err;
+ value &= 0xff;
+ value <<= 8;
+
+ low = spd_read_byte(device, 6); /* (low byte) */
+ 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 < 0) goto hw_err;
+ value &= 7;
+ if(ddr2) value++;
+ 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 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 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;
+
+}
+
+static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask)
+{
+ int i;
+ int cum;
+
+ for(i = cum = 0; i < DIMM_SOCKETS; i++) {
+ struct dimm_size sz;
+ if (dimm_mask & (1 << i)) {
+ sz = spd_get_dimm_size(ctrl->channel0[i]);
+ if (sz.side1 < 29) {
+ return -1; /* Report SPD error */
+ }
+ /* convert bits to multiples of 64MB */
+ sz.side1 -= 29;
+ cum += (1 << sz.side1);
+ /* DRB = 0x60 */
+ pci_write_config8(ctrl->f0, DRB + (i*2), cum);
+ if( sz.side2 > 28) {
+ sz.side2 -= 29;
+ cum += (1 << sz.side2);
+ }
+ pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum);
+ }
+ else {
+ pci_write_config8(ctrl->f0, DRB + (i*2), cum);
+ pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum);
+ }
+ }
+ /* set TOM top of memory 0xcc */
+ pci_write_config16(ctrl->f0, TOM, cum);
+ /* set TOLM top of low memory */
+ if(cum > 0x18) {
+ cum = 0x18;
+ }
+ cum <<= 11;
+ /* 0xc4 TOLM */
+ pci_write_config16(ctrl->f0, TOLM, cum);
+ return 0;
+}
+
+
+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(device, 2); /* Type */
+ if ((byte == 7) || (byte == 8)) {
+ dimm_mask |= (1 << i);
+ }
+ }
+ device = ctrl->channel1[i];
+ if (device) {
+ byte = spd_read_byte(device, 2);
+ if ((byte == 7) || (byte == 8)) {
+ dimm_mask |= (1 << (i + DIMM_SOCKETS));
+ }
+ }
+ }
+ return dimm_mask;
+}
+
+
+static int spd_set_row_attributes(const struct mem_controller *ctrl,
+ long dimm_mask)
+{
+
+ int value;
+ int reg;
+ int dra;
+ int cnt;
+
+ dra = 0;
+ for(cnt=0; cnt < 4; cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ reg =0;
+ value = spd_read_byte(ctrl->channel0[cnt], 3); /* rows */
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
+ reg += value & 0xf;
+
+ value = spd_read_byte(ctrl->channel0[cnt], 4); /* columns */
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
+ reg += value & 0xf;
+
+ value = spd_read_byte(ctrl->channel0[cnt], 17); /* banks */
+ if (value < 0) goto hw_err;
+ if ((value & 0xff) == 0) goto val_err;
+ reg += log2(value & 0xff);
+
+ /* Get the device width and convert it to a power of two */
+ value = spd_read_byte(ctrl->channel0[cnt], 13);
+ if (value < 0) goto hw_err;
+ value = log2(value & 0xff);
+ reg += value;
+ if(reg < 27) goto hw_err;
+ reg -= 27;
+ reg += (value << 2);
+
+ dra += reg << (cnt*8);
+ value = spd_read_byte(ctrl->channel0[cnt], 5);
+ if (value & 2)
+ dra += reg << ((cnt*8)+4);
+ }
+
+ /* 0x70 DRA */
+ pci_write_config32(ctrl->f0, DRA, dra);
+ goto out;
+
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ dra = 0;
+ out:
+ return dra;
+
+}
+
+
+static int spd_set_drt_attributes(const struct mem_controller *ctrl,
+ long dimm_mask, uint32_t drc)
+{
+ int value;
+ int reg;
+ uint32_t drt;
+ int cnt;
+ int first_dimm;
+ int cas_latency=0;
+ int latency;
+ uint32_t index = 0;
+ uint32_t index2 = 0;
+ static const unsigned char cycle_time[3] = {0x75,0x60,0x50};
+ static const int latency_indicies[] = { 26, 23, 9 };
+
+ /* 0x78 DRT */
+ drt = pci_read_config32(ctrl->f0, DRT);
+ drt &= 3; /* save bits 1:0 */
+
+ for(first_dimm = 0; first_dimm < 4; first_dimm++) {
+ if (dimm_mask & (1 << first_dimm))
+ break;
+ }
+
+ /* get dimm type */
+ value = spd_read_byte(ctrl->channel0[first_dimm], 2);
+ if(value == 8) {
+ drt |= (3<<5); /* back to bark write turn around & cycle add */
+ }
+
+ drt |= (3<<18); /* Trasmax */
+
+ for(cnt=0; cnt < 4; cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 18); /* CAS Latency */
+ /* Compute the lowest cas latency supported */
+ latency = log2(reg) -2;
+
+ /* Loop through and find a fast clock with a low latency */
+ for(index = 0; index < 3; index++, latency++) {
+ if ((latency < 2) || (latency > 4) ||
+ (!(reg & (1 << latency)))) {
+ continue;
+ }
+ value = spd_read_byte(ctrl->channel0[cnt],
+ latency_indicies[index]);
+
+ if(value <= cycle_time[drc&3]) {
+ if( latency > cas_latency) {
+ cas_latency = latency;
+ }
+ break;
+ }
+ }
+ }
+ index = (cas_latency-2);
+ if((index)==0) cas_latency = 20;
+ else if((index)==1) cas_latency = 25;
+ else cas_latency = 30;
+
+ for(cnt=0;cnt<4;cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 27)&0x0ff;
+ if(((index>>8)&0x0ff)<reg) {
+ index &= ~(0x0ff << 8);
+ index |= (reg << 8);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 28)&0x0ff;
+ if(((index>>16)&0x0ff)<reg) {
+ index &= ~(0x0ff << 16);
+ index |= (reg<<16);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 29)&0x0ff;
+ if(((index2>>0)&0x0ff)<reg) {
+ index2 &= ~(0x0ff << 0);
+ index2 |= (reg<<0);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 41)&0x0ff;
+ if(((index2>>8)&0x0ff)<reg) {
+ index2 &= ~(0x0ff << 8);
+ index2 |= (reg<<8);
+ }
+ reg = spd_read_byte(ctrl->channel0[cnt], 42)&0x0ff;
+ if(((index2>>16)&0x0ff)<reg) {
+ index2 &= ~(0x0ff << 16);
+ index2 |= (reg<<16);
+ }
+ }
+
+ /* get dimm speed */
+ value = cycle_time[drc&3];
+ if(value <= 0x50) { /* 200 MHz */
+ if((index&7) > 2) {
+ drt |= (2<<2); /* CAS latency 4 */
+ cas_latency = 40;
+ } else {
+ drt |= (1<<2); /* CAS latency 3 */
+ cas_latency = 30;
+ }
+ if((index&0x0ff00)<=0x03c00) {
+ drt |= (1<<8); /* Trp RAS Precharg */
+ } else {
+ drt |= (2<<8); /* Trp RAS Precharg */
+ }
+
+ /* Trcd RAS to CAS delay */
+ if((index2&0x0ff)<=0x03c) {
+ drt |= (0<<10);
+ } else {
+ drt |= (1<<10);
+ }
+
+ /* Tdal Write auto precharge recovery delay */
+ drt |= (1<<12);
+
+ /* Trc TRS min */
+ if((index2&0x0ff00)<=0x03700)
+ drt |= (0<<14);
+ else if((index2&0xff00)<=0x03c00)
+ drt |= (1<<14);
+ else
+ drt |= (2<<14); /* spd 41 */
+
+ drt |= (2<<16); /* Twr not defined for DDR docs say use 2 */
+
+ /* Trrd Row Delay */
+ if((index&0x0ff0000)<=0x0140000) {
+ drt |= (0<<20);
+ } else if((index&0x0ff0000)<=0x0280000) {
+ drt |= (1<<20);
+ } else if((index&0x0ff0000)<=0x03c0000) {
+ drt |= (2<<20);
+ } else {
+ drt |= (3<<20);
+ }
+
+ /* Trfc Auto refresh cycle time */
+ if((index2&0x0ff0000)<=0x04b0000) {
+ drt |= (0<<22);
+ } else if((index2&0x0ff0000)<=0x0690000) {
+ drt |= (1<<22);
+ } else {
+ drt |= (2<<22);
+ }
+ /* Docs say use 55 for all 200Mhz */
+ drt |= (0x055<<24);
+ }
+ else if(value <= 0x60) { /* 167 Mhz */
+ /* according to new documentation CAS latency is 00
+ * for bits 3:2 for all 167 Mhz
+ drt |= ((index&3)<<2); */ /* set CAS latency */
+ if((index&0x0ff00)<=0x03000) {
+ drt |= (1<<8); /* Trp RAS Precharg */
+ } else {
+ drt |= (2<<8); /* Trp RAS Precharg */
+ }
+
+ /* Trcd RAS to CAS delay */
+ if((index2&0x0ff)<=0x030) {
+ drt |= (0<<10);
+ } else {
+ drt |= (1<<10);
+ }
+
+ /* Tdal Write auto precharge recovery delay */
+ drt |= (2<<12);
+
+ /* Trc TRS min */
+ drt |= (2<<14); /* spd 41, but only one choice */
+
+ drt |= (2<<16); /* Twr not defined for DDR docs say 2 */
+
+ /* Trrd Row Delay */
+ if((index&0x0ff0000)<=0x0180000) {
+ drt |= (0<<20);
+ } else if((index&0x0ff0000)<=0x0300000) {
+ drt |= (1<<20);
+ } else {
+ drt |= (2<<20);
+ }
+
+ /* Trfc Auto refresh cycle time */
+ if((index2&0x0ff0000)<=0x0480000) {
+ drt |= (0<<22);
+ } else if((index2&0x0ff0000)<=0x0780000) {
+ drt |= (2<<22);
+ } else {
+ drt |= (2<<22);
+ }
+ /* Docs state to use 99 for all 167 Mhz */
+ drt |= (0x099<<24);
+ }
+ else if(value <= 0x75) { /* 133 Mhz */
+ drt |= ((index&3)<<2); /* set CAS latency */
+ if((index&0x0ff00)<=0x03c00) {
+ drt |= (1<<8); /* Trp RAS Precharg */
+ } else {
+ drt |= (2<<8); /* Trp RAS Precharg */
+ }
+
+ /* Trcd RAS to CAS delay */
+ if((index2&0x0ff)<=0x03c) {
+ drt |= (0<<10);
+ } else {
+ drt |= (1<<10);
+ }
+
+ /* Tdal Write auto precharge recovery delay */
+ drt |= (1<<12);
+
+ /* Trc TRS min */
+ drt |= (2<<14); /* spd 41, but only one choice */
+
+ drt |= (1<<16); /* Twr not defined for DDR docs say 1 */
+
+ /* Trrd Row Delay */
+ if((index&0x0ff0000)<=0x01e0000) {
+ drt |= (0<<20);
+ } else if((index&0x0ff0000)<=0x03c0000) {
+ drt |= (1<<20);
+ } else {
+ drt |= (2<<20);
+ }
+
+ /* Trfc Auto refresh cycle time */
+ if((index2&0x0ff0000)<=0x04b0000) {
+ drt |= (0<<22);
+ } else if((index2&0x0ff0000)<=0x0780000) {
+ drt |= (2<<22);
+ } else {
+ drt |= (2<<22);
+ }
+
+ /* Based on CAS latency */
+ if(index&7)
+ drt |= (0x099<<24);
+ else
+ drt |= (0x055<<24);
+
+ }
+ else {
+ die("Invalid SPD 9 bus speed.\r\n");
+ }
+
+ /* 0x78 DRT */
+ pci_write_config32(ctrl->f0, DRT, drt);
+
+ return(cas_latency);
+}
+
+static int spd_set_dram_controller_mode(const struct mem_controller *ctrl,
+ long dimm_mask)
+{
+ int value;
+ int reg;
+ int drc;
+ int cnt;
+ msr_t msr;
+ unsigned char dram_type = 0xff;
+ unsigned char ecc = 0xff;
+ unsigned char rate = 62;
+ static const unsigned char spd_rates[6] = {15,3,7,7,62,62};
+ static const unsigned char drc_rates[5] = {0,15,7,62,3};
+ static const unsigned char fsb_conversion[4] = {3,1,3,2};
+
+ /* 0x7c DRC */
+ drc = pci_read_config32(ctrl->f0, DRC);
+ for(cnt=0; cnt < 4; cnt++) {
+ if (!(dimm_mask & (1 << cnt))) {
+ continue;
+ }
+ value = spd_read_byte(ctrl->channel0[cnt], 11); /* ECC */
+ reg = spd_read_byte(ctrl->channel0[cnt], 2); /* Type */
+ if (value == 2) { /* RAM is ECC capable */
+ if (reg == 8) {
+ if ( ecc == 0xff ) {
+ ecc = 2;
+ }
+ else if (ecc == 1) {
+ die("ERROR - Mixed DDR & DDR2 RAM\r\n");
+ }
+ }
+ else if ( reg == 7 ) {
+ if ( ecc == 0xff) {
+ ecc = 1;
+ }
+ else if ( ecc > 1 ) {
+ die("ERROR - Mixed DDR & DDR2 RAM\r\n");
+ }
+ }
+ else {
+ die("ERROR - RAM not DDR\r\n");
+ }
+ }
+ else {
+ die("ERROR - Non ECC memory dimm\r\n");
+ }
+
+ value = spd_read_byte(ctrl->channel0[cnt], 12); /*refresh rate*/
+ value &= 0x0f; /* clip self refresh bit */
+ if (value > 5) goto hw_err;
+ if (rate > spd_rates[value])
+ rate = spd_rates[value];
+
+ value = spd_read_byte(ctrl->channel0[cnt], 9); /* cycle time */
+ if (value > 0x75) goto hw_err;
+ if (value <= 0x50) {
+ if (dram_type >= 2) {
+ if (reg == 8) { /*speed is good, is this ddr2?*/
+ dram_type = 2;
+ } else { /* not ddr2 so use ddr333 */
+ dram_type = 1;
+ }
+ }
+ }
+ else if (value <= 0x60) {
+ if (dram_type >= 1) dram_type = 1;
+ }
+ else dram_type = 0; /* ddr266 */
+
+ }
+ ecc = 2;
+ if (read_option(CMOS_VSTART_ECC_memory,CMOS_VLEN_ECC_memory,1) == 0) {
+ ecc = 0; /* ECC off in CMOS so disable it */
+ print_debug("ECC off\r\n");
+ }
+ else {
+ print_debug("ECC on\r\n");
+ }
+ drc &= ~(3 << 20); /* clear the ecc bits */
+ drc |= (ecc << 20); /* or in the calculated ecc bits */
+ for ( cnt = 1; cnt < 5; cnt++)
+ if (drc_rates[cnt] == rate)
+ break;
+ if (cnt < 5) {
+ drc &= ~(7 << 8); /* clear the rate bits */
+ drc |= (cnt << 8);
+ }
+
+ if (reg == 8) { /* independant clocks */
+ drc |= (1 << 4);
+ }
+
+ drc |= (1 << 26); /* set the overlap bit - the factory BIOS does */
+ drc |= (1 << 27); /* set DED retry enable - the factory BIOS does */
+ /* front side bus */
+ msr = rdmsr(0x2c);
+ value = msr.lo >> 16;
+ value &= 0x03;
+ drc &= ~(3 << 2); /* set the front side bus */
+ drc |= (fsb_conversion[value] << 2);
+ drc &= ~(3 << 0); /* set the dram type */
+ drc |= (dram_type << 0);
+
+ goto out;
+
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ drc = 0;
+ out:
+ return drc;
+}
+
+static void sdram_set_spd_registers(const struct mem_controller *ctrl)
+{
+ long dimm_mask;
+
+ /* Test if we can read the spd and if ram is ddr or ddr2 */
+ dimm_mask = spd_detect_dimms(ctrl);
+ if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
+ print_err("No memory for this cpu\r\n");
+ return;
+ }
+ return;
+}
+
+static void do_delay(void)
+{
+ int i;
+ unsigned char b;
+ for(i=0;i<16;i++)
+ b=inb(0x80);
+}
+
+#define TIMEOUT_LOOPS 300000
+
+#define DCALCSR 0x100
+#define DCALADDR 0x104
+#define DCALDATA 0x108
+
+static void set_on_dimm_termination_enable(const struct mem_controller *ctrl)
+{
+ unsigned char c1,c2;
+ unsigned int dimm,i;
+ unsigned int data32;
+ unsigned int t4;
+
+ /* Set up northbridge values */
+ /* ODT enable */
+ pci_write_config32(ctrl->f0, 0x88, 0xf0000180);
+ /* Figure out which slots are Empty, Single, or Double sided */
+ for(i=0,t4=0,c2=0;i<8;i+=2) {
+ c1 = pci_read_config8(ctrl->f0, DRB+i);
+ if(c1 == c2) continue;
+ c2 = pci_read_config8(ctrl->f0, DRB+1+i);
+ if(c1 == c2)
+ t4 |= (1 << (i*4));
+ else
+ t4 |= (2 << (i*4));
+ }
+ for(i=0;i<1;i++) {
+ if((t4&0x0f) == 1) {
+ if( ((t4>>8)&0x0f) == 0 ) {
+ data32 = 0x00000010; /* EEES */
+ break;
+ }
+ if ( ((t4>>16)&0x0f) == 0 ) {
+ data32 = 0x00003132; /* EESS */
+ break;
+ }
+ if ( ((t4>>24)&0x0f) == 0 ) {
+ data32 = 0x00335566; /* ESSS */
+ break;
+ }
+ data32 = 0x77bbddee; /* SSSS */
+ break;
+ }
+ if((t4&0x0f) == 2) {
+ if( ((t4>>8)&0x0f) == 0 ) {
+ data32 = 0x00003132; /* EEED */
+ break;
+ }
+ if ( ((t4>>8)&0x0f) == 2 ) {
+ data32 = 0xb373ecdc; /* EEDD */
+ break;
+ }
+ if ( ((t4>>16)&0x0f) == 0 ) {
+ data32 = 0x00b3a898; /* EESD */
+ break;
+ }
+ data32 = 0x777becdc; /* ESSD */
+ break;
+ }
+ die("Error - First dimm slot empty\r\n");
+ }
+
+ print_debug("ODT Value = ");
+ print_debug_hex32(data32);
+ print_debug("\r\n");
+
+ pci_write_config32(ctrl->f0, 0xb0, data32);
+
+ for(dimm=0;dimm<8;dimm+=1) {
+
+ write32(BAR+DCALADDR, 0x0b840001);
+ write32(BAR+DCALCSR, 0x83000003 | (dimm << 20));
+
+ for(i=0;i<1001;i++) {
+ data32 = read32(BAR+DCALCSR);
+ if(!(data32 & (1<<31)))
+ break;
+ }
+ }
+}
+static void set_receive_enable(const struct mem_controller *ctrl)
+{
+ unsigned int i;
+ unsigned int cnt,bit;
+ uint32_t recena=0;
+ uint32_t recenb=0;
+
+ {
+ unsigned int dimm;
+ unsigned int edge;
+ int32_t data32;
+ uint32_t data32_dram;
+ uint32_t dcal_data32_0;
+ uint32_t dcal_data32_1;
+ uint32_t dcal_data32_2;
+ uint32_t dcal_data32_3;
+ uint32_t work32l;
+ uint32_t work32h;
+ uint32_t data32r;
+ int32_t recen;
+ for(dimm=0;dimm<8;dimm+=1) {
+
+ if(!(dimm&1)) {
+ write32(BAR+DCALDATA+(17*4), 0x04020000);
+ write32(BAR+DCALCSR, 0x83800004 | (dimm << 20));
+
+ for(i=0;i<1001;i++) {
+ data32 = read32(BAR+DCALCSR);
+ if(!(data32 & (1<<31)))
+ break;
+ }
+ if(i>=1000)
+ continue;
+
+ dcal_data32_0 = read32(BAR+DCALDATA + 0);
+ dcal_data32_1 = read32(BAR+DCALDATA + 4);
+ dcal_data32_2 = read32(BAR+DCALDATA + 8);
+ dcal_data32_3 = read32(BAR+DCALDATA + 12);
+ }
+ else {
+ dcal_data32_0 = read32(BAR+DCALDATA + 16);
+ dcal_data32_1 = read32(BAR+DCALDATA + 20);
+ dcal_data32_2 = read32(BAR+DCALDATA + 24);
+ dcal_data32_3 = read32(BAR+DCALDATA + 28);
+ }
+
+ /* check if bank is installed */
+ if((dcal_data32_0 == 0) && (dcal_data32_2 == 0))
+ continue;
+ /* Calculate the timing value */
+ for(i=0,edge=0,bit=63,cnt=31,data32r=0,
+ work32l=dcal_data32_1,work32h=dcal_data32_3;
+ (i<4) && bit; i++) {
+ for(;;bit--,cnt--) {
+ if(work32l & (1<<cnt))
+ break;
+ if(!cnt) {
+ work32l = dcal_data32_0;
+ work32h = dcal_data32_2;
+ cnt = 32;
+ }
+ if(!bit) break;
+ }
+ for(;;bit--,cnt--) {
+ if(!(work32l & (1<<cnt)))
+ break;
+ if(!cnt) {
+ work32l = dcal_data32_0;
+ work32h = dcal_data32_2;
+ cnt = 32;
+ }
+ if(!bit) break;
+ }
+ if(!bit) {
+ break;
+ }
+ data32 = ((bit%8) << 1);
+ if(work32h & (1<<cnt))
+ data32 += 1;
+ if(data32 < 4) {
+ if(!edge) {
+ edge = 1;
+ }
+ else {
+ if(edge != 1) {
+ data32 = 0x0f;
+ }
+ }
+ }
+ if(data32 > 12) {
+ if(!edge) {
+ edge = 2;
+ }
+ else {
+ if(edge != 2) {
+ data32 = 0x00;
+ }
+ }
+ }
+ data32r += data32;
+ }
+
+ work32l = dcal_data32_0;
+ work32h = dcal_data32_2;
+ recen = data32r;
+ recen += 3;
+ recen = recen>>2;
+ for(cnt=5;cnt<24;) {
+ for(;;cnt++)
+ if(!(work32l & (1<<cnt)))
+ break;
+ for(;;cnt++) {
+ if(work32l & (1<<cnt))
+ break;
+ }
+ data32 = (((cnt-1)%8)<<1);
+ if(work32h & (1<<(cnt-1))) {
+ data32++;
+ }
+ /* test for frame edge cross overs */
+ if((edge == 1) && (data32 > 12) &&
+ (((recen+16)-data32) < 3)) {
+ data32 = 0;
+ cnt += 2;
+ }
+ if((edge == 2) && (data32 < 4) &&
+ ((recen - data32) > 12)) {
+ data32 = 0x0f;
+ cnt -= 2;
+ }
+ if(((recen+3) >= data32) && ((recen-3) <= data32))
+ break;
+ }
+ cnt--;
+ cnt /= 8;
+ cnt--;
+ if(recen&1)
+ recen+=2;
+ recen >>= 1;
+ recen += (cnt*8);
+ recen+=2;
+ recen <<= (dimm/2) * 8;
+ if(!(dimm&1)) {
+ recena |= recen;
+ }
+ else {
+ recenb |= recen;
+ }
+ }
+ }
+ /* Check for Eratta problem */
+ for(i=cnt=bit=0;i<4;i++) {
+ if (((recena>>(i*8))&0x0f)>7) {
+ cnt++; bit++;
+ }
+ else {
+ if((recena>>(i*8))&0x0f) {
+ cnt++;
+ }
+ }
+ }
+ if(bit) {
+ cnt-=bit;
+ if(cnt>1) {
+ for(i=0;i<4;i++) {
+ if(((recena>>(i*8))&0x0f)>7) {
+ recena &= ~(0x0f<<(i*8));
+ recena |= (7<<(i*8));
+ }
+ }
+ }
+ else {
+ for(i=0;i<4;i++) {
+ if(((recena>>(i*8))&0x0f)<8) {
+ recena &= ~(0x0f<<(i*8));
+ recena |= (8<<(i*8));
+ }
+ }
+ }
+ }
+ for(i=cnt=bit=0;i<4;i++) {
+ if (((recenb>>(i*8))&0x0f)>7) {
+ cnt++; bit++;
+ }
+ else {
+ if((recenb>>(i*8))&0x0f) {
+ cnt++;
+ }
+ }
+ }
+ if(bit) {
+ cnt-=bit;
+ if(cnt>1) {
+ for(i=0;i<4;i++) {
+ if(((recenb>>(i*8))&0x0f)>7) {
+ recenb &= ~(0x0f<<(i*8));
+ recenb |= (7<<(i*8));
+ }
+ }
+ }
+ else {
+ for(i=0;i<4;i++) {
+ if(((recenb>>(i*8))&0x0f)<8) {
+ recenb &= ~(0x0f<<(i*8));
+ recenb |= (8<<(i*8));
+ }
+ }
+ }
+ }
+
+// recena = 0x0000090a;
+// recenb = 0x0000090a;
+
+ print_debug("Receive enable A = ");
+ print_debug_hex32(recena);
+ print_debug(", Receive enable B = ");
+ print_debug_hex32(recenb);
+ print_debug("\r\n");
+
+ /* clear out the calibration area */
+ write32(BAR+DCALDATA+(16*4), 0x00000000);
+ write32(BAR+DCALDATA+(17*4), 0x00000000);
+ write32(BAR+DCALDATA+(18*4), 0x00000000);
+ write32(BAR+DCALDATA+(19*4), 0x00000000);
+
+ /* No command */
+ write32(BAR+DCALCSR, 0x0000000f);
+
+ write32(BAR+0x150, recena);
+ write32(BAR+0x154, recenb);
+}
+
+
+static void sdram_enable(int controllers, const struct mem_controller *ctrl)
+{
+ int i;
+ int cs;
+ int cnt;
+ int cas_latency;
+ long mask;
+ uint32_t drc;
+ uint32_t data32;
+ uint32_t mode_reg;
+ uint32_t *iptr;
+ volatile unsigned long *iptrv;
+ msr_t msr;
+ uint32_t scratch;
+ uint8_t byte;
+ uint16_t data16;
+ static const struct {
+ uint32_t clkgr[4];
+ } gearing [] = {
+ /* FSB 133 DIMM 266 */
+ {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
+ /* FSB 133 DIMM 333 */
+ {{ 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
+ /* FSB 133 DIMM 400 */
+ {{ 0x00000120, 0x00000000, 0x00000032, 0x00000010}},
+ /* FSB 167 DIMM 266 */
+ {{ 0x00005432, 0x00001000, 0x00004325, 0x00000000}},
+ /* FSB 167 DIMM 333 */
+ {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
+ /* FSB 167 DIMM 400 */
+ {{ 0x00154320, 0x00000000, 0x00065432, 0x00010000}},
+ /* FSB 200 DIMM 266 */
+ {{ 0x00000032, 0x00000010, 0x00000120, 0x00000000}},
+ /* FSB 200 DIMM 333 */
+ {{ 0x00065432, 0x00010000, 0x00054326, 0x00000000}},
+ /* FSB 200 DIMM 400 */
+ {{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
+ };
+
+ static const uint32_t dqs_data[] = {
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff,
+ 0xffffffff, 0xffffffff, 0x000000ff};
+
+ mask = spd_detect_dimms(ctrl);
+ print_debug("Starting SDRAM Enable\r\n");
+
+ /* 0x80 */
+#ifdef DIMM_MAP_LOGICAL
+ pci_write_config32(ctrl->f0, DRM,
+ 0x00210000 | DIMM_MAP_LOGICAL);
+#else
+ pci_write_config32(ctrl->f0, DRM, 0x00211248);
+#endif
+ /* set dram type and Front Side Bus freq. */
+ drc = spd_set_dram_controller_mode(ctrl, mask);
+ if( drc == 0) {
+ die("Error calculating DRC\r\n");
+ }
+ data32 = drc & ~(3 << 20); /* clear ECC mode */
+ data32 = data32 & ~(7 << 8); /* clear refresh rates */
+ data32 = data32 | (1 << 5); /* temp turn off of ODT */
+ /* Set gearing, then dram controller mode */
+ /* drc bits 1:0 = DIMM speed, bits 3:2 = FSB speed */
+ for(iptr = gearing[(drc&3)+((((drc>>2)&3)-1)*3)].clkgr,cnt=0;
+ cnt<4;cnt++) {
+ pci_write_config32(ctrl->f0, 0xa0+(cnt*4), iptr[cnt]);
+ }
+ /* 0x7c DRC */
+ pci_write_config32(ctrl->f0, DRC, data32);
+
+ /* turn the clocks on */
+ /* 0x8c CKDIS */
+ pci_write_config16(ctrl->f0, CKDIS, 0x0000);
+
+ /* 0x9a DDRCSR Take subsystem out of idle */
+ data16 = pci_read_config16(ctrl->f0, DDRCSR);
+ data16 &= ~(7 << 12);
+ data16 |= (3 << 12); /* use dual channel lock step */
+ pci_write_config16(ctrl->f0, DDRCSR, data16);
+
+ /* program row size DRB */
+ spd_set_ram_size(ctrl, mask);
+
+ /* program page size DRA */
+ spd_set_row_attributes(ctrl, mask);
+
+ /* program DRT timing values */
+ cas_latency = spd_set_drt_attributes(ctrl, mask, drc);
+
+ for(i=0;i<8;i++) { /* loop throught each dimm to test for row */
+ print_debug("DIMM ");
+ print_debug_hex8(i);
+ print_debug("\r\n");
+ /* Apply NOP */
+ do_delay();
+
+ write32(BAR + 0x100, (0x03000000 | (i<<20)));
+
+ write32(BAR+0x100, (0x83000000 | (i<<20)));
+
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+
+ }
+
+ /* Apply NOP */
+ do_delay();
+
+ for(cs=0;cs<8;cs++) {
+ write32(BAR + DCALCSR, (0x83000000 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Precharg all banks */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ if ((drc & 3) == 2) /* DDR2 */
+ write32(BAR+DCALADDR, 0x04000000);
+ else /* DDR1 */
+ write32(BAR+DCALADDR, 0x00000000);
+ write32(BAR+DCALCSR, (0x83000002 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* EMRS dll's enabled */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ if ((drc & 3) == 2) /* DDR2 */
+ /* fixme hard code AL additive latency */
+ write32(BAR+DCALADDR, 0x0b940001);
+ else /* DDR1 */
+ write32(BAR+DCALADDR, 0x00000001);
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ /* MRS reset dll's */
+ do_delay();
+ if ((drc & 3) == 2) { /* DDR2 */
+ if(cas_latency == 30)
+ mode_reg = 0x053a0000;
+ else
+ mode_reg = 0x054a0000;
+ }
+ else { /* DDR1 */
+ if(cas_latency == 20)
+ mode_reg = 0x012a0000;
+ else /* CAS Latency 2.5 */
+ mode_reg = 0x016a0000;
+ }
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALADDR, mode_reg);
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Precharg all banks */
+ do_delay();
+ do_delay();
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ if ((drc & 3) == 2) /* DDR2 */
+ write32(BAR+DCALADDR, 0x04000000);
+ else /* DDR1 */
+ write32(BAR+DCALADDR, 0x00000000);
+ write32(BAR+DCALCSR, (0x83000002 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Do 2 refreshes */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ do_delay();
+ /* for good luck do 6 more */
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
+ }
+ do_delay();
+ /* MRS reset dll's normal */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALADDR, (mode_reg & ~(1<<24)));
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Do only if DDR2 EMRS dll's enabled */
+ if ((drc & 3) == 2) { /* DDR2 */
+ do_delay();
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALADDR, (0x0b940001));
+ write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+ }
+
+ do_delay();
+ /* No command */
+ write32(BAR+DCALCSR, 0x0000000f);
+
+ /* DDR1 This is test code to copy some codes in the factory setup */
+
+ write32(BAR, 0x00100000);
+
+ if ((drc & 3) == 2) { /* DDR2 */
+ /* enable on dimm termination */
+ set_on_dimm_termination_enable(ctrl);
+ }
+
+ /* receive enable calibration */
+ set_receive_enable(ctrl);
+
+ /* DQS */
+ pci_write_config32(ctrl->f0, 0x94, 0x3904a100 );
+ for(i = 0, cnt = (BAR+0x200); i < 24; i++, cnt+=4) {
+ write32(cnt, dqs_data[i]);
+ }
+ pci_write_config32(ctrl->f0, 0x94, 0x3904a100 );
+
+ /* Enable refresh */
+ /* 0x7c DRC */
+ data32 = drc & ~(3 << 20); /* clear ECC mode */
+ pci_write_config32(ctrl->f0, DRC, data32);
+ write32(BAR+DCALCSR, 0x0008000f);
+
+ /* clear memory and init ECC */
+ print_debug("Clearing memory\r\n");
+ for(i=0;i<64;i+=4) {
+ write32(BAR+DCALDATA+i, 0x00000000);
+ }
+
+ for(cs=0;cs<8;cs++) {
+ write32(BAR+DCALCSR, (0x830831d8 | (cs<<20)));
+ data32 = read32(BAR+DCALCSR);
+ while(data32 & 0x80000000)
+ data32 = read32(BAR+DCALCSR);
+ }
+
+ /* Bring memory subsystem on line */
+ data32 = pci_read_config32(ctrl->f0, 0x98);
+ data32 |= (1 << 31);
+ pci_write_config32(ctrl->f0, 0x98, data32);
+ /* wait for completion */
+ print_debug("Waiting for mem complete\r\n");
+ while(1) {
+ data32 = pci_read_config32(ctrl->f0, 0x98);
+ if( (data32 & (1<<31)) == 0)
+ break;
+ }
+ print_debug("Done\r\n");
+
+ /* Set initialization complete */
+ /* 0x7c DRC */
+ drc |= (1 << 29);
+ data32 = drc & ~(3 << 20); /* clear ECC mode */
+ pci_write_config32(ctrl->f0, DRC, data32);
+
+ /* Set the ecc mode */
+ pci_write_config32(ctrl->f0, DRC, drc);
+
+ /* Enable memory scrubbing */
+ /* 0x52 MCHSCRB */
+ data16 = pci_read_config16(ctrl->f0, MCHSCRB);
+ data16 &= ~0x0f;
+ data16 |= ((2 << 2) | (2 << 0));
+ pci_write_config16(ctrl->f0, MCHSCRB, data16);
+
+ /* The memory is now setup, use it */
+ cache_lbmem(MTRR_TYPE_WRBACK);
+}
diff --git a/src/northbridge/intel/E7525/raminit.h b/src/northbridge/intel/E7525/raminit.h
new file mode 100644
index 0000000000..183ace8385
--- /dev/null
+++ b/src/northbridge/intel/E7525/raminit.h
@@ -0,0 +1,12 @@
+#ifndef RAMINIT_H
+#define RAMINIT_H
+
+#define DIMM_SOCKETS 4
+struct mem_controller {
+ unsigned node_id;
+ device_t f0, f1, f2, f3;
+ uint16_t channel0[DIMM_SOCKETS];
+ uint16_t channel1[DIMM_SOCKETS];
+};
+
+#endif /* RAMINIT_H */
diff --git a/src/northbridge/intel/E7525/raminit_test.c b/src/northbridge/intel/E7525/raminit_test.c
new file mode 100644
index 0000000000..2d44d25403
--- /dev/null
+++ b/src/northbridge/intel/E7525/raminit_test.c
@@ -0,0 +1,393 @@
+#include <unistd.h>
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+#include <setjmp.h>
+#include <device/pci_def.h>
+#include "e7525.h"
+
+jmp_buf end_buf;
+
+static int is_cpu_pre_c0(void)
+{
+ return 0;
+}
+
+#define PCI_ADDR(BUS, DEV, FN, WHERE) ( \
+ (((BUS) & 0xFF) << 16) | \
+ (((DEV) & 0x1f) << 11) | \
+ (((FN) & 0x07) << 8) | \
+ ((WHERE) & 0xFF))
+
+#define PCI_DEV(BUS, DEV, FN) ( \
+ (((BUS) & 0xFF) << 16) | \
+ (((DEV) & 0x1f) << 11) | \
+ (((FN) & 0x7) << 8))
+
+#define PCI_ID(VENDOR_ID, DEVICE_ID) \
+ ((((DEVICE_ID) & 0xFFFF) << 16) | ((VENDOR_ID) & 0xFFFF))
+
+typedef unsigned device_t;
+
+unsigned char pci_register[256*5*3*256];
+
+static uint8_t pci_read_config8(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = dev | where;
+ return pci_register[addr];
+}
+
+static uint16_t pci_read_config16(device_t dev, unsigned where)
+{
+ unsigned addr;
+ addr = dev | where;
+ return pci_register[addr] | (pci_register[addr + 1] << 8);
+}
+
+static uint32_t pci_read_config32(device_t dev, unsigned where)
+{
+ unsigned addr;
+ uint32_t value;
+ addr = dev | where;
+ value = pci_register[addr] |
+ (pci_register[addr + 1] << 8) |
+ (pci_register[addr + 2] << 16) |
+ (pci_register[addr + 3] << 24);
+
+ return value;
+
+}
+
+static void pci_write_config8(device_t dev, unsigned where, uint8_t value)
+{
+ unsigned addr;
+ addr = dev | where;
+ pci_register[addr] = value;
+}
+
+static void pci_write_config16(device_t dev, unsigned where, uint16_t value)
+{
+ unsigned addr;
+ addr = dev | where;
+ pci_register[addr] = value & 0xff;
+ pci_register[addr + 1] = (value >> 8) & 0xff;
+}
+
+static void pci_write_config32(device_t dev, unsigned where, uint32_t value)
+{
+ unsigned addr;
+ addr = dev | where;
+ pci_register[addr] = value & 0xff;
+ pci_register[addr + 1] = (value >> 8) & 0xff;
+ pci_register[addr + 2] = (value >> 16) & 0xff;
+ pci_register[addr + 3] = (value >> 24) & 0xff;
+}
+
+#define PCI_DEV_INVALID (0xffffffffU)
+static device_t pci_locate_device(unsigned pci_id, device_t dev)
+{
+ for(; dev <= PCI_DEV(255, 31, 7); dev += PCI_DEV(0,0,1)) {
+ unsigned int id;
+ id = pci_read_config32(dev, 0);
+ if (id == pci_id) {
+ return dev;
+ }
+ }
+ return PCI_DEV_INVALID;
+}
+
+
+
+
+static void uart_tx_byte(unsigned char data)
+{
+ write(STDOUT_FILENO, &data, 1);
+}
+static void hlt(void)
+{
+ longjmp(end_buf, 2);
+}
+#include "../../../arch/i386/lib/console.c"
+
+unsigned long log2(unsigned long x)
+{
+ // assume 8 bits per byte.
+ unsigned long i = 1 << (sizeof(x)*8 - 1);
+ unsigned long pow = sizeof(x) * 8 - 1;
+
+ if (! x) {
+ static const char errmsg[] = " called with invalid parameter of 0\n";
+ write(STDERR_FILENO, __func__, sizeof(__func__) - 1);
+ write(STDERR_FILENO, errmsg, sizeof(errmsg) - 1);
+ hlt();
+ }
+ for(; i > x; i >>= 1, pow--)
+ ;
+
+ return pow;
+}
+
+typedef struct msr_struct
+{
+ unsigned lo;
+ unsigned hi;
+} msr_t;
+
+static inline msr_t rdmsr(unsigned index)
+{
+ msr_t result;
+ result.lo = 0;
+ result.hi = 0;
+ return result;
+}
+
+static inline void wrmsr(unsigned index, msr_t msr)
+{
+}
+
+#include "raminit.h"
+
+#define SIO_BASE 0x2e
+
+static void hard_reset(void)
+{
+ /* FIXME implement the hard reset case... */
+ longjmp(end_buf, 3);
+}
+
+static void memreset_setup(void)
+{
+ /* Nothing to do */
+}
+
+static void memreset(int controllers, const struct mem_controller *ctrl)
+{
+ /* Nothing to do */
+}
+
+static inline void activate_spd_rom(const struct mem_controller *ctrl)
+{
+ /* nothing to do */
+}
+
+
+static uint8_t spd_mt4lsdt464a[256] =
+{
+ 0x80, 0x08, 0x04, 0x0C, 0x08, 0x01, 0x40, 0x00, 0x01, 0x70,
+ 0x54, 0x00, 0x80, 0x10, 0x00, 0x01, 0x8F, 0x04, 0x06, 0x01,
+ 0x01, 0x00, 0x0E, 0x75, 0x54, 0x00, 0x00, 0x0F, 0x0E, 0x0F,
+
+ 0x25, 0x08, 0x15, 0x08, 0x15, 0x08, 0x00, 0x12, 0x01, 0x4E,
+ 0x9C, 0xE4, 0xB7, 0x46, 0x2C, 0xFF, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x00,
+};
+
+static uint8_t spd_micron_512MB_DDR333[256] =
+{
+ 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x02, 0x48, 0x00, 0x04, 0x60,
+ 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01,
+ 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48,
+ 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x48, 0x30, 0x28, 0x50, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x10, 0x6f, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x01, 0x33, 0x36, 0x56, 0x44, 0x44, 0x46, 0x31,
+ 0x32, 0x38, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43,
+ 0x33, 0x03, 0x00, 0x03, 0x23, 0x17, 0x07, 0x5a, 0xb2, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static uint8_t spd_micron_256MB_DDR333[256] =
+{
+ 0x80, 0x08, 0x07, 0x0d, 0x0b, 0x01, 0x48, 0x00, 0x04, 0x60,
+ 0x70, 0x02, 0x82, 0x04, 0x04, 0x01, 0x0e, 0x04, 0x0c, 0x01,
+ 0x02, 0x26, 0xc0, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48,
+ 0x2a, 0x80, 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x3c, 0x48, 0x30, 0x23, 0x50, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x58, 0x2c, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0x01, 0x31, 0x38, 0x56, 0x44, 0x44, 0x46, 0x36,
+ 0x34, 0x37, 0x32, 0x47, 0x2d, 0x33, 0x33, 0x35, 0x43, 0x31,
+ 0x20, 0x01, 0x00, 0x03, 0x19, 0x17, 0x05, 0xb2, 0xf4, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+#define MAX_DIMMS 16
+static uint8_t spd_data[MAX_DIMMS*256];
+
+static unsigned spd_count, spd_fail_count;
+static int spd_read_byte(unsigned device, unsigned address)
+{
+ int result;
+ spd_count++;
+ if ((device < 0x50) || (device >= (0x50 +MAX_DIMMS))) {
+ result = -1;
+ }
+ else {
+ device -= 0x50;
+
+ if (address > 256) {
+ result = -1;
+ }
+ else if (spd_data[(device << 8) | 2] != 7) {
+ result = -1;
+ }
+ else {
+ result = spd_data[(device << 8) | address];
+ }
+ }
+ if (spd_count >= spd_fail_count) {
+ result = -1;
+ }
+ return result;
+}
+
+#include "raminit.c"
+#include "../../../sdram/generic_sdram.c"
+
+#define FIRST_CPU 1
+#define SECOND_CPU 1
+#define TOTAL_CPUS (FIRST_CPU + SECOND_CPU)
+#if 0
+static void raminit_main(void)
+{
+ /*
+ * GPIO28 of 8111 will control H0_MEMRESET_L
+ * GPIO29 of 8111 will control H1_MEMRESET_L
+ */
+ static const struct mem_controller cpu[] = {
+#if FIRST_CPU
+ {
+ .node_id = 0,
+ .f0 = PCI_DEV(0, 0x18, 0),
+ .f1 = PCI_DEV(0, 0x18, 1),
+ .f2 = PCI_DEV(0, 0x18, 2),
+ .f3 = PCI_DEV(0, 0x18, 3),
+ .channel0 = { 0x50+0, 0x50+2, 0x50+4, 0x50+6 },
+ .channel1 = { 0x50+1, 0x50+3, 0x50+5, 0x50+7 },
+ },
+#endif
+#if SECOND_CPU
+ {
+ .node_id = 1,
+ .f0 = PCI_DEV(0, 0x19, 0),
+ .f1 = PCI_DEV(0, 0x19, 1),
+ .f2 = PCI_DEV(0, 0x19, 2),
+ .f3 = PCI_DEV(0, 0x19, 3),
+ .channel0 = { 0x50+8, 0x50+10, 0x50+12, 0x50+14 },
+ .channel1 = { 0x50+9, 0x50+11, 0x50+13, 0x50+15 },
+ },
+#endif
+ };
+ console_init();
+ memreset_setup();
+ sdram_initialize(sizeof(cpu)/sizeof(cpu[0]), cpu);
+
+}
+#endif
+static void reset_tests(void)
+{
+ /* Clear the results of any previous tests */
+ memset(pci_register, 0, sizeof(pci_register));
+ memset(spd_data, 0, sizeof(spd_data));
+ spd_count = 0;
+ spd_fail_count = UINT_MAX;
+
+ pci_write_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP,
+ NBCAP_128Bit |
+ NBCAP_MP| NBCAP_BIG_MP |
+ /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */
+ (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) |
+ NBCAP_MEMCTRL);
+
+ pci_write_config32(PCI_DEV(0, 0x19, 3), NORTHBRIDGE_CAP,
+ NBCAP_128Bit |
+ NBCAP_MP| NBCAP_BIG_MP |
+ /* NBCAP_ECC | NBCAP_CHIPKILL_ECC | */
+ (NBCAP_MEMCLK_200MHZ << NBCAP_MEMCLK_SHIFT) |
+ NBCAP_MEMCTRL);
+}
+
+static void test1(void)
+{
+ reset_tests();
+
+ memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256);
+// raminit_main();
+}
+
+
+static void do_test2(int i)
+{
+ jmp_buf tmp_buf;
+ memcpy(&tmp_buf, &end_buf, sizeof(end_buf));
+ if (setjmp(end_buf) != 0) {
+ goto done;
+ }
+ reset_tests();
+ spd_fail_count = i;
+
+ print_debug("\r\nSPD will fail after: ");
+ print_debug_hex32(spd_fail_count);
+ print_debug(" accesses.\r\n");
+
+ memcpy(&spd_data[0*256], spd_micron_512MB_DDR333, 256);
+ memcpy(&spd_data[1*256], spd_micron_512MB_DDR333, 256);
+
+// raminit_main();
+
+ done:
+ memcpy(&end_buf, &tmp_buf, sizeof(end_buf));
+}
+
+static void test2(void)
+{
+ int i;
+ for(i = 0; i < 0x48; i++) {
+ do_test2(i);
+ }
+
+}
+
+int main(int argc, char **argv)
+{
+ if (setjmp(end_buf) != 0) {
+ return -1;
+ }
+ test1();
+ test2();
+ return 0;
+}