summaryrefslogtreecommitdiff
path: root/src/northbridge
diff options
context:
space:
mode:
authorEric Biederman <ebiederm@xmission.com>2004-03-11 15:01:31 +0000
committerEric Biederman <ebiederm@xmission.com>2004-03-11 15:01:31 +0000
commit5cd81730ecef18690f92d193b0381c103a5b3d9b (patch)
treef4d2755177561691661f8d945081df67bcc9cd1a /src/northbridge
parentf31d5542f6e193595da0f66aea68602910984861 (diff)
- Moved hlt() to it's own header.
- Reworked pnp superio device support. Now complete superio support is less than 100 lines. - Added support for hard coding resource assignments in Config.lb - Minor bug fixes to romcc - Initial support for catching the x86 processor BIST error codes. I've only seen this trigger once in production during a very suspcious reset but... - added raminit_test to test the code paths in raminit.c for the Opteron - Removed the IORESOURCE_SET bit and added IORESOURCE_ASSIGNED and IORESOURCE_STORED so we can tell what we have really done. - Added generic AGP/IOMMU setting code to x86 - Added an implementation of memmove and removed reserved identifiers from memcpy - Added minimal support for booting on pre b3 stepping K8 cores - Moved the checksum on amd8111 boards because our default location was on top of extended RTC registers - On the Hdama added support for enabling i2c hub so we can get at the temperature sensors. Not that i2c bus was implemented well enough to make that useful. - Redid the Opteron port so we should only need one reset and most of memory initialization is done in cpu_fixup. This is much, much faster. - Attempted to make the VGA IO region assigment work. The code seems to work now... - Redid the error handling in amdk8/raminit.c to distinguish between a bad value and a smbus error, and moved memory clearing out to cpufixup. - Removed CONFIG_KEYBOARD as it was useless. See pc87360/superio.c for how to setup a legacy keyboard properly. - Reworked the register values for standard hardware, moving the defintions from chip.h into the headers of the initialization routines. This is much saner and is actually implemented. - Made the hdama port an under clockers BIOS. I debuged so many interesting problems. - On amd8111_lpc added setup of architectural/legacy hardware - Enabled PCI error reporting as much as possible. - Enhanded build_opt_tbl to generate a header of the cmos option locations so that romcc compiled code can query the cmos options. - In romcc gracefully handle function names that degenerate into function pointers - Bumped the version to 1.1.6 as we are getting closer to 2.0 TODO finish optimizing the HT links of non dual boards TODO make all Opteron board work again TODO convert all superio devices to use the new helpers TODO convert the via/epia to freebios2 conventions TODO cpu fixup/setup by cpu type git-svn-id: svn://svn.coreboot.org/coreboot/trunk@1390 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge')
-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);