Author: stepan Date: 2007-06-27 23:07:10 +0200 (Wed, 27 Jun 2007) New Revision: 387
Added: LinuxBIOSv3/arch/x86/geodelx/geodelx.c LinuxBIOSv3/arch/x86/geodelx/stage0.S Removed: LinuxBIOSv3/arch/x86/geodelx.c LinuxBIOSv3/arch/x86/stage0_amd_geodelx.S Modified: LinuxBIOSv3/arch/x86/Makefile Log: make cpu code future proof
Signed-off-by: Stefan Reinauer stepan@coresystems.de Acked-by: Ronald G. Minnich rminnich@gmail.com
Modified: LinuxBIOSv3/arch/x86/Makefile =================================================================== --- LinuxBIOSv3/arch/x86/Makefile 2007-06-27 21:01:01 UTC (rev 386) +++ LinuxBIOSv3/arch/x86/Makefile 2007-06-27 21:07:10 UTC (rev 387) @@ -83,7 +83,7 @@ STAGE0_CAR_OBJ = stage0_i586.o else ifeq ($(CONFIG_CPU_AMD_GEODELX),y) - STAGE0_CAR_OBJ = stage0_amd_geodelx.o + STAGE0_CAR_OBJ = geodelx/stage0.o else STAGE0_CAR_OBJ = stage0_i586.o endif @@ -181,4 +181,13 @@ $(Q)printf " AS $(subst $(shell pwd)/,,$(@))\n" $(Q)$(AS) $(obj)/arch/x86/stage0_asm.s -o $@
+$(obj)/arch/x86/geodelx/stage0.o: $(src)/arch/x86/geodelx/stage0.S + $(Q)mkdir -p $(obj)/arch/x86/geodelx + $(Q)printf " CC $(subst $(shell pwd)/,,$(@))\n" + $(Q)$(CC) -E $(LINUXBIOSINCLUDE) $< \ + -o $(obj)/arch/x86/stage0_asm.s -DBOOTBLK=0x1f00 \ + -DRESRVED=0xf0 -DDATE="`date +%Y/%m/%d`" + $(Q)printf " AS $(subst $(shell pwd)/,,$(@))\n" + $(Q)$(AS) $(obj)/arch/x86/stage0_asm.s -o $@ + endif
Copied: LinuxBIOSv3/arch/x86/geodelx/geodelx.c (from rev 386, LinuxBIOSv3/arch/x86/geodelx.c) =================================================================== --- LinuxBIOSv3/arch/x86/geodelx/geodelx.c (rev 0) +++ LinuxBIOSv3/arch/x86/geodelx/geodelx.c 2007-06-27 21:07:10 UTC (rev 387) @@ -0,0 +1,580 @@ +/* + * This file is part of the LinuxBIOS project. + * + * Copyright (C) 2006 Indrek Kruusa indrek.kruusa@artecdesign.ee + * Copyright (C) 2006 Ronald G. Minnich rminnich@gmail.com + * Copyright (C) 2007 Advanced Micro Devices, Inc. + * + * 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 + */ +#include <types.h> +#include <lib.h> +#include <console.h> +#include <device/device.h> +#include <device/pci.h> +#include <string.h> +#include <msr.h> +#include <io.h> +#include <amd_geodelx.h> +#include <spd.h> + +/* all these functions used to be in a lot of fiddly little files. To + * make it easier to find functions, we are merging them here. This + * file is our first real cpu-specific support file and should serve + * as a model for v3 cpu-specific support. So, warning, you might + * think it makes sense to split this file up, but we've tried that, + * and it sucks. + */ + +/** + * geodelx_msr_init Set up Geode LX registers for sane behaviour. Set + * all low memory (under 1MB) to write back. Do some setup for cache + * as ram as well. + */ +void geodelx_msr_init(void) +{ + msr_t msr; + /* Setup access to the cache for under 1MB. */ + msr.hi = 0x24fffc02; + msr.lo = 0x1000A000; /* 0-A0000 write back */ + wrmsr(CPU_RCONF_DEFAULT, msr); + + msr.hi = 0x0; /* write back */ + msr.lo = 0x0; + wrmsr(CPU_RCONF_A0_BF, msr); + wrmsr(CPU_RCONF_C0_DF, msr); + wrmsr(CPU_RCONF_E0_FF, msr); + + /* Setup access to the cache for under 640K. Note MC not setup yet. */ + msr.hi = 0x20000000; + msr.lo = 0xfff80; + wrmsr(MSR_GLIU0 + 0x20, msr); + + msr.hi = 0x20000000; + msr.lo = 0x80fffe0; + wrmsr(MSR_GLIU0 + 0x21, msr); + + msr.hi = 0x20000000; + msr.lo = 0xfff80; + wrmsr(MSR_GLIU1 + 0x20, msr); + + msr.hi = 0x20000000; + msr.lo = 0x80fffe0; + wrmsr(MSR_GLIU1 + 0x21, msr); + +} + + +/** + * start_time1 Starts Timer 1 for port 61 use. FIXME try to figure + * out what these values mean. + */ +void start_timer1(void) +{ + outb(0x56, 0x43); + outb(0x12, 0x41); +} + +/** + * system_preinit Very early initialization needed for almost + * everything else. Currently, all we do is start timer1. + */ +void system_preinit(void) +{ + start_timer1(); +} + +/* cpu bug management */ +/** + * + * pci_deadlock Bugtool #465 and #609 PCI cache deadlock There is + * also fix code in cache and PCI functions. This bug is very is + * pervasive. + * + */ +static void pci_deadlock(void) +{ + msr_t msr; + + /* + * forces serialization of all load misses. Setting this bit prevents the + * DM pipe from backing up if a read request has to be held up waiting + * for PCI writes to complete. + */ + msr = rdmsr(CPU_DM_CONFIG0); + msr.lo |= DM_CONFIG0_LOWER_MISSER_SET; + wrmsr(CPU_DM_CONFIG0, msr); + + /* write serialize memory hole to PCI. Need to unWS when something is + * shadowed regardless of cachablility. + */ + msr.lo = 0x021212121; + msr.hi = 0x021212121; + wrmsr(CPU_RCONF_A0_BF, msr); + wrmsr(CPU_RCONF_C0_DF, msr); + wrmsr(CPU_RCONF_E0_FF, msr); +} + +/** disable_memory_reorder PBZ 3659: The MC reordered transactions + * incorrectly and breaks coherency. Disable reording and take a + * potential performance hit. This is safe to do here and not in + * MC init since there is nothing to maintain coherency with and + * the cache is not enabled yet. + */ +/****************************************************************************/ +static void disable_memory_reorder(void) +{ + msr_t msr; + + msr = rdmsr(MC_CF8F_DATA); + msr.hi |= CF8F_UPPER_REORDER_DIS_SET; + wrmsr(MC_CF8F_DATA, msr); +} + +/** + * Fix up register settings to manage known CPU bugs. For cpu + * version C3. Should be the only released version + */ +void cpu_bug(void) +{ + pci_deadlock(); + disable_memory_reorder(); + printk(BIOS_DEBUG, "Done cpubug fixes \n"); +} + +/** + * Reset the phase locked loop hardware. After power on as part of + * this operation, we have to set the clock hardware and reboot. Thus, + * we have to know if we have been here before. To do this, we use the + * RSTPLL_LOWER_SWFLAGS_SHIFT flag in the msrGlcpSysRstpll. Also, the + * clocks can either be configured via passed-in parameters or + * hardware straps. Once set, we yank the hardware reset line and + * hlt. We should never reach the hlt, but one never knows. + * + * @param manualconf If non-zero, use passed-in parameters to + * determine how to configure pll -- manual or automagic. + * If manual, use passed-in parameters pll_hi and pll_lo + * @param pll_hi value to use for the high 32 bits of the pll msr + * @param pll_lo value to use for the low 32 bits of the pll msr + */ +void pll_reset(int manualconf, u32 pll_hi, u32 pll_lo) +{ + msr_t msrGlcpSysRstpll; + + msrGlcpSysRstpll = rdmsr(GLCP_SYS_RSTPLL); + + printk(BIOS_DEBUG, + "_MSR GLCP_SYS_RSTPLL (%08x) value is: %08x:%08x\n", msrGlcpSysRstpll.hi, msrGlcpSysRstpll.lo); + post_code(POST_PLL_INIT); + + if (!(msrGlcpSysRstpll.lo & (1 << RSTPLL_LOWER_SWFLAGS_SHIFT))) { + printk(BIOS_DEBUG,"Configuring PLL\n"); + if (manualconf) { + post_code(POST_PLL_MANUAL); + /* CPU and GLIU mult/div (GLMC_CLK = GLIU_CLK / 2) */ + msrGlcpSysRstpll.hi = pll_hi; + + /* Hold Count - how long we will sit in reset */ + msrGlcpSysRstpll.lo = pll_lo; + } else { + /*automatic configuration (straps) */ + post_code(POST_PLL_STRAP); + msrGlcpSysRstpll.lo &= + ~(0xFF << RSTPPL_LOWER_HOLD_COUNT_SHIFT); + msrGlcpSysRstpll.lo |= + (0xDE << RSTPPL_LOWER_HOLD_COUNT_SHIFT); + msrGlcpSysRstpll.lo &= + ~(RSTPPL_LOWER_COREBYPASS_SET | + RSTPPL_LOWER_MBBYPASS_SET); + msrGlcpSysRstpll.lo |= + RSTPPL_LOWER_COREPD_SET | RSTPPL_LOWER_CLPD_SET; + } + /* Use SWFLAGS to remember: "we've already been here" */ + msrGlcpSysRstpll.lo |= (1 << RSTPLL_LOWER_SWFLAGS_SHIFT); + + /* "reset the chip" value */ + msrGlcpSysRstpll.lo |= RSTPPL_LOWER_CHIP_RESET_SET; + wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll); + + /* You should never get here..... The chip has reset. */ + printk(BIOS_EMERG,"CONFIGURING PLL FAILURE -- HALT\n"); + post_code(POST_PLL_RESET_FAIL); + __asm__ __volatile__("hlt\n"); + + } + printk(BIOS_DEBUG, "Done pll_reset\n"); + return; +} + + +/** + * Return the CPU clock rate. Rates in this system are always returned + * as multkiples of 33 Mhz. + * + */ +u32 cpu_speed(void) +{ + u32 speed; + msr_t msr; + + msr = rdmsr(GLCP_SYS_RSTPLL); + speed = ((((msr.hi >> RSTPLL_UPPER_CPUMULT_SHIFT) & 0x1F) + 1) * 333) / 10; + if ((((((msr.hi >> RSTPLL_UPPER_CPUMULT_SHIFT) & 0x1F) + 1) * 333) % 10) > 5) { + ++speed; + } + return (speed); +} + +/** + * Return the Geode Link clock rate. Rates in this system are always + * returned as multkiples of 33 Mhz. + * + */ +u32 geode_link_speed(void) +{ + unsigned int speed; + msr_t msr; + + msr = rdmsr(GLCP_SYS_RSTPLL); + speed = ((((msr.hi >> RSTPLL_UPPER_GLMULT_SHIFT) & 0x1F) + 1) * 333) / 10; + if ((((((msr.hi >> RSTPLL_UPPER_GLMULT_SHIFT) & 0x1F) + 1) * 333) % 10) > 5) { + ++speed; + } + return (speed); +} + + +/** + * Return the PCI bus clock rate. Rates in this system are always + * returned as multkiples of 33 Mhz. + * + */ +u32 pci_speed(void) +{ + msr_t msr; + + msr = rdmsr(GLCP_SYS_RSTPLL); + if (msr.hi & (1 << RSTPPL_LOWER_PCISPEED_SHIFT)) { + return (66); + } else { + return (33); + } +} + +/** + * set_delay_control. This is Black Magic DRAM timing + * juju(http://www.thefreedictionary.com/juju) Dram delay depends on + * cpu clock, memory bus clock, memory bus loading, memory bus + * termination, your middle initial (ha! caught you!), Geode Link + * clock rate, and dram timing specifications. From this the code + * computes a number which is "known to work". No, hardware is not an + * exact science. And, finally, if an FS2 (jtag debugger) is hooked + * up, then just don't to anything. This code was written by a master + * of the Dark Arts at AMD and should not be modified in any way. + * + * @param num_banks How many banks of DRAM there are + * @param dimm0 DIMM 0 SMBus address + * @param dimm1 DIMM 1 SMBus address + * @param sram_width Data width of the SDRAM + */ + +void set_delay_control(u8 dimm0, u8 dimm1) +{ + u32 msrnum, glspeed; + u8 spdbyte0, spdbyte1; + int numdimms = 0; + msr_t msr; + + glspeed = geode_link_speed(); + + /* fix delay controls for DM and IM arrays */ + msrnum = CPU_BC_MSS_ARRAY_CTL0; + msr.hi = 0; + msr.lo = 0x2814D352; + wrmsr(msrnum, msr); + + msrnum = CPU_BC_MSS_ARRAY_CTL1; + msr.hi = 0; + msr.lo = 0x1068334D; + wrmsr(msrnum, msr); + + msrnum = CPU_BC_MSS_ARRAY_CTL2; + msr.hi = 0x00000106; + msr.lo = 0x83104104; + wrmsr(msrnum, msr); + + msrnum = GLCP_FIFOCTL; + msr = rdmsr(msrnum); + msr.hi = 0x00000005; + wrmsr(msrnum, msr); + + /* Enable setting */ + msrnum = CPU_BC_MSS_ARRAY_CTL_ENA; + msr.hi = 0; + msr.lo = 0x00000001; + wrmsr(msrnum, msr); + + /* Debug Delay Control Setup Check + * + * Leave it alone if it has been setup. FS2 or something is here. + */ + msrnum = GLCP_DELAY_CONTROLS; + msr = rdmsr(msrnum); + if (msr.lo & ~(0x7C0)) { + return; + } + + /* + * Delay Controls based on DIMM loading. UGH! + * # of Devices = Module Width (SPD6) / Device Width(SPD13) * Physical Banks(SPD5) + * Note - We only support module width of 64. + */ + spdbyte0 = smbus_read_byte(dimm0, SPD_PRIMARY_SDRAM_WIDTH); + if (spdbyte0 != 0xFF) { + numdimms++; + spdbyte0 = (unsigned char)64 / spdbyte0 * + (unsigned char)(smbus_read_byte(dimm0, SPD_NUM_DIMM_BANKS)); + } else { + spdbyte0 = 0; + } + + spdbyte1 = smbus_read_byte(dimm1, SPD_PRIMARY_SDRAM_WIDTH); + if (spdbyte1 != 0xFF) { + numdimms++; + spdbyte1 = (unsigned char)64 / spdbyte1 * + (unsigned char)(smbus_read_byte(dimm1, SPD_NUM_DIMM_BANKS)); + } else { + spdbyte1 = 0; + } + +/* The current thinking. Subject to change... + +; "FUTURE ROBUSTNESS" PROPOSAL +; ---------------------------- +; DIMM Max MBUS MC 0x2000001A bits 26:24 +;DIMMs devices Frequency MCP 0x4C00000F Setting vvv +;----- ------- --------- ---------------------- ---------- +;1 4 400MHz 0x82*100FF 0x56960004 4 +;1 8 400MHz 0x82*100AA 0x56960004 4 +;1 16 400MHz 0x82*10055 0x56960004 4 +; +;2 4,4 400MHz 0x82710000 0x56960004 4 +;2 8,8 400MHz 0xC27100A5 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** +; +;2 16,4 >333 0xB27100A5 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** +;2 16,8 >333 0xB27100A5 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** +;2 16,16 >333 0xB2710000 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** +; +;1 4 <=333MHz 0x83*100FF 0x56960004 3 +;1 8 <=333MHz 0x83*100AA 0x56960004 3 +;1 16 <=333MHz 0x83*100AA 0x56960004 3 +; +;2 4,4 <=333MHz 0x837100A5 0x56960004 3 +;2 8,8 <=333MHz 0x937100A5 0x56960004 3 +; +;2 16,4 <=333MHz 0xB37100A5 0x56960004 3 *** OUT OF PUBLISHED ENVELOPE *** +;2 16,8 <=333MHz 0xB37100A5 0x56960004 3 *** OUT OF PUBLISHED ENVELOPE *** +;2 16,16 <=333MHz 0xB37100A5 0x56960004 3 *** OUT OF PUBLISHED ENVELOPE *** +;========================================================================= +;* - Bit 55 (disable SDCLK 1,3,5) should be set if there is a single DIMM in slot 0, +; but it should be clear for all 2 DIMM settings and if a single DIMM is in slot 1. +; Bits 54:52 should always be set to '111'. + +;No VTT termination +;------------------------------------- +;ADDR/CTL have 22 ohm series R +;DQ/DQM/DQS have 33 ohm series R +; +; DIMM Max MBUS +;DIMMs devices Frequency MCP 0x4C00000F Setting +;----- ------- --------- ---------------------- +;1 4 400MHz 0xF2F100FF 0x56960004 4 The MC changes improve Salsa. +;1 8 400MHz 0xF2F100FF 0x56960004 4 Delay controls no real change, +;1 4 <=333MHz 0xF2F100FF 0x56960004 3 just fixing typo in left side. +;1 8 <=333MHz 0xF2F100FF 0x56960004 3 +;1 16 <=333MHz 0xF2F100FF 0x56960004 3 +*/ + msr.hi = msr.lo = 0; + + if (spdbyte0 == 0 || spdbyte1 == 0) { + /* one dimm solution */ + if (spdbyte1 == 0) { + msr.hi |= 0x000800000; + } + spdbyte0 += spdbyte1; + if (spdbyte0 > 8) { + /* large dimm */ + if (glspeed < 334) { + msr.hi |= 0x0837100AA; + msr.lo |= 0x056960004; + } else { + msr.hi |= 0x082710055; + msr.lo |= 0x056960004; + } + } else if (spdbyte0 > 4) { + /* medium dimm */ + if (glspeed < 334) { + msr.hi |= 0x0837100AA; + msr.lo |= 0x056960004; + } else { + msr.hi |= 0x0827100AA; + msr.lo |= 0x056960004; + } + } else { + /* small dimm */ + if (glspeed < 334) { + msr.hi |= 0x0837100FF; + msr.lo |= 0x056960004; + } else { + msr.hi |= 0x0827100FF; + msr.lo |= 0x056960004; + } + } + } else { + /* two dimm solution */ + spdbyte0 += spdbyte1; + if (spdbyte0 > 24) { + /* huge dimms */ + if (glspeed < 334) { + msr.hi |= 0x0B37100A5; + msr.lo |= 0x056960004; + } else { + msr.hi |= 0x0B2710000; + msr.lo |= 0x056960004; + } + } else if (spdbyte0 > 16) { + /* large dimms */ + if (glspeed < 334) { + msr.hi |= 0x0B37100A5; + msr.lo |= 0x056960004; + } else { + msr.hi |= 0x0B27100A5; + msr.lo |= 0x056960004; + } + } else if (spdbyte0 >= 8) { + /* medium dimms */ + if (glspeed < 334) { + msr.hi |= 0x0937100A5; + msr.lo |= 0x056960004; + } else { + msr.hi |= 0x0C27100A5; + msr.lo |= 0x056960004; + } + } else { + /* small dimms */ + if (glspeed < 334) { + msr.hi |= 0x0837100A5; + msr.lo |= 0x056960004; + } else { + msr.hi |= 0x082710000; + msr.lo |= 0x056960004; + } + } + } + wrmsr(GLCP_DELAY_CONTROLS, msr); + return; +} + +/** + * cpu_reg_init. All cpu register settings, here in one place, and + * done in the proper order. + * + * @param debug_clock_disable Disable the debug clock to save power. Currently ignored, but we need to + * pick this up from a CMOS setting in future. + * @param dimm0 SMBus address of dimm0 (mainboard dependent) + * @param dimm1 SMBus address of dimm1 (mainboard dependent) + */ +void cpu_reg_init(int debug_clock_disable, u8 dimm0, u8 dimm1) +{ + int msrnum; + msr_t msr; + + /* Castle 2.0 BTM periodic sync period. */ + /* [40:37] 1 sync record per 256 bytes */ + msrnum = CPU_PF_CONF; + msr = rdmsr(msrnum); + msr.hi |= (0x8 << 5); + wrmsr(msrnum, msr); + + /* + ; Castle performance setting. + ; Enable Quack for fewer re-RAS on the MC + */ + msrnum = GLIU0_ARB; + msr = rdmsr(msrnum); + msr.hi &= ~ARB_UPPER_DACK_EN_SET; + msr.hi |= ARB_UPPER_QUACK_EN_SET; + wrmsr(msrnum, msr); + + msrnum = GLIU1_ARB; + msr = rdmsr(msrnum); + msr.hi &= ~ARB_UPPER_DACK_EN_SET; + msr.hi |= ARB_UPPER_QUACK_EN_SET; + wrmsr(msrnum, msr); + + /* GLIU port active enable, limit south pole masters (AES and PCI) to one outstanding transaction. */ + msrnum = GLIU1_PORT_ACTIVE; + msr = rdmsr(msrnum); + msr.lo &= ~0x880; + wrmsr(msrnum, msr); + + /* Set the Delay Control in GLCP */ + set_delay_control(dimm0, dimm1); + + /* Enable RSDC */ + msrnum = CPU_AC_SMM_CTL; + msr = rdmsr(msrnum); + msr.lo |= SMM_INST_EN_SET; + wrmsr(msrnum, msr); + + /* FPU imprecise exceptions bit */ + msrnum = CPU_FPU_MSR_MODE; + msr = rdmsr(msrnum); + msr.lo |= FPU_IE_SET; + wrmsr(msrnum, msr); + + /* Power Savers (Do after BIST) */ + /* Enable Suspend on HLT & PAUSE instructions */ + msrnum = CPU_XC_CONFIG; + msr = rdmsr(msrnum); + msr.lo |= XC_CONFIG_SUSP_ON_HLT | XC_CONFIG_SUSP_ON_PAUSE; + wrmsr(msrnum, msr); + + /* Enable SUSP and allow TSC to run in Suspend (keep speed detection happy) */ + msrnum = CPU_BC_CONF_0; + msr = rdmsr(msrnum); + msr.lo |= TSC_SUSP_SET | SUSP_EN_SET; + msr.lo &= 0x0F0FFFFFF; + msr.lo |= 0x002000000; /* PBZ213: Set PAUSEDLY = 2 */ + wrmsr(msrnum, msr); + + /* Disable the debug clock to save power. */ + /* NOTE: leave it enabled for fs2 debug */ + if (debug_clock_disable && 0){ + msrnum = GLCP_DBGCLKCTL; + msr.hi = 0; + msr.lo = 0; + wrmsr(msrnum, msr); + } + + /* Setup throttling delays to proper mode if it is ever enabled. */ + msrnum = GLCP_TH_OD; + msr.hi = 0; + msr.lo = 0x00000603C; + wrmsr(msrnum, msr); + /* fix cpu bugs */ +#warning testing fixing bugs in initram + cpu_bug(); +}
Copied: LinuxBIOSv3/arch/x86/geodelx/stage0.S (from rev 385, LinuxBIOSv3/arch/x86/stage0_amd_geodelx.S) =================================================================== --- LinuxBIOSv3/arch/x86/geodelx/stage0.S (rev 0) +++ LinuxBIOSv3/arch/x86/geodelx/stage0.S 2007-06-27 21:07:10 UTC (rev 387) @@ -0,0 +1,443 @@ +## +## This file is part of the LinuxBIOS project. +## +## Copyright (C) 2000,2007 Ronald G. Minnich rminnich@gmail.com +## Copyright (C) 2005 Eswar Nallusamy, LANL +## Copyright (C) 2005 Tyan +## (Written by Yinghai Lu yhlu@tyan.com for Tyan) +## Copyright (C) 2007 coresystems GmbH +## (Written by Stefan Reinauer stepan@coresystems.de for coresystems GmbH) +## Copyright (C) 2007 Advanced Micro Devices, Inc. +## +## 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; version 2 of the License. +## +## 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 +## + +/* Init code - Switch CPU to protected mode and enable Cache-as-Ram. */ + +#include "../macros.h" +#include <amd_geodelx.h> + +/* This is where the DCache will be mapped and be used as stack. It would be + * cool if it was the same base as LinuxBIOS normal stack. + */ +#define LX_STACK_BASE DCACHE_RAM_BASE +#define LX_STACK_END LX_STACK_BASE+(DCACHE_RAM_SIZE-4) + +#define LX_NUM_CACHELINES 0x080 /* There are 128 lines per way. */ +#define LX_CACHELINE_SIZE 0x020 /* There are 32 bytes per line. */ +#define LX_CACHEWAY_SIZE (LX_NUM_CACHELINES * LX_CACHELINE_SIZE) +#define CR0_CD 0x40000000 /* Bit 30 = Cache Disable */ +#define CR0_NW 0x20000000 /* Bit 29 = Not Write Through */ + +#define ROM_CODE_SEG 0x08 +#define ROM_DATA_SEG 0x10 + +#define CACHE_RAM_CODE_SEG 0x18 +#define CACHE_RAM_DATA_SEG 0x20 + + .code16 + .globl _stage0 +_stage0: + cli + + /* Save the BIST result. */ + movl %eax, %ebp; + + /* Thanks to kmliu@sis.com.tw for this TLB fix. */ + /* IMMEDIATELY invalidate the translation lookaside buffer before + * executing any further code. Even though paging is disabled we + * could still get false address translations due to the TLB if we + * didn't invalidate it. + */ + + xorl %eax, %eax + movl %eax, %cr3 /* Invalidate TLB */ + + /* Switch to protected mode. */ + + /* NOTE: With GNU assembler version 2.15.94.0.2.2 (i386-redhat-linux) + * using BFD version 2.15.94.0.2.2 20041220 this works fine without + * all the ld hackery and so on. So leave it as is with this comment. + */ + + data32 lgdt %cs:gdtptr + + movl %cr0, %eax + andl $0x7FFAFFD1, %eax /* PG, AM, WP, NE, TS, EM, MP = 0 */ + orl $0x60000001, %eax /* CD, NW, PE = 1 */ + movl %eax, %cr0 + + /* Restore BIST result. */ + movl %ebp, %eax + + // port80_post(0x23) + + /* Now we are in protected mode. Jump to a 32 bit code segment. */ + data32 ljmp $ROM_CODE_SEG, $protected_stage0 + /* I am leaving this weird jump in here in the event that future gas + * bugs force it to be used. + */ + #.byte 0x66 + .code32 + #ljmp $ROM_CODE_SEG, $protected_stage0 + + #.code16 + .align 4 + .globl gdt16 +gdt16 = . - _stage0 +gdt16x: + .word gdt16xend - gdt16x -1 /* Compute the table limit. */ + .long gdt16x + .word 0 + + /* selgdt 0x08, flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* selgdt 0x10, flat data segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 +gdt16xend: + + /* From now on we are 32bit. */ + .code32 + + /* We have two gdts where we could have one. That is ok. + * + * Let's not worry about this -- optimizing gdt is pointless since + * we're only in it for a little bit. + * + * BTW note the trick below: The GDT points to ITSELF, and the first + * good descriptor is at offset 8. So you word-align the table, and + * then because you chose 8, you get a nice 64-bit aligned GDT entry, + * which is good as this is the size of the entry. + * + * Just in case you ever wonder why people do this. + */ + .align 4 + .globl gdtptr + .globl gdt_limit +gdt_limit = gdt_end - gdt - 1 /* Compute the table limit. */ + +gdt: +gdtptr: + .word gdt_end - gdt -1 /* Compute the table limit. */ + .long gdt /* We know the offset. */ + .word 0 + + /* selgdt 0x08, flat code segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* selgdt 0x10, flat data segment */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 + + /* selgdt 0x18, flat code segment for CAR */ + .word 0xffff, 0x0000 + .byte 0x00, 0x9b, 0xcf, 0x00 + + /* selgdt 0x20, flat data segment for CAR */ + .word 0xffff, 0x0000 + .byte 0x00, 0x93, 0xcf, 0x00 +gdt_end: + + /* + * When we come here we are in protected mode. We expand the stack + * and copy the data segment from ROM to the memory. + * + * After that, we call the chipset bootstrap routine that + * does what is left of the chipset initialization. + * + * NOTE: Aligned to 4 so that we are sure that the prefetch + * cache will be reloaded. + */ + + .align 4 + .globl protected_stage0 +protected_stage0: + // This code was used by v2. TODO + lgdt %cs:gdtptr + ljmp $ROM_CODE_SEG, $__protected_stage0 + +.globl __protected_stage0 +__protected_stage0: + /* Save the BIST value. */ + movl %eax, %ebp + + port80_post(0x01) + + movw $ROM_DATA_SEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + /* Restore the BIST value to %eax. */ + movl %ebp, %eax + +.align 4 + /* Here begins CAR support. */ + /* This particular code is straight from LinuxBIOS V2. */ + + /* DCacheSetup: Setup data cache for use as RAM for a stack. */ +DCacheSetup: + + invd + /* Set cache properties. */ + movl $CPU_RCONF_DEFAULT, %ecx + rdmsr + /* 1MB system memory in write back 1|00100|00. */ + movl $0x010010000, %eax + wrmsr + + /* In LX DCDIS is set after POR which disables the cache..., clear + * this bit. + */ + movl CPU_DM_CONFIG0,%ecx + rdmsr + /* TODO: Make consistent with i$ init, either whole reg = 0, or just + * this bit... + */ + andl $(~(DM_CONFIG0_LOWER_DCDIS_SET)), %eax + wrmsr + + /* Get cache timing params from BIOS config data locations and apply. */ + /* Fix delay controls for DM and IM arrays. */ + movl $CPU_BC_MSS_ARRAY_CTL0, %ecx + xorl %edx, %edx + movl $0x2814D352, %eax + wrmsr + + movl $CPU_BC_MSS_ARRAY_CTL1, %ecx + xorl %edx, %edx + movl $0x1068334D, %eax + wrmsr + + movl $CPU_BC_MSS_ARRAY_CTL2, %ecx + movl $0x00000106, %edx + movl $0x83104104, %eax + wrmsr + + movl $GLCP_FIFOCTL, %ecx + rdmsr + movl $0x00000005, %edx + wrmsr + + /* Enable setting. */ + movl $CPU_BC_MSS_ARRAY_CTL_ENA, %ecx + xorl %edx, %edx + movl $0x01, %eax + wrmsr + + /* Get cleaned up. */ + xorl %edi, %edi + xorl %esi, %esi + xorl %ebp, %ebp + + /* DCache Ways0 through Ways7 will be tagged for + * LX_STACK_BASE + DCACHE_RAM_SIZE for holding stack. + */ + /* Remember, there is NO stack yet... */ + + /* Tell cache we want to fill Way 0 starting at the top. */ + xorl %edx, %edx + xorl %eax, %eax + movl $CPU_DC_INDEX, %ecx + wrmsr + + /* Startaddress for tag of Way0: ebp will hold the incrementing + * address. dont destroy! + */ + movl $LX_STACK_BASE, %ebp /* Init to start address. */ + /* Set valid bit and tag for this Way (B[31:12] : Cache tag value for + * line/way curr. selected by CPU_DC_INDEX. + */ + orl $1, %ebp + + /* Start tag Ways 0 with 128 lines with 32 bytes each: edi will hold + * the line counter. dont destroy! + */ + movl $LX_NUM_CACHELINES, %edi + +DCacheSetupFillWay: + /* Fill with dummy data: zero it so we can tell it from PCI memory + * space (returns FFs). + */ + /* We will now store a line (32 bytes = 4 x 8 bytes = 4 quad-words). */ + movw $0x04, %si + xorl %edx, %edx + xorl %eax, %eax + movl $CPU_DC_DATA, %ecx + +DCacheSetup_quadWordLoop: + wrmsr + decw %si + jnz DCacheSetup_quadWordLoop + + /* Set the tag for this line, need to do this for every new cache + * line to validate it! + */ + /* Accessing CPU_DC_TAG_I makes the LINE field in CPU_DC_INDEX + * increment and thus continue in the next cache line... + */ + xorl %edx, %edx + movl %ebp, %eax + movl $CPU_DC_TAG, %ecx + wrmsr + + /* Switch to next line. Lines are in Bits10:4. */ + /* When index is crossing 0x7F -> 0x80 writing a RSVD bit as 0x80 is + * not a valid CL anymore! + */ + movl $CPU_DC_INDEX, %ecx + rdmsr + /* TODO: Probably would be more elegant to calculate this from + * counter var edi... + */ + addl $0x010, %eax + wrmsr + + decl %edi + jnz DCacheSetupFillWay + + /* 1 Way has been filled, forward start address for next Way, + * terminate if we have reached end of desired address range. + */ + addl $LX_CACHEWAY_SIZE, %ebp + cmpl $LX_STACK_END, %ebp + jge leave_DCacheSetup + movl $LX_NUM_CACHELINES, %edi + + /* Switch to next way. */ + movl $CPU_DC_INDEX, %ecx + rdmsr + addl $0x01, %eax + /* Let's be sure: reset line index Bits10:4. */ + andl $0xFFFFF80F, %eax + wrmsr + + jmp DCacheSetupFillWay + +leave_DCacheSetup: + xorl %edi, %edi + xorl %esi, %esi + xorl %ebp, %ebp + + /* Disable the cache, but... DO NOT INVALIDATE the tags. */ + /* Memory reads and writes will all hit in the cache. */ + /* Cache updates and memory write-backs will not occur! */ + movl %cr0, %eax + orl $(CR0_CD + CR0_NW), %eax /* Set the CD and NW bits. */ + movl %eax, %cr0 + + /* Now point sp to the cached stack. */ + /* The stack will be fully functional at this location. No system + * memory is required at all! + */ + /* Set up the stack pointer. */ + movl $LX_STACK_END, %eax + movl %eax, %esp + + /* Test the stack. */ + movl $0x0F0F05A5A, %edx + pushl %edx + popl %ecx + cmpl %ecx, %edx + je DCacheSetupGood + movb $0xC5, %al + outb %al, $0x80 + +DCacheSetupBad: + hlt /* Issues */ + jmp DCacheSetupBad + +DCacheSetupGood: + /* If you wanted to maintain the stack in memory you would need to + * set the tags as dirty so the wbinvd would push out the old stack + * contents to memory. + */ + /* Clear the cache, the following code from crt0.S.lb will setup + * a new stack. + */ + wbinvd + + /* At this point, CAR should be working. */ + movl $(LX_STACK_END), %eax + movl %eax, %esp + + /* Load a different set of data segments. */ + movw $CACHE_RAM_DATA_SEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + +lout: + /* Restore the BIST result. */ + movl %ebp, %eax + /* We need to set ebp? No need. */ + movl %esp, %ebp + pushl %eax /* BIST */ + call stage1_main + /* We will not go back. */ + +fixed_mtrr_msr: + .long 0x250, 0x258, 0x259 + .long 0x268, 0x269, 0x26A + .long 0x26B, 0x26C, 0x26D + .long 0x26E, 0x26F +var_mtrr_msr: + .long 0x200, 0x201, 0x202, 0x203 + .long 0x204, 0x205, 0x206, 0x207 + .long 0x208, 0x209, 0x20A, 0x20B + .long 0x20C, 0x20D, 0x20E, 0x20F + .long 0x000 /* NULL, end of table */ + +# Reset vector. + +/* + * RVECTOR: size of reset vector, default is 0x10 + * RESRVED: size of vpd code, default is 0xf0 + * BOOTBLK: size of bootblock code, default is 0x1f00 (8k-256b) + */ + +SEGMENT_SIZE = 0x10000 +RVECTOR = 0x00010 + +# Due to YET ANOTHER BUG in GNU bintools, you can NOT have a code16 here. +# I think we should leave it this way forever, as the bugs come and +# go -- and come again. +# .code16 +# .section ".rom.text" +.section ".reset", "ax" + .globl _resetjump +_resetjump: + /* GNU bintools bugs again. This jumps to stage0 - 2. Sigh. */ +# jmp _stage0 + .byte 0xe9 + .int _stage0 - ( . + 2 ) + /* Note: The above jump is hand coded to work around bugs in binutils. + * 5 bytes are used for a 3 byte instruction. This works because x86 + * is little endian and allows us to use supported 32 bit relocations + * instead of the weird 16 bit relocations that binutils does not + * handle consistenly between versions because they are used so rarely. + */ +.byte 0 + +# Date? ID string? We might want to put something else in here. +.ascii DATE + +# Checksum. +#.word 0
Deleted: LinuxBIOSv3/arch/x86/geodelx.c =================================================================== --- LinuxBIOSv3/arch/x86/geodelx.c 2007-06-27 21:01:01 UTC (rev 386) +++ LinuxBIOSv3/arch/x86/geodelx.c 2007-06-27 21:07:10 UTC (rev 387) @@ -1,580 +0,0 @@ -/* - * This file is part of the LinuxBIOS project. - * - * Copyright (C) 2006 Indrek Kruusa indrek.kruusa@artecdesign.ee - * Copyright (C) 2006 Ronald G. Minnich rminnich@gmail.com - * Copyright (C) 2007 Advanced Micro Devices, Inc. - * - * 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 - */ -#include <types.h> -#include <lib.h> -#include <console.h> -#include <device/device.h> -#include <device/pci.h> -#include <string.h> -#include <msr.h> -#include <io.h> -#include <amd_geodelx.h> -#include <spd.h> - -/* all these functions used to be in a lot of fiddly little files. To - * make it easier to find functions, we are merging them here. This - * file is our first real cpu-specific support file and should serve - * as a model for v3 cpu-specific support. So, warning, you might - * think it makes sense to split this file up, but we've tried that, - * and it sucks. - */ - -/** - * geodelx_msr_init Set up Geode LX registers for sane behaviour. Set - * all low memory (under 1MB) to write back. Do some setup for cache - * as ram as well. - */ -void geodelx_msr_init(void) -{ - msr_t msr; - /* Setup access to the cache for under 1MB. */ - msr.hi = 0x24fffc02; - msr.lo = 0x1000A000; /* 0-A0000 write back */ - wrmsr(CPU_RCONF_DEFAULT, msr); - - msr.hi = 0x0; /* write back */ - msr.lo = 0x0; - wrmsr(CPU_RCONF_A0_BF, msr); - wrmsr(CPU_RCONF_C0_DF, msr); - wrmsr(CPU_RCONF_E0_FF, msr); - - /* Setup access to the cache for under 640K. Note MC not setup yet. */ - msr.hi = 0x20000000; - msr.lo = 0xfff80; - wrmsr(MSR_GLIU0 + 0x20, msr); - - msr.hi = 0x20000000; - msr.lo = 0x80fffe0; - wrmsr(MSR_GLIU0 + 0x21, msr); - - msr.hi = 0x20000000; - msr.lo = 0xfff80; - wrmsr(MSR_GLIU1 + 0x20, msr); - - msr.hi = 0x20000000; - msr.lo = 0x80fffe0; - wrmsr(MSR_GLIU1 + 0x21, msr); - -} - - -/** - * start_time1 Starts Timer 1 for port 61 use. FIXME try to figure - * out what these values mean. - */ -void start_timer1(void) -{ - outb(0x56, 0x43); - outb(0x12, 0x41); -} - -/** - * system_preinit Very early initialization needed for almost - * everything else. Currently, all we do is start timer1. - */ -void system_preinit(void) -{ - start_timer1(); -} - -/* cpu bug management */ -/** - * - * pci_deadlock Bugtool #465 and #609 PCI cache deadlock There is - * also fix code in cache and PCI functions. This bug is very is - * pervasive. - * - */ -static void pci_deadlock(void) -{ - msr_t msr; - - /* - * forces serialization of all load misses. Setting this bit prevents the - * DM pipe from backing up if a read request has to be held up waiting - * for PCI writes to complete. - */ - msr = rdmsr(CPU_DM_CONFIG0); - msr.lo |= DM_CONFIG0_LOWER_MISSER_SET; - wrmsr(CPU_DM_CONFIG0, msr); - - /* write serialize memory hole to PCI. Need to unWS when something is - * shadowed regardless of cachablility. - */ - msr.lo = 0x021212121; - msr.hi = 0x021212121; - wrmsr(CPU_RCONF_A0_BF, msr); - wrmsr(CPU_RCONF_C0_DF, msr); - wrmsr(CPU_RCONF_E0_FF, msr); -} - -/** disable_memory_reorder PBZ 3659: The MC reordered transactions - * incorrectly and breaks coherency. Disable reording and take a - * potential performance hit. This is safe to do here and not in - * MC init since there is nothing to maintain coherency with and - * the cache is not enabled yet. - */ -/****************************************************************************/ -static void disable_memory_reorder(void) -{ - msr_t msr; - - msr = rdmsr(MC_CF8F_DATA); - msr.hi |= CF8F_UPPER_REORDER_DIS_SET; - wrmsr(MC_CF8F_DATA, msr); -} - -/** - * Fix up register settings to manage known CPU bugs. For cpu - * version C3. Should be the only released version - */ -void cpu_bug(void) -{ - pci_deadlock(); - disable_memory_reorder(); - printk(BIOS_DEBUG, "Done cpubug fixes \n"); -} - -/** - * Reset the phase locked loop hardware. After power on as part of - * this operation, we have to set the clock hardware and reboot. Thus, - * we have to know if we have been here before. To do this, we use the - * RSTPLL_LOWER_SWFLAGS_SHIFT flag in the msrGlcpSysRstpll. Also, the - * clocks can either be configured via passed-in parameters or - * hardware straps. Once set, we yank the hardware reset line and - * hlt. We should never reach the hlt, but one never knows. - * - * @param manualconf If non-zero, use passed-in parameters to - * determine how to configure pll -- manual or automagic. - * If manual, use passed-in parameters pll_hi and pll_lo - * @param pll_hi value to use for the high 32 bits of the pll msr - * @param pll_lo value to use for the low 32 bits of the pll msr - */ -void pll_reset(int manualconf, u32 pll_hi, u32 pll_lo) -{ - msr_t msrGlcpSysRstpll; - - msrGlcpSysRstpll = rdmsr(GLCP_SYS_RSTPLL); - - printk(BIOS_DEBUG, - "_MSR GLCP_SYS_RSTPLL (%08x) value is: %08x:%08x\n", msrGlcpSysRstpll.hi, msrGlcpSysRstpll.lo); - post_code(POST_PLL_INIT); - - if (!(msrGlcpSysRstpll.lo & (1 << RSTPLL_LOWER_SWFLAGS_SHIFT))) { - printk(BIOS_DEBUG,"Configuring PLL\n"); - if (manualconf) { - post_code(POST_PLL_MANUAL); - /* CPU and GLIU mult/div (GLMC_CLK = GLIU_CLK / 2) */ - msrGlcpSysRstpll.hi = pll_hi; - - /* Hold Count - how long we will sit in reset */ - msrGlcpSysRstpll.lo = pll_lo; - } else { - /*automatic configuration (straps) */ - post_code(POST_PLL_STRAP); - msrGlcpSysRstpll.lo &= - ~(0xFF << RSTPPL_LOWER_HOLD_COUNT_SHIFT); - msrGlcpSysRstpll.lo |= - (0xDE << RSTPPL_LOWER_HOLD_COUNT_SHIFT); - msrGlcpSysRstpll.lo &= - ~(RSTPPL_LOWER_COREBYPASS_SET | - RSTPPL_LOWER_MBBYPASS_SET); - msrGlcpSysRstpll.lo |= - RSTPPL_LOWER_COREPD_SET | RSTPPL_LOWER_CLPD_SET; - } - /* Use SWFLAGS to remember: "we've already been here" */ - msrGlcpSysRstpll.lo |= (1 << RSTPLL_LOWER_SWFLAGS_SHIFT); - - /* "reset the chip" value */ - msrGlcpSysRstpll.lo |= RSTPPL_LOWER_CHIP_RESET_SET; - wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll); - - /* You should never get here..... The chip has reset. */ - printk(BIOS_EMERG,"CONFIGURING PLL FAILURE -- HALT\n"); - post_code(POST_PLL_RESET_FAIL); - __asm__ __volatile__("hlt\n"); - - } - printk(BIOS_DEBUG, "Done pll_reset\n"); - return; -} - - -/** - * Return the CPU clock rate. Rates in this system are always returned - * as multkiples of 33 Mhz. - * - */ -u32 cpu_speed(void) -{ - u32 speed; - msr_t msr; - - msr = rdmsr(GLCP_SYS_RSTPLL); - speed = ((((msr.hi >> RSTPLL_UPPER_CPUMULT_SHIFT) & 0x1F) + 1) * 333) / 10; - if ((((((msr.hi >> RSTPLL_UPPER_CPUMULT_SHIFT) & 0x1F) + 1) * 333) % 10) > 5) { - ++speed; - } - return (speed); -} - -/** - * Return the Geode Link clock rate. Rates in this system are always - * returned as multkiples of 33 Mhz. - * - */ -u32 geode_link_speed(void) -{ - unsigned int speed; - msr_t msr; - - msr = rdmsr(GLCP_SYS_RSTPLL); - speed = ((((msr.hi >> RSTPLL_UPPER_GLMULT_SHIFT) & 0x1F) + 1) * 333) / 10; - if ((((((msr.hi >> RSTPLL_UPPER_GLMULT_SHIFT) & 0x1F) + 1) * 333) % 10) > 5) { - ++speed; - } - return (speed); -} - - -/** - * Return the PCI bus clock rate. Rates in this system are always - * returned as multkiples of 33 Mhz. - * - */ -u32 pci_speed(void) -{ - msr_t msr; - - msr = rdmsr(GLCP_SYS_RSTPLL); - if (msr.hi & (1 << RSTPPL_LOWER_PCISPEED_SHIFT)) { - return (66); - } else { - return (33); - } -} - -/** - * set_delay_control. This is Black Magic DRAM timing - * juju(http://www.thefreedictionary.com/juju) Dram delay depends on - * cpu clock, memory bus clock, memory bus loading, memory bus - * termination, your middle initial (ha! caught you!), Geode Link - * clock rate, and dram timing specifications. From this the code - * computes a number which is "known to work". No, hardware is not an - * exact science. And, finally, if an FS2 (jtag debugger) is hooked - * up, then just don't to anything. This code was written by a master - * of the Dark Arts at AMD and should not be modified in any way. - * - * @param num_banks How many banks of DRAM there are - * @param dimm0 DIMM 0 SMBus address - * @param dimm1 DIMM 1 SMBus address - * @param sram_width Data width of the SDRAM - */ - -void set_delay_control(u8 dimm0, u8 dimm1) -{ - u32 msrnum, glspeed; - u8 spdbyte0, spdbyte1; - int numdimms = 0; - msr_t msr; - - glspeed = geode_link_speed(); - - /* fix delay controls for DM and IM arrays */ - msrnum = CPU_BC_MSS_ARRAY_CTL0; - msr.hi = 0; - msr.lo = 0x2814D352; - wrmsr(msrnum, msr); - - msrnum = CPU_BC_MSS_ARRAY_CTL1; - msr.hi = 0; - msr.lo = 0x1068334D; - wrmsr(msrnum, msr); - - msrnum = CPU_BC_MSS_ARRAY_CTL2; - msr.hi = 0x00000106; - msr.lo = 0x83104104; - wrmsr(msrnum, msr); - - msrnum = GLCP_FIFOCTL; - msr = rdmsr(msrnum); - msr.hi = 0x00000005; - wrmsr(msrnum, msr); - - /* Enable setting */ - msrnum = CPU_BC_MSS_ARRAY_CTL_ENA; - msr.hi = 0; - msr.lo = 0x00000001; - wrmsr(msrnum, msr); - - /* Debug Delay Control Setup Check - * - * Leave it alone if it has been setup. FS2 or something is here. - */ - msrnum = GLCP_DELAY_CONTROLS; - msr = rdmsr(msrnum); - if (msr.lo & ~(0x7C0)) { - return; - } - - /* - * Delay Controls based on DIMM loading. UGH! - * # of Devices = Module Width (SPD6) / Device Width(SPD13) * Physical Banks(SPD5) - * Note - We only support module width of 64. - */ - spdbyte0 = smbus_read_byte(dimm0, SPD_PRIMARY_SDRAM_WIDTH); - if (spdbyte0 != 0xFF) { - numdimms++; - spdbyte0 = (unsigned char)64 / spdbyte0 * - (unsigned char)(smbus_read_byte(dimm0, SPD_NUM_DIMM_BANKS)); - } else { - spdbyte0 = 0; - } - - spdbyte1 = smbus_read_byte(dimm1, SPD_PRIMARY_SDRAM_WIDTH); - if (spdbyte1 != 0xFF) { - numdimms++; - spdbyte1 = (unsigned char)64 / spdbyte1 * - (unsigned char)(smbus_read_byte(dimm1, SPD_NUM_DIMM_BANKS)); - } else { - spdbyte1 = 0; - } - -/* The current thinking. Subject to change... - -; "FUTURE ROBUSTNESS" PROPOSAL -; ---------------------------- -; DIMM Max MBUS MC 0x2000001A bits 26:24 -;DIMMs devices Frequency MCP 0x4C00000F Setting vvv -;----- ------- --------- ---------------------- ---------- -;1 4 400MHz 0x82*100FF 0x56960004 4 -;1 8 400MHz 0x82*100AA 0x56960004 4 -;1 16 400MHz 0x82*10055 0x56960004 4 -; -;2 4,4 400MHz 0x82710000 0x56960004 4 -;2 8,8 400MHz 0xC27100A5 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** -; -;2 16,4 >333 0xB27100A5 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** -;2 16,8 >333 0xB27100A5 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** -;2 16,16 >333 0xB2710000 0x56960004 4 *** OUT OF PUBLISHED ENVELOPE *** -; -;1 4 <=333MHz 0x83*100FF 0x56960004 3 -;1 8 <=333MHz 0x83*100AA 0x56960004 3 -;1 16 <=333MHz 0x83*100AA 0x56960004 3 -; -;2 4,4 <=333MHz 0x837100A5 0x56960004 3 -;2 8,8 <=333MHz 0x937100A5 0x56960004 3 -; -;2 16,4 <=333MHz 0xB37100A5 0x56960004 3 *** OUT OF PUBLISHED ENVELOPE *** -;2 16,8 <=333MHz 0xB37100A5 0x56960004 3 *** OUT OF PUBLISHED ENVELOPE *** -;2 16,16 <=333MHz 0xB37100A5 0x56960004 3 *** OUT OF PUBLISHED ENVELOPE *** -;========================================================================= -;* - Bit 55 (disable SDCLK 1,3,5) should be set if there is a single DIMM in slot 0, -; but it should be clear for all 2 DIMM settings and if a single DIMM is in slot 1. -; Bits 54:52 should always be set to '111'. - -;No VTT termination -;------------------------------------- -;ADDR/CTL have 22 ohm series R -;DQ/DQM/DQS have 33 ohm series R -; -; DIMM Max MBUS -;DIMMs devices Frequency MCP 0x4C00000F Setting -;----- ------- --------- ---------------------- -;1 4 400MHz 0xF2F100FF 0x56960004 4 The MC changes improve Salsa. -;1 8 400MHz 0xF2F100FF 0x56960004 4 Delay controls no real change, -;1 4 <=333MHz 0xF2F100FF 0x56960004 3 just fixing typo in left side. -;1 8 <=333MHz 0xF2F100FF 0x56960004 3 -;1 16 <=333MHz 0xF2F100FF 0x56960004 3 -*/ - msr.hi = msr.lo = 0; - - if (spdbyte0 == 0 || spdbyte1 == 0) { - /* one dimm solution */ - if (spdbyte1 == 0) { - msr.hi |= 0x000800000; - } - spdbyte0 += spdbyte1; - if (spdbyte0 > 8) { - /* large dimm */ - if (glspeed < 334) { - msr.hi |= 0x0837100AA; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x082710055; - msr.lo |= 0x056960004; - } - } else if (spdbyte0 > 4) { - /* medium dimm */ - if (glspeed < 334) { - msr.hi |= 0x0837100AA; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0827100AA; - msr.lo |= 0x056960004; - } - } else { - /* small dimm */ - if (glspeed < 334) { - msr.hi |= 0x0837100FF; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0827100FF; - msr.lo |= 0x056960004; - } - } - } else { - /* two dimm solution */ - spdbyte0 += spdbyte1; - if (spdbyte0 > 24) { - /* huge dimms */ - if (glspeed < 334) { - msr.hi |= 0x0B37100A5; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0B2710000; - msr.lo |= 0x056960004; - } - } else if (spdbyte0 > 16) { - /* large dimms */ - if (glspeed < 334) { - msr.hi |= 0x0B37100A5; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0B27100A5; - msr.lo |= 0x056960004; - } - } else if (spdbyte0 >= 8) { - /* medium dimms */ - if (glspeed < 334) { - msr.hi |= 0x0937100A5; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x0C27100A5; - msr.lo |= 0x056960004; - } - } else { - /* small dimms */ - if (glspeed < 334) { - msr.hi |= 0x0837100A5; - msr.lo |= 0x056960004; - } else { - msr.hi |= 0x082710000; - msr.lo |= 0x056960004; - } - } - } - wrmsr(GLCP_DELAY_CONTROLS, msr); - return; -} - -/** - * cpu_reg_init. All cpu register settings, here in one place, and - * done in the proper order. - * - * @param debug_clock_disable Disable the debug clock to save power. Currently ignored, but we need to - * pick this up from a CMOS setting in future. - * @param dimm0 SMBus address of dimm0 (mainboard dependent) - * @param dimm1 SMBus address of dimm1 (mainboard dependent) - */ -void cpu_reg_init(int debug_clock_disable, u8 dimm0, u8 dimm1) -{ - int msrnum; - msr_t msr; - - /* Castle 2.0 BTM periodic sync period. */ - /* [40:37] 1 sync record per 256 bytes */ - msrnum = CPU_PF_CONF; - msr = rdmsr(msrnum); - msr.hi |= (0x8 << 5); - wrmsr(msrnum, msr); - - /* - ; Castle performance setting. - ; Enable Quack for fewer re-RAS on the MC - */ - msrnum = GLIU0_ARB; - msr = rdmsr(msrnum); - msr.hi &= ~ARB_UPPER_DACK_EN_SET; - msr.hi |= ARB_UPPER_QUACK_EN_SET; - wrmsr(msrnum, msr); - - msrnum = GLIU1_ARB; - msr = rdmsr(msrnum); - msr.hi &= ~ARB_UPPER_DACK_EN_SET; - msr.hi |= ARB_UPPER_QUACK_EN_SET; - wrmsr(msrnum, msr); - - /* GLIU port active enable, limit south pole masters (AES and PCI) to one outstanding transaction. */ - msrnum = GLIU1_PORT_ACTIVE; - msr = rdmsr(msrnum); - msr.lo &= ~0x880; - wrmsr(msrnum, msr); - - /* Set the Delay Control in GLCP */ - set_delay_control(dimm0, dimm1); - - /* Enable RSDC */ - msrnum = CPU_AC_SMM_CTL; - msr = rdmsr(msrnum); - msr.lo |= SMM_INST_EN_SET; - wrmsr(msrnum, msr); - - /* FPU imprecise exceptions bit */ - msrnum = CPU_FPU_MSR_MODE; - msr = rdmsr(msrnum); - msr.lo |= FPU_IE_SET; - wrmsr(msrnum, msr); - - /* Power Savers (Do after BIST) */ - /* Enable Suspend on HLT & PAUSE instructions */ - msrnum = CPU_XC_CONFIG; - msr = rdmsr(msrnum); - msr.lo |= XC_CONFIG_SUSP_ON_HLT | XC_CONFIG_SUSP_ON_PAUSE; - wrmsr(msrnum, msr); - - /* Enable SUSP and allow TSC to run in Suspend (keep speed detection happy) */ - msrnum = CPU_BC_CONF_0; - msr = rdmsr(msrnum); - msr.lo |= TSC_SUSP_SET | SUSP_EN_SET; - msr.lo &= 0x0F0FFFFFF; - msr.lo |= 0x002000000; /* PBZ213: Set PAUSEDLY = 2 */ - wrmsr(msrnum, msr); - - /* Disable the debug clock to save power. */ - /* NOTE: leave it enabled for fs2 debug */ - if (debug_clock_disable && 0){ - msrnum = GLCP_DBGCLKCTL; - msr.hi = 0; - msr.lo = 0; - wrmsr(msrnum, msr); - } - - /* Setup throttling delays to proper mode if it is ever enabled. */ - msrnum = GLCP_TH_OD; - msr.hi = 0; - msr.lo = 0x00000603C; - wrmsr(msrnum, msr); - /* fix cpu bugs */ -#warning testing fixing bugs in initram - cpu_bug(); -}
Deleted: LinuxBIOSv3/arch/x86/stage0_amd_geodelx.S =================================================================== --- LinuxBIOSv3/arch/x86/stage0_amd_geodelx.S 2007-06-27 21:01:01 UTC (rev 386) +++ LinuxBIOSv3/arch/x86/stage0_amd_geodelx.S 2007-06-27 21:07:10 UTC (rev 387) @@ -1,443 +0,0 @@ -## -## This file is part of the LinuxBIOS project. -## -## Copyright (C) 2000,2007 Ronald G. Minnich rminnich@gmail.com -## Copyright (C) 2005 Eswar Nallusamy, LANL -## Copyright (C) 2005 Tyan -## (Written by Yinghai Lu yhlu@tyan.com for Tyan) -## Copyright (C) 2007 coresystems GmbH -## (Written by Stefan Reinauer stepan@coresystems.de for coresystems GmbH) -## Copyright (C) 2007 Advanced Micro Devices, Inc. -## -## 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; version 2 of the License. -## -## 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 -## - -/* Init code - Switch CPU to protected mode and enable Cache-as-Ram. */ - -#include "macros.h" -#include <amd_geodelx.h> - -/* This is where the DCache will be mapped and be used as stack. It would be - * cool if it was the same base as LinuxBIOS normal stack. - */ -#define LX_STACK_BASE DCACHE_RAM_BASE -#define LX_STACK_END LX_STACK_BASE+(DCACHE_RAM_SIZE-4) - -#define LX_NUM_CACHELINES 0x080 /* There are 128 lines per way. */ -#define LX_CACHELINE_SIZE 0x020 /* There are 32 bytes per line. */ -#define LX_CACHEWAY_SIZE (LX_NUM_CACHELINES * LX_CACHELINE_SIZE) -#define CR0_CD 0x40000000 /* Bit 30 = Cache Disable */ -#define CR0_NW 0x20000000 /* Bit 29 = Not Write Through */ - -#define ROM_CODE_SEG 0x08 -#define ROM_DATA_SEG 0x10 - -#define CACHE_RAM_CODE_SEG 0x18 -#define CACHE_RAM_DATA_SEG 0x20 - - .code16 - .globl _stage0 -_stage0: - cli - - /* Save the BIST result. */ - movl %eax, %ebp; - - /* Thanks to kmliu@sis.com.tw for this TLB fix. */ - /* IMMEDIATELY invalidate the translation lookaside buffer before - * executing any further code. Even though paging is disabled we - * could still get false address translations due to the TLB if we - * didn't invalidate it. - */ - - xorl %eax, %eax - movl %eax, %cr3 /* Invalidate TLB */ - - /* Switch to protected mode. */ - - /* NOTE: With GNU assembler version 2.15.94.0.2.2 (i386-redhat-linux) - * using BFD version 2.15.94.0.2.2 20041220 this works fine without - * all the ld hackery and so on. So leave it as is with this comment. - */ - - data32 lgdt %cs:gdtptr - - movl %cr0, %eax - andl $0x7FFAFFD1, %eax /* PG, AM, WP, NE, TS, EM, MP = 0 */ - orl $0x60000001, %eax /* CD, NW, PE = 1 */ - movl %eax, %cr0 - - /* Restore BIST result. */ - movl %ebp, %eax - - // port80_post(0x23) - - /* Now we are in protected mode. Jump to a 32 bit code segment. */ - data32 ljmp $ROM_CODE_SEG, $protected_stage0 - /* I am leaving this weird jump in here in the event that future gas - * bugs force it to be used. - */ - #.byte 0x66 - .code32 - #ljmp $ROM_CODE_SEG, $protected_stage0 - - #.code16 - .align 4 - .globl gdt16 -gdt16 = . - _stage0 -gdt16x: - .word gdt16xend - gdt16x -1 /* Compute the table limit. */ - .long gdt16x - .word 0 - - /* selgdt 0x08, flat code segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0xcf, 0x00 - - /* selgdt 0x10, flat data segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x93, 0xcf, 0x00 -gdt16xend: - - /* From now on we are 32bit. */ - .code32 - - /* We have two gdts where we could have one. That is ok. - * - * Let's not worry about this -- optimizing gdt is pointless since - * we're only in it for a little bit. - * - * BTW note the trick below: The GDT points to ITSELF, and the first - * good descriptor is at offset 8. So you word-align the table, and - * then because you chose 8, you get a nice 64-bit aligned GDT entry, - * which is good as this is the size of the entry. - * - * Just in case you ever wonder why people do this. - */ - .align 4 - .globl gdtptr - .globl gdt_limit -gdt_limit = gdt_end - gdt - 1 /* Compute the table limit. */ - -gdt: -gdtptr: - .word gdt_end - gdt -1 /* Compute the table limit. */ - .long gdt /* We know the offset. */ - .word 0 - - /* selgdt 0x08, flat code segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0xcf, 0x00 - - /* selgdt 0x10, flat data segment */ - .word 0xffff, 0x0000 - .byte 0x00, 0x93, 0xcf, 0x00 - - /* selgdt 0x18, flat code segment for CAR */ - .word 0xffff, 0x0000 - .byte 0x00, 0x9b, 0xcf, 0x00 - - /* selgdt 0x20, flat data segment for CAR */ - .word 0xffff, 0x0000 - .byte 0x00, 0x93, 0xcf, 0x00 -gdt_end: - - /* - * When we come here we are in protected mode. We expand the stack - * and copy the data segment from ROM to the memory. - * - * After that, we call the chipset bootstrap routine that - * does what is left of the chipset initialization. - * - * NOTE: Aligned to 4 so that we are sure that the prefetch - * cache will be reloaded. - */ - - .align 4 - .globl protected_stage0 -protected_stage0: - // This code was used by v2. TODO - lgdt %cs:gdtptr - ljmp $ROM_CODE_SEG, $__protected_stage0 - -.globl __protected_stage0 -__protected_stage0: - /* Save the BIST value. */ - movl %eax, %ebp - - port80_post(0x01) - - movw $ROM_DATA_SEG, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - movw %ax, %fs - movw %ax, %gs - - /* Restore the BIST value to %eax. */ - movl %ebp, %eax - -.align 4 - /* Here begins CAR support. */ - /* This particular code is straight from LinuxBIOS V2. */ - - /* DCacheSetup: Setup data cache for use as RAM for a stack. */ -DCacheSetup: - - invd - /* Set cache properties. */ - movl $CPU_RCONF_DEFAULT, %ecx - rdmsr - /* 1MB system memory in write back 1|00100|00. */ - movl $0x010010000, %eax - wrmsr - - /* In LX DCDIS is set after POR which disables the cache..., clear - * this bit. - */ - movl CPU_DM_CONFIG0,%ecx - rdmsr - /* TODO: Make consistent with i$ init, either whole reg = 0, or just - * this bit... - */ - andl $(~(DM_CONFIG0_LOWER_DCDIS_SET)), %eax - wrmsr - - /* Get cache timing params from BIOS config data locations and apply. */ - /* Fix delay controls for DM and IM arrays. */ - movl $CPU_BC_MSS_ARRAY_CTL0, %ecx - xorl %edx, %edx - movl $0x2814D352, %eax - wrmsr - - movl $CPU_BC_MSS_ARRAY_CTL1, %ecx - xorl %edx, %edx - movl $0x1068334D, %eax - wrmsr - - movl $CPU_BC_MSS_ARRAY_CTL2, %ecx - movl $0x00000106, %edx - movl $0x83104104, %eax - wrmsr - - movl $GLCP_FIFOCTL, %ecx - rdmsr - movl $0x00000005, %edx - wrmsr - - /* Enable setting. */ - movl $CPU_BC_MSS_ARRAY_CTL_ENA, %ecx - xorl %edx, %edx - movl $0x01, %eax - wrmsr - - /* Get cleaned up. */ - xorl %edi, %edi - xorl %esi, %esi - xorl %ebp, %ebp - - /* DCache Ways0 through Ways7 will be tagged for - * LX_STACK_BASE + DCACHE_RAM_SIZE for holding stack. - */ - /* Remember, there is NO stack yet... */ - - /* Tell cache we want to fill Way 0 starting at the top. */ - xorl %edx, %edx - xorl %eax, %eax - movl $CPU_DC_INDEX, %ecx - wrmsr - - /* Startaddress for tag of Way0: ebp will hold the incrementing - * address. dont destroy! - */ - movl $LX_STACK_BASE, %ebp /* Init to start address. */ - /* Set valid bit and tag for this Way (B[31:12] : Cache tag value for - * line/way curr. selected by CPU_DC_INDEX. - */ - orl $1, %ebp - - /* Start tag Ways 0 with 128 lines with 32 bytes each: edi will hold - * the line counter. dont destroy! - */ - movl $LX_NUM_CACHELINES, %edi - -DCacheSetupFillWay: - /* Fill with dummy data: zero it so we can tell it from PCI memory - * space (returns FFs). - */ - /* We will now store a line (32 bytes = 4 x 8 bytes = 4 quad-words). */ - movw $0x04, %si - xorl %edx, %edx - xorl %eax, %eax - movl $CPU_DC_DATA, %ecx - -DCacheSetup_quadWordLoop: - wrmsr - decw %si - jnz DCacheSetup_quadWordLoop - - /* Set the tag for this line, need to do this for every new cache - * line to validate it! - */ - /* Accessing CPU_DC_TAG_I makes the LINE field in CPU_DC_INDEX - * increment and thus continue in the next cache line... - */ - xorl %edx, %edx - movl %ebp, %eax - movl $CPU_DC_TAG, %ecx - wrmsr - - /* Switch to next line. Lines are in Bits10:4. */ - /* When index is crossing 0x7F -> 0x80 writing a RSVD bit as 0x80 is - * not a valid CL anymore! - */ - movl $CPU_DC_INDEX, %ecx - rdmsr - /* TODO: Probably would be more elegant to calculate this from - * counter var edi... - */ - addl $0x010, %eax - wrmsr - - decl %edi - jnz DCacheSetupFillWay - - /* 1 Way has been filled, forward start address for next Way, - * terminate if we have reached end of desired address range. - */ - addl $LX_CACHEWAY_SIZE, %ebp - cmpl $LX_STACK_END, %ebp - jge leave_DCacheSetup - movl $LX_NUM_CACHELINES, %edi - - /* Switch to next way. */ - movl $CPU_DC_INDEX, %ecx - rdmsr - addl $0x01, %eax - /* Let's be sure: reset line index Bits10:4. */ - andl $0xFFFFF80F, %eax - wrmsr - - jmp DCacheSetupFillWay - -leave_DCacheSetup: - xorl %edi, %edi - xorl %esi, %esi - xorl %ebp, %ebp - - /* Disable the cache, but... DO NOT INVALIDATE the tags. */ - /* Memory reads and writes will all hit in the cache. */ - /* Cache updates and memory write-backs will not occur! */ - movl %cr0, %eax - orl $(CR0_CD + CR0_NW), %eax /* Set the CD and NW bits. */ - movl %eax, %cr0 - - /* Now point sp to the cached stack. */ - /* The stack will be fully functional at this location. No system - * memory is required at all! - */ - /* Set up the stack pointer. */ - movl $LX_STACK_END, %eax - movl %eax, %esp - - /* Test the stack. */ - movl $0x0F0F05A5A, %edx - pushl %edx - popl %ecx - cmpl %ecx, %edx - je DCacheSetupGood - movb $0xC5, %al - outb %al, $0x80 - -DCacheSetupBad: - hlt /* Issues */ - jmp DCacheSetupBad - -DCacheSetupGood: - /* If you wanted to maintain the stack in memory you would need to - * set the tags as dirty so the wbinvd would push out the old stack - * contents to memory. - */ - /* Clear the cache, the following code from crt0.S.lb will setup - * a new stack. - */ - wbinvd - - /* At this point, CAR should be working. */ - movl $(LX_STACK_END), %eax - movl %eax, %esp - - /* Load a different set of data segments. */ - movw $CACHE_RAM_DATA_SEG, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - -lout: - /* Restore the BIST result. */ - movl %ebp, %eax - /* We need to set ebp? No need. */ - movl %esp, %ebp - pushl %eax /* BIST */ - call stage1_main - /* We will not go back. */ - -fixed_mtrr_msr: - .long 0x250, 0x258, 0x259 - .long 0x268, 0x269, 0x26A - .long 0x26B, 0x26C, 0x26D - .long 0x26E, 0x26F -var_mtrr_msr: - .long 0x200, 0x201, 0x202, 0x203 - .long 0x204, 0x205, 0x206, 0x207 - .long 0x208, 0x209, 0x20A, 0x20B - .long 0x20C, 0x20D, 0x20E, 0x20F - .long 0x000 /* NULL, end of table */ - -# Reset vector. - -/* - * RVECTOR: size of reset vector, default is 0x10 - * RESRVED: size of vpd code, default is 0xf0 - * BOOTBLK: size of bootblock code, default is 0x1f00 (8k-256b) - */ - -SEGMENT_SIZE = 0x10000 -RVECTOR = 0x00010 - -# Due to YET ANOTHER BUG in GNU bintools, you can NOT have a code16 here. -# I think we should leave it this way forever, as the bugs come and -# go -- and come again. -# .code16 -# .section ".rom.text" -.section ".reset", "ax" - .globl _resetjump -_resetjump: - /* GNU bintools bugs again. This jumps to stage0 - 2. Sigh. */ -# jmp _stage0 - .byte 0xe9 - .int _stage0 - ( . + 2 ) - /* Note: The above jump is hand coded to work around bugs in binutils. - * 5 bytes are used for a 3 byte instruction. This works because x86 - * is little endian and allows us to use supported 32 bit relocations - * instead of the weird 16 bit relocations that binutils does not - * handle consistenly between versions because they are used so rarely. - */ -.byte 0 - -# Date? ID string? We might want to put something else in here. -.ascii DATE - -# Checksum. -#.word 0