diff options
Diffstat (limited to 'src/northbridge/amd')
-rw-r--r-- | src/northbridge/amd/amdk8/Config.lb | 7 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/amdk8.h | 12 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/coherent_ht.c | 469 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/cpu_rev.c | 7 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/early_ht.c | 3 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/incoherent_ht.c | 244 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/misc_control.c | 198 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/northbridge.c | 86 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/raminit.c | 907 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/raminit.h | 5 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/raminit_test.c | 442 | ||||
-rw-r--r-- | src/northbridge/amd/amdk8/reset_test.c | 11 |
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); |