Author: stepan
Date: 2007-05-04 20:58:42 +0200 (Fri, 04 May 2007)
New Revision: 2630
Removed:
trunk/LinuxBIOSv2/src/northbridge/amd/lx/chipsetinit.c
Modified:
trunk/LinuxBIOSv2/src/northbridge/amd/lx/Config.lb
trunk/LinuxBIOSv2/src/northbridge/amd/lx/chip.h
trunk/LinuxBIOSv2/src/northbridge/amd/lx/grphinit.c
trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridge.c
trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridgeinit.c
trunk/LinuxBIOSv2/src/northbridge/amd/lx/pll_reset.c
trunk/LinuxBIOSv2/src/northbridge/amd/lx/raminit.c
Log:
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 <marc.jones(a)amd.com>
Acked-by: Stefan Reinauer <stepan(a)coresystems.de>
Modified: trunk/LinuxBIOSv2/src/northbridge/amd/lx/Config.lb
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/Config.lb 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/Config.lb 2007-05-04 18:58:42 UTC (rev 2630)
@@ -1,5 +1,4 @@
config chip.h
object northbridge.o
object northbridgeinit.o
-object chipsetinit.o
object grphinit.o
Modified: trunk/LinuxBIOSv2/src/northbridge/amd/lx/chip.h
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/chip.h 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/chip.h 2007-05-04 18:58:42 UTC (rev 2630)
@@ -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;
Deleted: trunk/LinuxBIOSv2/src/northbridge/amd/lx/chipsetinit.c
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/chipsetinit.c 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/chipsetinit.c 2007-05-04 18:58:42 UTC (rev 2630)
@@ -1,384 +0,0 @@
-#include <console/console.h>
-#include <arch/io.h>
-#include <stdint.h>
-#include <device/device.h>
-#include <device/pci.h>
-#include <device/pci_ids.h>
-#include <stdlib.h>
-#include <string.h>
-#include <bitops.h>
-#include "chip.h"
-#include "northbridge.h"
-#include <cpu/amd/lxdef.h>
-#include <cpu/x86/msr.h>
-#include <cpu/x86/cache.h>
-
-
-/* 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
- }
- }
-
-}
Modified: trunk/LinuxBIOSv2/src/northbridge/amd/lx/grphinit.c
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/grphinit.c 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/grphinit.c 2007-05-04 18:58:42 UTC (rev 2630)
@@ -1,3 +1,9 @@
+/*
+*
+* Copyright (C) 2007 Advanced Micro Devices
+*
+*/
+
#include <arch/io.h>
#include <stdint.h>
#include <cpu/amd/vr.h>
@@ -3,29 +9,6 @@
#include <console/console.h>
-/*
- * 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.
*/
@@ -40,7 +23,7 @@
/* 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 @@
* 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);
Modified: trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridge.c
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridge.c 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridge.c 2007-05-04 18:58:42 UTC (rev 2630)
@@ -1,3 +1,9 @@
+/*
+*
+* Copyright (C) 2007 Advanced Micro Devices
+*
+*/
+
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
@@ -7,13 +13,13 @@
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
-#include "chip.h"
-#include "northbridge.h"
#include <cpu/cpu.h>
#include <cpu/amd/lxdef.h>
#include <cpu/x86/msr.h>
#include <cpu/x86/cache.h>
#include <cpu/amd/vr.h>
+#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 @@
/* 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:
- * <a> represents the IRQ for INTA,
- * <b> represents the IRQ for INTB,
- * <c> represents the IRQ for INTC, and
- * <d> 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 @@
//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 @@
/* 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_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);
Modified: trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridgeinit.c
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridgeinit.c 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/northbridgeinit.c 2007-05-04 18:58:42 UTC (rev 2630)
@@ -1,3 +1,9 @@
+/*
+*
+* Copyright (C) 2007 Advanced Micro Devices
+*
+*/
+
#include <console/console.h>
#include <arch/io.h>
#include <stdint.h>
@@ -13,7 +19,6 @@
#include <cpu/x86/msr.h>
#include <cpu/x86/cache.h>
-/* put this here for now, we are not sure where it belongs */
struct gliutable {
unsigned long desc_name;
@@ -36,9 +41,10 @@
{.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 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 @@
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 @@
}
}
-/* 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 @@
* 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 @@
/* 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 @@
}
}
+
/* ***************************************************************************/
/* **/
/* * GLPCIInit*/
@@ -255,8 +233,8 @@
/* */
/* 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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
/* * 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 @@
}
-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 @@
* 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 @@
* 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 @@
msr_t msr;
// Set the Enable Register.
-
msr = rdmsr(GLPCI_REN);
msr.lo &= 0xFFFF00FF;
msr.lo |= ( (shadowLo & 0xFFFF0000) >> 8);
@@ -592,26 +543,13 @@
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 @@
/***************************************************************************
*
- * RCONFInit
+ * L1Init
* Set up RCONF_DEFAULT and any other RCONF registers needed
*
* DEVRC_RCONF_DEFAULT:
@@ -639,14 +577,12 @@
#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 @@
}
// 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 @@
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 @@
// 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 @@
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 @@
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__);
}
Modified: trunk/LinuxBIOSv2/src/northbridge/amd/lx/pll_reset.c
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/pll_reset.c 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/pll_reset.c 2007-05-04 18:58:42 UTC (rev 2630)
@@ -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 @@
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);
- 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);
+ }
+}
+
Modified: trunk/LinuxBIOSv2/src/northbridge/amd/lx/raminit.c
===================================================================
--- trunk/LinuxBIOSv2/src/northbridge/amd/lx/raminit.c 2007-05-04 18:47:52 UTC (rev 2629)
+++ trunk/LinuxBIOSv2/src/northbridge/amd/lx/raminit.c 2007-05-04 18:58:42 UTC (rev 2630)
@@ -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 <cpu/amd/lxdef.h>
+#include <arch/io.h>
+#include <spd.h>
+#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;
+ if (dimm == DIMM0){
+ msr.hi &= 0xFFFF0000;
+ msr.hi |= dimm_setting;
+ }else{
+ msr.hi &= 0x0000FFFF;
+ msr.hi |= dimm_setting << 16;
+ }
wrmsr(MC_CF07_DATA, msr);
- msr.lo &= 0xFFFFFFFD;
- 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;
+ msr.lo|= ((rate0 * (GeodeLinkSpeed()/2))/16) << CF07_LOWER_REF_INT_SHIFT;
wrmsr(MC_CF07_DATA, msr);
- msr.lo &= 0xFFFFFFF7;
- 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;
+ }
- /* 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
+ /************************** 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;
+
+
+ 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);
+ 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);
- msr.lo &= ~((0x01 << 27) | 0x01);
- wrmsr(MC_CF07_DATA, msr);
+}
- //Delay
- i=inb(0x61);
- while (i==inb(0x61));
- i=inb(0x61);
- while (i==inb(0x61));
- i=inb(0x61);
- while (i==inb(0x61));
+static void EnableMTest (void){
+ msr_t msr;
- /* 8. load Mode Register by set and clear PROG_DRAM */
+ 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();
+
+ /* Set Extended Mode Registers */
+ set_extended_mode_registers();
+
+ /* 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)));
+
+
+ /* 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
- /* Fixes from Jordan Crouse of AMD. */
-
/* 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");
+
+
+}