diff --git a/arch/x86/amd/stage0.S b/arch/x86/amd/stage0.S index 2863f3bc02..830a7936a5 100644 --- a/arch/x86/amd/stage0.S +++ b/arch/x86/amd/stage0.S @@ -178,8 +178,6 @@ __protected_stage0: /* Restore the BIST value to %eax. */ movl %ebp, %eax - /*for normal part %ebx already contain cpu_init_detected from fallback call */ - cache_as_ram_setup: movb $0xA0, %al diff --git a/arch/x86/stage1.c b/arch/x86/stage1.c index 759744ddad..89ab9d479d 100644 --- a/arch/x86/stage1.c +++ b/arch/x86/stage1.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -138,12 +139,16 @@ int legacy(struct mem_file *archive, char *name, void *where, struct lb_memory * } #endif /* CONFIG_PAYLOAD_ELF_LOADER */ -/* +/** * This function is called from assembler code with its argument on the * stack. Force the compiler to generate always correct code for this case. * We have cache as ram running and can start executing code in C. + * @param bist Built In Self Test value + * @param init_detected This (optionally set) value is used on some platforms (e.g. k8) to indicate + * that we are restarting after some sort of reconfiguration. Note that we could use it on geode but + * do not at present. */ -void __attribute__((stdcall)) stage1_main(u32 bist) +void __attribute__((stdcall)) stage1_main(u32 bist, u32 init_detected) { struct global_vars globvars; int ret; @@ -178,6 +183,8 @@ void __attribute__((stdcall)) stage1_main(u32 bist) * NEVER run this on an AP! */ global_vars_init(&globvars); + globvars.bist = bist; + globvars.init_detected = init_detected; hardware_stage1(); diff --git a/include/arch/x86/amd/k8/k8.h b/include/arch/x86/amd/k8/k8.h index 4307420f6b..10d704c28c 100644 --- a/include/arch/x86/amd/k8/k8.h +++ b/include/arch/x86/amd/k8/k8.h @@ -20,6 +20,8 @@ /* Until we resolve a better way to do this, work around it with a value "too large to fail" */ +#ifndef AMD_K8_H +#define AMD_K8_H /* Socket types */ #define SOCKET_AM2 0x11 #define SOCKET_L1 0x10 @@ -62,6 +64,7 @@ /* Definitions of various K8 registers for REV F*/ /* Function 0 */ +#define NODEID 0x60 #define HT_TRANSACTION_CONTROL 0x68 #define HTTC_DIS_RD_B_P (1 << 0) #define HTTC_DIS_RD_DW_P (1 << 1) @@ -611,7 +614,8 @@ struct node_core_id { unsigned coreid; }; -// it can be used to get unitid and coreid it running only +/* use this to get the nodeid and core it of the current cpu (but not other CPUs) */ +/* the nb_cfg_54 indicates the setting of bit 54 (InitApicIdCpuIdLo) */ struct node_core_id get_node_core_id(unsigned int nb_cfg_54); struct device; @@ -627,3 +631,5 @@ struct hw_mem_hole_info { struct hw_mem_hole_info get_hw_mem_hole_info(void); #endif /* ! ASSEMBLY */ + +#endif /* AMD_K8_H */ diff --git a/include/arch/x86/amd_geodelx.h b/include/arch/x86/amd_geodelx.h index 36e27e1329..a17c447d33 100644 --- a/include/arch/x86/amd_geodelx.h +++ b/include/arch/x86/amd_geodelx.h @@ -1258,6 +1258,18 @@ #ifndef __ASSEMBLER__ +/* This is new. + * We're not using it yet on Geode. + * K8 requires it and, for future ports, we are going to require it. + * it's a useful placeholder for platform info that usually ends up + * scattered everywhere. On K8, it is initially stored at the base of stack + * in cache-as-ram and then copied out once ram is started. + */ +struct sys_info { + int empty; +}; + + /* * Write to a Virtual Register * @param class_index The register index diff --git a/include/console.h b/include/console.h index 68d359fefc..8b5b195910 100644 --- a/include/console.h +++ b/include/console.h @@ -60,19 +60,6 @@ struct printk_buffer { }; #endif -/* - * struct global_vars is managed entirely from C code. Keep in mind that there - * is NO buffer at the end of the struct, so having zero-sized arrays at the - * end or similar stuff for which the compiler can't determine the final size - * will corrupt memory. If you don't try to be clever, everything will be fine. - */ -struct global_vars { -#ifdef CONFIG_CONSOLE_BUFFER - struct printk_buffer *printk_buffer; -#endif - unsigned int loglevel; -}; - int printk(int msg_level, const char *fmt, ...) __attribute__((format (printf, 2, 3))); EXPORT_SYMBOL(printk); void banner(int msg_level, const char *msg); diff --git a/include/globalvars.h b/include/globalvars.h new file mode 100644 index 0000000000..356be346c7 --- /dev/null +++ b/include/globalvars.h @@ -0,0 +1,51 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GLOBALVARS_H +#define GLOBALVARS_H + +/* you need to include all files that might be referenced in the global variables struct */ +#include +#include +/* the sys_info struct is architecture-dependent, with parameters controlled from mainboard.h in some cases */ +#ifdef CONFIG_CPU_AMD_K8 +#include +#include +#include +#endif + +#ifdef CONFIG_CPU_AMD_GEODELX +#include +#endif + +/* + * struct global_vars is managed entirely from C code. Keep in mind that there + * is NO buffer at the end of the struct, so having zero-sized arrays at the + * end or similar stuff for which the compiler can't determine the final size + * will corrupt memory. If you don't try to be clever, everything will be fine. + */ +struct global_vars { +#ifdef CONFIG_CONSOLE_BUFFER + struct printk_buffer *printk_buffer; +#endif + unsigned int loglevel; + /* these two values are of interest in many stages */ + u32 bist; + u32 init_detected; + struct sys_info sys_info; +}; + +#endif /* GLOBALVARS_H */ diff --git a/mainboard/amd/Kconfig b/mainboard/amd/Kconfig index 81e9b70ef1..cde0ae71a8 100644 --- a/mainboard/amd/Kconfig +++ b/mainboard/amd/Kconfig @@ -53,6 +53,7 @@ config BOARD_AMD_SERENGETI select CPU_AMD_K8 select NORTHBRIDGE_AMD_K8 select SOUTHBRIDGE_AMD_AMD8111 + select SUPERIO_WINBOND_W83627HF select IOAPIC help AMD Serengeti diff --git a/mainboard/amd/serengeti/dts b/mainboard/amd/serengeti/dts index f1425f9c4f..23f1a81936 100644 --- a/mainboard/amd/serengeti/dts +++ b/mainboard/amd/serengeti/dts @@ -40,5 +40,9 @@ /config/("southbridge/amd/amd8111/nic.dts"); }; }; + ioport@2e { + /config/("superio/winbond/w83627hf/dts"); + com1enable = "1"; + }; }; }; diff --git a/mainboard/amd/serengeti/initram.c b/mainboard/amd/serengeti/initram.c index 9a15b66937..fbed95419c 100644 --- a/mainboard/amd/serengeti/initram.c +++ b/mainboard/amd/serengeti/initram.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,20 @@ #include #include +#define RC0 ((1<<0)<<8) +#define RC1 ((1<<1)<<8) +#define RC2 ((1<<2)<<8) +#define RC3 ((1<<3)<<8) + +#define DIMM0 0x50 +#define DIMM1 0x51 +#define DIMM2 0x52 +#define DIMM3 0x53 +#define DIMM4 0x54 +#define DIMM5 0x55 +#define DIMM6 0x56 +#define DIMM7 0x57 + # warning fix hard_reset void hard_reset(void) { @@ -49,17 +64,203 @@ void memreset(int controllers, const struct mem_controller *ctrl) void activate_spd_rom(const struct mem_controller *ctrl) { - /* nothing to do */ +#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)); + + smbus_write_byte(SMBUS_HUB, 0x03, 0); +} + +u8 spd_read_byte(u16 device, u8 address) +{ + int smbus_read_byte(u16 device, u16 address); + return smbus_read_byte(device, address); } /** - * main for initram for the Gigabyte m57sli. + * main for initram for the AMD Serengeti + * @param bist Built In Self Test, which is used to indicate status of self test + * @param init_detected Used to indicate that we have been started via init + * @returns 0 on success + * The purpose of this code is to not only get ram going, but get any other cpus/cores going. + * The two activities are very tightly connected and not really seperable. + * The BSP (boot strap processor? ) Core 0 is responsible for all training or all sockets. Note that + * this need not be socket 0; one great strength of coreboot, as opposed to other BIOSes, is that it could + * always boot with with a CPU in any socket, and even with empty sockets (as opposed to, e.g., the BIOS + * that came installed on the Sun Ultra 40, which would freeze if one CPU were not installed). + * The bringup proceeds in several sections. The cool part is that this code is run by all CPUs, and + * control flow is managed by seeing which CPU we are -- BSP or AP? + * */ +/* + * bist is defined by the CPU hardware and is present in EAX on first instruction of coreboot. + * Its value is implementation defined. + * + * init_detected is used to determine if we did a soft reset as required by a reprogramming of the + * hypertransport links. If we did this kind of reset, bit 11 will be set in the MTRRdefType_MSR MSR. + * That may seem crazy, but there are not lots of places to hide a bit when the CPU does a reset. + * This value is picked up in assembly, or it should be. + */ int main(void) { + void enable_smbus(void); + u32 bist, u32 init_detected; + static const u16 spd_addr[] = { + //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, +#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, +#endif + + }; + + struct sys_info *sysinfo; + int needs_reset; int i; + unsigned bsp_apicid = 0; printk(BIOS_DEBUG, "Hi there from stage1\n"); post_code(POST_START_OF_MAIN); + sysinfo = &(global_vars()->sys_info); + + bist = sysinfo->bist; + init_detected = sysinfo->init_detected; + /* We start out by looking at bist. Where was bist set? */ + /* well, here we are. For starters, we need to know if this is cpu0 core0. + * cpu0 core 0 will do all the DRAM setup. + */ + if (bist) { + printk(BIOS_EMERG, "Bist 0x%x\n", bist); + die("bist failure"); + } else + bsp_apicid = init_cpus(init_detected, sysinfo); + +// 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, 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 +#endif + 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 + /* 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_other_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 + +#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); +#endif + +#if K8_SET_FIDVID == 1 + + { + msr_t msr; + msr=rdmsr(0xc0010042); + print_debug("begin msr fid, vid "); print_debug_hex32( msr.hi ); print_debug_hex32(msr.lo); print_debug("\r\n"); + + } + + enable_fid_change(); + + enable_fid_change_on_sb(sysinfo->sbbusn, sysinfo->sbdn); + + init_fidvid_bsp(bsp_apicid); + + // show final fid and vid + { + msr_t msr; + msr=rdmsr(0xc0010042); + print_debug("end msr fid, vid "); print_debug_hex32( msr.hi ); print_debug_hex32(msr.lo); print_debug("\r\n"); + + } +#endif + +#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) { + print_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; + 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? */ +// init_timer(); // Need to use TMICT to synconize FID/VID + + sdram_initialize(sysinfo->nodes, sysinfo->ctrl, sysinfo); + +#if 0 + 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, 0x19, 2), 0x98); +#endif + + post_cache_as_ram(); // bsp swtich stack to ram and copy sysinfo ram now + +1 printk(BIOS_DEBUG, "stage1 returns\n"); return 0; diff --git a/mainboard/amd/serengeti/stage1.c b/mainboard/amd/serengeti/stage1.c index d8bcfdd40f..ad6658bf57 100644 --- a/mainboard/amd/serengeti/stage1.c +++ b/mainboard/amd/serengeti/stage1.c @@ -25,14 +25,14 @@ #include #include #include -#include -#include #include #include #include #include #include - +#include +#include +#include static const struct rmap register_values[] = { /* Careful set limit registers before base registers which contain the enables */ @@ -289,8 +289,12 @@ static const struct rmap register_values[] = { void amd8111_enable_rom(void); +#define SERIAL_DEV W83627HF_SP1 +#define SERIAL_IOBASE 0x3f8 + void hardware_stage1(void) { + void w83627hf_enable_serial(u8 dev, u8 serial, u16 iobase); void enumerate_ht_chain(void); int max; printk(BIOS_ERR, "Stage1: enable rom ...\n"); @@ -299,6 +303,7 @@ void hardware_stage1(void) enumerate_ht_chain(); amd8111_enable_rom(); printk(BIOS_ERR, "Done.\n"); + w83627hf_enable_serial(0x2e, SERIAL_DEV, SERIAL_IOBASE); post_code(POST_START_OF_MAIN); } diff --git a/northbridge/amd/k8/coherent_ht.c b/northbridge/amd/k8/coherent_ht.c index e0ce04ee6f..13196c001c 100644 --- a/northbridge/amd/k8/coherent_ht.c +++ b/northbridge/amd/k8/coherent_ht.c @@ -1689,9 +1689,15 @@ int optimize_link_read_pointers(unsigned nodes) return needs_reset; } -inline unsigned get_nodes(void) +/** + * get_nodes + * see page 46 of the BKDG Publication # 26094 Revision: 3.30 Issue Date: February 2006 + * @returns an int containing the node id. + * The format of the register is 32 bits, and the node count is in bits 4-6 + */ +unsigned int get_nodes(void) { - return ((pci_conf1_read_config32(PCI_BDF(0, 0x18, 0), 0x60)>>4) & 7) + 1; + return ((pci_conf1_read_config32(PCI_BDF(0, 0x18, 0), NODEID)>>4) & 7) + 1; } int optimize_link_coherent_ht(void) diff --git a/northbridge/amd/k8/dqs.c b/northbridge/amd/k8/dqs.c index fadacbb41f..36e2e7f4b6 100644 --- a/northbridge/amd/k8/dqs.c +++ b/northbridge/amd/k8/dqs.c @@ -27,12 +27,12 @@ #include #include #include -#include -#include #include #include #include #include +#include +#include #include /* diff --git a/northbridge/amd/k8/incoherent_ht.c b/northbridge/amd/k8/incoherent_ht.c index a32f97ca30..3b7893efd8 100644 --- a/northbridge/amd/k8/incoherent_ht.c +++ b/northbridge/amd/k8/incoherent_ht.c @@ -756,7 +756,7 @@ static void ht_setup_chains(u8 ht_c_num, struct sys_info *sysinfo) } -unsigned get_nodes(void); +unsigned int get_nodes(void); void ht_setup_chains_x(struct sys_info *sysinfo) {