From: Marc Jones Date: Fri, 4 May 2007 18:58:42 +0000 (+0000) Subject: This patch adds support for the northbridge integrated into the AMD X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=734daf699ceb8603f53003ab36eb85b8a76e3cf9;p=coreboot.git This patch adds support for the northbridge integrated into the AMD Geode LX platform, including memory and graphics. (rediffed for whitespace) Signed-off-by: Marc Jones Acked-by: Stefan Reinauer git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2630 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- diff --git a/src/northbridge/amd/lx/Config.lb b/src/northbridge/amd/lx/Config.lb index ee8cd206f..dc7c15962 100644 --- a/src/northbridge/amd/lx/Config.lb +++ b/src/northbridge/amd/lx/Config.lb @@ -1,5 +1,4 @@ config chip.h object northbridge.o object northbridgeinit.o -object chipsetinit.o object grphinit.o diff --git a/src/northbridge/amd/lx/chip.h b/src/northbridge/amd/lx/chip.h index 1a237d727..5fa7948c1 100644 --- a/src/northbridge/amd/lx/chip.h +++ b/src/northbridge/amd/lx/chip.h @@ -1,7 +1,12 @@ +/* +* +* Copyright (C) 2007 Advanced Micro Devices +* +*/ + struct northbridge_amd_lx_config { - uint16_t irqmap; - int setupflash; + }; extern struct chip_operations northbridge_amd_lx_ops; diff --git a/src/northbridge/amd/lx/chipsetinit.c b/src/northbridge/amd/lx/chipsetinit.c deleted file mode 100644 index 4e0d32951..000000000 --- a/src/northbridge/amd/lx/chipsetinit.c +++ /dev/null @@ -1,384 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "chip.h" -#include "northbridge.h" -#include -#include -#include - - -/* the structs in this file only set msr.lo. But ... that may not always be true */ - -struct msrinit { - unsigned long msrnum; - msr_t msr; -}; - -/* Master Configuration Register for Bus Masters.*/ -struct msrinit SB_MASTER_CONF_TABLE[] = { - {USB1_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00008f000}}, /* NOTE: Must be 1st entry in table*/ - {USB2_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00008f000}}, - {ATA_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00048f000}}, - {AC97_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00008f000}}, - {MDD_SB_GLD_MSR_CONF, {.hi=0,.lo=0x00000f000}}, -/* GLPCI_SB_GLD_MSR_CONF, 0x0FFFFFFFF*/ -/* GLCP_SB_GLD_MSR_CONF, 0x0FFFFFFFF*/ -/* GLIU_SB_GLD_MSR_CONF, 0x0*/ - {0,{0,0}} -}; - -/* 5535_A3 Clock Gating*/ -struct msrinit CS5535_CLOCK_GATING_TABLE[] = { - { USB1_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - { USB2_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - { GLIU_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}}, - { GLPCI_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - { GLCP_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}}, - { MDD_SB_GLD_MSR_PM, {.hi=0,.lo=0x050554111}}, - { ATA_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - { AC97_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - {0,{0,0}} -}; - -/* 5536 Clock Gating*/ -struct msrinit CS5536_CLOCK_GATING_TABLE[] = { -/* MSR Setting*/ - { GLIU_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}}, - { GLPCI_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - { GLCP_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000004}}, - { MDD_SB_GLD_MSR_PM, {.hi=0,.lo=0x050554111}}, /* SMBus clock gating errata (PBZ 2226 & SiBZ 3977)*/ - { ATA_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - { AC97_SB_GLD_MSR_PM, {.hi=0,.lo=0x000000005}}, - {0,{0,0}} -}; - -struct acpiinit { - unsigned short ioreg; - unsigned long regdata; - unsigned short iolen; -}; - -struct acpiinit acpi_init_table[] = { - {ACPI_BASE+0x00, 0x01000000, 4}, - {ACPI_BASE+0x08, 0, 4}, - {ACPI_BASE+0x0C, 0, 4}, - {ACPI_BASE+0x1C, 0, 4}, - {ACPI_BASE+0x18, 0x0FFFFFFFF, 4}, - {ACPI_BASE+0x00, 0x0000FFFF, 4}, - - {PM_SCLK, 0x000000E00, 4}, - {PM_SED, 0x000004601, 4}, - {PM_SIDD, 0x000008C02, 4}, - {PM_WKD, 0x0000000A0, 4}, - {PM_WKXD, 0x0000000A0, 4}, - {0,0,0} -}; - -/* return 1 if we are a 5536-based system */ -static int is_5536(void){ - msr_t msr; - msr = rdmsr(GLIU_SB_GLD_MSR_CAP); - msr.lo >>= 20; - printk_debug("is_5536: msr.lo is 0x%x(==5 means 5536)\n", msr.lo&0xf); - return ((msr.lo&0xf) == 5); -} -/* ***************************************************************************/ -/* **/ -/* * pmChipsetInit*/ -/* **/ -/* * Program ACPI LBAR and initialize ACPI registers.*/ -/* * */ -/* **/ -/* * Entry:*/ -/* * None*/ -/* **/ -/* * Exit:*/ -/* * None*/ -/* **/ -/* * Destroys:*/ -/* * None*/ -/* **/ -/* ***************************************************************************/ -static void -pmChipsetInit(void) { - unsigned long val = 0; - unsigned short port; - - port = (PMLogic_BASE + 0x010); - val = 0x0E00 ; /* 1ms*/ - outl(val, port); - - /* PM_WKXD*/ - /* Make sure bits[3:0]=0000b to clear the*/ - /* saved Sx state*/ - port = (PMLogic_BASE + 0x034); - val = 0x0A0 ; /* 5ms*/ - outl(val, port); - - /* PM_WKD*/ - port = (PMLogic_BASE + 0x030); - outl(val, port); - - /* PM_SED*/ - port = (PMLogic_BASE + 0x014); -/* mov eax, 0x057642 ; 100ms, works*/ - val = 0x04601 ; /* 5ms*/ - outl(val, port); - - /* PM_SIDD*/ - port = (PMLogic_BASE + 0x020); -/* mov eax, 0x0AEC84 ; 200ms, works*/ - val = 0x08C02 ; /* 10ms*/ - outl(val, port); - - /* GPIO24 OUT_AUX1 function is the external signal for 5535's vsb_working_aux*/ - /* which is de-asserted when 5535 enters Standby(S3 or S5) state.*/ - /* On Hawk, GPIO24 controls all voltage rails except Vmem and Vstandby. This means*/ - /* GX2 will be fully de-powered if this control de-asserts in S3/S5.*/ - /* */ - /* GPIO24 is setup in preChipsetInit for two reasons*/ - /* 1. GPIO24 at reset defaults to disabled, since this signal is vsb_work_aux on*/ - /* Hawk it controls the FET's for all voltage rails except Vstanby & Vmem.*/ - /* BIOS needs to enable GPIO24 as OUT_AUX1 & OUTPUT_EN early so it is driven*/ - /* by 5535.*/ - /* 2. Non-PM builds will require GPIO24 enabled for instant-off power button*/ - /* */ - - /* GPIO11 OUT_AUX1 function is the external signal for 5535's slp_clk_n which is asserted*/ - /* when 5535 enters Sleep(S1) state.*/ - /* On Hawk, GPIO11 is connected to control input of external clock generator*/ - /* for 14MHz, PCI, USB & LPC clocks.*/ - /* Programming of GPIO11 will be done by VSA PM code. During VSA Init. BIOS writes*/ - /* PM Core Virual Register indicating if S1 Clocks should be On or Off. This is based*/ - /* on a Setup item. We do not want to leave GPIO11 enabled because of a Hawk board*/ - /* problem. With GPIO11 enabled in S3, something is back-driving GPIO11 causing it to*/ - /* float to 1.6-1.7V.*/ - -} - -struct FLASH_DEVICE { - unsigned char fType; /* Flash type: NOR or NAND */ - unsigned char fInterface; /* Flash interface: I/O or Memory */ - unsigned long fMask; /* Flash size/mask */ -}; - -struct FLASH_DEVICE FlashInitTable[] = { - { FLASH_TYPE_NAND, FLASH_IF_MEM, FLASH_MEM_4K }, /* CS0, or Flash Device 0 */ - { FLASH_TYPE_NONE, 0, 0 }, /* CS1, or Flash Device 1 */ - { FLASH_TYPE_NONE, 0, 0 }, /* CS2, or Flash Device 2 */ - { FLASH_TYPE_NONE, 0, 0 }, /* CS3, or Flash Device 3 */ -}; - -#define FlashInitTableLen (sizeof(FlashInitTable)/sizeof(FlashInitTable[0])) - -uint32_t FlashPort[] = { - MDD_LBAR_FLSH0, - MDD_LBAR_FLSH1, - MDD_LBAR_FLSH2, - MDD_LBAR_FLSH3 - }; - -/*************************************************************************** - * - * ChipsetFlashSetup - * - * Flash LBARs need to be setup before VSA init so the PCI BARs have - * correct size info. Call this routine only if flash needs to be - * configured (don't call it if you want IDE). - * - * Entry: - * Exit: - * Destroys: - * - **************************************************************************/ -static void ChipsetFlashSetup(void) -{ - msr_t msr; - int i; - int numEnabled = 0; - - printk_debug("ChipsetFlashSetup++\n"); - for (i = 0; i < FlashInitTableLen; i++) { - if (FlashInitTable[i].fType != FLASH_TYPE_NONE) { - printk_debug("Enable CS%d\n", i); - /* we need to configure the memory/IO mask */ - msr = rdmsr(FlashPort[i]); - msr.hi = 0; /* start with the "enabled" bit clear */ - if (FlashInitTable[i].fType == FLASH_TYPE_NAND) - msr.hi |= 0x00000002; - else - msr.hi &= ~0x00000002; - if (FlashInitTable[i].fInterface == FLASH_IF_MEM) - msr.hi |= 0x00000004; - else - msr.hi &= ~0x00000004; - msr.hi |= FlashInitTable[i].fMask; - printk_debug("WRMSR(0x%08X, %08X_%08X)\n", FlashPort[i], msr.hi, msr.lo); - wrmsr(FlashPort[i], msr); - - /* now write-enable the device */ - msr = rdmsr(MDD_NORF_CNTRL); - msr.lo |= (1 << i); - printk_debug("WRMSR(0x%08X, %08X_%08X)\n", MDD_NORF_CNTRL, msr.hi, msr.lo); - wrmsr(MDD_NORF_CNTRL, msr); - - /* update the number enabled */ - numEnabled++; - } - } - - /* enable the flash */ - if (0 != numEnabled) { - msr = rdmsr(MDD_PIN_OPT); - msr.lo &= ~1; /* PIN_OPT_IDE */ - printk_debug("WRMSR(0x%08X, %08X_%08X)\n", MDD_PIN_OPT, msr.hi, msr.lo); - wrmsr(MDD_PIN_OPT, msr); - } - printk_debug("ChipsetFlashSetup--\n"); - -} - - - -/* ***************************************************************************/ -/* **/ -/* * ChipsetGeodeLinkInit*/ -/* * Handle chipset specific GeodeLink settings here. */ -/* * Called from GeodeLink init code.*/ -/* **/ -/* * Entry:*/ -/* * Exit:*/ -/* * Destroys: GS*/ -/* **/ -/* ***************************************************************************/ -static void -ChipsetGeodeLinkInit(void){ - msr_t msr; - unsigned long msrnum; - unsigned long totalmem; - - if (is_5536()) - return; - /* SWASIF for A1 DMA */ - /* Set all memory to "just above systop" PCI so DMA will work*/ - /* check A1*/ - msrnum = MSR_SB_GLCP + 0x17; - msr = rdmsr(msrnum); - if ((msr.lo&0xff) == 0x11) - return; - - totalmem = (sizeram() << 20) - 1; - totalmem >>= 12; - totalmem = ~totalmem; - totalmem &= 0xfffff; - msr.lo = totalmem; - msr.hi = 0x20000000; /* Port 1 (PCI)*/ - msrnum = MSR_SB_GLIU + 0x20; /* */; - wrmsr(msrnum, msr); -} - -void -chipsetinit (struct northbridge_amd_lx_config *nb){ - msr_t msr; - struct msrinit *csi; - int i; - unsigned long msrnum; - - outb( P80_CHIPSET_INIT, 0x80); - ChipsetGeodeLinkInit(); -#if 0 - /* we hope NEVER to be in linuxbios when S3 resumes - if (! IsS3Resume()) */ - { - struct acpiinit *aci = acpi_init_table; - while (aci->ioreg){ - if (aci->iolen == 2) { - outw(aci->regdata, aci->ioreg); - inw(aci->ioreg); - } else { - outl(aci->regdata, aci->ioreg); - inl(aci->ioreg); - } - } - - pmChipsetInit(); - } -#endif - - - if (!is_5536()) { - /* Setup USB. Need more details. #118.18*/ - msrnum = MSR_SB_USB1 + 8; - msr.lo = 0x00012090; - msr.hi = 0; - wrmsr(msrnum, msr); - msrnum = MSR_SB_USB2 + 8; - wrmsr(msrnum, msr); - } - - /* set hd IRQ */ - outl (GPIOL_2_SET, GPIOL_INPUT_ENABLE); - outl (GPIOL_2_SET, GPIOL_IN_AUX1_SELECT); - - /* Allow IO read and writes during a ATA DMA operation.*/ - /* This could be done in the HD rom but do it here for easier debugging.*/ - - msrnum = ATA_SB_GLD_MSR_ERR; - msr = rdmsr(msrnum); - msr.lo &= ~0x100; - wrmsr(msrnum, msr); - - /* Enable Post Primary IDE.*/ - msrnum = GLPCI_SB_CTRL; - msr = rdmsr(msrnum); - msr.lo |= GLPCI_CRTL_PPIDE_SET; - wrmsr(msrnum, msr); - - - /* Set up Master Configuration Register*/ - /* If 5536, use same master config settings as 5535, except for OHCI MSRs*/ - if (is_5536()) - i = 2; - else - i = 0; - - csi = &SB_MASTER_CONF_TABLE[i]; - for(; csi->msrnum; csi++){ - msr.lo = csi->msr.lo; - msr.hi = csi->msr.hi; - wrmsr(csi->msrnum, msr); // MSR - see table above - } - - - /* Flash Setup*/ - printk_err("%sDOING ChipsetFlashSetup()!!!!!!!!!!!!!!!!!!\n", nb->setupflash? " " : "NOT"); - if (nb->setupflash) - ChipsetFlashSetup(); - - - - /* */ - /* Set up Hardware Clock Gating*/ - /* */ - /* if (getnvram(TOKEN_SB_CLK_GATE) != TVALUE_DISABLE) */ - { - if (is_5536()) - csi = CS5536_CLOCK_GATING_TABLE; - else - csi = CS5535_CLOCK_GATING_TABLE; - - for(; csi->msrnum; csi++){ - msr.lo = csi->msr.lo; - msr.hi = csi->msr.hi; - wrmsr(csi->msrnum, msr); // MSR - see table above - } - } - -} diff --git a/src/northbridge/amd/lx/grphinit.c b/src/northbridge/amd/lx/grphinit.c index af9e9fef4..038ee8d53 100644 --- a/src/northbridge/amd/lx/grphinit.c +++ b/src/northbridge/amd/lx/grphinit.c @@ -1,33 +1,16 @@ +/* +* +* Copyright (C) 2007 Advanced Micro Devices +* +*/ + #include #include #include #include -/* - * Write to a Virtual Register - * AX = Class/Index - * CX = data to write - */ -void vrWrite(uint16_t wClassIndex, uint16_t wData) -{ - outl(((uint32_t) VR_UNLOCK << 16) | wClassIndex, VRC_INDEX); - outw(wData, VRC_DATA); -} /* - * Read from a Virtual Register - * AX = Class/Index - * Returns a 16-bit word of data - */ -uint16_t vrRead(uint16_t wClassIndex) -{ - uint16_t wData; - outl(((uint32_t) VR_UNLOCK << 16) | wClassIndex, VRC_INDEX); - wData = inw(VRC_DATA); - return wData; -} - -/* * This function mirrors the Graphics_Init routine in GeodeROM. */ void graphics_init(void) @@ -40,7 +23,7 @@ void graphics_init(void) /* Call SoftVG with the main configuration parameters. */ /* NOTE: SoftVG expects the memory size to be given in 2MB blocks */ - wClassIndex = (VRC_VG << 8) + VG_MEM_SIZE; + wClassIndex = (VRC_VG << 8) + VG_CONFIG; /* * Graphics Driver Enabled (13) 0, NO (lets BIOS controls the GP) @@ -52,12 +35,12 @@ void graphics_init(void) * PLL Reference Clock Bypass(0) 0, Default */ - /* video RAM has to be given in 2MB chunks + /* Video RAM has to be given in 2MB chunks * the value is read @ 7:1 (value in 7:0 looks like /2) * so we can add the real value in megabytes */ - wData = 0x0800 | (CONFIG_VIDEO_MB & VG_MEM_MASK); + wData = VG_CFG_DRIVER | VG_CFG_PRIORITY | VG_CFG_DSCRT | (CONFIG_VIDEO_MB & VG_MEM_MASK); vrWrite(wClassIndex, wData); res = vrRead(wClassIndex); diff --git a/src/northbridge/amd/lx/northbridge.c b/src/northbridge/amd/lx/northbridge.c index b014118da..88dfe1252 100644 --- a/src/northbridge/amd/lx/northbridge.c +++ b/src/northbridge/amd/lx/northbridge.c @@ -1,3 +1,9 @@ +/* +* +* Copyright (C) 2007 Advanced Micro Devices +* +*/ + #include #include #include @@ -7,13 +13,13 @@ #include #include #include -#include "chip.h" -#include "northbridge.h" #include #include #include #include #include +#include "chip.h" +#include "northbridge.h" /* here is programming for the various MSRs.*/ @@ -56,9 +62,11 @@ extern void graphics_init(void); extern void cpubug(void); +extern void chipsetinit(void); +extern void print_conf(void); +extern uint32_t get_systop(void); void northbridge_init_early(void); -void chipsetinit(struct northbridge_amd_lx_config *nb); void setup_realmode_idt(void); void do_vsmbios(void); @@ -97,309 +105,42 @@ struct msr_defaults { /* todo: add a resource record. We don't do this here because this may be called when * very little of the platform is actually working. */ -int -sizeram(void) +int sizeram(void) { msr_t msr; int sizem = 0; unsigned short dimm; - msr = rdmsr(0x20000018); - printk_debug("sizeram: %08x:%08x\n", msr.hi, msr.lo); + msr = rdmsr(MC_CF07_DATA); + printk_debug("sizeram: _MSR MC_CF07_DATA: %08x:%08x\n", msr.hi, msr.lo); /* dimm 0 */ dimm = msr.hi; - sizem = (1 << ((dimm >> 12)-1)) * 8; - + /* installed? */ + if ((dimm & 7) != 7){ + sizem = 4 << ((dimm >> 12) & 0x0F); + } /* dimm 1*/ dimm = msr.hi >> 16; /* installed? */ - if ((dimm & 7) != 7) - sizem += (1 << ((dimm >> 12)-1)) * 8; + if ((dimm & 7) != 7){ + sizem += 4 << ((dimm >> 12) & 0x0F); + } - printk_debug("sizeram: sizem 0x%x\n", sizem); + printk_debug("sizeram: sizem 0x%xMB\n", sizem); return sizem; } -/* note that dev is NOT used -- yet */ -static void irq_init_steering(struct device *dev, uint16_t irq_map) { - /* Set up IRQ steering */ - uint32_t pciAddr = 0x80000000 | (CHIPSET_DEV_NUM << 11) | 0x5C; - - printk_debug("%s(%08X [%08X], %04X)\n", __FUNCTION__, dev, pciAddr, irq_map); - - /* The IRQ steering values (in hex) are effectively dcba, where: - * represents the IRQ for INTA, - * represents the IRQ for INTB, - * represents the IRQ for INTC, and - * represents the IRQ for INTD. - * Thus, a value of irq_map = 0xAA5B translates to: - * INTA = IRQB (IRQ 11) - * INTB = IRQ5 (IRQ 5) - * INTC = IRQA (IRQ 10) - * INTD = IRQA (IRQ 10) - */ - outl(pciAddr & ~3, 0xCF8); - outl(irq_map, 0xCFC); -} -/* - * setup_lx_cache - * - * Returns the amount of memory (in KB) available to the system. This is the - * total amount of memory less the amount of memory reserved for SMM use. - * - */ -static int -setup_lx_cache(void) -{ - msr_t msr; - unsigned long long val; - int sizekbytes, sizereg; - - sizekbytes = sizeram() * 1024; - printk_debug("setup_lx_cache: enable for %d KB\n", sizekbytes); - /* build up the rconf word. */ - /* the SYSTOP bits 27:8 are actually the top bits from 31:12. Book fails to say that */ - /* set romrp */ - val = ((unsigned long long) ROM_PROPERTIES) << 56; - /* make rom base useful for 1M roms */ - /* Flash base address -- sized for 1M for now*/ - val |= ((unsigned long long) 0xfff00)<<36; - /* set the devrp properties */ - val |= ((unsigned long long) DEVICE_PROPERTIES) << 28; - /* Take our TOM, RIGHT shift 12, since it page-aligned, then LEFT-shift 8 for reg. */ - /* yank off memory for the SMM handler */ - sizekbytes -= SMM_SIZE; - sizereg = sizekbytes; - sizereg >>= 2; - sizereg <<= 8; - val |= sizereg; - val |= RAM_PROPERTIES; - msr.lo = val; - msr.hi = (val >> 32); - - // GX3 - //msr.hi = 0x04FFFC02; - //msr.lo = 0x1077BE00; - - //sizekbytes = 122616; - - printk_debug("msr 0x%08X will be set to %08x:%08x\n", CPU_RCONF_DEFAULT, msr.hi, msr.lo); - wrmsr(CPU_RCONF_DEFAULT, msr); - - enable_cache(); - wbinvd(); - return sizekbytes; -} - -/* we have to do this here. We have not found a nicer way to do it */ -void -setup_lx(void) -{ - - unsigned long tmp, tmp2; - msr_t msr; - unsigned long size_kb, membytes; - - size_kb = setup_lx_cache(); - -#if 0 // andrei: this is done in northbridge.c SMMGL0Init and SystemInit! - membytes = size_kb * 1024; - /* NOTE! setup_lx_cache returns the SIZE OF RAM - RAMADJUST! - * so it is safe to use. You should NOT at this point call - * sizeram() directly. - */ - - /* we need to set 0x10000028 and 0x40000029 */ - /* - * These two descriptors cover the range from 1 MB (0x100000) to - * SYSTOP (a.k.a. TOM, or Top of Memory) - */ - - - /* fixme: SMM MSR 0x10000026 and 0x400000023 */ - /* calculate the OFFSET field */ - tmp = membytes - SMM_OFFSET; - tmp >>= 12; - tmp <<= 8; - tmp |= 0x20000000; - tmp |= (SMM_OFFSET >> 24); - - /* calculate the PBASE and PMASK fields */ - tmp2 = (SMM_OFFSET << 8) & 0xFFF00000; /* shift right 12 then left 20 == left 8 */ - tmp2 |= (((~(SMM_SIZE * 1024) + 1) >> 12) & 0xfffff); - printk_debug("MSR 0x%x is now 0x%x:0x%x\n", 0x10000026, tmp, tmp2); - msr.hi = tmp; - msr.lo = tmp2; - wrmsr(0x10000026, msr); -#endif -} - static void enable_shadow(device_t dev) { } -void print_conf(void) { - int i; - unsigned long iol; - msr_t msr; - - int cpu_msr_defs[] = { L2_CONFIG_MSR, CPU_IM_CONFIG, - CPU_DM_CONFIG0, CPU_DM_CONFIG1, CPU_DM_PFLOCK, CPU_RCONF_DEFAULT, - CPU_RCONF_BYPASS, CPU_RCONF_A0_BF, CPU_RCONF_C0_DF, CPU_RCONF_E0_FF, - CPU_RCONF_SMM, CPU_RCONF_DMM, GLCP_DELAY_CONTROLS, GL_END - }; - - int gliu0_msr_defs[] = {MSR_GLIU0_BASE1, MSR_GLIU0_BASE2, MSR_GLIU0_BASE3, MSR_GLIU0_BASE4, MSR_GLIU0_BASE5, MSR_GLIU0_BASE6, - GLIU0_P2D_BMO_0, GLIU0_P2D_BMO_1, MSR_GLIU0_SYSMEM, - GLIU0_P2D_RO_0, GLIU0_P2D_RO_1, GLIU0_P2D_RO_2, MSR_GLIU0_SHADOW, - GLIU0_IOD_BM_0, GLIU0_IOD_BM_1, GLIU0_IOD_BM_2, - GLIU0_IOD_SC_0, GLIU0_IOD_SC_1, GLIU0_IOD_SC_2, GLIU0_IOD_SC_3, GLIU0_IOD_SC_4, GLIU0_IOD_SC_5, - GLIU0_GLD_MSR_COH, GL_END - }; - - int gliu1_msr_defs[] = {MSR_GLIU1_BASE1, MSR_GLIU1_BASE2, MSR_GLIU1_BASE3, MSR_GLIU1_BASE4, MSR_GLIU1_BASE5, MSR_GLIU1_BASE6, - MSR_GLIU1_BASE7, MSR_GLIU1_BASE8, MSR_GLIU1_BASE9, MSR_GLIU1_BASE10, - GLIU1_P2D_R_0, GLIU1_P2D_R_1, GLIU1_P2D_R_2, GLIU1_P2D_R_3, MSR_GLIU1_SHADOW, - GLIU1_IOD_BM_0, GLIU1_IOD_BM_1, GLIU1_IOD_BM_2, - GLIU1_IOD_SC_0, GLIU1_IOD_SC_1, GLIU1_IOD_SC_2, GLIU1_IOD_SC_3, - GLIU1_GLD_MSR_COH, GL_END - }; - - int rconf_msr[] = { CPU_RCONF0, CPU_RCONF1, CPU_RCONF2, CPU_RCONF3, CPU_RCONF4, - CPU_RCONF5, CPU_RCONF6, CPU_RCONF7, GL_END - }; - - int cs5536_msr[] = { MDD_LBAR_GPIO, MDD_LBAR_FLSH0, MDD_LBAR_FLSH1, MDD_LEG_IO, MDD_PIN_OPT, - MDD_IRQM_ZLOW, MDD_IRQM_ZHIGH, MDD_IRQM_PRIM, GL_END - }; - - int pci_msr[] = { GLPCI_CTRL, GLPCI_ARB, GLPCI_REN, GLPCI_A0_BF, GLPCI_C0_DF, GLPCI_E0_FF, - GLPCI_RC0, GLPCI_RC1, GLPCI_RC2, GLPCI_RC3, GLPCI_EXT_MSR, GLPCI_SPARE, - GL_END - }; - - int dma_msr[] = { MDD_DMA_MAP, MDD_DMA_SHAD1, MDD_DMA_SHAD2, MDD_DMA_SHAD3, MDD_DMA_SHAD4, - MDD_DMA_SHAD5, MDD_DMA_SHAD6, MDD_DMA_SHAD7, MDD_DMA_SHAD8, - MDD_DMA_SHAD9, GL_END - }; - - - printk_debug("---------- CPU ------------\n"); - - for(i = 0; cpu_msr_defs[i] != GL_END; i++) { - msr = rdmsr(cpu_msr_defs[i]); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", cpu_msr_defs[i], msr.hi, msr.lo); - } - - printk_debug("---------- GLIU 0 ------------\n"); - - for(i = 0; gliu0_msr_defs[i] != GL_END; i++) { - msr = rdmsr(gliu0_msr_defs[i]); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", gliu0_msr_defs[i], msr.hi, msr.lo); - } - - printk_debug("---------- GLIU 1 ------------\n"); - - for(i = 0; gliu1_msr_defs[i] != GL_END; i++) { - msr = rdmsr(gliu1_msr_defs[i]); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", gliu1_msr_defs[i], msr.hi, msr.lo); - } - - printk_debug("---------- RCONF ------------\n"); - - for(i = 0; rconf_msr[i] != GL_END; i++) { - msr = rdmsr(rconf_msr[i]); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", rconf_msr[i], msr.hi, msr.lo); - } - - printk_debug("---------- VARIA ------------\n"); - msr = rdmsr(0x51300010); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", 0x51300010, msr.hi, msr.lo); - - msr = rdmsr(0x51400015); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", 0x51400015, msr.hi, msr.lo); - - printk_debug("---------- DIVIL IRQ ------------\n"); - msr = rdmsr(MDD_IRQM_YLOW); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", MDD_IRQM_YLOW, msr.hi, msr.lo); - msr = rdmsr(MDD_IRQM_YHIGH); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", MDD_IRQM_YHIGH, msr.hi, msr.lo); - msr = rdmsr(MDD_IRQM_ZLOW); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", MDD_IRQM_ZLOW, msr.hi, msr.lo); - msr = rdmsr(MDD_IRQM_ZHIGH); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", MDD_IRQM_ZHIGH, msr.hi, msr.lo); - - - printk_debug("---------- PCI ------------\n"); - - for(i = 0; pci_msr[i] != GL_END; i++) { - msr = rdmsr(pci_msr[i]); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", pci_msr[i], msr.hi, msr.lo); - } - - printk_debug("---------- LPC/UART DMA ------------\n"); - - for(i = 0; dma_msr[i] != GL_END; i++) { - msr = rdmsr(dma_msr[i]); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", dma_msr[i], msr.hi, msr.lo); - } - - printk_debug("---------- CS5536 ------------\n"); - - for(i = 0; cs5536_msr[i] != GL_END; i++) { - msr = rdmsr(cs5536_msr[i]); - printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", cs5536_msr[i], msr.hi, msr.lo); - } - - iol = inl(GPIOL_INPUT_ENABLE); - printk_debug("IOR 0x%08X is now 0x%08X\n", GPIOL_INPUT_ENABLE, iol); - iol = inl(GPIOL_EVENTS_ENABLE); - printk_debug("IOR 0x%08X is now 0x%08X\n", GPIOL_EVENTS_ENABLE, iol); - iol = inl(GPIOL_INPUT_INVERT_ENABLE); - printk_debug("IOR 0x%08X is now 0x%08X\n", GPIOL_INPUT_INVERT_ENABLE, iol); - iol = inl(GPIO_MAPPER_X); - printk_debug("IOR 0x%08X is now 0x%08X\n", GPIO_MAPPER_X, iol); - -} - -static void enable_L2_cache(void) { - msr_t msr; - - /* Instruction Memory Configuration register - * set EBE bit, required when L2 cache is enabled - */ - msr = rdmsr(CPU_IM_CONFIG); - msr.lo |= 0x400; - wrmsr(CPU_IM_CONFIG, msr); - - /* Data Memory Subsystem Configuration register - * set EVCTONRPL bit, required when L2 cache is enabled in victim mode - */ - msr = rdmsr(CPU_DM_CONFIG0); - msr.lo |= 0x4000; - wrmsr(CPU_DM_CONFIG0, msr); - - /* invalidate L2 cache */ - msr.hi = 0x00; - msr.lo = 0x10; - wrmsr(L2_CONFIG_MSR, msr); - - /* Enable L2 cache */ - msr.hi = 0x00; - msr.lo = 0x0f; - wrmsr(L2_CONFIG_MSR, msr); - - printk_debug("L2 cache enabled\n"); -} - static void northbridge_init(device_t dev) { //msr_t msr; - struct northbridge_amd_lx_config *nb = (struct northbridge_amd_lx_config *)dev->chip_info; printk_spew(">> Entering northbridge.c: %s\n", __FUNCTION__); @@ -412,8 +153,6 @@ static void northbridge_init(device_t dev) //msr.hi |= 0x3; //msr.lo |= 0x30000; -// not needed (also irq steering is in legacy vsm so it wouldnt work either) -// irq_init_steering(dev, nb->irqmap); //printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU0_SHADOW, msr.hi, msr.lo); //printk_debug("MSR 0x%08X is now 0x%08X:0x%08X\n", MSR_GLIU1_SHADOW, msr.hi, msr.lo); @@ -521,7 +260,7 @@ static void pci_domain_set_resources(device_t dev) /* Report the memory regions */ idx = 10; ram_resource(dev, idx++, 0, 640); - ram_resource(dev, idx++, 1024, ((sizeram() - CONFIG_VIDEO_MB) * 1024) - SMM_SIZE - 1024); + ram_resource(dev, idx++, 1024, (get_systop()- 0x100000)/1024 ); // Systop - 1 MB -> KB } assign_resources(&dev->link[0]); @@ -529,25 +268,23 @@ static void pci_domain_set_resources(device_t dev) static void pci_domain_enable(device_t dev) { - struct northbridge_amd_lx_config *nb = (struct northbridge_amd_lx_config *)dev->chip_info; printk_spew(">> Entering northbridge.c: %s\n", __FUNCTION__); // do this here for now -- this chip really breaks our device model - enable_L2_cache(); northbridge_init_early(); cpubug(); - chipsetinit(nb); - setup_lx(); + chipsetinit(); + setup_realmode_idt(); printk_debug("Before VSA:\n"); - print_conf(); + // print_conf(); do_vsmbios(); // do the magic stuff here, so prepare your tambourine ;) printk_debug("After VSA:\n"); - print_conf(); + // print_conf(); graphics_init(); pci_set_method(dev); diff --git a/src/northbridge/amd/lx/northbridgeinit.c b/src/northbridge/amd/lx/northbridgeinit.c index 21d2736bc..52fab514a 100644 --- a/src/northbridge/amd/lx/northbridgeinit.c +++ b/src/northbridge/amd/lx/northbridgeinit.c @@ -1,3 +1,9 @@ +/* +* +* Copyright (C) 2007 Advanced Micro Devices +* +*/ + #include #include #include @@ -13,7 +19,6 @@ #include #include -/* put this here for now, we are not sure where it belongs */ struct gliutable { unsigned long desc_name; @@ -36,9 +41,10 @@ struct gliutable gliu1table[] = { {.desc_name=MSR_GLIU1_BASE1,.desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= 0x0FFF80}, /* 0-7FFFF to MC*/ {.desc_name=MSR_GLIU1_BASE2,.desc_type= BM,.hi= MSR_GL0 + 0x0,.lo= (0x80 << 20) +0x0FFFE0}, /* 80000-9ffff to Mc*/ {.desc_name=MSR_GLIU1_SHADOW,.desc_type= SC_SHADOW,.hi= MSR_GL0 + 0x0,.lo= 0x03}, /* C0000-Fffff split to MC and PCI (sub decode)*/ - {.desc_name=MSR_GLIU1_SYSMEM,.desc_type= R_SYSMEM,.hi= MSR_GL0,.lo= 0x0}, /* Cat0xc and fix dynamicly.*/ - {.desc_name=MSR_GLIU1_SMM,.desc_type= BM_SMM,.hi= MSR_GL0,.lo= 0x0}, /* Cat0xc and fix dynamicly.*/ + {.desc_name=MSR_GLIU1_SYSMEM,.desc_type= R_SYSMEM,.hi= MSR_GL0,.lo= 0x0}, /* Catch and fix dynamicly.*/ + {.desc_name=MSR_GLIU1_SMM,.desc_type= BM_SMM,.hi= MSR_GL0,.lo= 0x0}, /* Catch and fix dynamicly.*/ {.desc_name=GLIU1_GLD_MSR_COH,.desc_type= OTHER,.hi= 0x0,.lo= GL1_GLIU0}, + {.desc_name=MSR_GLIU1_FPU_TRAP,.desc_type= SCIO,.hi= (GL1_GLCP << 29) + 0x0,.lo= 0x033000F0}, /* FooGlue FPU 0xF0*/ {.desc_name=GL_END,.desc_type= GL_END,.hi= 0x0,.lo= 0x0}, }; @@ -51,54 +57,36 @@ struct msrinit { struct msrinit ClockGatingDefault [] = { {GLIU0_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}}, - /* MC must stay off in SDR mode. It is turned on in CPUBug??? lotus #77.142*/ - {MC_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, - {GLIU1_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}}, - {VG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, /* lotus #77.163*/ + {MC_GLD_MSR_PM, {.hi=0x00,.lo=0x0001}}, + {VG_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}}, {GP_GLD_MSR_PM, {.hi=0x00,.lo=0x0001}}, - /*{DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0155}},*/ //GX3 - {GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}}, + {DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0555}}, + {GLIU1_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}}, + {GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0014}}, {GLPCI_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}}, - /*{FG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, */ /* Always on*/ //GX3 + {VIP_GLD_MSR_PM, {.hi=0x00,.lo=0x0005}}, + {AES_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}}, + {CPU_BC_PMODE_MSR, {.hi=0x00,.lo=0x70303}}, {0xffffffff, {0xffffffff, 0xffffffff}}, }; - /* All On*/ -struct msrinit ClockGatingAllOn[] = { - {GLIU0_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}}, - {MC_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}}, - {GLIU1_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}}, - {VG_GLD_MSR_PM, {.hi=0x00, .lo=0x00}}, - {GP_GLD_MSR_PM, {.hi=0x00,.lo=0x000000001}}, - /*{DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}}, */ //GX3 - {GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}}, - {GLPCI_GLD_MSR_PM, {.hi=0x00,.lo=0x0FFFFFFFF}}, - /*{FG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, */ //GX3 - {0xffffffff, {0xffffffff, 0xffffffff}}, -}; - /* Performance*/ -struct msrinit ClockGatingPerformance[] = { - {VG_GLD_MSR_PM, {.hi=0x00,.lo=0x0000}}, /* lotus #77.163*/ - {GP_GLD_MSR_PM, {.hi=0x00,.lo=0x0001}}, - /*{DF_GLD_MSR_PM, {.hi=0x00,.lo=0x0155}}, */ //GX3 - {GLCP_GLD_MSR_PM, {.hi=0x00,.lo=0x0015}}, - {0xffffffff, {0xffffffff, 0xffffffff}}, -}; /* */ /* SET GeodeLink PRIORITY*/ /* */ struct msrinit GeodeLinkPriorityTable [] = { - {CPU_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0220}}, /* CPU Priority.*/ - /*{DF_GLD_MSR_MASTER_CONF, {.hi=0x00,.lo=0x0000}},*/ /* DF Priority.*/ //GX3 - {VG_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0720}}, /* VG Primary and Secondary Priority.*/ - {GP_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0010}}, /* Graphics Priority.*/ - {GLPCI_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0027}}, /* GLPCI Priority + PID*/ - {GLCP_GLD_MSR_CONF, {.hi=0x00,.lo=0x0001}}, /* GLCP Priority + PID*/ - {VIP_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0622}}, /* VIP PID*/ - {AES_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0013}}, /* AES PID*/ + {CPU_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0220}}, + {DF_GLD_MSR_MASTER_CONF, {.hi=0x00,.lo=0x0000}}, + {VG_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0720}}, + {GP_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0010}}, + {GLPCI_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0017}}, + {GLCP_GLD_MSR_CONF, {.hi=0x00,.lo=0x0001}}, + {VIP_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0622}}, + {AES_GLD_MSR_CONFIG, {.hi=0x00,.lo=0x0013}}, {0x0FFFFFFFF, {0x0FFFFFFFF, 0x0FFFFFFFF}}, /* END*/ }; +extern int sizeram(void); + static void writeglmsr(struct gliutable *gl){ msr_t msr; @@ -106,10 +94,7 @@ writeglmsr(struct gliutable *gl){ msr.lo = gl->lo; msr.hi = gl->hi; wrmsr(gl->desc_name, msr); // MSR - see table above - // printk_debug("%s: write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo); //GX3 - /* they do this, so we do this */ - msr = rdmsr(gl->desc_name); - // printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo); // GX3 + printk_debug("%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo); // GX3 } static void @@ -124,14 +109,8 @@ ShadowInit(struct gliutable *gl) } } -/* NOTE: transcribed from assembly code. There is the usual redundant assembly nonsense in here. - * CLEAN ME UP - */ -/* yes, this duplicates later code, but it seems that is how they want it done. - */ extern int sizeram(void); -static void -SysmemInit(struct gliutable *gl) +static void SysmemInit(struct gliutable *gl) { msr_t msr; int sizembytes, sizebytes; @@ -141,51 +120,51 @@ SysmemInit(struct gliutable *gl) * system. We will adjust for SMM now and Frame Buffer later. */ sizembytes = sizeram(); - printk_debug("%s: enable for %dm bytes\n", __FUNCTION__, sizembytes); + printk_debug("%s: enable for %dMBytes\n", __FUNCTION__, sizembytes); sizebytes = sizembytes << 20; - sizebytes -= ((SMM_SIZE)<<10); + sizebytes -= ((SMM_SIZE * 1024) + 1); printk_debug("usable RAM: %d bytes\n", sizebytes); + /* 20 bit address The bottom 12 bits go into bits 20-31 in msr.lo + The top 8 bits go into 0-7 of msr.hi. */ + sizebytes--; msr.hi = (gl->hi & 0xFFFFFF00) | (sizebytes >> 24); - /* set up sizebytes to fit into msr.lo */ - sizebytes <<= 8; /* what? well, we want bits 23:12 in bits 31:20. */ + sizebytes <<= 8; /* move bits 23:12 in bits 31:20. */ sizebytes &= 0xfff00000; - sizebytes |= 0x100; + sizebytes |= 0x100; /* start at 1MB */ msr.lo = sizebytes; wrmsr(gl->desc_name, msr); // MSR - see table above - msr = rdmsr(gl->desc_name); - /* printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, - gl->desc_name, msr.hi, msr.lo); */ // GX3 + printk_debug("%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, + gl->desc_name, msr.hi, msr.lo); } -static void -SMMGL0Init(struct gliutable *gl) { +static void SMMGL0Init(struct gliutable *gl) { msr_t msr; int sizebytes = sizeram()<<20; long offset; - sizebytes -= ((SMM_SIZE)<<10); + sizebytes -= (SMM_SIZE*1024); printk_debug("%s: %d bytes\n", __FUNCTION__, sizebytes); + /* calculate the Two's complement offset */ offset = sizebytes - SMM_OFFSET; offset = (offset >> 12) & 0x000fffff; - printk_debug("%s: offset is 0x%08x\n", __FUNCTION__, offset); + printk_debug("%s: offset is 0x%08x\n", __FUNCTION__, SMM_OFFSET); - msr.hi = offset << 8 | MSR_MC; + msr.hi = offset << 8 | gl->hi; msr.hi |= SMM_OFFSET>>24; msr.lo = SMM_OFFSET << 8; msr.lo |= ((~(SMM_SIZE*1024)+1)>>12)&0xfffff; wrmsr(gl->desc_name, msr); // MSR - See table above - msr = rdmsr(gl->desc_name); - printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo); + printk_debug("%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo); } -static void -SMMGL1Init(struct gliutable *gl) { + +static void SMMGL1Init(struct gliutable *gl) { msr_t msr; printk_debug("%s:\n", __FUNCTION__ ); @@ -193,16 +172,14 @@ SMMGL1Init(struct gliutable *gl) { /* I don't think this is needed */ msr.hi &= 0xffffff00; msr.hi |= (SMM_OFFSET >> 24); - msr.lo = SMM_OFFSET << 8; + msr.lo = (SMM_OFFSET << 8) & 0xFFF00000; msr.lo |= ((~(SMM_SIZE*1024)+1)>>12)&0xfffff; wrmsr(gl->desc_name, msr); // MSR - See table above - msr = rdmsr(gl->desc_name); - printk_debug("%s: AFTER write msr 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo); + printk_debug("%s: MSR 0x%08x, val 0x%08x:0x%08x\n", __FUNCTION__, gl->desc_name, msr.hi, msr.lo); } -static void -GLIUInit(struct gliutable *gl){ +static void GLIUInit(struct gliutable *gl){ while (gl->desc_type != GL_END){ switch(gl->desc_type){ @@ -229,6 +206,7 @@ GLIUInit(struct gliutable *gl){ } } + /* ***************************************************************************/ /* **/ /* * GLPCIInit*/ @@ -255,8 +233,8 @@ static void GLPCIInit(void){ /* */ /* R0 - GLPCI settings for Conventional Memory space.*/ /* */ - msr.hi = (0x09F000 >> 12) << GLPCI_RC_UPPER_TOP_SHIFT /* 640*/; - msr.lo = 0 /* 0*/; + msr.hi = (0x09F000 >> 12) << GLPCI_RC_UPPER_TOP_SHIFT; /* 640 */ + msr.lo = 0; /* 0*/ msr.lo |= GLPCI_RC_LOWER_EN_SET+ GLPCI_RC_LOWER_PF_SET + GLPCI_RC_LOWER_WC_SET; msrnum = GLPCI_RC0; wrmsr(msrnum, msr); @@ -283,8 +261,7 @@ static void GLPCIInit(void){ /* So we need a high page aligned addresss (pah) and low page aligned address (pal) * pah is from msr.hi << 12 | msr.low >> 20. pal is msr.lo << 12 */ - printk_debug("GLPCI r1: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi); - pah = ((msr.hi &0xff) << 12) | ((msr.lo >> 20) & 0xfff); + pah = ((msr.hi & 0xFF) << 12) | ((msr.lo >> 20) & 0xFFF); /* we have the page address. Now make it a page-aligned address */ pah <<= 12; @@ -292,24 +269,25 @@ static void GLPCIInit(void){ msr.hi = pah; msr.lo = pal; msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET | GLPCI_RC_LOWER_WC_SET; - printk_debug("GLPCI r1: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi); + printk_debug("GLPCI R1: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi); msrnum = GLPCI_RC1; wrmsr(msrnum, msr); } /* */ - /* R2 - GLPCI settings for SMM space.*/ + /* R2 - GLPCI settings for SMM space */ /* */ msr.hi = ((SMM_OFFSET+(SMM_SIZE*1024-1)) >> 12) << GLPCI_RC_UPPER_TOP_SHIFT; msr.lo = (SMM_OFFSET >> 12) << GLPCI_RC_LOWER_BASE_SHIFT; msr.lo |= GLPCI_RC_LOWER_EN_SET | GLPCI_RC_LOWER_PF_SET; + printk_debug("GLPCI R2: system msr.lo 0x%08x msr.hi 0x%08x\n", msr.lo, msr.hi); msrnum = GLPCI_RC2; wrmsr(msrnum, msr); /* this is done elsewhere already, but it does no harm to do it more than once */ /* write serialize memory hole to PCI. Need to to unWS when something is shadowed regardless of cachablility.*/ - msr.lo = 0x021212121 /* cache disabled and write serialized*/; - msr.hi = 0x021212121 /* cache disabled and write serialized*/; + msr.lo = 0x021212121; /* cache disabled and write serialized */ + msr.hi = 0x021212121; /* cache disabled and write serialized */ msrnum = CPU_RCONF_A0_BF; wrmsr(msrnum, msr); @@ -340,17 +318,16 @@ static void GLPCIInit(void){ msrnum = CPU_DM_CONFIG0; msr = rdmsr(msrnum); msr.hi &= ~ (7 << DM_CONFIG0_UPPER_WSREQ_SHIFT); - msr.hi |= 2 << DM_CONFIG0_UPPER_WSREQ_SHIFT ; /* reduce to 1 for safe mode.*/ + msr.hi |= 2 << DM_CONFIG0_UPPER_WSREQ_SHIFT; /* reduce to 1 for safe mode */ wrmsr(msrnum, msr); /* we are ignoring the 5530 case for now, and perhaps forever. */ /* */ - /* 5535 NB Init*/ + /* 553x NB Init*/ /* */ /* Arbiter setup */ - enable_preempt = GLPCI_ARB_LOWER_PRE0_SET | GLPCI_ARB_LOWER_PRE1_SET | GLPCI_ARB_LOWER_PRE2_SET | GLPCI_ARB_LOWER_CPRE_SET; enable_cpu_override = GLPCI_ARB_LOWER_COV_SET; enable_bus_parking = GLPCI_ARB_LOWER_PARK_SET; @@ -392,10 +369,10 @@ static void GLPCIInit(void){ wrmsr(msrnum, msr); - /* Set GLPCI Latency Timer.*/ + /* Set GLPCI Latency Timer */ msrnum = GLPCI_CTRL; msr = rdmsr(msrnum); - msr.hi |= 0x1F << GLPCI_CTRL_UPPER_LAT_SHIFT; /* Change once 1.x is gone.*/ + msr.hi |= 0x1F << GLPCI_CTRL_UPPER_LAT_SHIFT; /* Change once 1.x is gone */ wrmsr(msrnum, msr); /* GLPCI_SPARE*/ @@ -404,7 +381,6 @@ static void GLPCIInit(void){ msr.lo &= ~ 0x7; msr.lo |= GLPCI_SPARE_LOWER_AILTO_SET | GLPCI_SPARE_LOWER_PPD_SET | GLPCI_SPARE_LOWER_PPC_SET | GLPCI_SPARE_LOWER_MPC_SET | GLPCI_SPARE_LOWER_NSE_SET | GLPCI_SPARE_LOWER_SUPO_SET; wrmsr(msrnum, msr); - } @@ -420,35 +396,13 @@ static void GLPCIInit(void){ /* * Modified:*/ /* **/ /* ***************************************************************************/ -static void -ClockGatingInit (void){ +static void ClockGatingInit (void){ msr_t msr; struct msrinit *gating = ClockGatingDefault; int i; -#if 0 - mov cx, TOKEN_CLK_GATE - NOSTACK bx, GetNVRAMValueBX - cmp al, TVALUE_CG_OFF - je gatingdone - - cmp al, TVALUE_CG_DEFAULT - jb allon - ja performance - lea si, ClockGatingDefault - jmp nextdevice - -allon: - lea si, ClockGatingAllOn - jmp nextdevice - -performance: - lea si, ClockGatingPerformance -#endif - for(i = 0; gating->msrnum != 0xffffffff; i++) { msr = rdmsr(gating->msrnum); - //printk_debug("%s: MSR 0x%08x is 0x%08x:0x%08x\n", __FUNCTION__, gating->msrnum, msr.hi, msr.lo); //GX3 msr.hi |= gating->msr.hi; msr.lo |= gating->msr.lo; /* printk_debug("%s: MSR 0x%08x will be set to 0x%08x:0x%08x\n", __FUNCTION__, @@ -459,15 +413,13 @@ performance: } -static void -GeodeLinkPriority(void){ +static void GeodeLinkPriority(void){ msr_t msr; struct msrinit *prio = GeodeLinkPriorityTable; int i; for(i = 0; prio->msrnum != 0xffffffff; i++) { msr = rdmsr(prio->msrnum); - // printk_debug("%s: MSR 0x%08x is 0x%08x:0x%08x\n", __FUNCTION__, prio->msrnum, msr.hi, msr.lo); // GX3 msr.hi |= prio->msr.hi; msr.lo &= ~0xfff; msr.lo |= prio->msr.lo; @@ -485,9 +437,9 @@ GeodeLinkPriority(void){ * If the setShadow function is used then all shadow descriptors * will stay sync'ed. */ -static uint64_t getShadow(void) -{ +static uint64_t getShadow(void){ msr_t msr; + msr = rdmsr(MSR_GLIU0_SHADOW); return ( ( (uint64_t) msr.hi ) << 32 ) | msr.lo; } @@ -499,8 +451,8 @@ static uint64_t getShadow(void) * This is part of the PCI lockup solution * Entry: EDX:EAX is the shadow settings */ -static void setShadowRCONF(uint32_t shadowHi, uint32_t shadowLo) -{ +static void setShadowRCONF(uint32_t shadowHi, uint32_t shadowLo){ + // ok this is whacky bit translation time. int bit; uint8_t shadowByte; @@ -557,7 +509,6 @@ static void setShadowGLPCI(uint32_t shadowHi, uint32_t shadowLo) msr_t msr; // Set the Enable Register. - msr = rdmsr(GLPCI_REN); msr.lo &= 0xFFFF00FF; msr.lo |= ( (shadowLo & 0xFFFF0000) >> 8); @@ -592,26 +543,13 @@ static void setShadow(uint64_t shadowSettings) msr.hi &= 0xFFFF0000; // maintain PDID in upper EDX msr.hi |= ((uint32_t) (shadowSettings >> 32)) & 0x0000FFFF; wrmsr(pTable->desc_name, msr); // MSR - See the table above - } } } } -/************************************************************************** - * - * shadowRom - * - * Set up a stack for ease of further testing - * - * Entry: - * Exit: - * Destroys: - * - **************************************************************************/ -static void -shadowRom(void) -{ +static void rom_shadow_settings(void){ + uint64_t shadowSettings = getShadow(); shadowSettings &= (uint64_t) 0xFFFF00000000FFFFULL; // Disable read & writes shadowSettings |= (uint64_t) 0x00000000F0000000ULL; // Enable reads for F0000-FFFFF @@ -623,7 +561,7 @@ shadowRom(void) /*************************************************************************** * - * RCONFInit + * L1Init * Set up RCONF_DEFAULT and any other RCONF registers needed * * DEVRC_RCONF_DEFAULT: @@ -639,14 +577,12 @@ shadowRom(void) #define ROMBASE_RCONF_DEFAULT 0xFFFC0000 #define ROMRC_RCONF_DEFAULT 0x25 -static void -RCONFInit(void) +static void enable_L1_cache(void) { struct gliutable *gl = 0; int i; msr_t msr; uint8_t SysMemCacheProp; - //uint8_t RegionProp; /* Locate SYSMEM entry in GLIU0table */ for(i = 0; gliu0table[i].desc_name != GL_END; i++) { @@ -661,11 +597,8 @@ RCONFInit(void) } // sysdescfound: - /* found the descriptor... get its contents */ msr = rdmsr(gl->desc_name); - printk_debug("SYSDESC: 0x%08X:0x%08X\n",msr.hi,msr.lo); - /* 20 bit address - The bottom 12 bits go into bits 20-31 in eax, the * top 8 bits go into 0-7 of edx. */ @@ -673,13 +606,11 @@ RCONFInit(void) msr.lo = ((msr.lo << 12) | (msr.lo >> 20)) & 0x000FFFFF; msr.lo <<= RCONF_DEFAULT_LOWER_SYSTOP_SHIFT; // 8 - printk_debug("RCONF LO: 0x%08X\n",msr.lo); - // Set Default SYSMEM region properties - msr.lo &= ~SYSMEM_RCONF_WRITETHROUGH; // 8 (or ~8) + msr.lo &= ~SYSMEM_RCONF_WRITETHROUGH; // NOT writethrough == writeback 8 (or ~8) // Set PCI space cache properties - msr.hi = (DEVRC_RCONF_DEFAULT >> 4); // only need the bottom bits and lets clean the rest of edx + msr.hi = (DEVRC_RCONF_DEFAULT >> 4); // setting is split betwwen hi and lo... msr.lo |= (DEVRC_RCONF_DEFAULT << 28); // Set the ROMBASE. This is usually FFFC0000h @@ -690,6 +621,7 @@ RCONFInit(void) // now program RCONF_DEFAULT wrmsr(CPU_RCONF_DEFAULT, msr); + printk_debug("CPU_RCONF_DEFAULT (1808): 0x%08X:0x%08X\n",msr.hi,msr.lo); // RCONF_BYPASS: Cache tablewalk properties and SMM/DMM header access properties. // Set to match system memory cache properties. @@ -699,21 +631,84 @@ RCONFInit(void) msr.lo = (msr.lo & 0xFFFF0000) | (SysMemCacheProp << 8) | SysMemCacheProp; wrmsr(CPU_RCONF_BYPASS, msr); - printk_debug("CPU_RCONF_SMM (180E) 0x%08x : 0x%08x\n", msr.hi, msr.lo); + printk_debug("CPU_RCONF_BYPASS (180A): 0x%08x : 0x%08x\n", msr.hi, msr.lo); } +static void enable_L2_cache(void) { + msr_t msr; + + /* Instruction Memory Configuration register + * set EBE bit, required when L2 cache is enabled + */ + msr = rdmsr(CPU_IM_CONFIG); + msr.lo |= 0x400; + wrmsr(CPU_IM_CONFIG, msr); + + /* Data Memory Subsystem Configuration register + * set EVCTONRPL bit, required when L2 cache is enabled in victim mode + */ + msr = rdmsr(CPU_DM_CONFIG0); + msr.lo |= 0x4000; + wrmsr(CPU_DM_CONFIG0, msr); + + /* invalidate L2 cache */ + msr.hi = 0x00; + msr.lo = 0x10; + wrmsr(CPU_BC_L2_CONF, msr); + + /* Enable L2 cache */ + msr.hi = 0x00; + msr.lo = 0x0f; + wrmsr(CPU_BC_L2_CONF, msr); + + printk_debug("L2 cache enabled\n"); +} + +static void setup_lx_cache(void) +{ + msr_t msr; + + enable_L1_cache(); + enable_L2_cache(); + + // Make sure all INVD instructions are treated as WBINVD. We do this + // because we've found some programs which require this behavior. + msr = rdmsr(CPU_DM_CONFIG0); + msr.lo |= DM_CONFIG0_LOWER_WBINVD_SET; + wrmsr(CPU_DM_CONFIG0, msr); + + x86_enable_cache(); + wbinvd(); +} + +uint32_t get_systop(void) { + struct gliutable *gl = 0; + uint32_t systop; + msr_t msr; + int i; + + for(i = 0; gliu0table[i].desc_name != GL_END; i++) { + if (gliu0table[i].desc_type == R_SYSMEM) { + gl = &gliu0table[i]; + break; + } + } + if (gl) { + msr = rdmsr(gl->desc_name); + systop = ((msr.hi & 0xFF) << 24) | ((msr.lo & 0xFFF00000) >> 8); + systop += 0x1000; /* 4K */ + }else{ + systop = ((sizeram() - CONFIG_VIDEO_MB) * 1024) - SMM_SIZE - 1024; + } + return systop; +} /****************************************************************************/ /* * northbridge_init_early */ /* **/ /* * Core Logic initialization: Host bridge*/ /* **/ -/* * Entry:*/ -/* * Exit:*/ -/* * Modified:*/ -/* **/ /* ***************************************************************************/ - void northbridge_init_early(void) { msr_t msr; @@ -723,34 +718,21 @@ void northbridge_init_early(void) for(i = 0; gliutables[i]; i++) GLIUInit(gliutables[i]); - GeodeLinkPriority(); - - shadowRom(); - - // GeodeROM ensures that the BIOS waits the required 1 second before - // allowing anything to access PCI - // PCIDelay(); - - RCONFInit(); - - // The cacheInit function in GeodeROM tests cache and, among other things, - // makes sure all INVD instructions are treated as WBINVD. We do this - // because we've found some programs which require this behavior. - // That subset of cacheInit() is implemented here: - - /* GX3 OK */ - msr = rdmsr(CPU_DM_CONFIG0); - msr.lo |= DM_CONFIG0_LOWER_WBINVD_SET; - wrmsr(CPU_DM_CONFIG0, msr); - /* Now that the descriptor to memory is set up.*/ /* The memory controller needs one read to synch its lines before it can be used.*/ i = *(int *) 0; + GeodeLinkPriority(); + + setup_lx_cache(); + + rom_shadow_settings(); + GLPCIInit(); + ClockGatingInit(); - __asm__("FINIT\n"); - /* CPUBugsFix -- called elsewhere */ + + __asm__ __volatile__("FINIT\n"); printk_debug("Exit %s\n", __FUNCTION__); } diff --git a/src/northbridge/amd/lx/pll_reset.c b/src/northbridge/amd/lx/pll_reset.c index 13e21be8d..39a2e270f 100644 --- a/src/northbridge/amd/lx/pll_reset.c +++ b/src/northbridge/amd/lx/pll_reset.c @@ -1,6 +1,10 @@ -#define POST_CODE(x) outb(0x80, x) +/* +* +* Copyright (C) 2007 Advanced Micro Devices +* +*/ -static void pll_reset(void) +static void pll_reset(char manualconf) { msr_t msrGlcpSysRstpll; @@ -12,32 +16,75 @@ static void pll_reset(void) print_debug_hex32(msrGlcpSysRstpll.hi); print_debug(":"); print_debug_hex32(msrGlcpSysRstpll.lo); - print_debug("\n"); + print_debug("\r\n"); + POST_CODE(POST_PLL_INIT); - msrGlcpSysRstpll.lo &= 0x80000000; - - // If the "we've already been here" flag is set, don't reconfigure the pll - if ( !(msrGlcpSysRstpll.lo) ) - { // we haven't configured the PLL; do it now - print_debug("CONFIGURING PLL"); - - POST_CODE(0x77); - - // HARDCODED VALUES MOVED BACK TO auto.c AS THEY HAVE TO BE BOARD-SPECIFIC - // (this file is included from there) - + if (!(msrGlcpSysRstpll.lo & (1 << RSTPLL_LOWER_SWFLAGS_SHIFT))){ + print_debug("Configuring PLL\n"); + if(manualconf){ + POST_CODE(POST_PLL_MANUAL); /* CPU and GLIU mult/div (GLMC_CLK = GLIU_CLK / 2) */ msrGlcpSysRstpll.hi = PLLMSRhi; /* Hold Count - how long we will sit in reset */ msrGlcpSysRstpll.lo = PLLMSRlo; - + } + 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 |= 0x80000000; + msrGlcpSysRstpll.lo |= (1 << RSTPLL_LOWER_SWFLAGS_SHIFT); /* "reset the chip" value */ - msrGlcpSysRstpll.lo |= 0x00000001; - + msrGlcpSysRstpll.lo |= RSTPPL_LOWER_CHIP_RESET_SET; wrmsr(GLCP_SYS_RSTPLL, msrGlcpSysRstpll); + + /* You should never get here..... The chip has reset.*/ + print_debug("CONFIGURING PLL FAILURE\n"); + POST_CODE(POST_PLL_RESET_FAIL); + __asm__ __volatile__("hlt\n"); + + } + print_debug("Done cpuRegInit\n"); + return; +} + +static unsigned int CPUSpeed(void){ + unsigned int 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); +} +static unsigned int GeodeLinkSpeed(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); } +static unsigned int PCISpeed(void){ + msr_t msr; + + msr = rdmsr(GLCP_SYS_RSTPLL); + if (msr.hi & (1 << RSTPPL_LOWER_PCISPEED_SHIFT)){ + return(66); + } + else{ + return(33); + } +} + diff --git a/src/northbridge/amd/lx/raminit.c b/src/northbridge/amd/lx/raminit.c index f1ae87d69..39ae1de57 100644 --- a/src/northbridge/amd/lx/raminit.c +++ b/src/northbridge/amd/lx/raminit.c @@ -1,123 +1,769 @@ +/* +* This file is part of the LinuxBIOS project. +* +* Copyright (C) 2007 Advanced Micro Devices +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 as +* published by the Free Software Foundation. +* +* 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 +#include +#include +#include "southbridge/amd/cs5536/cs5536.h" +static const unsigned char NumColAddr[] = {0x00,0x10,0x11,0x00,0x00,0x00,0x00,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F}; -static void sdram_set_registers(const struct mem_controller *ctrl) -{ +static void auto_size_dimm(unsigned int dimm){ + uint32_t dimm_setting; + uint16_t dimm_size; + uint8_t spd_byte; + msr_t msr; + + dimm_setting = 0; + + /* Check that we have a dimm */ + if (spd_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF){ + return; } -/* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence - * Section 4.1.4, GX/CS5535 GeodeROM Porting guide */ -static void sdram_enable(int controllers, const struct mem_controller *ctrl) -{ - int i; - msr_t msr; + /* Field: Module Banks per DIMM */ + /* EEPROM byte usage: (5) Number of DIMM Banks */ + spd_byte = spd_read_byte(dimm, SPD_NUM_DIMM_BANKS); + if ((MIN_MOD_BANKS > spd_byte) && (spd_byte > MAX_MOD_BANKS)){ + print_debug("Number of module banks not compatible\r\n"); + POST_CODE(ERROR_BANK_SET); + __asm__ __volatile__("hlt\n"); + } + dimm_setting |= (spd_byte >> 1) << CF07_UPPER_D0_MB_SHIFT; - /* DRAM initialization sequence according to the documentation: - * 1) Initialize the following GLMC registers/bits based on Serial Presence Detect (SPD) values: - * — MSR 20000018h except REF_INT bits [23:8] - * — MSR 20000019h - */ - // This is done by sdram_set_spd_registers() that is called by sdram/generic_sdram.c just before this - // sdram_set_spd_registers is responsible for reading ram settings from spd rom and configuring sdram conrtoller - // Here follows generic sdram initialization procedure. + /* Field: Banks per SDRAM device */ + /* EEPROM byte usage: (17) Number of Banks on SDRAM Device */ + spd_byte = spd_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM); + if ((MIN_DEV_BANKS > spd_byte) && (spd_byte > MAX_DEV_BANKS)){ + print_debug("Number of device banks not compatible\r\n"); + POST_CODE(ERROR_BANK_SET); + __asm__ __volatile__("hlt\n"); + } + dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT; - /* 2) Initialize the following GLMC registers: - * — MSR 2000001Ah[15:8] = C8h - * — MSR 20002004h[2] = 0, [0] = 1 + + /*; Field: DIMM size + *; EEPROM byte usage: (3) Number or Row Addresses + *; (4) Number of Column Addresses + *; (5) Number of DIMM Banks + *; (31) Module Bank Density + *; Size = Module Density * Module Banks */ - msr.hi = 0x00000000; - msr.lo = 0x130AD101; - wrmsr(MC_CF1017_DATA, msr); + if ((spd_read_byte(dimm, SPD_NUM_ROWS) & 0xF0) || (spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)){ + print_debug("Assymetirc DIMM not compatible\r\n"); + POST_CODE(ERROR_UNSUPPORTED_DIMM); + __asm__ __volatile__("hlt\n"); + } - //ok - msr.hi = 0x00000000; - msr.lo = 0x00000001; - wrmsr(MC_GLD_MSR_PM, msr); + dimm_size = spd_read_byte(dimm, SPD_BANK_DENSITY); + dimm_size |= (dimm_size << 8); /* align so 1GB(bit0) is bit 8, this is a little weird to get gcc to not optimize this out*/ + dimm_size &= 0x01FC; /* and off 2GB DIMM size : not supported and the 1GB size we just moved up to bit 8 as well as all the extra on top*/ - /* 3) Release MASK_CKE[1:0] (MSR 2000001Dh[9:8] = 11) */ + /* Module Density * Module Banks */ + dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1; /* shift to multiply by # DIMM banks */ + dimm_size = __builtin_ctz(dimm_size); + if (dimm_size > 8){ /* 8 is 1GB only support 1GB per DIMM */ + print_debug("Only support up to 1 GB per DIMM\r\n"); + POST_CODE(ERROR_DENSITY_DIMM); + __asm__ __volatile__("hlt\n"); + } + dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT; - msr.hi = 0x00000000; - msr.lo = 0x00000000; - wrmsr(MC_CFCLK_DBUG, msr); - // reset memory controller +/*; Field: PAGE size +*; EEPROM byte usage: (4) Number of Column Addresses +*; PageSize = 2^# Column Addresses * Data width in bytes (should be 8bytes for a normal DIMM) +* +*; But this really works by magic. +*;If ma[12:0] is the memory address pins, and pa[12:0] is the physical column address +*;that MC generates, here is how the MC assigns the pa onto the ma pins: +* +*;ma 12 11 10 09 08 07 06 05 04 03 02 01 00 +*;------------------------------------------- +*;pa 09 08 07 06 05 04 03 (7 col addr bits = 1K page size) +*;pa 10 09 08 07 06 05 04 03 (8 col addr bits = 2K page size) +*;pa 11 10 09 08 07 06 05 04 03 (9 col addr bits = 4K page size) +*;pa 12 11 10 09 08 07 06 05 04 03 (10 col addr bits = 8K page size) +*;pa 13 AP 12 11 10 09 08 07 06 05 04 03 (11 col addr bits = 16K page size) +*;pa 14 13 AP 12 11 10 09 08 07 06 05 04 03 (12 col addr bits = 32K page size) +*; *AP=autoprecharge bit +* +*;Remember that pa[2:0] are zeroed out since it's a 64-bit data bus (8 bytes), +*;so lower 3 address bits are dont_cares.So from the table above, +*;it's easier to see what the old code is doing: if for example,#col_addr_bits=7(06h), +*;it adds 3 to get 10, then does 2^10=1K. Get it?*/ + + spd_byte = NumColAddr[spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF]; + if (spd_byte > MAX_COL_ADDR) { + print_debug("DIMM page size not compatible\r\n"); + POST_CODE(ERROR_SET_PAGE); + __asm__ __volatile__("hlt\n"); + } + spd_byte -=7; + if (spd_byte > 5){ /* if the value is above 6 it means >12 address lines */ + spd_byte = 7; /* which means >32k so set to disabled */ + } + dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT; /* 0=1k,1=2k,2=4k,etc */ + msr = rdmsr(MC_CF07_DATA); - msr.lo |= 0x00000002; - wrmsr(MC_CF07_DATA, msr); - msr.lo &= 0xFFFFFFFD; + if (dimm == DIMM0){ + msr.hi &= 0xFFFF0000; + msr.hi |= dimm_setting; + }else{ + msr.hi &= 0x0000FFFF; + msr.hi |= dimm_setting << 16; + } wrmsr(MC_CF07_DATA, msr); +} - /* 4. set and clear REF_TST 16 times, more shouldn't hurt - * why this is before EMRS and MRS ? */ - for (i = 0; i < 19; i++) { +static void checkDDRMax(void){ + uint8_t spd_byte0, spd_byte1; + uint16_t speed; + + /* PC133 identifier */ + spd_byte0 = spd_read_byte(DIMM0, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); + if (spd_byte0 == 0xFF){ + spd_byte0=0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX); + if (spd_byte1 == 0xFF){ + spd_byte1=0; + } + + /* I don't think you need this check. + if (spd_byte0 < 0xA0 || spd_byte0 < 0xA0){ + print_debug("DIMM overclocked. Check GeodeLink Speed\r\n"); + POST_CODE(POST_PLL_MEM_FAIL); + __asm__ __volatile__("hlt\n"); + }*/ + + + /* Use the slowest DIMM */ + if (spd_byte0 < spd_byte1){ + spd_byte0 = spd_byte1; + } + + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + speed = 2*((10000/(((spd_byte0 >> 4) * 10) + (spd_byte0 & 0x0F)))); + + /* current speed > max speed? */ + if (GeodeLinkSpeed() > speed){ + print_debug("DIMM overclocked. Check GeodeLink Speed\r\n"); + POST_CODE(POST_PLL_MEM_FAIL); + __asm__ __volatile__("hlt\n"); + } +} + + +const uint16_t REF_RATE[] = {15, 3, 7, 31, 62, 125}; /* ns */ + +static void set_refresh_rate(void){ + uint8_t spd_byte0, spd_byte1; + uint16_t rate0, rate1; + msr_t msr; + + spd_byte0 = spd_read_byte(DIMM0, SPD_REFRESH); + spd_byte0 &= 0xF; + if (spd_byte0 > 5){ + spd_byte0 = 5; + } + rate0 = REF_RATE[spd_byte0]; + + spd_byte1 = spd_read_byte(DIMM1, SPD_REFRESH); + spd_byte1 &= 0xF; + if (spd_byte1 > 5){ + spd_byte1 = 5; + } + rate1 = REF_RATE[spd_byte1]; + + /* Use the faster rate (lowest number) */ + if (rate0 > rate1){ + rate0 = rate1; + } + msr = rdmsr(MC_CF07_DATA); - msr.lo |= 0x00000008; - wrmsr(MC_CF07_DATA, msr); - msr.lo &= 0xFFFFFFF7; + msr.lo|= ((rate0 * (GeodeLinkSpeed()/2))/16) << CF07_LOWER_REF_INT_SHIFT; wrmsr(MC_CF07_DATA, msr); } - /* 5) Initialize REF_INT (MSR 20000018h[23:8]) to set refresh interval. */ - msr.lo |= 0x3A00; - wrmsr(MC_CF07_DATA, msr); +const uint8_t CASDDR[] = {5, 5, 2, 6, 3, 7, 4, 0}; /* 1(1.5), 1.5, 2, 2.5, 3, 3.5, 4, 0 */ - /* 6) Perform load-mode with MSR_BA = 01 (MSR 200000018h[29:28] = 01) - * to initialize DIMM Extended Mode register. - * Load-mode is performed by setting/clearing PROG_DRAM (MSR 200000018h[0]). - */ -// eeldus et bit29 = 0, mida ta praegu ka on - msr.lo |= ((0x01 << 28) | 0x01); - wrmsr(MC_CF07_DATA, msr); +static void setCAS(void){ +/*;***************************************************************************** +;* +;* setCAS +;* EEPROM byte usage: (18) SDRAM device attributes - CAS latency +;* EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5 +;* EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1 +;* +;* The CAS setting is based on the information provided in each DIMMs SPD. +;* The speed at which a DIMM can run is described relative to the slowest +;* CAS the DIMM supports. Each speed for the relative CAS settings is +;* checked that it is within the GeodeLink speed. If it isn't within the GeodeLink +;* speed, the CAS setting is removed from the list of good settings for +;* the DIMM. This is done for both DIMMs and the lists are compared to +;* find the lowest common CAS latency setting. If there are no CAS settings +;* in common we out a ERROR_DIFF_DIMMS (78h) to port 80h and halt. +;* +;* Entry: +;* Exit: Set fastest CAS Latency based on GeodeLink speed and SPD information. +;* Destroys: We really use everything ! +;*****************************************************************************/ + uint16_t glspeed, dimm_speed; + uint8_t spd_byte, casmap0, casmap1; + msr_t msr; - msr.lo &= ~((0x01 << 28) | 0x01); - wrmsr(MC_CF07_DATA, msr); + glspeed = GeodeLinkSpeed(); + + /************************** DIMM0 **********************************/ + casmap0 = spd_read_byte(DIMM0, SPD_ACCEPTABLE_CAS_LATENCIES); + if (casmap0 != 0xFF){ + /* IF -.5 timing is supported, check -.5 timing > GeodeLink */ + spd_byte = spd_read_byte(DIMM0, SPD_SDRAM_CYCLE_TIME_2ND); + if(spd_byte != 0){ + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + dimm_speed = 2*(10000/(((spd_byte >> 4) * 10) + (spd_byte & 0x0F))); + if (dimm_speed >= glspeed){ + /* IF -1 timing is supported, check -1 timing > GeodeLink */ + spd_byte = spd_read_byte(DIMM0, SPD_SDRAM_CYCLE_TIME_3RD); + if(spd_byte != 0){ + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + dimm_speed = 2*(10000/(((spd_byte >> 4) * 10) + (spd_byte & 0x0F))); + if (dimm_speed <= glspeed){ + /* set we can use -.5 timing but not -1 */ + spd_byte = 31 - __builtin_clz((uint32_t)casmap0); /* just want bits in the lower byte since we have to cast to a 32 */ + casmap0 &= 0xFF << (--spd_byte); + } + } /*MIN_CYCLE_10 !=0 */ + } + else{ /* Timing_05 < GLspeed, can't use -.5 or -1 timing */ + spd_byte = 31 - __builtin_clz((uint32_t)casmap0); /* just want bits in the lower byte since we have to cast to a 32 */ + casmap0 &= 0xFF << (spd_byte); + } + } /*MIN_CYCLE_05 !=0 */ + } + else{ /* No DIMM */ + casmap0=0; + } + + /************************** DIMM1 **********************************/ + casmap1 = spd_read_byte(DIMM1, SPD_ACCEPTABLE_CAS_LATENCIES); + if (casmap1 != 0xFF){ + /* IF -.5 timing is supported, check -.5 timing > GeodeLink */ + spd_byte = spd_read_byte(DIMM1, SPD_SDRAM_CYCLE_TIME_2ND); + if(spd_byte != 0){ + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + dimm_speed = 2*(10000/(((spd_byte >> 4) * 10) + (spd_byte & 0x0F))); + if (dimm_speed >= glspeed){ + /* IF -1 timing is supported, check -1 timing > GeodeLink */ + spd_byte = spd_read_byte(DIMM1, SPD_SDRAM_CYCLE_TIME_3RD); + if(spd_byte != 0){ + /* Turn SPD ns time into MHZ. Check what the asm does to this math. */ + dimm_speed = 2*(10000/(((spd_byte >> 4) * 10) + (spd_byte & 0x0F))); + if (dimm_speed <= glspeed){ + /* set we can use -.5 timing but not -1 */ + spd_byte =31 - __builtin_clz((uint32_t)casmap1); /* just want bits in the lower byte since we have to cast to a 32 */ + casmap1 &= 0xFF << (--spd_byte); + } + } /*MIN_CYCLE_10 !=0 */ + } + else{ /* Timing_05 < GLspeed, can't use -.5 or -1 timing */ + spd_byte = 31 - __builtin_clz((uint32_t)casmap1); /* just want bits in the lower byte since we have to cast to a 32 */ + casmap1 &= 0xFF << (spd_byte); + } + } /*MIN_CYCLE_05 !=0 */ + } + else{ /* No DIMM */ + casmap1=0; + } + + /********************* CAS_LAT MAP COMPARE ***************************/ + if (casmap0 == 0){ + spd_byte = CASDDR[__builtin_ctz((uint32_t)casmap1)]; + } + else if (casmap1 == 0){ + spd_byte = CASDDR[__builtin_ctz((uint32_t)casmap0)]; + } + else if ((casmap0 &= casmap1)){ + spd_byte = CASDDR[__builtin_ctz((uint32_t)casmap0)]; + } + else{ + print_debug("DIMM CAS Latencies not compatible\r\n"); + POST_CODE(ERROR_DIFF_DIMMS); + __asm__ __volatile__("hlt\n"); + } + + + msr = rdmsr(MC_CF8F_DATA); + msr.lo &= ~(7 << CF8F_LOWER_CAS_LAT_SHIFT); + msr.lo |= spd_byte << CF8F_LOWER_CAS_LAT_SHIFT; + wrmsr(MC_CF8F_DATA, msr); +} + + +static void set_latencies(void){ + uint32_t memspeed, dimm_setting; + uint8_t spd_byte0, spd_byte1; + msr_t msr; + + memspeed = GeodeLinkSpeed()/2; + dimm_setting=0; + + /* MC_CF8F setup */ + /* tRAS */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRAS); + if (spd_byte0 == 0xFF){ + spd_byte0=0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRAS); + if (spd_byte1 == 0xFF){ + spd_byte1=0; + } + if (spd_byte0 < spd_byte1){ + spd_byte0 = spd_byte1; + } + + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = (spd_byte0 * memspeed)/1000; + if(((spd_byte0 * memspeed)%1000)){ + ++spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT; + + + /* tRP */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRP); + if (spd_byte0 == 0xFF){ + spd_byte0=0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRP); + if (spd_byte1 == 0xFF){ + spd_byte1=0; + } + if (spd_byte0 < spd_byte1){ + spd_byte0 = spd_byte1; + } + + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = ((spd_byte0 >> 2) * memspeed)/1000; + if((((spd_byte0 >> 2) * memspeed)%1000)){ + ++spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_PRE2ACT_SHIFT; + + + /* tRCD */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRCD); + if (spd_byte0 == 0xFF){ + spd_byte0=0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRCD); + if (spd_byte1 == 0xFF){ + spd_byte1=0; + } + if (spd_byte0 < spd_byte1){ + spd_byte0 = spd_byte1; + } + + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = ((spd_byte0 >> 2) * memspeed)/1000; + if((((spd_byte0 >> 2) * memspeed)%1000)){ + ++spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2CMD_SHIFT; + + + /* tRRD */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRRD); + if (spd_byte0 == 0xFF){ + spd_byte0=0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRRD); + if (spd_byte1 == 0xFF){ + spd_byte1=0; + } + if (spd_byte0 < spd_byte1){ + spd_byte0 = spd_byte1; + } + + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = ((spd_byte0 >> 2) * memspeed)/1000; + if((((spd_byte0 >> 2) * memspeed)%1000)){ + ++spd_byte1; + } + dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2ACT_SHIFT; + + + /* tRC = tRP + tRAS */ + dimm_setting |= (((dimm_setting >> CF8F_LOWER_ACT2PRE_SHIFT) & 0x0F) + ((dimm_setting >> CF8F_LOWER_PRE2ACT_SHIFT) & 0x07)) \ + << CF8F_LOWER_ACT2ACTREF_SHIFT; - /* 7. Reset DLL, Bit 27 is undocumented in GX datasheet, - * it is documented in LX datasheet */ - /* load Mode Register by set and clear PROG_DRAM */ -// eeldus et bit27:28=00, mida nad ka on + msr = rdmsr(MC_CF8F_DATA); + msr.lo &= 0xF00000FF; + msr.lo |= dimm_setting; + msr.hi |= CF8F_UPPER_REORDER_DIS_SET; + wrmsr(MC_CF8F_DATA, msr); + + /* MC_CF1017 setup */ + /* tRFC */ + spd_byte0 = spd_read_byte(DIMM0, SPD_tRFC); + if (spd_byte0 == 0xFF){ + spd_byte0=0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_tRFC); + if (spd_byte1 == 0xFF){ + spd_byte1=0; + } + if (spd_byte0 < spd_byte1){ + spd_byte0 = spd_byte1; + } + + if (spd_byte0){ + /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */ + spd_byte1 = (spd_byte0 * memspeed)/1000; + if(((spd_byte0 * memspeed)%1000)){ + ++spd_byte1; + } + } + else{ /* Not all SPDs have tRFC setting. Use this formula tRFC = tRC + 1 clk */ + spd_byte1 = ((dimm_setting >> CF8F_LOWER_ACT2ACTREF_SHIFT) & 0x0F) + 1; + } + dimm_setting = spd_byte1 << CF1017_LOWER_REF2ACT_SHIFT; /* note this clears the cf8f dimm setting */ + msr = rdmsr(MC_CF1017_DATA); + msr.lo &= ~(0x1F << CF1017_LOWER_REF2ACT_SHIFT); + msr.lo |= dimm_setting; + wrmsr(MC_CF1017_DATA, msr); + + /* tWTR: Set tWTR to 2 for 400MHz and above GLBUS (200Mhz mem) other wise it stay default(1) */ + if (memspeed > 198){ + msr = rdmsr(MC_CF1017_DATA); + msr.lo &= ~(0x7 << CF1017_LOWER_WR_TO_RD_SHIFT); + msr.lo |= 2 << CF1017_LOWER_WR_TO_RD_SHIFT; + wrmsr(MC_CF1017_DATA, msr); + } +} + +static void set_extended_mode_registers(void){ + uint8_t spd_byte0, spd_byte1; + msr_t msr; + spd_byte0 = spd_read_byte(DIMM0, SPD_DEVICE_ATTRIBUTES_GENERAL); + if (spd_byte0 == 0xFF){ + spd_byte0=0; + } + spd_byte1 = spd_read_byte(DIMM1, SPD_DEVICE_ATTRIBUTES_GENERAL); + if (spd_byte1 == 0xFF){ + spd_byte1=0; + } + spd_byte1 &= spd_byte0; + msr = rdmsr(MC_CF07_DATA); - msr.lo |= ((0x01 << 27) | 0x01); - wrmsr(MC_CF07_DATA, msr); - msr.lo &= ~((0x01 << 27) | 0x01); + if (spd_byte1 & 1){ /* Drive Strength Control */ + msr.lo |= CF07_LOWER_EMR_DRV_SET; + } + if (spd_byte1 & 2){ /* FET Control */ + msr.lo |= CF07_LOWER_EMR_QFC_SET; + } wrmsr(MC_CF07_DATA, msr); +} + +static void EnableMTest (void){ + msr_t msr; + + msr = rdmsr(GLCP_DELAY_CONTROLS); + msr.hi &= ~(7 << 20); /* clear bits 54:52 */ + if (GeodeLinkSpeed() < 200){ + msr.hi |= 2 << 20; + } + wrmsr(GLCP_DELAY_CONTROLS, msr); + + msr = rdmsr(MC_CFCLK_DBUG); + msr.hi |= CFCLK_UPPER_MTST_B2B_DIS_SET | CFCLK_UPPER_MTEST_EN_SET | CFCLK_UPPER_MTST_RBEX_EN_SET; + msr.lo |= CFCLK_LOWER_TRISTATE_DIS_SET; + wrmsr(MC_CFCLK_DBUG, msr); + + print_debug("Enabled MTest for TLA debug\r\n"); +} + +static void sdram_set_registers(const struct mem_controller *ctrl) +{ + msr_t msr; + uint32_t msrnum; + + /* Set Timing Control */ + msrnum = MC_CF1017_DATA; + msr = rdmsr(msrnum); + msr.lo &= ~(7 << CF1017_LOWER_RD_TMG_CTL_SHIFT); + if (GeodeLinkSpeed() < 334){ + msr.lo |= (3 << CF1017_LOWER_RD_TMG_CTL_SHIFT); + } + else{ + msr.lo |= (4 << CF1017_LOWER_RD_TMG_CTL_SHIFT); + } + wrmsr(msrnum, msr); + + /* Set Refresh Staggering */ + msrnum = MC_CF07_DATA; + msr = rdmsr(msrnum); + msr.lo &= ~0xF0; + msr.lo |= 0x40; /* set refresh to 4SDRAM clocks */ + wrmsr(msrnum, msr); + + /* Memory Interleave: Set HOI here otherwise default is LOI */ + /* msrnum = MC_CF8F_DATA; + msr = rdmsr(msrnum); + msr.hi |= CF8F_UPPER_HOI_LOI_SET; + wrmsr(msrnum, msr); */ +} + + +static void sdram_set_spd_registers(const struct mem_controller *ctrl) +{ + uint8_t spd_byte; + + POST_CODE(POST_MEM_SETUP); // post_70h + + spd_byte = spd_read_byte(DIMM0, SPD_MODULE_ATTRIBUTES); + /* Check DIMM is not Register and not Buffered DIMMs. */ + if ((spd_byte != 0xFF) && (spd_byte & 3) ){ + print_debug("DIMM0 NOT COMPATIBLE\r\n"); + POST_CODE(ERROR_UNSUPPORTED_DIMM); + __asm__ __volatile__("hlt\n"); + } + spd_byte = spd_read_byte(DIMM1, SPD_MODULE_ATTRIBUTES); + if ((spd_byte != 0xFF) && (spd_byte & 3)){ + print_debug("DIMM1 NOT COMPATIBLE\r\n"); + POST_CODE(ERROR_UNSUPPORTED_DIMM); + __asm__ __volatile__("hlt\n"); + } + + POST_CODE(POST_MEM_SETUP2); // post_72h + + /* Check that the memory is not overclocked. */ + checkDDRMax(); + + /* Size the DIMMS */ + POST_CODE(POST_MEM_SETUP3); // post_73h + auto_size_dimm(DIMM0); + POST_CODE(POST_MEM_SETUP4); // post_74h + auto_size_dimm(DIMM1); + + /* Set CAS latency */ + POST_CODE(POST_MEM_SETUP5); // post_75h + setCAS(); + + /* Set all the other latencies here (tRAS, tRP....) */ + set_latencies(); - //Delay - i=inb(0x61); - while (i==inb(0x61)); - i=inb(0x61); - while (i==inb(0x61)); - i=inb(0x61); - while (i==inb(0x61)); + /* Set Extended Mode Registers */ + set_extended_mode_registers(); - /* 8. load Mode Register by set and clear PROG_DRAM */ + /* Set Memory Refresh Rate */ + set_refresh_rate(); + +} + +/* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence + * Section 4.1.4, GX/CS5535 GeodeROM Porting guide */ +static void sdram_enable(int controllers, const struct mem_controller *ctrl) +{ + uint32_t i, msrnum; + msr_t msr; + +/********************************************************************* +;* Turn on MC/DIMM interface per JEDEC +;* 1) Clock stabilizes > 200us +;* 2) Assert CKE +;* 3) Precharge All to put all banks into an idles state +;* 4) EMRS to enable DLL +;* 6) MRS w/ memory config & reset DLL set +;* 7) Wait 200 clocks (2us) +;* 8) Precharge All and 2 Auto refresh +;* 9) MRS w/ memory config & reset DLL clear +;* 8) DDR SDRAM ready for normal operation +;********************************************************************/ + POST_CODE(POST_MEM_ENABLE); // post_76h + + /* Only enable MTest for TLA memory debug */ + /*EnableMTest();*/ + + /* If both Page Size = "Not Installed" we have a problems and should halt. */ msr = rdmsr(MC_CF07_DATA); - msr.lo |= 0x01; - wrmsr(MC_CF07_DATA, msr); - msr.lo &= ~0x01; - wrmsr(MC_CF07_DATA, msr); + if ((msr.hi & ((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))) \ + == ((7 << CF07_UPPER_D1_PSZ_SHIFT) | (7 << CF07_UPPER_D0_PSZ_SHIFT))){ + print_debug("No memory in the system\r\n"); + POST_CODE(ERROR_NO_DIMMS); + __asm__ __volatile__("hlt\n"); + } - /* wait 200 SDCLKs */ - for (i = 0; i < 200; i++) - outb(0xaa, 0x80); + /* Set CKEs */ + msrnum = MC_CFCLK_DBUG; + msr = rdmsr(msrnum); + msr.lo &= ~(CFCLK_LOWER_MASK_CKE_SET0 | CFCLK_LOWER_MASK_CKE_SET1); + wrmsr(msrnum, msr); + + + /* Force Precharge All on next command, EMRS */ + msrnum = MC_CFCLK_DBUG; + msr = rdmsr(msrnum); + msr.lo |= CFCLK_LOWER_FORCE_PRE_SET; + wrmsr(msrnum,msr); + + + /* EMRS to enable DLL (pre-setup done in setExtendedModeRegisters) */ + msrnum = MC_CF07_DATA; + msr = rdmsr(msrnum); + msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET; + wrmsr(msrnum, msr); + msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DDR_SET); + wrmsr(msrnum, msr); + + + /* Clear Force Precharge All */ + msrnum = MC_CFCLK_DBUG; + msr = rdmsr(msrnum); + msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET; + wrmsr(msrnum, msr); + + + /* MRS Reset DLL - set */ + msrnum = MC_CF07_DATA; + msr = rdmsr(msrnum); + msr.lo |= CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET; + wrmsr(msrnum,msr); + msr.lo &= ~(CF07_LOWER_PROG_DRAM_SET | CF07_LOWER_LOAD_MODE_DLL_RESET); + wrmsr(msrnum, msr); + + + /* 2us delay (200 clocks @ 200Mhz). We probably really don't need this but.... better safe. */ + /* Wait 2 PORT61 ticks. between 15us and 30us */ + /* This would be endless if the timer is stuck. */ + while ((inb(0x61))); /* find the first edge */ + while (!(~inb(0x61))); - print_debug("DRAM controller init done.\r\n"); - /* Fixes from Jordan Crouse of AMD. */ + /* Force Precharge All on the next command, auto-refresh */ + msrnum = MC_CFCLK_DBUG; + msr = rdmsr(msrnum); + msr.lo |= CFCLK_LOWER_FORCE_PRE_SET; + wrmsr(msrnum, msr); + + + /* Manually AUTO refresh #1 */ + /* If auto refresh was not enabled above we would need to do 8 refreshes to prime the pump before these 2. */ + msrnum = MC_CF07_DATA; + msr = rdmsr(msrnum); + msr.lo |= CF07_LOWER_REF_TEST_SET; + wrmsr(msrnum, msr); + msr.lo &= ~CF07_LOWER_REF_TEST_SET; + wrmsr(msrnum, msr); + + /* Clear Force Precharge All */ + msrnum = MC_CFCLK_DBUG; + msr = rdmsr(msrnum); + msr.lo &= ~CFCLK_LOWER_FORCE_PRE_SET; + wrmsr(msrnum, msr); + + + /* Manually AUTO refresh */ + /* The MC should insert the right delay between the refreshes */ + msrnum = MC_CF07_DATA; + msr = rdmsr(msrnum); + msr.lo |= CF07_LOWER_REF_TEST_SET; + wrmsr(msrnum, msr); + msr.lo &= ~CF07_LOWER_REF_TEST_SET; + wrmsr(msrnum, msr); + + + /* MRS Reset DLL - clear */ + msrnum = MC_CF07_DATA; + msr = rdmsr(msrnum); + msr.lo |= CF07_LOWER_PROG_DRAM_SET; + wrmsr(msrnum, msr); + msr.lo &= ~CF07_LOWER_PROG_DRAM_SET; + wrmsr(msrnum, msr); + + + /* Allow MC to tristate during idle cycles with MTEST OFF */ + msrnum = MC_CFCLK_DBUG; + msr = rdmsr(msrnum); + msr.lo &= ~CFCLK_LOWER_TRISTATE_DIS_SET; + wrmsr(msrnum, msr); + + + /* Disable SDCLK DIMM1 slot if no DIMM installed to save power. */ + msr = rdmsr(MC_CF07_DATA); + if ((msr.hi & (7 << CF07_UPPER_D1_PSZ_SHIFT)) == (7 << CF07_UPPER_D1_PSZ_SHIFT)){ + msrnum = GLCP_DELAY_CONTROLS; + msr = rdmsr(msrnum); + msr.hi |= (1 << 23); /* SDCLK bit for 2.0 */ + wrmsr(msrnum, msr); + } + + /* Set PMode0 Sensitivity Counter */ + msr.lo = 0; /* pmode 0=0 most aggressive */ + msr.hi = 0x200; /* pmode 1=200h */ + wrmsr(MC_CF_PMCTR, msr); + + + /* Set PMode1 Up delay enable */ + msrnum = MC_CF1017_DATA; + msr = rdmsr(msrnum); + msr.lo |= (209 << 8); /* bits[15:8] = 209 */ + wrmsr(msrnum, msr); + + print_debug("DRAM controller init done.\r\n"); + POST_CODE(POST_MEM_SETUP_GOOD); //0x7E /* make sure there is nothing stale in the cache */ - __asm__("wbinvd\n"); + /* CAR stack is in the cache __asm__ __volatile__("wbinvd\n");*/ - print_debug("RAM DLL lock\r\n"); /* The RAM dll needs a write to lock on so generate a few dummy writes */ + /* Note: The descriptor needs to be enabled to point at memory */ volatile unsigned long *ptr; for (i=0;i<5;i++) { ptr = (void *)i; *ptr = (unsigned long)i; } + /* SWAPSiF for PBZ 4112 (Errata 34) */ + /* check for failed DLL settings now that we have done a memory write. */ + msrnum = GLCP_DELAY_CONTROLS; + msr = rdmsr(msrnum); + if ((msr.lo & 0x7FF) == 0x104) { + + /* If you had it you would need to clear out the fail boot count flag */ + /* (depending on where it counts from etc).*/ + + /* The reset we are about to perform clears the PM_SSC register in the */ + /* 5536 so will need to store the S3 resume flag in NVRAM otherwise */ + /* it would do a normal boot */ + + /* Reset the system */ + msrnum = MDD_SOFT_RESET; + msr = rdmsr(msrnum); + msr.lo |= 1; + wrmsr(msrnum, msr); +} + print_debug("RAM DLL lock\r\n"); + }