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:
parent
9c9083ba4a
commit
734daf699c
|
@ -1,5 +1,4 @@
|
|||
config chip.h
|
||||
object northbridge.o
|
||||
object northbridgeinit.o
|
||||
object chipsetinit.o
|
||||
object grphinit.o
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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__);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue