summaryrefslogtreecommitdiff
path: root/src/northbridge/amd
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd')
-rw-r--r--src/northbridge/amd/amdk8/Config.lb7
-rw-r--r--src/northbridge/amd/amdk8/amdk8.h12
-rw-r--r--src/northbridge/amd/amdk8/coherent_ht.c469
-rw-r--r--src/northbridge/amd/amdk8/cpu_rev.c7
-rw-r--r--src/northbridge/amd/amdk8/early_ht.c3
-rw-r--r--src/northbridge/amd/amdk8/incoherent_ht.c244
-rw-r--r--src/northbridge/amd/amdk8/misc_control.c198
-rw-r--r--src/northbridge/amd/amdk8/northbridge.c86
-rw-r--r--src/northbridge/amd/amdk8/raminit.c907
-rw-r--r--src/northbridge/amd/amdk8/raminit.h5
-rw-r--r--src/northbridge/amd/amdk8/raminit_test.c442
-rw-r--r--src/northbridge/amd/amdk8/reset_test.c11
12 files changed, 1558 insertions, 833 deletions
diff --git a/src/northbridge/amd/amdk8/Config.lb b/src/northbridge/amd/amdk8/Config.lb
index 0110e218ce..3b249161fd 100644
--- a/src/northbridge/amd/amdk8/Config.lb
+++ b/src/northbridge/amd/amdk8/Config.lb
@@ -1,4 +1,9 @@
config chip.h
object northbridge.o
driver misc_control.o
-driver mcf0_control.o
+
+makerule raminit_test
+ depends "$(TOP)/src/northbridge/amd/amdk8/raminit_test.c"
+ depends "$(TOP)/src/northbridge/amd/amdk8/raminit.c"
+ action "$(HOSTCC) $(HOSTCFLAGS) $(CPUFLAGS) -Wno-unused-function -I$(TOP)/src/include -g $< -o $@"
+end
diff --git a/src/northbridge/amd/amdk8/amdk8.h b/src/northbridge/amd/amdk8/amdk8.h
index c8ae95e383..ca8e8dc3d2 100644
--- a/src/northbridge/amd/amdk8/amdk8.h
+++ b/src/northbridge/amd/amdk8/amdk8.h
@@ -38,6 +38,15 @@
#define HTTC_HI_PRI_BYP_CNT_MASK 3
+/* Function 1 */
+#define PCI_IO_BASE0 0xc0
+#define PCI_IO_BASE1 0xc8
+#define PCI_IO_BASE2 0xd0
+#define PCI_IO_BASE3 0xd8
+#define PCI_IO_BASE_VGA_EN (1 << 4)
+#define PCI_IO_BASE_NO_ISA (1 << 5)
+
+
/* Function 2 */
#define DRAM_CSBASE 0x40
#define DRAM_CSMASK 0x60
@@ -124,6 +133,9 @@
#define DCL_UnBufDimm (1<<18)
#define DCL_32ByteEn (1<<19)
#define DCL_x4DIMM_SHIFT 20
+#define DCL_DisInRcvrs (1<<24)
+#define DCL_BypMax_SHIFT 25
+#define DCL_En2T (1<<28)
#define DRAM_CONFIG_HIGH 0x94
#define DCH_ASYNC_LAT_SHIFT 0
#define DCH_ASYNC_LAT_MASK 0xf
diff --git a/src/northbridge/amd/amdk8/coherent_ht.c b/src/northbridge/amd/amdk8/coherent_ht.c
index 83fbd40beb..5b6ea16e4e 100644
--- a/src/northbridge/amd/amdk8/coherent_ht.c
+++ b/src/northbridge/amd/amdk8/coherent_ht.c
@@ -14,7 +14,10 @@
*/
#include <device/pci_def.h>
+#include <device/pci_ids.h>
+#include <device/hypertransport_def.h>
#include "arch/romcc_io.h"
+#include "amdk8.h"
/*
* Until we have a completely dynamic setup we want
@@ -39,10 +42,6 @@
#define CONNECTION_0_2 UP
#endif
-#ifndef CONNECTION_1_0
-#define CONNECTION_1_0 ACROSS
-#endif
-
#ifndef CONNECTION_1_3
#define CONNECTION_1_3 UP
#endif
@@ -63,7 +62,7 @@
typedef uint8_t u8;
typedef uint32_t u32;
-typedef int8_t bool;
+typedef int bool;
#define TRUE (-1)
#define FALSE (0)
@@ -95,51 +94,15 @@ static void disable_probes(void)
u32 val;
- print_debug("Disabling read/write/fill probes for UP... ");
+ 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);
- print_debug("done.\r\n");
+ print_spew("done.\r\n");
}
-//BY LYH
-#if 0
-#define WAIT_TIMES 1000
-static void wait_ap_stop(u8 node)
-{
- unsigned long reg;
- unsigned long i;
- for(i=0;i<WAIT_TIMES;i++) {
- unsigned long regx;
- regx = pci_read_config32(NODE_HT(node),0x6c);
- if((regx & (1<<4))==1) break;
- }
- reg = pci_read_config32(NODE_HT(node),0x6c);
- reg &= ~(1<<4); // clear it
- pci_write_config32(NODE_HT(node), 0x6c, reg);
-
-}
-static void notify_bsp_ap_is_stopped(void)
-{
- unsigned long reg;
- unsigned long apic_id;
- apic_id = *((volatile unsigned long *)(APIC_DEFAULT_BASE+APIC_ID));
- apic_id >>= 24;
-/* print_debug("applicaton cpu apic_id: ");
- print_debug_hex32(apic_id);
- }*/
- if(apic_id!=0) { //AP apic_id == node_id ??
-// set the ColdResetbit to notify BSP that AP is stopped
- reg = pci_read_config32(NODE_HT(apic_id), 0x6C);
- reg |= 1<<4;
- pci_write_config32(NODE_HT(apic_id), 0x6C, reg);
- }
-
-}
-#endif
-//BY LYH END
static void enable_routing(u8 node)
{
@@ -168,14 +131,14 @@ static void enable_routing(u8 node)
*/
/* Enable routing table */
- print_debug("Enabling routing table for node ");
- print_debug_hex32(node);
+ print_spew("Enabling routing table for node ");
+ print_spew_hex32(node);
val=pci_read_config32(NODE_HT(node), 0x6c);
- val &= ~((1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0));
+ val &= ~((1<<1)|(1<<0));
pci_write_config32(NODE_HT(node), 0x6c, val);
- print_debug(" done.\r\n");
+ print_spew(" done.\r\n");
}
#if CONFIG_MAX_CPUS > 1
@@ -184,84 +147,97 @@ static void rename_temp_node(u8 node)
{
uint32_t val;
- print_debug("Renaming current temp node to ");
- print_debug_hex32(node);
+ print_spew("Renaming current temp node to ");
+ print_spew_hex32(node);
val=pci_read_config32(NODE_HT(7), 0x60);
val &= (~7); /* clear low bits. */
val |= node; /* new node */
pci_write_config32(NODE_HT(7), 0x60, val);
-//BY LYH
-#if 0
- if(node!=0) {
- wait_ap_stop(node);
- }
-#endif
-//BY LYH END
-
-
- print_debug(" done.\r\n");
-
-
+ print_spew(" done.\r\n");
}
static bool check_connection(u8 src, u8 dest, u8 link)
{
- /* this function does 2 things:
- * 1) detect whether the coherent HT link is connected.
- * 2) verify that the coherent hypertransport link
- * is established and actually working by reading the
- * remote node's vendor/device id
- */
-
+ /* See if we have a valid connection to dest */
u32 val;
- /* 1) */
- val=pci_read_config32(NODE_HT(src), 0x98+link);
+ /* Detect if the coherent HT link is connected. */
+ val = pci_read_config32(NODE_HT(src), 0x98+link);
if ( (val&0x17) != 0x03)
return 0;
- /* 2) */
- val=pci_read_config32(NODE_HT(dest),0);
+ /* Verify that the coherent hypertransport link is
+ * established and actually working by reading the
+ * remode node's vendor/device id
+ */
+ val = pci_read_config32(NODE_HT(dest),0);
if(val != 0x11001022)
return 0;
return 1;
}
-static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2)
+static unsigned read_freq_cap(device_t dev, unsigned pos)
+{
+ /* Handle bugs in valid hypertransport frequency reporting */
+ unsigned freq_cap;
+ uint32_t id;
+
+ freq_cap = pci_read_config16(dev, pos);
+ freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */
+
+ id = pci_read_config32(dev, 0);
+
+ /* AMD 8131 Errata 48 */
+ if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) {
+ freq_cap &= ~(1 << HT_FREQ_800Mhz);
+ }
+ /* AMD 8151 Errata 23 */
+ if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) {
+ freq_cap &= ~(1 << HT_FREQ_800Mhz);
+ }
+ /* AMD K8 Unsupported 1Ghz? */
+ if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) {
+ freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+ }
+ return freq_cap;
+}
+
+static int optimize_connection(device_t node1, uint8_t link1, device_t node2, uint8_t link2)
{
static const uint8_t link_width_to_pow2[]= { 3, 4, 0, 5, 1, 2, 0, 0 };
static const uint8_t pow2_to_link_width[] = { 0x7, 4, 5, 0, 1, 3 };
uint16_t freq_cap1, freq_cap2, freq_cap, freq_mask;
- uint8_t width_cap1, width_cap2, width_cap, width, ln_width1, ln_width2;
- uint8_t freq;
+ uint8_t width_cap1, width_cap2, width_cap, width, old_width, ln_width1, ln_width2;
+ uint8_t freq, old_freq;
+ int needs_reset;
/* Set link width and frequency */
+ /* Initially assume everything is already optimized and I don't need a reset */
+ needs_reset = 0;
+
/* Get the frequency capabilities */
- freq_cap1 = pci_read_config16(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ_CAP);
- freq_cap2 = pci_read_config16(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ_CAP);
+ freq_cap1 = read_freq_cap(node1, link1 + PCI_HT_CAP_HOST_FREQ_CAP);
+ freq_cap2 = read_freq_cap(node2, link2 + PCI_HT_CAP_HOST_FREQ_CAP);
/* Calculate the highest possible frequency */
-#if 1
- /* FIXME!!!!!!!
- * This method of computing the fastes frequency is broken.
- * Because the frequencies (i.e. 100Mhz) are not ordered.
- */
- freq = log2(freq_cap1 & freq_cap2 & 0xff);
-#else
- /* Only allow supported frequencies 800Mhz and below */
- freq = log2(freq_cap1 & freq_cap2 & 0x3f);
-#endif
+ freq = log2(freq_cap1 & freq_cap2);
+
+ /* See if I am changing the link freqency */
+ old_freq = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ);
+ needs_reset |= old_freq != freq;
+ old_freq = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ);
+ needs_reset |= old_freq != freq;
/* Set the Calulcated link frequency */
- pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_FREQ, freq);
- pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_FREQ, freq);
+ pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_FREQ, freq);
+ pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_FREQ, freq);
/* Get the width capabilities */
- width_cap1 = pci_read_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH);
- width_cap2 = pci_read_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH);
+ width_cap1 = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH);
+ width_cap2 = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH);
/* Calculate node1's input width */
ln_width1 = link_width_to_pow2[width_cap1 & 7];
@@ -278,45 +254,38 @@ static void optimize_connection(u8 node1, u8 link1, u8 node2, u8 link2)
}
width |= pow2_to_link_width[ln_width1] << 4;
+ /* See if I am changing node1's width */
+ old_width = pci_read_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1);
+ needs_reset |= old_width != width;
+
/* Set node1's widths */
- pci_write_config8(NODE_HT(node1), 0x80 + link1 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+ pci_write_config8(node1, link1 + PCI_HT_CAP_HOST_WIDTH + 1, width);
- /* Set node2's widths */
+ /* Calculate node2's width */
width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
- pci_write_config8(NODE_HT(node2), 0x80 + link2 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+
+ /* See if I am changing node2's width */
+ old_width = pci_read_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1);
+ needs_reset |= old_width != width;
+
+ /* Set node2's widths */
+ pci_write_config8(node2, link2 + PCI_HT_CAP_HOST_WIDTH + 1, width);
+
+ return needs_reset;
}
static void fill_row(u8 node, u8 row, u32 value)
{
-#if 0
- print_debug("fill_row: pci_write_config32(");
- print_debug_hex32(NODE_HT(node));
- print_debug_char(',');
- print_debug_hex32(0x40 + (row << 2));
- print_debug_char(',');
- print_debug_hex32(value);
- print_debug(")\r\n");
-#endif
pci_write_config32(NODE_HT(node), 0x40+(row<<2), value);
}
static void setup_row(u8 source, u8 dest, u8 cpus)
{
-#if 0
- printk_spew("setting up link from node %d to %d (%d cpus)\r\n",
- source, dest, cpus);
-#endif
-
fill_row(source,dest,generate_row(source,dest,cpus));
}
static void setup_temp_row(u8 source, u8 dest, u8 cpus)
{
-#if 0
- printk_spew("setting up temp. link from node %d to %d (%d cpus)\r\n",
- source, dest, cpus);
-#endif
-
fill_row(source,7,generate_temp_row(source,dest,cpus));
}
@@ -345,9 +314,8 @@ static void setup_remote_node(u8 node, u8 cpus)
};
uint8_t row;
int i;
-#if 1
- print_debug("setup_remote_node\r\n");
-#endif
+
+ print_spew("setup_remote_node\r\n");
for(row=0; row<cpus; row++)
setup_remote_row(node, row, cpus);
@@ -356,18 +324,11 @@ static void setup_remote_node(u8 node, u8 cpus)
uint32_t value;
uint8_t reg;
reg = pci_reg[i];
-#if 0
- print_debug("copying reg: ");
- print_debug_hex8(reg);
- print_debug("\r\n");
-#endif
value = pci_read_config32(NODE_MP(0), reg);
pci_write_config32(NODE_MP(7), reg, value);
}
-#if 1
- print_debug("setup_remote_done\r\n");
-#endif
+ print_spew("setup_remote_done\r\n");
}
#endif
@@ -381,79 +342,91 @@ static void setup_temp_node(u8 node, u8 cpus)
}
#endif
-static u8 setup_uniprocessor(void)
+static void setup_uniprocessor(void)
{
- print_debug("Enabling UP settings\r\n");
+ print_spew("Enabling UP settings\r\n");
disable_probes();
- return 1;
}
+struct setup_smp_result {
+ int cpus;
+ int needs_reset;
+};
+
#if CONFIG_MAX_CPUS > 1
-static u8 setup_smp(void)
+static struct setup_smp_result setup_smp(void)
{
- u8 cpus=2;
+ struct setup_smp_result result;
+ result.cpus = 2;
+ result.needs_reset = 0;
- print_debug("Enabling SMP settings\r\n");
+ print_spew("Enabling SMP settings\r\n");
- setup_row(0,0,cpus);
+ setup_row(0, 0, result.cpus);
/* Setup and check a temporary connection to node 1 */
- setup_temp_row(0,1,cpus);
+ setup_temp_row(0, 1, result.cpus);
if (!check_connection(0, 7, CONNECTION_0_1)) {
- print_debug("No connection to Node 1.\r\n");
+ print_spew("No connection to Node 1.\r\n");
clear_temp_row(0); /* delete temp connection */
setup_uniprocessor(); /* and get up working */
- return 1;
+ result.cpus = 1;
+ return result;
}
/* We found 2 nodes so far */
- optimize_connection(0, CONNECTION_0_1, 7, CONNECTION_1_0);
- setup_node(0, cpus); /* Node 1 is there. Setup Node 0 correctly */
- setup_remote_node(1, cpus); /* Setup the routes on the remote node */
+ result.needs_reset =
+ optimize_connection(NODE_HT(0), 0x80 + CONNECTION_0_1, NODE_HT(7), 0x80 + CONNECTION_0_1);
+ setup_node(0, result.cpus); /* Node 1 is there. Setup Node 0 correctly */
+ setup_remote_node(1, result.cpus); /* Setup the routes on the remote node */
rename_temp_node(1); /* Rename Node 7 to Node 1 */
enable_routing(1); /* Enable routing on Node 1 */
clear_temp_row(0); /* delete temporary connection */
#if CONFIG_MAX_CPUS > 2
- cpus=4;
+ result.cpus=4;
/* Setup and check temporary connection from Node 0 to Node 2 */
- setup_temp_row(0,2,cpus);
+ setup_temp_row(0,2, result.cpus);
if (!check_connection(0, 7, CONNECTION_0_2)) {
- print_debug("No connection to Node 2.\r\n");
+ print_spew("No connection to Node 2.\r\n");
clear_temp_row(0); /* delete temp connection */
- return 2;
+ result.cpus = 2;
+ return result;
}
/* We found 3 nodes so far. Now setup a temporary
* connection from node 0 to node 3 via node 1
*/
- setup_temp_row(0,1,cpus); /* temp. link between nodes 0 and 1 */
- setup_temp_row(1,3,cpus); /* temp. link between nodes 1 and 3 */
+ setup_temp_row(0,1, result.cpus); /* temp. link between nodes 0 and 1 */
+ setup_temp_row(1,3, result.cpus); /* temp. link between nodes 1 and 3 */
if (!check_connection(1, 7, CONNECTION_1_3)) {
- print_debug("No connection to Node 3.\r\n");
+ print_spew("No connection to Node 3.\r\n");
clear_temp_row(0); /* delete temp connection */
clear_temp_row(1); /* delete temp connection */
- return 2;
+ result.cpus = 2;
+ return result;
}
+#warning "FIXME optimize the physical connections"
+
/* We found 4 nodes so far. Now setup all nodes for 4p */
- setup_node(0, cpus); /* The first 2 nodes are configured */
- setup_node(1, cpus); /* already. Just configure them for 4p */
+ setup_node(0, result.cpus); /* The first 2 nodes are configured */
+ setup_node(1, result.cpus); /* already. Just configure them for 4p */
- setup_temp_row(0,2,cpus);
- setup_temp_node(2,cpus);
+ setup_temp_row(0,2, result.cpus);
+ setup_temp_node(2, result.cpus);
rename_temp_node(2);
enable_routing(2);
- setup_temp_row(0,1,cpus);
- setup_temp_row(1,3,cpus);
- setup_temp_node(3,cpus);
+ setup_temp_row(0,1, result.cpus);
+ setup_temp_row(1,3, result.cpus);
+ setup_temp_node(3, result.cpus);
rename_temp_node(3);
enable_routing(3); /* enable routing on node 3 (temp.) */
@@ -463,52 +436,52 @@ static u8 setup_smp(void)
clear_temp_row(3);
#endif
- print_debug_hex32(cpus);
+ print_debug_hex32(result.cpus);
print_debug(" nodes initialized.\r\n");
- return cpus;
+ return result;
}
#endif
#if CONFIG_MAX_CPUS > 1
-static unsigned detect_mp_capabilities(unsigned cpus)
+static unsigned verify_mp_capabilities(unsigned cpus)
{
unsigned node, row, mask;
bool mp_cap=TRUE;
-#if 1
- print_debug("detect_mp_capabilities: ");
- print_debug_hex32(cpus);
- print_debug("\r\n");
-#endif
- if (cpus>2)
+ if (cpus > 2) {
mask=0x06; /* BigMPCap */
- else
+ } else {
mask=0x02; /* MPCap */
+ }
for (node=0; node<cpus; node++) {
- if ((pci_read_config32(NODE_MC(node), 0xe8) & mask)!=mask)
- mp_cap=FALSE;
+ if ((pci_read_config32(NODE_MC(node), 0xe8) & mask) != mask) {
+ mp_cap = FALSE;
+ }
}
- if (mp_cap)
+ if (mp_cap) {
return cpus;
+ }
/* one of our cpus is not mp capable */
- print_debug("One of the CPUs is not MP capable. Going back to UP\r\n");
+ print_err("One of the CPUs is not MP capable. Going back to UP\r\n");
- for (node=cpus; node>0; node--)
- for (row=cpus; row>0; row--)
- fill_row(NODE_HT(node-1), row-1, DEFAULT);
-
- return setup_uniprocessor();
+ for (node = cpus; node > 0; node--) {
+ for (row = cpus; row > 0; row--) {
+ fill_row(NODE_HT(node-1), row-1, DEFAULT);
+ }
+ }
+ setup_uniprocessor();
+ return 1;
}
#endif
static void coherent_ht_finalize(unsigned cpus)
{
- int node;
+ unsigned node;
bool rev_a0;
/* set up cpu count and node count and enable Limit
@@ -517,53 +490,149 @@ static void coherent_ht_finalize(unsigned cpus)
* registers on Hammer A0 revision.
*/
-#if 1
+#if 0
print_debug("coherent_ht_finalize\r\n");
#endif
- rev_a0= is_cpu_rev_a0();
-
- for (node=0; node<cpus; node++) {
- u32 val;
- val=pci_read_config32(NODE_HT(node), 0x60);
+ rev_a0 = is_cpu_rev_a0();
+ for (node = 0; node < cpus; node++) {
+ device_t dev;
+ uint32_t val;
+ dev = NODE_HT(node);
+
+ /* Set the Total CPU and Node count in the system */
+ val = pci_read_config32(dev, 0x60);
val &= (~0x000F0070);
val |= ((cpus-1)<<16)|((cpus-1)<<4);
- pci_write_config32(NODE_HT(node),0x60,val);
-
- val=pci_read_config32(NODE_HT(node), 0x68);
-#if 1
- val |= 0x00008000;
-#else
- val |= 0x0f00c800; // 0x00008000->0f00c800 BY LYH
-#endif
- pci_write_config32(NODE_HT(node),0x68,val);
+ 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);
+ 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);
if (rev_a0) {
- pci_write_config32(NODE_HT(node),0x94,0);
- pci_write_config32(NODE_HT(node),0xb4,0);
- pci_write_config32(NODE_HT(node),0xd4,0);
+ pci_write_config32(dev, 0x94, 0);
+ pci_write_config32(dev, 0xb4, 0);
+ pci_write_config32(dev, 0xd4, 0);
}
+
+
}
-#if 1
+
+#if 0
print_debug("done\r\n");
#endif
}
+static int apply_cpu_errata_fixes(unsigned cpus, int needs_reset)
+{
+ unsigned node;
+ for(node = 0; node < cpus; node++) {
+ device_t dev;
+ uint32_t cmd;
+ dev = NODE_MC(node);
+ if (is_cpu_pre_c0()) {
+
+ /* Errata 66
+ * Limit the number of downstream posted requests to 1
+ */
+ cmd = pci_read_config32(dev, 0x70);
+ if ((cmd & (3 << 0)) != 2) {
+ cmd &= ~(3<<0);
+ cmd |= (2<<0);
+ pci_write_config32(dev, 0x70, cmd );
+ needs_reset = 1;
+ }
+ cmd = pci_read_config32(dev, 0x7c);
+ if ((cmd & (3 << 4)) != 0) {
+ cmd &= ~(3<<4);
+ cmd |= (0<<4);
+ pci_write_config32(dev, 0x7c, cmd );
+ needs_reset = 1;
+ }
+ /* Clock Power/Timing Low */
+ cmd = pci_read_config32(dev, 0xd4);
+ if (cmd != 0x000D0001) {
+ cmd = 0x000D0001;
+ pci_write_config32(dev, 0xd4, cmd);
+ needs_reset = 1; /* Needed? */
+ }
+
+ }
+ else {
+ uint32_t cmd_ref;
+ /* Errata 98
+ * Set Clk Ramp Hystersis to 7
+ * Clock Power/Timing Low
+ */
+ cmd_ref = 0x04e20707; /* Registered */
+ cmd = pci_read_config32(dev, 0xd4);
+ if(cmd != cmd_ref) {
+ pci_write_config32(dev, 0xd4, cmd_ref );
+ needs_reset = 1; /* Needed? */
+ }
+ }
+ }
+ return needs_reset;
+}
+
+static int optimize_link_read_pointers(unsigned cpus, int needs_reset)
+{
+ unsigned node;
+ for(node = 0; node < cpus; node = node + 1) {
+ device_t f0_dev, f3_dev;
+ uint32_t cmd_ref, cmd;
+ int link;
+ f0_dev = NODE_HT(node);
+ f3_dev = NODE_MC(node);
+ cmd_ref = cmd = pci_read_config32(f3_dev, 0xdc);
+ for(link = 0; link < 3; link = link + 1) {
+ uint32_t link_type;
+ unsigned reg;
+ reg = 0x98 + (link * 0x20);
+ link_type = pci_read_config32(f0_dev, reg);
+ if (link_type & LinkConnected) {
+ cmd &= 0xff << (link *8);
+ /* FIXME this assumes the device on the other side is an AMD device */
+ cmd |= 0x25 << (link *8);
+ }
+ }
+ if (cmd != cmd_ref) {
+ pci_write_config32(f3_dev, 0xdc, cmd);
+ needs_reset = 1;
+ }
+ }
+ return needs_reset;
+}
+
static int setup_coherent_ht_domain(void)
{
- unsigned cpus;
- int reset_needed = 0;
+ struct setup_smp_result result;
+ result.cpus = 1;
+ result.needs_reset = 0;
enable_bsp_routing();
#if CONFIG_MAX_CPUS == 1
- cpus=setup_uniprocessor();
+ setup_uniprocessor();
#else
- cpus=setup_smp();
- cpus=detect_mp_capabilities(cpus);
+ result = setup_smp();
+ result.cpus = verify_mp_capabilities(result.cpus);
+#endif
+ coherent_ht_finalize(result.cpus);
+ result.needs_reset = apply_cpu_errata_fixes(result.cpus, result.needs_reset);
+#if CONFIG_MAX_CPUS > 1 /* Why doesn't this work on the solo? */
+ result.needs_reset = optimize_link_read_pointers(result.cpus, result.needs_reset);
#endif
- coherent_ht_finalize(cpus);
- /* FIXME this should probably go away again. */
- coherent_ht_mainboard(cpus);
- return reset_needed;
+ return result.needs_reset;
}
diff --git a/src/northbridge/amd/amdk8/cpu_rev.c b/src/northbridge/amd/amdk8/cpu_rev.c
index 51f235905e..0c4c5f8fbd 100644
--- a/src/northbridge/amd/amdk8/cpu_rev.c
+++ b/src/northbridge/amd/amdk8/cpu_rev.c
@@ -16,10 +16,15 @@ static unsigned int cpuid(unsigned int op)
static int is_cpu_rev_a0(void)
{
- return (cpuid(1) & 0xffff) == 0x0f10;
+ return (cpuid(1) & 0xffef) == 0x0f00;
}
static int is_cpu_pre_c0(void)
{
return (cpuid(1) & 0xffef) < 0x0f48;
}
+
+static int is_cpu_pre_b3(void)
+{
+ return (cpuid(1) & 0xffef) < 0x0f41;
+}
diff --git a/src/northbridge/amd/amdk8/early_ht.c b/src/northbridge/amd/amdk8/early_ht.c
index 4de8fa1075..90f258e1bc 100644
--- a/src/northbridge/amd/amdk8/early_ht.c
+++ b/src/northbridge/amd/amdk8/early_ht.c
@@ -1,4 +1,4 @@
-static int enumerate_ht_chain(unsigned link)
+static int enumerate_ht_chain(void)
{
/* 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
@@ -49,3 +49,4 @@ static int enumerate_ht_chain(unsigned link)
} 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
new file mode 100644
index 0000000000..711100a045
--- /dev/null
+++ b/src/northbridge/amd/amdk8/incoherent_ht.c
@@ -0,0 +1,244 @@
+#include <device/pci_def.h>
+#include <device/pci_ids.h>
+#include <device/hypertransport_def.h>
+
+static unsigned ht_lookup_slave_capability(device_t dev)
+{
+ unsigned pos;
+ uint8_t hdr_type;
+
+ hdr_type = pci_read_config8(dev, PCI_HEADER_TYPE);
+ pos = 0;
+ hdr_type &= 0x7f;
+
+ if ((hdr_type == PCI_HEADER_TYPE_NORMAL) ||
+ (hdr_type == PCI_HEADER_TYPE_BRIDGE)) {
+ pos = PCI_CAPABILITY_LIST;
+ }
+ if (pos > PCI_CAP_LIST_NEXT) {
+ pos = pci_read_config8(dev, pos);
+ }
+ while(pos != 0) { /* loop through the linked list */
+ uint8_t cap;
+ cap = pci_read_config8(dev, pos + PCI_CAP_LIST_ID);
+ if (cap == PCI_CAP_ID_HT) {
+ uint16_t flags;
+
+ flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+ if ((flags >> 13) == 0) {
+ /* Entry is a Slave secondary, success... */
+ break;
+ }
+ }
+ pos = pci_read_config8(dev, pos + PCI_CAP_LIST_NEXT);
+ }
+ return pos;
+}
+
+static void ht_collapse_previous_enumeration(unsigned bus)
+{
+ device_t dev;
+
+ /* Spin through the devices and collapse any previous
+ * hypertransport enumeration.
+ */
+ for(dev = PCI_DEV(bus, 0, 0); dev <= PCI_DEV(bus, 0x1f, 0x7); dev += PCI_DEV(0, 1, 0)) {
+ uint32_t id;
+ unsigned pos, flags;
+
+ id = pci_read_config32(dev, PCI_VENDOR_ID);
+ if ((id == 0xffffffff) || (id == 0x00000000) ||
+ (id == 0x0000ffff) || (id == 0xffff0000)) {
+ continue;
+ }
+ pos = ht_lookup_slave_capability(dev);
+ if (!pos) {
+ continue;
+ }
+
+ /* Clear the unitid */
+ flags = pci_read_config16(dev, pos + PCI_CAP_FLAGS);
+ flags &= ~0x1f;
+ pci_write_config16(dev, pos + PCI_CAP_FLAGS, flags);
+ }
+}
+
+
+static unsigned ht_read_freq_cap(device_t dev, unsigned pos)
+{
+ /* Handle bugs in valid hypertransport frequency reporting */
+ unsigned freq_cap;
+ uint32_t id;
+
+ freq_cap = pci_read_config16(dev, pos);
+ freq_cap &= ~(1 << HT_FREQ_VENDOR); /* Ignore Vendor HT frequencies */
+
+ id = pci_read_config32(dev, 0);
+
+ /* AMD 8131 Errata 48 */
+ if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8131_PCIX << 16))) {
+ freq_cap &= ~(1 << HT_FREQ_800Mhz);
+ }
+ /* AMD 8151 Errata 23 */
+ if (id == (PCI_VENDOR_ID_AMD | (PCI_DEVICE_ID_AMD_8151_SYSCTRL << 16))) {
+ freq_cap &= ~(1 << HT_FREQ_800Mhz);
+ }
+ /* AMD K8 Unsupported 1Ghz? */
+ if (id == (PCI_VENDOR_ID_AMD | (0x1100 << 16))) {
+ freq_cap &= ~(1 << HT_FREQ_1000Mhz);
+ }
+ return freq_cap;
+}
+
+#define LINK_OFFS(WIDTH,FREQ,FREQ_CAP) \
+ (((WIDTH & 0xff) << 16) | ((FREQ & 0xff) << 8) | (FREQ_CAP & 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_WIDTH, \
+ PCI_HT_CAP_HOST_FREQ, \
+ PCI_HT_CAP_HOST_FREQ_CAP)
+
+#define PCI_HT_SLAVE0_OFFS LINK_OFFS( \
+ 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_WIDTH1, \
+ PCI_HT_CAP_SLAVE_FREQ1, \
+ PCI_HT_CAP_SLAVE_FREQ_CAP1)
+
+static int ht_optimize_link(
+ device_t dev1, uint8_t pos1, unsigned offs1,
+ device_t dev2, uint8_t pos2, unsigned offs2)
+{
+ 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;
+ uint8_t freq, old_freq;
+ int needs_reset;
+ /* Set link width and frequency */
+
+ /* Initially assume everything is already optimized and I don't need a reset */
+ needs_reset = 0;
+
+ /* Get the frequency capabilities */
+ freq_cap1 = ht_read_freq_cap(dev1, pos1 + LINK_FREQ_CAP(offs1));
+ freq_cap2 = ht_read_freq_cap(dev2, pos2 + LINK_FREQ_CAP(offs2));
+
+ /* Calculate the highest possible frequency */
+ freq = log2(freq_cap1 & freq_cap2);
+
+ /* See if I am changing the link freqency */
+ old_freq = pci_read_config8(dev1, pos1 + LINK_FREQ(offs1));
+ needs_reset |= old_freq != freq;
+ old_freq = pci_read_config8(dev2, pos2 + LINK_FREQ(offs2));
+ needs_reset |= old_freq != freq;
+
+ /* Set the Calulcated link frequency */
+ pci_write_config8(dev1, pos1 + LINK_FREQ(offs1), freq);
+ pci_write_config8(dev2, pos2 + LINK_FREQ(offs2), freq);
+
+ /* Get the width capabilities */
+ width_cap1 = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1));
+ width_cap2 = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2));
+
+ /* Calculate dev1's input width */
+ ln_width1 = link_width_to_pow2[width_cap1 & 7];
+ ln_width2 = link_width_to_pow2[(width_cap2 >> 4) & 7];
+ if (ln_width1 > ln_width2) {
+ ln_width1 = ln_width2;
+ }
+ width = pow2_to_link_width[ln_width1];
+ /* Calculate dev1's output width */
+ ln_width1 = link_width_to_pow2[(width_cap1 >> 4) & 7];
+ ln_width2 = link_width_to_pow2[width_cap2 & 7];
+ if (ln_width1 > ln_width2) {
+ ln_width1 = ln_width2;
+ }
+ width |= pow2_to_link_width[ln_width1] << 4;
+
+ /* See if I am changing dev1's width */
+ old_width = pci_read_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1);
+ needs_reset |= old_width != width;
+
+ /* Set dev1's widths */
+ pci_write_config8(dev1, pos1 + LINK_WIDTH(offs1) + 1, width);
+
+ /* Calculate dev2's width */
+ width = ((width & 0x70) >> 4) | ((width & 0x7) << 4);
+
+ /* See if I am changing dev2's width */
+ old_width = pci_read_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1);
+ needs_reset |= old_width != width;
+
+ /* Set dev2's widths */
+ pci_write_config8(dev2, pos2 + LINK_WIDTH(offs2) + 1, width);
+
+ return needs_reset;
+}
+
+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.
+ */
+ unsigned next_unitid, last_unitid;
+ int reset_needed;
+ unsigned uoffs;
+
+#warning "FIXME handle multiple chains!"
+
+ /* Make certain the HT bus is not enumerated */
+ ht_collapse_previous_enumeration(0);
+
+ reset_needed = 0;
+ uoffs = PCI_HT_HOST_OFFS;
+ next_unitid = 1;
+ do {
+ uint32_t id;
+ uint8_t pos;
+ unsigned flags, count;
+ device_t dev = PCI_DEV(0, 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)) {
+ break;
+ }
+ pos = ht_lookup_slave_capability(dev);
+ if (!pos) {
+ print_err("HT link capability not found\r\n");
+ break;
+ }
+ /* Setup the Hypertransport link */
+ reset_needed |= ht_optimize_link(udev, upos, uoffs, dev, pos, PCI_HT_SLAVE0_OFFS);
+
+ /* 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);
+
+ /* Remeber the location of the last device */
+ udev = PCI_DEV(0, next_unitid, 0);
+ upos = pos;
+ uoffs = PCI_HT_SLAVE1_OFFS;
+
+ /* Compute the number of unitids consumed */
+ count = (flags >> 5) & 0x1f;
+ next_unitid += count;
+
+ } while((last_unitid != next_unitid) && (next_unitid <= 0x1f));
+ return reset_needed;
+}
diff --git a/src/northbridge/amd/amdk8/misc_control.c b/src/northbridge/amd/amdk8/misc_control.c
index fe797aa580..df28bd0331 100644
--- a/src/northbridge/amd/amdk8/misc_control.c
+++ b/src/northbridge/amd/amdk8/misc_control.c
@@ -14,21 +14,96 @@
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
+#include <part/hard_reset.h>
#include "./cpu_rev.c"
+#include "amdk8.h"
+
+#define IOMMU_APETURE_SIZE (64*1024*1024) /* 64M */
+static void mcf3_read_resources(device_t dev)
+{
+ struct resource *resource;
+ /* Read the generic PCI resources */
+ pci_dev_read_resources(dev);
+
+ /* If we are not the first processor don't allocate the gart apeture */
+ if (dev->path.u.pci.devfn != PCI_DEVFN(24, 3)) {
+ return;
+ }
+
+ /* Add a 64M Gart apeture resource */
+ if (dev->resources < MAX_RESOURCES) {
+ resource = &dev->resource[dev->resources];
+ dev->resources++;
+ resource->base = 0;
+ resource->size = IOMMU_APETURE_SIZE;
+ resource->align = log2(resource->size);
+ resource->gran = log2(resource->size);
+ resource->limit = 0xffffffff; /* 4G */
+ resource->flags = IORESOURCE_MEM;
+ resource->index = 0x94;
+ }
+ else {
+ printk_err("%s Unexpeted resource shortage\n", dev_path(dev));
+ }
+}
+
+static void mcf3_set_resources(device_t dev)
+{
+ struct resource *resource, *last;
+ last = &dev->resource[dev->resources];
+ for(resource = &dev->resource[0]; resource < last; resource++) {
+ if (resource->index == 0x94) {
+ device_t pdev;
+ uint32_t base;
+ uint32_t size;
+
+ size = (0<<6)|(0<<5)|(0<<4)|((log2(resource->size) - 25) << 1)|(0<<0);
+ base = ((resource->base) >> 25) & 0x00007fff;
+
+ pdev = 0;
+ while(pdev = dev_find_device(PCI_VENDOR_ID_AMD, 0x1103, pdev)) {
+ /* I want a 64M GART apeture */
+ pci_write_config32(pdev, 0x90, (0<<6)|(0<<5)|(0<<4)|(1<<1)|(0<<0));
+ /* Store the GART base address */
+ pci_write_config32(pdev, 0x94, base);
+ /* Don't set the GART Table base address */
+ pci_write_config32(pdev, 0x98, 0);
+
+ printk_debug(
+ "%s %02x <- [0x%08lx - 0x%08lx] mem <gart>\n",
+ dev_path(pdev),
+ resource->index,
+ resource->base, resource->base + resource->size - 1);
+ }
+ /* Remember this resource has been stored */
+ resource->flags |= IORESOURCE_STORED;
+
+ }
+ }
+ /* Set the generic PCI resources */
+ pci_dev_set_resources(dev);
+}
-static cpu_reset_count = 0;
static void misc_control_init(struct device *dev)
{
- uint32_t cmd;
+ uint32_t cmd, cmd_ref;
+ int needs_reset;
+ struct device *f0_dev, *f2_dev;
printk_debug("NB: Function 3 Misc Control.. ");
-
- /* disable error reporting */
+ needs_reset = 0;
+
+ /* Disable Machine checks from Invalid Locations.
+ * This is needed for PC backwards compatibility.
+ */
cmd = pci_read_config32(dev, 0x44);
cmd |= (1<<6) | (1<<25);
pci_write_config32(dev, 0x44, cmd );
if (is_cpu_pre_c0()) {
- /* errata 58 */
+
+ /* Errata 58
+ * Disable CPU low power states C2, C1 and throttling
+ */
cmd = pci_read_config32(dev, 0x80);
cmd &= ~(1<<0);
pci_write_config32(dev, 0x80, cmd );
@@ -36,62 +111,86 @@ static void misc_control_init(struct device *dev)
cmd &= ~(1<<24);
cmd &= ~(1<<8);
pci_write_config32(dev, 0x84, cmd );
- /* errata 66 */
+
+ /* Errata 66
+ * Limit the number of downstream posted requests to 1
+ */
cmd = pci_read_config32(dev, 0x70);
- cmd &= ~(1<<0);
- cmd |= (1<<1);
- pci_write_config32(dev, 0x70, cmd );
+ if ((cmd & (3 << 0)) != 2) {
+ cmd &= ~(3<<0);
+ cmd |= (2<<0);
+ pci_write_config32(dev, 0x70, cmd );
+ needs_reset = 1;
+ }
cmd = pci_read_config32(dev, 0x7c);
- cmd &= ~(3<<4);
- pci_write_config32(dev, 0x7c, cmd );
+ if ((cmd & (3 << 4)) != 0) {
+ cmd &= ~(3<<4);
+ cmd |= (0<<4);
+ pci_write_config32(dev, 0x7c, cmd );
+ needs_reset = 1;
+ }
+ /* Clock Power/Timing Low */
+ cmd = pci_read_config32(dev, 0xd4);
+ if (cmd != 0x000D0001) {
+ cmd = 0x000D0001;
+ pci_write_config32(dev, 0xd4, cmd);
+ needs_reset = 1; /* Needed? */
+ }
}
else {
- /* errata 98 */
-#if 0
+ uint32_t dcl;
+ f2_dev = dev_find_slot(0, dev->path.u.pci.devfn - 3 + 2);
+ /* Errata 98
+ * Set Clk Ramp Hystersis to 7
+ * Clock Power/Timing Low
+ */
+ cmd_ref = 0x04e20707; /* Registered */
+ dcl = pci_read_config32(f2_dev, DRAM_CONFIG_LOW);
+ if (dcl & DCL_UnBufDimm) {
+ cmd_ref = 0x000D0701; /* Unbuffered */
+ }
cmd = pci_read_config32(dev, 0xd4);
- if(cmd != 0x04e20707) {
- cmd = 0x04e20707;
- pci_write_config32(dev, 0xd4, cmd );
- hard_reset();
+ if(cmd != cmd_ref) {
+ pci_write_config32(dev, 0xd4, cmd_ref );
+ needs_reset = 1; /* Needed? */
}
-#endif
-
- cmd = 0x04e20707;
- pci_write_config32(dev, 0xd4, cmd );
}
-
-/*
- * FIXME: This preprocessor check is a mere workaround.
- * The right fix is to walk over all links on all nodes
- * and set the FIFO read pointer optimization value to
- * 0x25 for each link connected to an AMD HT device.
- *
- * The reason this is only enabled for machines with more
- * than one CPU is that Athlon64 machines don't have the
- * link at all that is optimized in the code.
- */
-
-#if CONFIG_MAX_CPUS > 1
-#if HAVE_HARD_RESET==1
- cpu_reset_count++;
- cmd = pci_read_config32(dev, 0xdc);
- if((cmd & 0x0000ff00) != 0x02500) {
- cmd &= 0xffff00ff;
- cmd |= 0x00002500;
- pci_write_config32(dev, 0xdc, cmd );
- if(cpu_reset_count==CONFIG_MAX_CPUS) {
- printk_debug("resetting cpu\n");
- hard_reset();
+ /* Optimize the Link read pointers */
+ f0_dev = dev_find_slot(0, dev->path.u.pci.devfn - 3);
+ if (f0_dev) {
+ int link;
+ cmd_ref = cmd = pci_read_config32(dev, 0xdc);
+ for(link = 0; link < 3; link++) {
+ uint32_t link_type;
+ unsigned reg;
+ /* 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 & LinkConnected) {
+ cmd &= 0xff << (link *8);
+ /* FIXME this assumes the device on the other side is an AMD device */
+ cmd |= 0x25 << (link *8);
+ }
+ }
+ if (cmd != cmd_ref) {
+ pci_write_config32(dev, 0xdc, cmd);
+ needs_reset = 1;
}
- }
-#endif
-#endif
+ }
+ else {
+ printk_err("Missing f0 device!\n");
+ }
+ if (needs_reset) {
+ printk_debug("resetting cpu\n");
+ hard_reset();
+ }
printk_debug("done.\n");
}
+
static struct device_operations mcf3_ops = {
- .read_resources = pci_dev_read_resources,
- .set_resources = pci_dev_set_resources,
+ .read_resources = mcf3_read_resources,
+ .set_resources = mcf3_set_resources,
.enable_resources = pci_dev_enable_resources,
.init = misc_control_init,
.scan_bus = 0,
@@ -102,4 +201,3 @@ static struct pci_driver mcf3_driver __pci_driver = {
.vendor = PCI_VENDOR_ID_AMD,
.device = 0x1103,
};
-
diff --git a/src/northbridge/amd/amdk8/northbridge.c b/src/northbridge/amd/amdk8/northbridge.c
index e62aded451..12d8f73c0b 100644
--- a/src/northbridge/amd/amdk8/northbridge.c
+++ b/src/northbridge/amd/amdk8/northbridge.c
@@ -38,7 +38,7 @@ struct mem_range *sizeram(void)
mmio_basek &= ~((256*1024) - 1);
#endif
-#if 1
+#if 0
printk_debug("mmio_base: %dKB\n", mmio_basek);
#endif
@@ -383,8 +383,14 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned
{
unsigned long rbase, rlimit;
unsigned reg, link;
+
/* Make certain the resource has actually been set */
- if (!(resource->flags & IORESOURCE_SET)) {
+ if (!(resource->flags & IORESOURCE_ASSIGNED)) {
+ return;
+ }
+
+ /* If I have already stored this resource don't worry about it */
+ if (resource->flags & IORESOURCE_STORED) {
return;
}
@@ -401,7 +407,7 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned
/* Get the register and link */
reg = resource->index & ~3;
link = resource->index & 3;
-
+
if (resource->flags & IORESOURCE_IO) {
uint32_t base, limit;
compute_allocate_resource(&dev->link[link], resource,
@@ -415,13 +421,14 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned
limit |= rlimit & 0x01fff000;
limit |= (link & 3) << 4;
limit |= (nodeid & 7);
- if (reg == 0xc8){
- /* hack to set vga for test */
- /* factory: b0: 03 0a 00 00 00 0b 00 00 */
- f1_write_config32(0xb0, 0xa03);
- f1_write_config32(0xb4, 0xb00);
- base |= 0x30;
+
+ if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
+ base |= PCI_IO_BASE_VGA_EN;
+ }
+ if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_NO_ISA) {
+ base |= PCI_IO_BASE_NO_ISA;
}
+
f1_write_config32(reg + 0x4, limit);
f1_write_config32(reg, base);
}
@@ -441,6 +448,7 @@ static void amdk8_set_resource(device_t dev, struct resource *resource, unsigned
f1_write_config32(reg + 0x4, limit);
f1_write_config32(reg, base);
}
+ resource->flags |= IORESOURCE_STORED;
printk_debug(
"%s %02x <- [0x%08lx - 0x%08lx] node %d link %d %s\n",
dev_path(dev),
@@ -483,51 +491,46 @@ unsigned int amdk8_scan_root_bus(device_t root, unsigned int max)
return max;
}
-void amdk8_enable_resources(struct device *dev)
+static void mcf0_control_init(struct device *dev)
{
- uint16_t ctrl;
- unsigned link;
- unsigned int vgalink = -1;
-
- ctrl = pci_read_config16(dev, PCI_BRIDGE_CONTROL);
- ctrl |= dev->link[0].bridge_ctrl;
- printk_debug("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
- printk_err("%s bridge ctrl <- %04x\n", dev_path(dev), ctrl);
- pci_write_config16(dev, PCI_BRIDGE_CONTROL, ctrl);
-
-#if 0
- /* let's see what link VGA is on */
- for(link = 0; link < dev->links; link++) {
- device_t child;
- printk_err("Kid %d of k8: bridge ctrl says: 0x%x\n", link, dev->link[link].bridge_ctrl);
- if (dev->link[link].bridge_ctrl & PCI_BRIDGE_CTL_VGA)
- vgalink = link;
- }
-
- if (vgalink != =1) {
- /* now find the IOPAIR that goes to vgalink and set the vga enable in the base part (0x30) */
- /* now allocate an MMIOPAIR and point it to the CPU0, LINK=vgalink */
- /* now set IORR1 so it has a hole for the 0xa0000-0xcffff region */
- }
+ uint32_t cmd;
+
+#if 1
+ printk_debug("NB: Function 0 Misc Control.. ");
+ /* improve latency and bandwith on HT */
+ cmd = pci_read_config32(dev, 0x68);
+ cmd &= 0xffff80ff;
+ cmd |= 0x00004800;
+ pci_write_config32(dev, 0x68, cmd );
#endif
- pci_dev_enable_resources(dev);
- //enable_childrens_resources(dev);
+#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
+ printk_debug("done.\n");
}
-
-
static struct device_operations northbridge_operations = {
.read_resources = amdk8_read_resources,
.set_resources = amdk8_set_resources,
-// .enable_resources = pci_dev_enable_resources,
- .enable_resources = amdk8_enable_resources,
- .init = 0,
+ .enable_resources = pci_dev_enable_resources,
+ .init = mcf0_control_init,
.scan_bus = amdk8_scan_chains,
.enable = 0,
};
+static struct pci_driver mcf0_driver __pci_driver = {
+ .ops = &northbridge_operations,
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = 0x1100,
+};
+
+
static void enumerate(struct chip *chip)
{
chip_enumerate(chip);
@@ -538,4 +541,3 @@ struct chip_control northbridge_amd_amdk8_control = {
.name = "AMD K8 Northbridge",
.enumerate = enumerate,
};
-
diff --git a/src/northbridge/amd/amdk8/raminit.c b/src/northbridge/amd/amdk8/raminit.c
index 006ab196df..bc73fcba16 100644
--- a/src/northbridge/amd/amdk8/raminit.c
+++ b/src/northbridge/amd/amdk8/raminit.c
@@ -1,202 +1,21 @@
#include <cpu/k8/mtrr.h>
#include "raminit.h"
+#include "amdk8.h"
-#define ENABLE_IOMMU 1
-
-/* Function 2 */
-#define DRAM_CSBASE 0x40
-#define DRAM_CSMASK 0x60
-#define DRAM_BANK_ADDR_MAP 0x80
-#define DRAM_TIMING_LOW 0x88
-#define DTL_TCL_SHIFT 0
-#define DTL_TCL_MASK 0x7
-#define DTL_CL_2 1
-#define DTL_CL_3 2
-#define DTL_CL_2_5 5
-#define DTL_TRC_SHIFT 4
-#define DTL_TRC_MASK 0xf
-#define DTL_TRC_BASE 7
-#define DTL_TRC_MIN 7
-#define DTL_TRC_MAX 22
-#define DTL_TRFC_SHIFT 8
-#define DTL_TRFC_MASK 0xf
-#define DTL_TRFC_BASE 9
-#define DTL_TRFC_MIN 9
-#define DTL_TRFC_MAX 24
-#define DTL_TRCD_SHIFT 12
-#define DTL_TRCD_MASK 0x7
-#define DTL_TRCD_BASE 0
-#define DTL_TRCD_MIN 2
-#define DTL_TRCD_MAX 6
-#define DTL_TRRD_SHIFT 16
-#define DTL_TRRD_MASK 0x7
-#define DTL_TRRD_BASE 0
-#define DTL_TRRD_MIN 2
-#define DTL_TRRD_MAX 4
-#define DTL_TRAS_SHIFT 20
-#define DTL_TRAS_MASK 0xf
-#define DTL_TRAS_BASE 0
-#define DTL_TRAS_MIN 5
-#define DTL_TRAS_MAX 15
-#define DTL_TRP_SHIFT 24
-#define DTL_TRP_MASK 0x7
-#define DTL_TRP_BASE 0
-#define DTL_TRP_MIN 2
-#define DTL_TRP_MAX 6
-#define DTL_TWR_SHIFT 28
-#define DTL_TWR_MASK 0x1
-#define DTL_TWR_BASE 2
-#define DTL_TWR_MIN 2
-#define DTL_TWR_MAX 3
-#define DRAM_TIMING_HIGH 0x8c
-#define DTH_TWTR_SHIFT 0
-#define DTH_TWTR_MASK 0x1
-#define DTH_TWTR_BASE 1
-#define DTH_TWTR_MIN 1
-#define DTH_TWTR_MAX 2
-#define DTH_TRWT_SHIFT 4
-#define DTH_TRWT_MASK 0x7
-#define DTH_TRWT_BASE 1
-#define DTH_TRWT_MIN 1
-#define DTH_TRWT_MAX 6
-#define DTH_TREF_SHIFT 8
-#define DTH_TREF_MASK 0x1f
-#define DTH_TREF_100MHZ_4K 0x00
-#define DTH_TREF_133MHZ_4K 0x01
-#define DTH_TREF_166MHZ_4K 0x02
-#define DTH_TREF_200MHZ_4K 0x03
-#define DTH_TREF_100MHZ_8K 0x08
-#define DTH_TREF_133MHZ_8K 0x09
-#define DTH_TREF_166MHZ_8K 0x0A
-#define DTH_TREF_200MHZ_8K 0x0B
-#define DTH_TWCL_SHIFT 20
-#define DTH_TWCL_MASK 0x7
-#define DTH_TWCL_BASE 1
-#define DTH_TWCL_MIN 1
-#define DTH_TWCL_MAX 2
-#define DRAM_CONFIG_LOW 0x90
-#define DCL_DLL_Disable (1<<0)
-#define DCL_D_DRV (1<<1)
-#define DCL_QFC_EN (1<<2)
-#define DCL_DisDqsHys (1<<3)
-#define DCL_DramInit (1<<8)
-#define DCL_DramEnable (1<<10)
-#define DCL_MemClrStatus (1<<11)
-#define DCL_ESR (1<<12)
-#define DCL_SRS (1<<13)
-#define DCL_128BitEn (1<<16)
-#define DCL_DimmEccEn (1<<17)
-#define DCL_UnBufDimm (1<<18)
-#define DCL_32ByteEn (1<<19)
-#define DCL_x4DIMM_SHIFT 20
-#define DRAM_CONFIG_HIGH 0x94
-#define DCH_ASYNC_LAT_SHIFT 0
-#define DCH_ASYNC_LAT_MASK 0xf
-#define DCH_ASYNC_LAT_BASE 0
-#define DCH_ASYNC_LAT_MIN 0
-#define DCH_ASYNC_LAT_MAX 15
-#define DCH_RDPREAMBLE_SHIFT 8
-#define DCH_RDPREAMBLE_MASK 0xf
-#define DCH_RDPREAMBLE_BASE ((2<<1)+0) /* 2.0 ns */
-#define DCH_RDPREAMBLE_MIN ((2<<1)+0) /* 2.0 ns */
-#define DCH_RDPREAMBLE_MAX ((9<<1)+1) /* 9.5 ns */
-#define DCH_IDLE_LIMIT_SHIFT 16
-#define DCH_IDLE_LIMIT_MASK 0x7
-#define DCH_IDLE_LIMIT_0 0
-#define DCH_IDLE_LIMIT_4 1
-#define DCH_IDLE_LIMIT_8 2
-#define DCH_IDLE_LIMIT_16 3
-#define DCH_IDLE_LIMIT_32 4
-#define DCH_IDLE_LIMIT_64 5
-#define DCH_IDLE_LIMIT_128 6
-#define DCH_IDLE_LIMIT_256 7
-#define DCH_DYN_IDLE_CTR_EN (1 << 19)
-#define DCH_MEMCLK_SHIFT 20
-#define DCH_MEMCLK_MASK 0x7
-#define DCH_MEMCLK_100MHZ 0
-#define DCH_MEMCLK_133MHZ 2
-#define DCH_MEMCLK_166MHZ 5
-#define DCH_MEMCLK_200MHZ 7
-#define DCH_MEMCLK_VALID (1 << 25)
-#define DCH_MEMCLK_EN0 (1 << 26)
-#define DCH_MEMCLK_EN1 (1 << 27)
-#define DCH_MEMCLK_EN2 (1 << 28)
-#define DCH_MEMCLK_EN3 (1 << 29)
-
-/* Function 3 */
-#define MCA_NB_CONFIG 0x44
-#define MNC_ECC_EN (1 << 22)
-#define MNC_CHIPKILL_EN (1 << 23)
-#define SCRUB_CONTROL 0x58
-#define SCRUB_NONE 0
-#define SCRUB_40ns 1
-#define SCRUB_80ns 2
-#define SCRUB_160ns 3
-#define SCRUB_320ns 4
-#define SCRUB_640ns 5
-#define SCRUB_1_28us 6
-#define SCRUB_2_56us 7
-#define SCRUB_5_12us 8
-#define SCRUB_10_2us 9
-#define SCRUB_20_5us 10
-#define SCRUB_41_0us 11
-#define SCRUB_81_9us 12
-#define SCRUB_163_8us 13
-#define SCRUB_327_7us 14
-#define SCRUB_655_4us 15
-#define SCRUB_1_31ms 16
-#define SCRUB_2_62ms 17
-#define SCRUB_5_24ms 18
-#define SCRUB_10_49ms 19
-#define SCRUB_20_97ms 20
-#define SCRUB_42ms 21
-#define SCRUB_84ms 22
-#define SC_DRAM_SCRUB_RATE_SHFIT 0
-#define SC_DRAM_SCRUB_RATE_MASK 0x1f
-#define SC_L2_SCRUB_RATE_SHIFT 8
-#define SC_L2_SCRUB_RATE_MASK 0x1f
-#define SC_L1D_SCRUB_RATE_SHIFT 16
-#define SC_L1D_SCRUB_RATE_MASK 0x1f
-#define SCRUB_ADDR_LOW 0x5C
-#define SCRUB_ADDR_HIGH 0x60
-#define NORTHBRIDGE_CAP 0xE8
-#define NBCAP_128Bit 0x0001
-#define NBCAP_MP 0x0002
-#define NBCAP_BIG_MP 0x0004
-#define NBCAP_ECC 0x0004
-#define NBCAP_CHIPKILL_ECC 0x0010
-#define NBCAP_MEMCLK_SHIFT 5
-#define NBCAP_MEMCLK_MASK 3
-#define NBCAP_MEMCLK_100MHZ 3
-#define NBCAP_MEMCLK_133MHZ 2
-#define NBCAP_MEMCLK_166MHZ 1
-#define NBCAP_MEMCLK_200MHZ 0
-#define NBCAP_MEMCTRL 0x0100
-
-
+#if (CONFIG_LB_MEM_TOPK & (CONFIG_LB_MEM_TOPK -1)) != 0
+# error "CONFIG_LB_MEM_TOPK must be a power of 2"
+#endif
static void setup_resource_map(const unsigned int *register_values, int max)
{
int i;
-
- unsigned int amd8111_link_nr;
-
- print_debug("setting up resource map....\r\n");
- /*
- * determine the HT link number the southbridge is connected to
- * bits 8-9 of the Unit ID register
- */
- amd8111_link_nr = (pci_read_config32(PCI_DEV(0, 0x18, 0), 0x64) & 0x00000300) >> 8;
- print_debug(" AMD8111 southbridge is connected to HT link ");
- print_debug_hex32(amd8111_link_nr);
- print_debug("\r\n");
-
-
- print_debug("setting up resource map....\r\n");
+ print_debug("setting up resource map....");
+#if 0
+ print_debug("\r\n");
+#endif
for(i = 0; i < max; i += 3) {
device_t dev;
unsigned where;
unsigned long reg;
-
#if 0
print_debug_hex32(register_values[i]);
print_debug(" <-");
@@ -208,19 +27,6 @@ static void setup_resource_map(const unsigned int *register_values, int max)
reg = pci_read_config32(dev, where);
reg &= register_values[i+1];
reg |= register_values[i+2];
-
- /*
- * set correct HT link to the southbridge
- * otherwise we cut of the acces to the flash we are from
- *
- */
- if (where == 0xBC)
- reg |= amd8111_link_nr << 4;
- if (where == 0xC4)
- reg |= amd8111_link_nr << 4;
- if (where == 0xE0)
- reg |= amd8111_link_nr << 8;
-
pci_write_config32(dev, where, reg);
#if 0
reg = pci_read_config32(register_values[i]);
@@ -952,29 +758,22 @@ static void sdram_set_registers(const struct mem_controller *ctrl)
* [31: 8] Reserved
*/
PCI_ADDR(0, 0x18, 3, 0x60), 0xffffff00, 0x00000000,
-
-#if ENABLE_IOMMU != 0
- /* BY LYH add IOMMU 64M APERTURE */
- PCI_ADDR(0, 0x18, 3, 0x94), 0xffff8000, 0x00000f70,
- PCI_ADDR(0, 0x18, 3, 0x90), 0xffffff80, 0x00000002,
- PCI_ADDR(0, 0x18, 3, 0x98), 0x0000000f, 0x00068300,
-#endif
};
int i;
int max;
- print_debug("setting up CPU");
- print_debug_hex8(ctrl->node_id);
- print_debug(" northbridge registers\r\n");
+ print_spew("setting up CPU");
+ print_spew_hex8(ctrl->node_id);
+ print_spew(" northbridge registers\r\n");
max = sizeof(register_values)/sizeof(register_values[0]);
for(i = 0; i < max; i += 3) {
device_t dev;
unsigned where;
unsigned long reg;
#if 0
- print_debug_hex32(register_values[i]);
- print_debug(" <-");
- print_debug_hex32(register_values[i+2]);
- print_debug("\r\n");
+ print_spew_hex32(register_values[i]);
+ print_spew(" <-");
+ print_spew_hex32(register_values[i+2]);
+ print_spew("\r\n");
#endif
dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x18, 0) + ctrl->f0;
where = register_values[i] & 0xff;
@@ -990,10 +789,26 @@ static void sdram_set_registers(const struct mem_controller *ctrl)
pci_write_config32(register_values[i], reg);
#endif
}
- print_debug("done.\r\n");
+ print_spew("done.\r\n");
}
+static void hw_enable_ecc(const struct mem_controller *ctrl)
+{
+ uint32_t dcl, nbcap;
+ nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
+ dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
+ dcl &= ~DCL_DimmEccEn;
+ if (nbcap & NBCAP_ECC) {
+ dcl |= DCL_DimmEccEn;
+ }
+ if (read_option(CMOS_VSTART_ECC_memory, CMOS_VLEN_ECC_memory, 1) == 0) {
+ dcl &= ~DCL_DimmEccEn;
+ }
+ pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+
+}
+
static int is_dual_channel(const struct mem_controller *ctrl)
{
uint32_t dcl;
@@ -1042,46 +857,60 @@ static struct dimm_size spd_get_dimm_size(unsigned device)
* sides of an assymetric dimm.
*/
value = spd_read_byte(device, 3); /* rows */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
sz.side1 += value & 0xf;
value = spd_read_byte(device, 4); /* columns */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xf) == 0) goto val_err;
sz.side1 += value & 0xf;
value = spd_read_byte(device, 17); /* banks */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xff) == 0) goto val_err;
sz.side1 += log2(value & 0xff);
/* Get the module data width and convert it to a power of two */
value = spd_read_byte(device, 7); /* (high byte) */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
value &= 0xff;
value <<= 8;
low = spd_read_byte(device, 6); /* (low byte) */
- if (low < 0) goto out;
+ if (low < 0) goto hw_err;
value = value | (low & 0xff);
+ if ((value != 72) && (value &= 64)) goto val_err;
sz.side1 += log2(value);
/* side 2 */
value = spd_read_byte(device, 5); /* number of physical banks */
- if (value <= 1) goto out;
+ if (value < 0) goto hw_err;
+ if (value == 1) goto out;
+ if (value != 2) goto val_err;
/* Start with the symmetrical case */
sz.side2 = sz.side1;
value = spd_read_byte(device, 3); /* rows */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */
sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */
sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */
value = spd_read_byte(device, 4); /* columns */
- if (value < 0) goto out;
+ if (value < 0) goto hw_err;
+ if ((value & 0xff) == 0) goto val_err;
sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */
sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */
+ goto out;
+ val_err:
+ die("Bad SPD value\r\n");
+ /* If an hw_error occurs report that I have no memory */
+hw_err:
+ sz.side1 = 0;
+ sz.side2 = 0;
out:
return sz;
}
@@ -1091,15 +920,6 @@ static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz
uint32_t base0, base1, map;
uint32_t dch;
-#if 0
- print_debug("set_dimm_size: (");
- print_debug_hex32(sz.side1);
- print_debug_char(',');
- print_debug_hex32(sz.side2);
- print_debug_char(',');
- print_debug_hex32(index);
- print_debug(")\r\n");
-#endif
if (sz.side1 != sz.side2) {
sz.side2 = 0;
}
@@ -1147,15 +967,22 @@ static void set_dimm_size(const struct mem_controller *ctrl, struct dimm_size sz
}
}
-static void spd_set_ram_size(const struct mem_controller *ctrl)
+static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask)
{
int i;
- for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ for(i = 0; i < DIMM_SOCKETS; i++) {
struct dimm_size sz;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
sz = spd_get_dimm_size(ctrl->channel0[i]);
+ if (sz.side1 == 0) {
+ return -1; /* Report SPD error */
+ }
set_dimm_size(ctrl, sz, i);
}
+ return dimm_mask;
}
static void route_dram_accesses(const struct mem_controller *ctrl,
@@ -1191,20 +1018,13 @@ static void set_top_mem(unsigned tom_k)
{
/* Error if I don't have memory */
if (!tom_k) {
- set_bios_reset();
- print_debug("No memory - reset");
- /* enable cf9 */
- pci_write_config8(PCI_DEV(0, 0x04, 3), 0x41, 0xf1);
- /* reset */
- outb(0x0e, 0x0cf9);
+ die("No memory?");
}
-#if 1
/* Report the amount of memory. */
- print_debug("RAM: 0x");
- print_debug_hex32(tom_k);
- print_debug(" KB\r\n");
-#endif
+ print_spew("RAM: 0x");
+ print_spew_hex32(tom_k);
+ print_spew(" KB\r\n");
/* Now set top of memory */
msr_t msr;
@@ -1238,7 +1058,6 @@ static unsigned long interleave_chip_selects(const struct mem_controller *ctrl)
uint32_t csbase_inc;
int chip_selects, index;
int bits;
- int dual_channel;
unsigned common_size;
uint32_t csbase, csmask;
@@ -1306,9 +1125,8 @@ static unsigned long interleave_chip_selects(const struct mem_controller *ctrl)
csbase += csbase_inc;
}
-#if 1
- print_debug("Interleaved\r\n");
-#endif
+ print_spew("Interleaved\r\n");
+
/* Return the memory size in K */
return common_size << (15 + bits);
}
@@ -1368,7 +1186,6 @@ static unsigned long order_chip_selects(const struct mem_controller *ctrl)
/* Compute the memory mask */
csmask = ((size -1) << 21);
csmask |= 0xfe00; /* For now don't optimize */
-#warning "Don't forget to optimize the DIMM size"
/* Write the new base register */
pci_write_config32(ctrl->f2, DRAM_CSBASE + (canidate << 2), csbase);
@@ -1380,18 +1197,13 @@ static unsigned long order_chip_selects(const struct mem_controller *ctrl)
return (tom & ~0xff000000) << 15;
}
-static void order_dimms(const struct mem_controller *ctrl)
+unsigned long memory_end_k(const struct mem_controller *ctrl, int max_node_id)
{
- unsigned long tom, tom_k, base_k;
unsigned node_id;
-
- tom_k = interleave_chip_selects(ctrl);
- if (!tom_k) {
- tom_k = order_chip_selects(ctrl);
- }
- /* Compute the memory base address */
- base_k = 0;
- for(node_id = 0; node_id < ctrl->node_id; node_id++) {
+ unsigned end_k;
+ /* Find the last memory address used */
+ end_k = 0;
+ for(node_id = 0; node_id < max_node_id; node_id++) {
uint32_t limit, base;
unsigned index;
index = node_id << 3;
@@ -1399,32 +1211,44 @@ static void order_dimms(const struct mem_controller *ctrl)
/* Only look at the limit if the base is enabled */
if ((base & 3) == 3) {
limit = pci_read_config32(ctrl->f1, 0x44 + index);
- base_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
+ end_k = ((limit + 0x00010000) & 0xffff0000) >> 2;
}
}
+ return end_k;
+}
+
+static void order_dimms(const struct mem_controller *ctrl)
+{
+ unsigned long tom_k, base_k;
+
+ if (read_option(CMOS_VSTART_interleave_chip_selects, CMOS_VLEN_interleave_chip_selects, 1) != 0) {
+ tom_k = interleave_chip_selects(ctrl);
+ } else {
+ print_debug("Interleaving disabled\r\n");
+ tom_k = 0;
+ }
+ if (!tom_k) {
+ tom_k = order_chip_selects(ctrl);
+ }
+ /* Compute the memory base address */
+ base_k = memory_end_k(ctrl, ctrl->node_id);
tom_k += base_k;
-#if 0
- print_debug("base_k: ");
- print_debug_hex32(base_k);
- print_debug(" tom_k: ");
- print_debug_hex32(tom_k);
- print_debug("\r\n");
-#endif
route_dram_accesses(ctrl, base_k, tom_k);
set_top_mem(tom_k);
}
-static void disable_dimm(const struct mem_controller *ctrl, unsigned index)
+static long disable_dimm(const struct mem_controller *ctrl, unsigned index, long dimm_mask)
{
print_debug("disabling dimm");
print_debug_hex8(index);
print_debug("\r\n");
pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+0)<<2), 0);
pci_write_config32(ctrl->f2, DRAM_CSBASE + (((index << 1)+1)<<2), 0);
+ dimm_mask &= ~(1 << index);
+ return dimm_mask;
}
-
-static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl)
+static long spd_handle_unbuffered_dimms(const struct mem_controller *ctrl, long dimm_mask)
{
int i;
int registered;
@@ -1432,12 +1256,14 @@ static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl)
uint32_t dcl;
unbuffered = 0;
registered = 0;
- for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ for(i = 0; (i < DIMM_SOCKETS); i++) {
int value;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
value = spd_read_byte(ctrl->channel0[i], 21);
if (value < 0) {
- disable_dimm(ctrl, i);
- continue;
+ return -1;
}
/* Registered dimm ? */
if (value & (1 << 1)) {
@@ -1468,15 +1294,40 @@ static void spd_handle_unbuffered_dimms(const struct mem_controller *ctrl)
print_debug("Unbuffered\r\n");
}
#endif
+ return dimm_mask;
}
-static void spd_enable_2channels(const struct mem_controller *ctrl)
+static unsigned int spd_detect_dimms(const struct mem_controller *ctrl)
+{
+ unsigned dimm_mask;
+ int i;
+ dimm_mask = 0;
+ for(i = 0; i < DIMM_SOCKETS; i++) {
+ int byte;
+ unsigned device;
+ device = ctrl->channel0[i];
+ if (device) {
+ byte = spd_read_byte(ctrl->channel0[i], 2); /* Type */
+ if (byte == 7) {
+ dimm_mask |= (1 << i);
+ }
+ }
+ device = ctrl->channel1[i];
+ if (device) {
+ byte = spd_read_byte(ctrl->channel1[i], 2);
+ if (byte == 7) {
+ dimm_mask |= (1 << (i + DIMM_SOCKETS));
+ }
+ }
+ }
+ return dimm_mask;
+}
+
+static long spd_enable_2channels(const struct mem_controller *ctrl, long dimm_mask)
{
int i;
uint32_t nbcap;
/* SPD addresses to verify are identical */
-#warning "FINISHME review and see if these are the bytes I need"
- /* FINISHME review and see if these are the bytes I need */
static const unsigned addresses[] = {
2, /* Type should be DDR SDRAM */
3, /* *Row addresses */
@@ -1499,40 +1350,52 @@ static void spd_enable_2channels(const struct mem_controller *ctrl)
41, /* *Minimum Active to Active/Auto Refresh Time(Trc) */
42, /* *Minimum Auto Refresh Command Time(Trfc) */
};
+ /* If the dimms are not in pairs do not do dual channels */
+ if ((dimm_mask & ((1 << DIMM_SOCKETS) - 1)) !=
+ ((dimm_mask >> DIMM_SOCKETS) & ((1 << DIMM_SOCKETS) - 1))) {
+ goto single_channel;
+ }
+ /* If the cpu is not capable of doing dual channels don't do dual channels */
nbcap = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
if (!(nbcap & NBCAP_128Bit)) {
- return;
+ goto single_channel;
}
for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
unsigned device0, device1;
int value0, value1;
int j;
+ /* If I don't have a dimm skip this one */
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
device0 = ctrl->channel0[i];
device1 = ctrl->channel1[i];
- if (!device1)
- return;
for(j = 0; j < sizeof(addresses)/sizeof(addresses[0]); j++) {
unsigned addr;
addr = addresses[j];
value0 = spd_read_byte(device0, addr);
if (value0 < 0) {
- break;
+ return -1;
}
value1 = spd_read_byte(device1, addr);
if (value1 < 0) {
- return;
+ return -1;
}
if (value0 != value1) {
- return;
+ goto single_channel;
}
}
}
- print_debug("Enabling dual channel memory\r\n");
+ print_spew("Enabling dual channel memory\r\n");
uint32_t dcl;
dcl = pci_read_config32(ctrl->f2, DRAM_CONFIG_LOW);
dcl &= ~DCL_32ByteEn;
dcl |= DCL_128BitEn;
pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
+ return dimm_mask;
+ single_channel:
+ dimm_mask &= ~((1 << (DIMM_SOCKETS *2)) - (1 << DIMM_SOCKETS));
+ return dimm_mask;
}
struct mem_param {
@@ -1606,17 +1469,22 @@ static const struct mem_param *get_mem_param(unsigned min_cycle_time)
if (!param->cycle_time) {
die("min_cycle_time to low");
}
-#if 1
+ print_spew(param->name);
+#ifdef DRAM_MIN_CYCLE_TIME
print_debug(param->name);
#endif
return param;
}
-static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
+struct spd_set_memclk_result {
+ const struct mem_param *param;
+ long dimm_mask;
+};
+static struct spd_set_memclk_result spd_set_memclk(const struct mem_controller *ctrl, long dimm_mask)
{
/* Compute the minimum cycle time for these dimms */
- const struct mem_param *param;
- unsigned min_cycle_time, min_latency;
+ struct spd_set_memclk_result result;
+ unsigned min_cycle_time, min_latency, bios_cycle_time;
int i;
uint32_t value;
@@ -1631,25 +1499,26 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
value = pci_read_config32(ctrl->f3, NORTHBRIDGE_CAP);
min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK];
+ bios_cycle_time = min_cycle_times[
+ read_option(CMOS_VSTART_max_mem_clock, CMOS_VLEN_max_mem_clock, 0)];
+ if (bios_cycle_time > min_cycle_time) {
+ min_cycle_time = bios_cycle_time;
+ }
min_latency = 2;
-#if 0
- print_debug("min_cycle_time: ");
- print_debug_hex8(min_cycle_time);
- print_debug(" min_latency: ");
- print_debug_hex8(min_latency);
- print_debug("\r\n");
-#endif
-
/* Compute the least latency with the fastest clock supported
* by both the memory controller and the dimms.
*/
- for(i = 0; (i < 4) && (ctrl->channel0[i]); i++) {
+ for(i = 0; i < DIMM_SOCKETS; i++) {
int new_cycle_time, new_latency;
int index;
int latencies;
int latency;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
+
/* First find the supported CAS latencies
* Byte 18 for DDR SDRAM is interpreted:
* bit 0 == CAS Latency = 1.0
@@ -1679,7 +1548,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
}
value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
if (value < 0) {
- continue;
+ goto hw_error;
}
/* Only increase the latency if we decreas the clock */
@@ -1699,15 +1568,6 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
if (new_latency > min_latency) {
min_latency = new_latency;
}
-#if 0
- print_debug("i: ");
- print_debug_hex8(i);
- print_debug(" min_cycle_time: ");
- print_debug_hex8(min_cycle_time);
- print_debug(" min_latency: ");
- print_debug_hex8(min_latency);
- print_debug("\r\n");
-#endif
}
/* Make a second pass through the dimms and disable
* any that cannot support the selected memclk and cas latency.
@@ -1718,9 +1578,12 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
int latency;
int index;
int value;
- int dimm;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
latencies = spd_read_byte(ctrl->channel0[i], 18);
- if (latencies <= 0) {
+ if (latencies < 0) goto hw_error;
+ if (latencies == 0) {
goto dimm_err;
}
@@ -1742,6 +1605,7 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
/* Read the min_cycle_time for this latency */
value = spd_read_byte(ctrl->channel0[i], latency_indicies[index]);
+ if (value < 0) goto hw_error;
/* All is good if the selected clock speed
* is what I need or slower.
@@ -1751,22 +1615,15 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
}
/* Otherwise I have an error, disable the dimm */
dimm_err:
- disable_dimm(ctrl, i);
+ dimm_mask = disable_dimm(ctrl, i, dimm_mask);
}
-#if 0
- print_debug("min_cycle_time: ");
- print_debug_hex8(min_cycle_time);
- print_debug(" min_latency: ");
- print_debug_hex8(min_latency);
- print_debug("\r\n");
-#endif
/* Now that I know the minimum cycle time lookup the memory parameters */
- param = get_mem_param(min_cycle_time);
+ result.param = get_mem_param(min_cycle_time);
/* Update DRAM Config High with our selected memory speed */
value = pci_read_config32(ctrl->f2, DRAM_CONFIG_HIGH);
value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT);
- value |= param->dch_memclk;
+ value |= result.param->dch_memclk;
pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, value);
static const unsigned latencies[] = { DTL_CL_2, DTL_CL_2_5, DTL_CL_3 };
@@ -1776,7 +1633,12 @@ static const struct mem_param *spd_set_memclk(const struct mem_controller *ctrl)
value |= latencies[min_latency - 2] << DTL_TCL_SHIFT;
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, value);
- return param;
+ result.dimm_mask = dimm_mask;
+ return result;
+ hw_error:
+ result.param = (const struct mem_param *)0;
+ result.dimm_mask = -1;
+ return result;
}
@@ -1795,7 +1657,7 @@ static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_p
clocks = DTL_TRC_MIN;
}
if (clocks > DTL_TRC_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
@@ -1806,7 +1668,7 @@ static int update_dimm_Trc(const struct mem_controller *ctrl, const struct mem_p
dtl &= ~(DTL_TRC_MASK << DTL_TRC_SHIFT);
dtl |= ((clocks - DTL_TRC_BASE) << DTL_TRC_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1824,7 +1686,7 @@ static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_
clocks = DTL_TRFC_MIN;
}
if (clocks > DTL_TRFC_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRFC_SHIFT) & DTL_TRFC_MASK) + DTL_TRFC_BASE;
@@ -1834,7 +1696,7 @@ static int update_dimm_Trfc(const struct mem_controller *ctrl, const struct mem_
dtl &= ~(DTL_TRFC_MASK << DTL_TRFC_SHIFT);
dtl |= ((clocks - DTL_TRFC_BASE) << DTL_TRFC_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
@@ -1845,16 +1707,12 @@ static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_
int value;
value = spd_read_byte(ctrl->channel0[i], 29);
if (value < 0) return -1;
-#if 0
clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1);
-#else
- clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
-#endif
if (clocks < DTL_TRCD_MIN) {
clocks = DTL_TRCD_MIN;
}
if (clocks > DTL_TRCD_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRCD_SHIFT) & DTL_TRCD_MASK) + DTL_TRCD_BASE;
@@ -1864,7 +1722,7 @@ static int update_dimm_Trcd(const struct mem_controller *ctrl, const struct mem_
dtl &= ~(DTL_TRCD_MASK << DTL_TRCD_SHIFT);
dtl |= ((clocks - DTL_TRCD_BASE) << DTL_TRCD_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1874,12 +1732,12 @@ static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_
int value;
value = spd_read_byte(ctrl->channel0[i], 28);
if (value < 0) return -1;
- clocks = (value + ((param->divisor & 0xff) << 1) -1)/((param->divisor & 0xff) << 1);
+ clocks = (value + (param->divisor << 1) -1)/(param->divisor << 1);
if (clocks < DTL_TRRD_MIN) {
clocks = DTL_TRRD_MIN;
}
if (clocks > DTL_TRRD_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRRD_SHIFT) & DTL_TRRD_MASK) + DTL_TRRD_BASE;
@@ -1889,7 +1747,7 @@ static int update_dimm_Trrd(const struct mem_controller *ctrl, const struct mem_
dtl &= ~(DTL_TRRD_MASK << DTL_TRRD_SHIFT);
dtl |= ((clocks - DTL_TRRD_BASE) << DTL_TRRD_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1904,7 +1762,7 @@ static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_
clocks = DTL_TRAS_MIN;
}
if (clocks > DTL_TRAS_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRAS_SHIFT) & DTL_TRAS_MASK) + DTL_TRAS_BASE;
@@ -1914,7 +1772,7 @@ static int update_dimm_Tras(const struct mem_controller *ctrl, const struct mem_
dtl &= ~(DTL_TRAS_MASK << DTL_TRAS_SHIFT);
dtl |= ((clocks - DTL_TRAS_BASE) << DTL_TRAS_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -1924,25 +1782,12 @@ static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_p
int value;
value = spd_read_byte(ctrl->channel0[i], 27);
if (value < 0) return -1;
-#if 0
clocks = (value + (param->divisor << 1) - 1)/(param->divisor << 1);
-#else
- clocks = (value + ((param->divisor & 0xff) << 1) - 1)/((param->divisor & 0xff) << 1);
-#endif
-#if 0
- print_debug("Trp: ");
- print_debug_hex8(clocks);
- print_debug(" spd value: ");
- print_debug_hex8(value);
- print_debug(" divisor: ");
- print_debug_hex8(param->divisor);
- print_debug("\r\n");
-#endif
if (clocks < DTL_TRP_MIN) {
clocks = DTL_TRP_MIN;
}
if (clocks > DTL_TRP_MAX) {
- return -1;
+ return 0;
}
dtl = pci_read_config32(ctrl->f2, DRAM_TIMING_LOW);
old_clocks = ((dtl >> DTL_TRP_SHIFT) & DTL_TRP_MASK) + DTL_TRP_BASE;
@@ -1952,7 +1797,7 @@ static int update_dimm_Trp(const struct mem_controller *ctrl, const struct mem_p
dtl &= ~(DTL_TRP_MASK << DTL_TRP_SHIFT);
dtl |= ((clocks - DTL_TRP_BASE) << DTL_TRP_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_LOW, dtl);
- return 0;
+ return 1;
}
static void set_Twr(const struct mem_controller *ctrl, const struct mem_param *param)
@@ -1998,7 +1843,7 @@ static int update_dimm_Tref(const struct mem_controller *ctrl, const struct mem_
dth &= ~(DTH_TREF_MASK << DTH_TREF_SHIFT);
dth |= (tref << DTH_TREF_SHIFT);
pci_write_config32(ctrl->f2, DRAM_TIMING_HIGH, dth);
- return 0;
+ return 1;
}
@@ -2019,7 +1864,7 @@ static int update_dimm_x4(const struct mem_controller *ctrl, const struct mem_pa
dcl |= (1 << dimm);
}
pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
- return 0;
+ return 1;
}
static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_param *param, int i)
@@ -2035,7 +1880,7 @@ static int update_dimm_ecc(const struct mem_controller *ctrl, const struct mem_p
dcl &= ~DCL_DimmEccEn;
pci_write_config32(ctrl->f2, DRAM_CONFIG_LOW, dcl);
}
- return 0;
+ return 1;
}
static int count_dimms(const struct mem_controller *ctrl)
@@ -2045,7 +1890,7 @@ static int count_dimms(const struct mem_controller *ctrl)
dimms = 0;
for(index = 0; index < 8; index += 2) {
uint32_t csbase;
- csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + index << 2));
+ csbase = pci_read_config32(ctrl->f2, (DRAM_CSBASE + (index << 2)));
if (csbase & 1) {
dimms += 1;
}
@@ -2126,7 +1971,7 @@ static void set_Trwt(const struct mem_controller *ctrl, const struct mem_param *
}
}
if ((clocks < DTH_TRWT_MIN) || (clocks > DTH_TRWT_MAX)) {
- die("Unknown Trwt");
+ die("Unknown Trwt\r\n");
}
dth = pci_read_config32(ctrl->f2, DRAM_TIMING_HIGH);
@@ -2240,7 +2085,6 @@ static void set_read_preamble(const struct mem_controller *ctrl, const struct me
static void set_max_async_latency(const struct mem_controller *ctrl, const struct mem_param *param)
{
uint32_t dch;
- int i;
unsigned async_lat;
int dimms;
@@ -2287,33 +2131,37 @@ static void set_idle_cycle_limit(const struct mem_controller *ctrl, const struct
pci_write_config32(ctrl->f2, DRAM_CONFIG_HIGH, dch);
}
-static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param)
+static long spd_set_dram_timing(const struct mem_controller *ctrl, const struct mem_param *param, long dimm_mask)
{
- int dimms;
int i;
- int rc;
init_Tref(ctrl, param);
- for(i = 0; (i < 4) && ctrl->channel0[i]; i++) {
+ for(i = 0; i < DIMM_SOCKETS; i++) {
int rc;
+ if (!(dimm_mask & (1 << i))) {
+ continue;
+ }
/* DRAM Timing Low Register */
- if (update_dimm_Trc (ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trfc(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trcd(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trrd(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Tras(ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_Trp (ctrl, param, i) < 0) goto dimm_err;
+ if ((rc = update_dimm_Trc (ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trfc(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trcd(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trrd(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Tras(ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_Trp (ctrl, param, i)) <= 0) goto dimm_err;
/* DRAM Timing High Register */
- if (update_dimm_Tref(ctrl, param, i) < 0) goto dimm_err;
+ if ((rc = update_dimm_Tref(ctrl, param, i)) <= 0) goto dimm_err;
+
/* DRAM Config Low */
- if (update_dimm_x4 (ctrl, param, i) < 0) goto dimm_err;
- if (update_dimm_ecc(ctrl, param, i) < 0) goto dimm_err;
+ if ((rc = update_dimm_x4 (ctrl, param, i)) <= 0) goto dimm_err;
+ if ((rc = update_dimm_ecc(ctrl, param, i)) <= 0) goto dimm_err;
continue;
dimm_err:
- disable_dimm(ctrl, i);
-
+ if (rc < 0) {
+ return -1;
+ }
+ dimm_mask = disable_dimm(ctrl, i, dimm_mask);
}
/* DRAM Timing Low Register */
set_Twr(ctrl, param);
@@ -2327,18 +2175,45 @@ static void spd_set_dram_timing(const struct mem_controller *ctrl, const struct
set_read_preamble(ctrl, param);
set_max_async_latency(ctrl, param);
set_idle_cycle_limit(ctrl, param);
+ return dimm_mask;
}
static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
+ struct spd_set_memclk_result result;
const struct mem_param *param;
+ long dimm_mask;
+ hw_enable_ecc(ctrl);
activate_spd_rom(ctrl);
- spd_enable_2channels(ctrl);
- spd_set_ram_size(ctrl);
- spd_handle_unbuffered_dimms(ctrl);
- param = spd_set_memclk(ctrl);
- spd_set_dram_timing(ctrl, param);
+ dimm_mask = spd_detect_dimms(ctrl);
+ if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
+ print_debug("No memory for this cpu\r\n");
+ return;
+ }
+ dimm_mask = spd_enable_2channels(ctrl, dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_set_ram_size(ctrl , dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_handle_unbuffered_dimms(ctrl, dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ result = spd_set_memclk(ctrl, dimm_mask);
+ param = result.param;
+ dimm_mask = result.dimm_mask;
+ if (dimm_mask < 0)
+ goto hw_spd_err;
+ dimm_mask = spd_set_dram_timing(ctrl, param , dimm_mask);
+ if (dimm_mask < 0)
+ goto hw_spd_err;
order_dimms(ctrl);
+ return;
+ hw_spd_err:
+ /* Unrecoverable error reading SPD data */
+ print_err("SPD error - reset\r\n");
+ hard_reset();
+ return;
}
#define TIMEOUT_LOOPS 300000
@@ -2346,29 +2221,44 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
{
int i;
+ /* Error if I don't have memory */
+ if (memory_end_k(ctrl, controllers) == 0) {
+ die("No memory\r\n");
+ }
+
/* Before enabling memory start the memory clocks */
for(i = 0; i < controllers; i++) {
uint32_t dch;
dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
- dch |= DCH_MEMCLK_VALID;
- pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch);
+ if (dch & (DCH_MEMCLK_EN0|DCH_MEMCLK_EN1|DCH_MEMCLK_EN2|DCH_MEMCLK_EN3)) {
+ dch |= DCH_MEMCLK_VALID;
+ pci_write_config32(ctrl[i].f2, DRAM_CONFIG_HIGH, dch);
+ }
+ else {
+ /* Disable dram receivers */
+ uint32_t dcl;
+ dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
+ dcl |= DCL_DisInRcvrs;
+ pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+ }
}
/* And if necessary toggle the the reset on the dimms by hand */
memreset(controllers, ctrl);
for(i = 0; i < controllers; i++) {
- uint32_t dcl;
+ uint32_t dcl, dch;
+ /* Skip everything if I don't have any memory on this controller */
+ dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
+ if (!(dch & DCH_MEMCLK_VALID)) {
+ continue;
+ }
+
/* Toggle DisDqsHys to get it working */
dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
-#if 0
- print_debug("dcl: ");
- print_debug_hex32(dcl);
- print_debug("\r\n");
-#endif
if (dcl & DCL_DimmEccEn) {
uint32_t mnc;
- print_debug("ECC enabled\r\n");
+ print_spew("ECC enabled\r\n");
mnc = pci_read_config32(ctrl[i].f3, MCA_NB_CONFIG);
mnc |= MNC_ECC_EN;
if (dcl & DCL_128BitEn) {
@@ -2387,7 +2277,13 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
}
for(i = 0; i < controllers; i++) {
- uint32_t dcl;
+ uint32_t dcl, dch;
+ /* Skip everything if I don't have any memory on this controller */
+ dch = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_HIGH);
+ if (!(dch & DCH_MEMCLK_VALID)) {
+ continue;
+ }
+
print_debug("Initializing memory: ");
int loops = 0;
do {
@@ -2399,151 +2295,98 @@ static void sdram_enable(int controllers, const struct mem_controller *ctrl)
} while(((dcl & DCL_DramInit) != 0) && (loops < TIMEOUT_LOOPS));
if (loops >= TIMEOUT_LOOPS) {
print_debug(" failed\r\n");
- } else {
- print_debug(" done\r\n");
+ continue;
}
- if (dcl & DCL_DimmEccEn) {
- print_debug("Clearing memory: ");
- if (!is_cpu_pre_c0()) {
- /* Wait until the automatic ram scrubber is finished */
- dcl &= ~(DCL_MemClrStatus | DCL_DramEnable);
- pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
- do {
- dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
- } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) );
- }
- uint32_t base, last_scrub_k, scrub_k;
- uint32_t cnt,zstart,zend;
- msr_t msr,msr_201;
-
- /* First make certain the scrubber is disabled */
- pci_write_config32(ctrl[i].f3, SCRUB_CONTROL,
- (SCRUB_NONE << 16) | (SCRUB_NONE << 8) | (SCRUB_NONE << 0));
-
- /* load the start and end for the memory block to clear */
- msr_201 = rdmsr(0x201);
- zstart = pci_read_config32(ctrl[0].f1, 0x40 + (i*8));
- zend = pci_read_config32(ctrl[0].f1, 0x44 + (i*8));
- zstart >>= 16;
- zend >>=16;
-#if 1
- print_debug("addr ");
- print_debug_hex32(zstart);
- print_debug("-");
- print_debug_hex32(zend);
- print_debug("\r\n");
-#endif
-
- /* Disable fixed mtrrs */
- msr = rdmsr(MTRRdefType_MSR);
- msr.lo &= ~(1<<10);
- wrmsr(MTRRdefType_MSR, msr);
-
- /* turn on the wrap 32 disable */
- msr = rdmsr(0xc0010015);
- msr.lo |= (1<<17);
- wrmsr(0xc0010015,msr);
-
- for(;zstart<zend;zstart+=4) {
-
- /* test for the last 64 meg of 4 gig space */
- if(zstart == 0x0fc)
- continue;
-
- /* disable cache */
- __asm__ volatile(
- "movl %%cr0, %0\n\t"
- "orl $0x40000000, %0\n\t"
- "movl %0, %%cr0\n\t"
- :"=r" (cnt)
- );
-
- /* Set the variable mtrrs to write combine */
- msr.lo = 1 + ((zstart&0x0ff)<<24);
- msr.hi = (zstart&0x0ff00)>>8;
- wrmsr(0x200,msr);
-
- /* Set the limit to 64 meg of ram */
- msr.hi = 0x000000ff;
- msr.lo = 0xfc000800;
- wrmsr(0x201,msr);
-
- /* enable cache */
- __asm__ volatile(
- "movl %%cr0, %0\n\t"
- "andl $0x9fffffff, %0\n\t"
- "movl %0, %%cr0\n\t"
- :"=r" (cnt)
- );
- /* Set fs base address */
- msr.lo = (zstart&0xff) << 24;
- msr.hi = (zstart&0xff00) >> 8;
- wrmsr(0xc0000100,msr);
-
- print_debug_char((zstart > 0x0ff)?'+':'-');
-
- /* clear memory 64meg */
- __asm__ volatile(
- "1: \n\t"
- "movl %0, %%fs:(%1)\n\t"
- "addl $4,%1\n\t"
- "subl $1,%2\n\t"
- "jnz 1b\n\t"
- :
- : "a" (0), "D" (0), "c" (0x01000000)
- );
- }
-
- /* disable cache */
- __asm__ volatile(
- "movl %%cr0, %0\n\t"
- "orl $0x40000000, %0\n\t"
- "movl %0, %%cr0\n\t"
- :"=r" (cnt)
- );
-
- /* restore msr registers */
- msr = rdmsr(MTRRdefType_MSR);
- msr.lo |= 0x0400;
- wrmsr(MTRRdefType_MSR, msr);
-
- /* Restore the variable mtrrs */
- msr.lo = 6;
- msr.hi = 0;
- wrmsr(0x200,msr);
- wrmsr(0x201,msr_201);
-
- /* Set fs base to 0 */
- msr.lo = 0;
- msr.hi = 0;
- wrmsr(0xc0000100,msr);
-
- /* enable cache */
- __asm__ volatile(
- "movl %%cr0, %0\n\t"
- "andl $0x9fffffff, %0\n\t"
- "movl %0, %%cr0\n\t"
- :"=r" (cnt)
- );
-
- /* turn off the wrap 32 disable */
- msr = rdmsr(0xc0010015);
- msr.lo &= ~(1<<17);
- wrmsr(0xc0010015,msr);
-
- /* Find the Srub base address for this cpu */
- base = pci_read_config32(ctrl[i].f1, 0x40 + (ctrl[i].node_id << 3));
- base &= 0xffff0000;
-
- /* Set the scrub base address registers */
- pci_write_config32(ctrl[i].f3, SCRUB_ADDR_LOW, base << 8);
- pci_write_config32(ctrl[i].f3, SCRUB_ADDR_HIGH, base >> 24);
-
- /* Enable scrubbing at the lowest possible rate */
- pci_write_config32(ctrl[i].f3, SCRUB_CONTROL,
- (SCRUB_84ms << 16) | (SCRUB_84ms << 8) | (SCRUB_84ms << 0));
-
- print_debug("done\r\n");
+ if (!is_cpu_pre_c0()) {
+ /* Wait until it is safe to touch memory */
+ dcl &= ~(DCL_MemClrStatus | DCL_DramEnable);
+ pci_write_config32(ctrl[i].f2, DRAM_CONFIG_LOW, dcl);
+ do {
+ dcl = pci_read_config32(ctrl[i].f2, DRAM_CONFIG_LOW);
+ } while(((dcl & DCL_MemClrStatus) == 0) || ((dcl & DCL_DramEnable) == 0) );
}
+ print_debug(" done\r\n");
}
+
+ /* Make certain the first 1M of memory is intialized */
+ msr_t msr, msr_201;
+ uint32_t cnt;
+
+ /* Save the value of msr_201 */
+ msr_201 = rdmsr(0x201);
+
+ print_debug("Clearing LinuxBIOS memory: ");
+
+ /* disable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* Disable fixed mtrrs */
+ msr = rdmsr(MTRRdefType_MSR);
+ msr.lo &= ~(1<<10);
+ wrmsr(MTRRdefType_MSR, msr);
+
+
+ /* Set the variable mtrrs to write combine */
+ msr.hi = 0;
+ msr.lo = 0 | MTRR_TYPE_WRCOMB;
+ wrmsr(0x200, msr);
+
+ /* Set the limit to 1M of ram */
+ msr.hi = 0x000000ff;
+ msr.lo = (~((CONFIG_LB_MEM_TOPK << 10) - 1)) | 0x800;
+ wrmsr(0x201, msr);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* clear memory 1meg */
+ __asm__ volatile(
+ "1: \n\t"
+ "movl %0, %%fs:(%1)\n\t"
+ "addl $4,%1\n\t"
+ "subl $4,%2\n\t"
+ "jnz 1b\n\t"
+ :
+ : "a" (0), "D" (0), "c" (1024*1024)
+ );
+
+ /* disable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "orl $0x40000000, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ /* restore msr registers */
+ msr = rdmsr(MTRRdefType_MSR);
+ msr.lo |= 0x0400;
+ wrmsr(MTRRdefType_MSR, msr);
+
+
+ /* Restore the variable mtrrs */
+ msr.hi = 0;
+ msr.lo = MTRR_TYPE_WRBACK;
+ wrmsr(0x200, msr);
+ wrmsr(0x201, msr_201);
+
+ /* enable cache */
+ __asm__ volatile(
+ "movl %%cr0, %0\n\t"
+ "andl $0x9fffffff, %0\n\t"
+ "movl %0, %%cr0\n\t"
+ :"=r" (cnt)
+ );
+
+ print_debug(" done\r\n");
}
diff --git a/src/northbridge/amd/amdk8/raminit.h b/src/northbridge/amd/amdk8/raminit.h
index 7622cb7621..157dd13ee3 100644
--- a/src/northbridge/amd/amdk8/raminit.h
+++ b/src/northbridge/amd/amdk8/raminit.h
@@ -1,11 +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[4]; //By LYH
- uint16_t channel1[4]; //By LYH
+ uint16_t channel0[DIMM_SOCKETS];
+ uint16_t channel1[DIMM_SOCKETS];
};
diff --git a/src/northbridge/amd/amdk8/raminit_test.c b/src/northbridge/amd/amdk8/raminit_test.c
new file mode 100644
index 0000000000..8e323ea859
--- /dev/null
+++ b/src/northbridge/amd/amdk8/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 "amdk8.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/amd/amdk8/reset_test.c b/src/northbridge/amd/amdk8/reset_test.c
index 9105324f33..7f4336ce5f 100644
--- a/src/northbridge/amd/amdk8/reset_test.c
+++ b/src/northbridge/amd/amdk8/reset_test.c
@@ -1,4 +1,5 @@
#include <stdint.h>
+#include <arch/smp/lapic.h>
#define NODE_ID 0x60
#define HT_INIT_CONTROL 0x6c
@@ -6,11 +7,13 @@
#define HTIC_BIOSR_Detect (1<<5)
#define HTIC_INIT_Detect (1<<6)
-
static int cpu_init_detected(void)
{
unsigned long htic;
- htic = pci_read_config32(PCI_DEV(0, 0x18, 0), HT_INIT_CONTROL);
+ device_t dev;
+
+ dev = PCI_DEV(0, 0x18 + lapicid(), 0);
+ htic = pci_read_config32(dev, HT_INIT_CONTROL);
return !!(htic & HTIC_INIT_Detect);
}
@@ -31,11 +34,11 @@ static int cold_reset_detected(void)
return !(htic & HTIC_ColdR_Detect);
}
-static void distinguish_cpu_resets(unsigned node_id)
+static void distinguish_cpu_resets(void)
{
uint32_t htic;
device_t device;
- device = PCI_DEV(0, 0x18 + node_id, 0);
+ device = PCI_DEV(0, 0x18 + lapicid(), 0);
htic = pci_read_config32(device, HT_INIT_CONTROL);
htic |= HTIC_ColdR_Detect | HTIC_BIOSR_Detect | HTIC_INIT_Detect;
pci_write_config32(device, HT_INIT_CONTROL, htic);