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@amd.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2630 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
Marc Jones 2007-05-04 18:58:42 +00:00 committed by Stefan Reinauer
parent 9c9083ba4a
commit 734daf699c
8 changed files with 995 additions and 980 deletions

View File

@ -1,5 +1,4 @@
config chip.h
object northbridge.o
object northbridgeinit.o
object chipsetinit.o
object grphinit.o

View File

@ -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;

View File

@ -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
}
}
}

View File

@ -1,33 +1,16 @@
/*
*
* Copyright (C) 2007 Advanced Micro Devices
*
*/
#include <arch/io.h>
#include <stdint.h>
#include <cpu/amd/vr.h>
#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.
*/
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);

View File

@ -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 @@ 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:
* <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 @@ 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);

View File

@ -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 @@ 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__);
}

View File

@ -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);
}
}

View File

@ -1,123 +1,769 @@
#include <cpu/amd/lxdef.h>
/*
* 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 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;
}
/* 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;
/* 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;
/*; 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
*/
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");
}
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*/
/* 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;
/*; 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);
if (dimm == DIMM0){
msr.hi &= 0xFFFF0000;
msr.hi |= dimm_setting;
}else{
msr.hi &= 0x0000FFFF;
msr.hi |= dimm_setting << 16;
}
wrmsr(MC_CF07_DATA, msr);
}
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|= ((rate0 * (GeodeLinkSpeed()/2))/16) << CF07_LOWER_REF_INT_SHIFT;
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 */
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;
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;
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);
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();
/* 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)
{
int i;
uint32_t i, msrnum;
msr_t msr;
/* 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.
/*********************************************************************
;* 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
/* 2) Initialize the following GLMC registers:
* MSR 2000001Ah[15:8] = C8h
* MSR 20002004h[2] = 0, [0] = 1
*/
msr.hi = 0x00000000;
msr.lo = 0x130AD101;
wrmsr(MC_CF1017_DATA, msr);
/* Only enable MTest for TLA memory debug */
/*EnableMTest();*/
//ok
msr.hi = 0x00000000;
msr.lo = 0x00000001;
wrmsr(MC_GLD_MSR_PM, msr);
/* 3) Release MASK_CKE[1:0] (MSR 2000001Dh[9:8] = 11) */
msr.hi = 0x00000000;
msr.lo = 0x00000000;
wrmsr(MC_CFCLK_DBUG, msr);
// reset memory controller
/* If both Page Size = "Not Installed" we have a problems and should halt. */
msr = rdmsr(MC_CF07_DATA);
msr.lo |= 0x00000002;
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++) {
msr = rdmsr(MC_CF07_DATA);
msr.lo |= 0x00000008;
wrmsr(MC_CF07_DATA, msr);
msr.lo &= 0xFFFFFFF7;
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");
}
/* 5) Initialize REF_INT (MSR 20000018h[23:8]) to set refresh interval. */
msr.lo |= 0x3A00;
wrmsr(MC_CF07_DATA, msr);
/* 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);
msr.lo &= ~((0x01 << 28) | 0x01);
wrmsr(MC_CF07_DATA, msr);
/* Set CKEs */
msrnum = MC_CFCLK_DBUG;
msr = rdmsr(msrnum);
msr.lo &= ~(CFCLK_LOWER_MASK_CKE_SET0 | CFCLK_LOWER_MASK_CKE_SET1);
wrmsr(msrnum, msr);
/* 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
/* 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);
msr.lo |= ((0x01 << 27) | 0x01);
wrmsr(MC_CF07_DATA, msr);
msr.lo &= ~((0x01 << 27) | 0x01);
wrmsr(MC_CF07_DATA, msr);
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);
}
//Delay
i=inb(0x61);
while (i==inb(0x61));
i=inb(0x61);
while (i==inb(0x61));
i=inb(0x61);
while (i==inb(0x61));
/* Set PMode0 Sensitivity Counter */
msr.lo = 0; /* pmode 0=0 most aggressive */
msr.hi = 0x200; /* pmode 1=200h */
wrmsr(MC_CF_PMCTR, msr);
/* 8. load Mode Register by set and clear PROG_DRAM */
msr = rdmsr(MC_CF07_DATA);
msr.lo |= 0x01;
wrmsr(MC_CF07_DATA, msr);
msr.lo &= ~0x01;
wrmsr(MC_CF07_DATA, msr);
/* wait 200 SDCLKs */
for (i = 0; i < 200; i++)
outb(0xaa, 0x80);
/* 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");
/* Fixes from Jordan Crouse of AMD. */
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");
}