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