diff --git a/arch/x86/amd/k8/stage1.c b/arch/x86/amd/k8/stage1.c index 93b04d856f..c729de262f 100644 --- a/arch/x86/amd/k8/stage1.c +++ b/arch/x86/amd/k8/stage1.c @@ -27,6 +27,16 @@ #include #include +/** + * Set the MTRR for initial ram access. + * be warned, this will be used by core other than core 0/node 0 or core0/node0 when cpu_reset. + * This warning has some significance I don't yet understand. + */ +void set_init_ram_access(void) +{ + set_var_mtrr(0, 0x00000000, CONFIG_CBMEMK << 10, MTRR_TYPE_WRBACK); +} + /** * Disable Cache As RAM (CAR) after memory is setup. * @@ -60,5 +70,7 @@ void disable_car(void) [carsizequads] "i" (CONFIG_CARSIZE/4) : "memory", "%edi", "%esi", "%ecx"); banner(BIOS_DEBUG, "Disable_car: done wbinvd"); + /* we're now running in ram. Although this will be called again, it does no harm to call it here. */ + set_init_ram_access(); banner(BIOS_DEBUG, "disable_car: done"); } diff --git a/arch/x86/amd/model_fxx/init_cpus.c b/arch/x86/amd/model_fxx/init_cpus.c index 2e5e443373..81489372df 100644 --- a/arch/x86/amd/model_fxx/init_cpus.c +++ b/arch/x86/amd/model_fxx/init_cpus.c @@ -246,11 +246,33 @@ void wait_ap_started(unsigned ap_apicid, void *gp) } } +/** + * disable cache as ram on a BSP. + * For reasons not totally known we are saving ecx and edx. + * That will work on k8 as we copy the stack and return in the same stack frame. + */ +void disable_cache_as_ram_bsp(void) +{ + __asm__ volatile ( +// "pushl %eax\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + ); + + disable_cache_as_ram(); + __asm__ volatile ( + "popl %ecx\n\t" + "popl %edx\n\t" +// "popl %eax\n\t" + ); +} + + /** * wait for all apics to start. Make sure we don't wait on ourself. * @param bsp_apicid The BSP APIC ID */ -static void wait_all_aps_started(unsigned bsp_apicid) +void wait_all_aps_started(unsigned bsp_apicid) { for_each_ap(bsp_apicid, 0, wait_ap_started, (void *) 0); } diff --git a/include/arch/x86/amd/k8/k8.h b/include/arch/x86/amd/k8/k8.h index f4c8a7be79..47e33702dd 100644 --- a/include/arch/x86/amd/k8/k8.h +++ b/include/arch/x86/amd/k8/k8.h @@ -743,22 +743,7 @@ static inline __attribute__((always_inline)) void disable_cache_as_ram(void) ); } -static void disable_cache_as_ram_bsp(void) -{ - __asm__ volatile ( -// "pushl %eax\n\t" - "pushl %edx\n\t" - "pushl %ecx\n\t" - ); - - disable_cache_as_ram(); - __asm__ volatile ( - "popl %ecx\n\t" - "popl %edx\n\t" -// "popl %eax\n\t" - ); -} - +void disable_cache_as_ram_bsp(void); #endif /* ! ASSEMBLY */ diff --git a/include/arch/x86/cpu.h b/include/arch/x86/cpu.h index 1747e97800..34672e2612 100644 --- a/include/arch/x86/cpu.h +++ b/include/arch/x86/cpu.h @@ -243,13 +243,7 @@ static inline void clear_init_ram(void) } -/* be warned, this file will be used by core other than core 0/node 0 or core0/node0 when cpu_reset*/ -static void set_init_ram_access(void) -{ - set_var_mtrr(0, 0x00000000, CONFIG_CBMEMK << 10, MTRR_TYPE_WRBACK); -} - - +void set_init_ram_access(void); void * bottom_of_stack(void); EXPORT_SYMBOL(bottom_of_stack); diff --git a/mainboard/amd/serengeti/Makefile b/mainboard/amd/serengeti/Makefile index d038491699..85b8083bbd 100644 --- a/mainboard/amd/serengeti/Makefile +++ b/mainboard/amd/serengeti/Makefile @@ -23,6 +23,7 @@ STAGE0_MAINBOARD_SRC := $(src)/lib/clog2.c \ $(src)/mainboard/$(MAINBOARDDIR)/stage1.c \ $(src)/mainboard/$(MAINBOARDDIR)/option_table.c \ + $(src)/arch/x86/stage1_mtrr.c \ $(src)/southbridge/amd/amd8111/stage1_smbus.c \ $(src)/southbridge/amd/amd8111/stage1_ctrl.c \ $(src)/southbridge/amd/amd8111/stage1_enable_rom.c \ diff --git a/mainboard/amd/serengeti/initram.c b/mainboard/amd/serengeti/initram.c index 5ff6ccaa9f..47a5b19d5a 100644 --- a/mainboard/amd/serengeti/initram.c +++ b/mainboard/amd/serengeti/initram.c @@ -51,14 +51,21 @@ #define DIMM6 0x56 #define DIMM7 0x57 -# warning fix hard_reset -void hard_reset(void) -{ -} -void memreset_setup(void) +/* this code is very mainboard dependent, sadly. */ +/** + * call the amd 8111 memreset_setup_amd8111 function to jam the GPIOs to reset memory. + */ +static void memreset_setup(void) { + void memreset_setup_amd8111(u8 data, u16 offset); + //GPIO on amd8111 to enable MEMRST ???? + memreset_setup_amd8111((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(1<<0), 0xc0 + 16); //REVC_MEMRST_EN=1 + memreset_setup_amd8111((0 << 7)|(0 << 6)|(0<<5)|(0<<4)|(1<<2)|(0<<0), 0xc0 + 17); } +/** + * this is a no op on this platform. + */ void memreset(int controllers, const struct mem_controller *ctrl) { } @@ -66,25 +73,30 @@ void memreset(int controllers, const struct mem_controller *ctrl) void activate_spd_rom(const struct mem_controller *ctrl) { #define SMBUS_HUB 0x18 - int smbus_write_byte(u16 device, u16 address, u8 val); - int ret,i; - u16 device=(ctrl->channel0[0])>>8; - /* the very first write always get COL_STS=1 and ABRT_STS=1, so try another time*/ - i=2; - do { - ret = smbus_write_byte(SMBUS_HUB, 0x01, device); - } while ((ret!=0) && (i-->0)); + int smbus_write_byte(u16 device, u16 address, u8 val); + int ret, i; + u16 device = (ctrl->channel0[0]) >> 8; + /* the very first write always get COL_STS=1 and ABRT_STS=1, so try another time */ + i = 2; + do { + ret = smbus_write_byte(SMBUS_HUB, 0x01, device); + } while ((ret != 0) && (i-- > 0)); - smbus_write_byte(SMBUS_HUB, 0x03, 0); + smbus_write_byte(SMBUS_HUB, 0x03, 0); } +/** + * read a byte from spd. + * @param device device to read from + * @param address address in the spd ROM + * @return the value of the byte at that address. + */ u8 spd_read_byte(u16 device, u8 address) { int smbus_read_byte(u16 device, u16 address); - return smbus_read_byte(device, address); + return smbus_read_byte(device, address); } - /** * main for initram for the AMD Serengeti * @param init_detected Used to indicate that we have been started via init @@ -113,30 +125,33 @@ int main(void) */ void enable_smbus(void); void enable_fid_change_on_sb(u16 sbbusn, u16 sbdn); + void soft_reset_x(unsigned sbbusn, unsigned sbdn); u32 init_detected; static const u16 spd_addr[] = { - //first node - RC0|DIMM0, RC0|DIMM2, 0, 0, - RC0|DIMM1, RC0|DIMM3, 0, 0, + //first node + RC0 | DIMM0, RC0 | DIMM2, 0, 0, + RC0 | DIMM1, RC0 | DIMM3, 0, 0, #if CONFIG_MAX_PHYSICAL_CPUS > 1 - //second node - RC1|DIMM0, RC1|DIMM2, RC1|DIMM4, RC1|DIMM6, - RC1|DIMM1, RC1|DIMM3, RC1|DIMM5, RC1|DIMM7, + //second node + RC1 | DIMM0, RC1 | DIMM2, RC1 | DIMM4, RC1 | DIMM6, + RC1 | DIMM1, RC1 | DIMM3, RC1 | DIMM5, RC1 | DIMM7, #endif #if CONFIG_MAX_PHYSICAL_CPUS > 2 - // third node - RC2|DIMM0, RC2|DIMM2, 0, 0, - RC2|DIMM1, RC2|DIMM3, 0, 0, - // four node - RC3|DIMM0, RC3|DIMM2, RC3|DIMM4, RC3|DIMM6, - RC3|DIMM1, RC3|DIMM3, RC3|DIMM5, RC3|DIMM7, + // third node + RC2 | DIMM0, RC2 | DIMM2, 0, 0, + RC2 | DIMM1, RC2 | DIMM3, 0, 0, + // four node + RC3 | DIMM0, RC3 | DIMM2, RC3 | DIMM4, RC3 | DIMM6, + RC3 | DIMM1, RC3 | DIMM3, RC3 | DIMM5, RC3 | DIMM7, #endif }; struct sys_info *sysinfo; - int needs_reset; int i; - unsigned bsp_apicid = 0; + int needs_reset; + unsigned bsp_apicid = 0; + struct msr msr; + printk(BIOS_DEBUG, "Hi there from stage1\n"); post_code(POST_START_OF_MAIN); sysinfo = &(global_vars()->sys_info); @@ -146,116 +161,91 @@ int main(void) */ bsp_apicid = init_cpus(init_detected, sysinfo); -// dump_mem(DCACHE_RAM_BASE+DCACHE_RAM_SIZE-0x200, DCACHE_RAM_BASE+DCACHE_RAM_SIZE); +// dump_mem(DCACHE_RAM_BASE+DCACHE_RAM_SIZE-0x200, DCACHE_RAM_BASE+DCACHE_RAM_SIZE); #if 0 - dump_pci_device(PCI_DEV(0, 0x18, 0)); + dump_pci_device(PCI_DEV(0, 0x18, 0)); dump_pci_device(PCI_DEV(0, 0x19, 0)); #endif printk(BIOS_DEBUG, "bsp_apicid=%02x\n", bsp_apicid); #if MEM_TRAIN_SEQ == 1 - set_sysinfo_in_ram(0); // in BSP so could hold all ap until sysinfo is in ram + set_sysinfo_in_ram(0); // in BSP so could hold all ap until sysinfo is in ram #endif - setup_coherent_ht_domain(); // routing table and start other core0 + setup_coherent_ht_domain(); // routing table and start other core0 wait_all_core0_started(); #if CONFIG_LOGICAL_CPUS==1 - // It is said that we should start core1 after all core0 launched + // It is said that we should start core1 after all core0 launched /* becase optimize_link_coherent_ht is moved out from setup_coherent_ht_domain, * So here need to make sure last core0 is started, esp for two way system, * (there may be apic id conflicts in that case) */ - start_all_cores(); + start_all_cores(); wait_all_other_cores_started(bsp_apicid); #endif - + /* it will set up chains and store link pair for optimization later */ - ht_setup_chains_x(sysinfo); // it will init sblnk and sbbusn, nodes, sbdn + ht_setup_chains_x(sysinfo); // it will init sblnk and sbbusn, nodes, sbdn #if 0 //it your CPU min fid is 1G, you can change HT to 1G and FID to max one time. - needs_reset = optimize_link_coherent_ht(); - needs_reset |= optimize_link_incoherent_ht(sysinfo); + needs_reset = optimize_link_coherent_ht(); + needs_reset |= optimize_link_incoherent_ht(sysinfo); #endif -#if K8_SET_FIDVID == 1 - - { - struct msr msr; - msr=rdmsr(FIDVID_STATUS); - printk(BIOS_DEBUG, "begin msr fid, vid %08x:%08x\n", msr.hi ,msr.lo); - - } + msr = rdmsr(FIDVID_STATUS); + printk(BIOS_DEBUG, "begin msr fid, vid %08x:%08x\n", + msr.hi, msr.lo); enable_fid_change(); enable_fid_change_on_sb(sysinfo->sbbusn, sysinfo->sbdn); - init_fidvid_bsp(bsp_apicid); + init_fidvid_bsp(bsp_apicid); - // show final fid and vid - { - struct msr msr; - msr=rdmsr(FIDVID_STATUS); - printk(BIOS_DEBUG, "begin msr fid, vid %08x:%08x\n", msr.hi ,msr.lo); - - } -#endif + msr = rdmsr(FIDVID_STATUS); + printk(BIOS_DEBUG, "begin msr fid, vid %08x:%08x\n", + msr.hi, msr.lo); #if 1 needs_reset = optimize_link_coherent_ht(); needs_reset |= optimize_link_incoherent_ht(sysinfo); - // fidvid change will issue one LDTSTOP and the HT change will be effective too - if (needs_reset) { - printk(BIOS_INFO, "ht reset -\r\n"); -#warning define soft_reset_x -//FIXME soft_reset_x(sysinfo->sbbusn, sysinfo->sbdn); - } + // fidvid change will issue one LDTSTOP and the HT change will be effective too + if (needs_reset) { + printk(BIOS_INFO, "ht reset -\r\n"); + soft_reset_x(sysinfo->sbbusn, sysinfo->sbdn); + } #endif allow_all_aps_stop(bsp_apicid); - //It's the time to set ctrl in sysinfo now; + //It's the time to set ctrl in sysinfo now; fill_mem_ctrl(sysinfo->nodes, sysinfo->ctrl, spd_addr); enable_smbus(); -#if 0 - for(i=0;i<4;i++) { - activate_spd_rom(&cpu[i]); - dump_smbus_registers(); - } -#endif - -#if 0 - for(i=1;i<256;i<<=1) { - change_i2c_mux(i); - dump_smbus_registers(); - } -#endif - memreset_setup(); //do we need apci timer, tsc...., only debug need it for better output - /* all ap stopped? */ + /* all ap stopped? */ // init_timer(); // Need to use TMICT to synconize FID/VID sdram_initialize(sysinfo->nodes, sysinfo->ctrl, sysinfo); #if 0 - print_pci_devices(); + print_pci_devices(); #endif #if 0 // dump_pci_devices(); - dump_pci_device_index_wait(PCI_DEV(0, 0x18, 2), 0x98); + dump_pci_device_index_wait(PCI_DEV(0, 0x18, 2), 0x98); dump_pci_device_index_wait(PCI_DEV(0, 0x19, 2), 0x98); #endif #warning re-implement post_cache_as_ram - // post_cache_as_ram(); // bsp swtich stack to ram and copy sysinfo ram now + // post_cache_as_ram(); // bsp switch stack to ram and copy sysinfo ram now printk(BIOS_DEBUG, "stage1 returns\n"); return 0; diff --git a/mainboard/amd/serengeti/mainboard.h b/mainboard/amd/serengeti/mainboard.h index 7f790e71c1..50a5e17d6e 100644 --- a/mainboard/amd/serengeti/mainboard.h +++ b/mainboard/amd/serengeti/mainboard.h @@ -33,12 +33,6 @@ #define SB_HT_CHAIN_UNITID_OFFSET_ONLY 1 #define ENABLE_APIC_EXT_ID 0 #define LIFT_BSP_APIC_ID 1 -#warning clean up confusion on FIDVID. v2 was inconsistent. -/* In v2 there is confusion on the settings of these. - * The serengeti config sets it to zero. - * In the model_fxx support it is hardwired to 1. - * We'll assume that setting it to 1 is ok. - */ #define K8_SET_FIDVID 1 /* MSR FIDVID_CTL and FIDVID_STATUS are shared by cores, * so may don't need to do twice */ diff --git a/southbridge/amd/amd8111/stage1_reset.c b/southbridge/amd/amd8111/stage1_reset.c index 31b3f89fe8..cfb4a1955a 100644 --- a/southbridge/amd/amd8111/stage1_reset.c +++ b/southbridge/amd/amd8111/stage1_reset.c @@ -30,7 +30,10 @@ void hard_reset(void) { - u32 dev; + void set_bios_reset(void); + unsigned get_sblk(void); + u8 node_link_to_bus(unsigned int node, unsigned int link); + u32 busdevfn; unsigned int bus; unsigned int node = 0; unsigned int link = get_sblk(); @@ -39,9 +42,9 @@ void hard_reset(void) * There can only be one 8111 on a hypertransport chain/bus. */ bus = node_link_to_bus(node, link); - pci_locate_device_on_bus(0, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_ISA, &dev); + pci_conf1_find_on_bus(0, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_ISA, &busdevfn); /* Reset */ set_bios_reset(); - pci_write_config8(dev, 0x47, 1); + pci_conf1_write_config8(busdevfn, 0x47, 1); } diff --git a/southbridge/amd/amd8111/stage1_smbus.c b/southbridge/amd/amd8111/stage1_smbus.c index d7f969bcfb..ba4cac22ec 100644 --- a/southbridge/amd/amd8111/stage1_smbus.c +++ b/southbridge/amd/amd8111/stage1_smbus.c @@ -305,3 +305,17 @@ u8 spd_read_byte(u16 device, u8 address) return smbus_read_byte(device, address); } +/** + * memreset_setup_amd8111 + * This function is part of a complex dance played between the mainboard and + * the southbridge. We don't want to export SMBUS_IO_BASE, but neither can the + * amd8111 know about what GPIOs connect to what reset lines. So + * we split the difference. The mainboard must call this function with bytes + * to be output to accomplish reset, as well as the offset from IOBASE; + * amd8111 will output those bytes to SMBIOS_IOBASE. + * The caller of this function must have called spd_init for it to work correctly. + */ +void memreset_setup_amd8111(u8 data, u16 offset) +{ + outb(data, SMBUS_IO_BASE + offset); +}