preliminary GX DRAM initization. It is not working yet.
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@2181 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
parent
02bb7892fe
commit
108dd2c01e
|
@ -14,7 +14,6 @@
|
|||
#define NORTHBRIDGE_FILE "northbridge.c"
|
||||
/*
|
||||
*/
|
||||
|
||||
static void optimize_xbus(device_t dev)
|
||||
{
|
||||
/* Optimise X-Bus performance */
|
||||
|
@ -119,7 +118,7 @@ static void pci_domain_set_resources(device_t dev)
|
|||
{
|
||||
device_t mc_dev;
|
||||
uint32_t pci_tolm;
|
||||
|
||||
#if 0
|
||||
pci_tolm = find_pci_tolm(&dev->link[0]);
|
||||
mc_dev = dev->link[0].children;
|
||||
if (mc_dev) {
|
||||
|
@ -162,6 +161,7 @@ static void pci_domain_set_resources(device_t dev)
|
|||
ram_resource(dev, idx++, 0, tolmk);
|
||||
}
|
||||
assign_resources(&dev->link[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
static unsigned int pci_domain_scan_bus(device_t dev, unsigned int max)
|
||||
|
|
|
@ -1,357 +1,111 @@
|
|||
#include <cpu/amd/gx2def.h>
|
||||
|
||||
/*
|
||||
This software and ancillary information (herein called SOFTWARE )
|
||||
called LinuxBIOS is made available under the terms described
|
||||
here. The SOFTWARE has been approved for release with associated
|
||||
LA-CC Number 00-34 . Unless otherwise indicated, this SOFTWARE has
|
||||
been authored by an employee or employees of the University of
|
||||
California, operator of the Los Alamos National Laboratory under
|
||||
Contract No. W-7405-ENG-36 with the U.S. Department of Energy. The
|
||||
U.S. Government has rights to use, reproduce, and distribute this
|
||||
SOFTWARE. The public may copy, distribute, prepare derivative works
|
||||
and publicly display this SOFTWARE without charge, provided that this
|
||||
Notice and any statement of authorship are reproduced on all copies.
|
||||
Neither the Government nor the University makes any warranty, express
|
||||
or implied, or assumes any liability or responsibility for the use of
|
||||
this SOFTWARE. If SOFTWARE is modified to produce derivative works,
|
||||
such modified SOFTWARE should be clearly marked, so as not to confuse
|
||||
it with the version available from LANL.
|
||||
*/
|
||||
/* Copyright 2000, Ron Minnich, Advanced Computing Lab, LANL
|
||||
* rminnich@lanl.gov
|
||||
*/
|
||||
|
||||
/* SDRAM initialization for GX1 - translated from Christer Weinigel's
|
||||
assembler version into C.
|
||||
|
||||
Hamish Guthrie 10/4/2005 hamish@prodigi.ch
|
||||
*/
|
||||
/* just converted to GX2 by ron minnich -- this is probably mostly wrong
|
||||
* I am just putting in a placeholder to start building gx2 support
|
||||
*/
|
||||
|
||||
#define NUM_REFRESH 8
|
||||
#define TEST_DATA1 0x05A5A5A5A
|
||||
#define TEST_DATA2 0x0DEADBEEF
|
||||
|
||||
void setGX2Mem(unsigned int addr, unsigned int data)
|
||||
static void sdram_set_registers(const struct mem_controller *ctrl)
|
||||
{
|
||||
writel(data, (volatile void *)addr);
|
||||
}
|
||||
|
||||
unsigned int getGX2Mem(unsigned int addr)
|
||||
{
|
||||
return (unsigned int)readl((const volatile void *)addr);
|
||||
}
|
||||
|
||||
void do_refresh(void)
|
||||
{
|
||||
unsigned int tval, i;
|
||||
|
||||
outb(0x71, 0x80);
|
||||
tval = getGX2Mem(GX_BASE + MC_MEM_CNTRL1);
|
||||
tval |= RFSHTST;
|
||||
for(i=0; i>NUM_REFRESH; i++)
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
outb(0x72, 0x80);
|
||||
}
|
||||
|
||||
|
||||
void enable_dimm(void)
|
||||
{
|
||||
unsigned int tval, i;
|
||||
|
||||
outb(0x73, 0x80);
|
||||
|
||||
/* start SDCLCK's */
|
||||
tval = getGX2Mem(GX_BASE + MC_MEM_CNTRL1);
|
||||
tval &= ~SDCLKSTRT;
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
tval |= SDCLKSTRT;
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
|
||||
/* Unmask SDCLK's */
|
||||
tval = getGX2Mem(GX_BASE + MC_MEM_CNTRL2);
|
||||
tval &= ~(SDCLK_MASK | SDCLKOUT_MASK);
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL2, tval);
|
||||
tval = getGX2Mem(GX_BASE + MC_MEM_CNTRL2);
|
||||
|
||||
/* Wait for clocks to unmask */
|
||||
for(i=0; i<5000; i++)
|
||||
outb(0, 0xed);
|
||||
|
||||
/* Refresh memory */
|
||||
tval = getGX2Mem(GX_BASE + MC_MEM_CNTRL1);
|
||||
tval |= RFSHTST;
|
||||
for(i=0; i<NUM_REFRESH; i++)
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
tval &= ~RFSHTST;
|
||||
|
||||
/* Start the SDCLK's */
|
||||
tval &= ~PROGRAM_SDRAM;
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
tval |= PROGRAM_SDRAM | 0x00002000; /* Set refresh timing */
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
tval &= ~PROGRAM_SDRAM;
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
|
||||
/* Refresh memory again */
|
||||
tval = getGX2Mem(GX_BASE + MC_MEM_CNTRL1);
|
||||
tval |= RFSHTST;
|
||||
for(i=0; i>NUM_REFRESH; i++)
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, tval);
|
||||
|
||||
for(i=0; i<2000; i++)
|
||||
outb(0, 0xed);
|
||||
outb(0x74, 0x80);
|
||||
}
|
||||
|
||||
static unsigned int size_dimm(int dimm_shift)
|
||||
{
|
||||
int bank_cfg = 0x700; /* MC_BANK_CFG for 512M */
|
||||
unsigned int offset = 0x10000000; /* Offset 256M */
|
||||
int failed_flag = 1;
|
||||
|
||||
do {
|
||||
setGX2Mem(0, TEST_DATA1);
|
||||
setGX2Mem(offset, TEST_DATA2);
|
||||
setGX2Mem(0x100, 0); /* Clear the bus */
|
||||
if (getGX2Mem(0) != TEST_DATA1) {
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG,
|
||||
getGX2Mem(GX_BASE + MC_BANK_CFG) & ~(DIMM_SZ << dimm_shift));
|
||||
bank_cfg -= 0x100;
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG,
|
||||
getGX2Mem(GX_BASE + MC_BANK_CFG) | (bank_cfg << dimm_shift));
|
||||
do_refresh();
|
||||
offset >>= 1;
|
||||
} else {
|
||||
failed_flag = 0;
|
||||
break;
|
||||
}
|
||||
} while (bank_cfg >= 0);
|
||||
|
||||
if (failed_flag)
|
||||
return (0x0070 << dimm_shift);
|
||||
else
|
||||
return(getGX2Mem(GX_BASE + MC_BANK_CFG) & (DIMM_SZ << dimm_shift));
|
||||
|
||||
}
|
||||
|
||||
static unsigned int module_banks(int dimm_shift)
|
||||
{
|
||||
int page_size = 0x800; /* Smallest page = 1K * 2 banks */
|
||||
int comp_banks;
|
||||
|
||||
#if 0
|
||||
print_debug("MC_BANK_CFG = ");
|
||||
print_debug_hex32(getGX2Mem(GX_BASE + MC_BANK_CFG));
|
||||
print_debug("\r\n");
|
||||
#endif
|
||||
|
||||
/* retrieve the page size from the MC register */
|
||||
page_size <<= (((getGX2Mem(GX_BASE + MC_BANK_CFG) & (DIMM_PG_SZ << dimm_shift)) >> dimm_shift) >> 4);
|
||||
|
||||
#if 0
|
||||
print_debug(" page_size = ");
|
||||
print_debug_hex32(page_size);
|
||||
print_debug("\r\n");
|
||||
#endif
|
||||
|
||||
comp_banks = (((getGX2Mem(GX_BASE + MC_BANK_CFG) & (DIMM_COMP_BNK << dimm_shift)) >> dimm_shift) >> 12);
|
||||
page_size <<= comp_banks;
|
||||
|
||||
setGX2Mem(0, TEST_DATA1);
|
||||
setGX2Mem(page_size, TEST_DATA2);
|
||||
setGX2Mem(0x100, 0); /* Clear the bus */
|
||||
if (getGX2Mem(page_size) != TEST_DATA2) {
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG,
|
||||
getGX2Mem(GX_BASE + MC_BANK_CFG) & ~(DIMM_MOD_BNK << dimm_shift));
|
||||
do_refresh();
|
||||
}
|
||||
#if 0
|
||||
print_debug("MC_BANK_CFG = ");
|
||||
print_debug_hex32(getGX2Mem(GX_BASE + MC_BANK_CFG));
|
||||
print_debug("\r\n");
|
||||
#endif
|
||||
return(getGX2Mem(GX_BASE + MC_BANK_CFG) & (DIMM_MOD_BNK << dimm_shift));
|
||||
}
|
||||
|
||||
static unsigned int component_banks(int dimm_shift)
|
||||
{
|
||||
int page_size = 0x800; /* Smallest page = 1K * 2 banks */
|
||||
|
||||
#if 0
|
||||
print_debug("MC_BANK_CFG = ");
|
||||
print_debug_hex32(getGX2Mem(GX_BASE + MC_BANK_CFG));
|
||||
print_debug("\r\n");
|
||||
#endif
|
||||
|
||||
page_size = page_size << (((getGX2Mem(GX_BASE + MC_BANK_CFG) & (DIMM_PG_SZ << dimm_shift)) >> dimm_shift) >> 4);
|
||||
|
||||
#if 0
|
||||
print_debug(" page_size = ");
|
||||
print_debug_hex32(page_size);
|
||||
print_debug("\r\n");
|
||||
#endif
|
||||
|
||||
setGX2Mem(0, TEST_DATA1);
|
||||
setGX2Mem(page_size, TEST_DATA2);
|
||||
setGX2Mem(0x100, 0); /* Clear the bus */
|
||||
if (getGX2Mem(0) != TEST_DATA1) {
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG,
|
||||
getGX2Mem(GX_BASE + MC_BANK_CFG) & ~(DIMM_COMP_BNK << dimm_shift));
|
||||
do_refresh();
|
||||
}
|
||||
#if 0
|
||||
print_debug("MC_BANK_CFG = ");
|
||||
print_debug_hex32(getGX2Mem(GX_BASE + MC_BANK_CFG));
|
||||
print_debug("\r\n");
|
||||
#endif
|
||||
return(getGX2Mem(GX_BASE + MC_BANK_CFG) & (DIMM_COMP_BNK << dimm_shift));
|
||||
}
|
||||
|
||||
static unsigned int page_size(int dimm_shift)
|
||||
{
|
||||
unsigned int page_test_offset = 0x2000;
|
||||
unsigned int temp;
|
||||
int page_size_config = 0x40;
|
||||
unsigned int probe_config;
|
||||
|
||||
do {
|
||||
setGX2Mem(0, TEST_DATA1);
|
||||
setGX2Mem(page_test_offset, TEST_DATA2);
|
||||
setGX2Mem(0x100, 0);
|
||||
temp = getGX2Mem(0);
|
||||
setGX2Mem(0, 0);
|
||||
if(temp == TEST_DATA1) {
|
||||
#if 0
|
||||
print_debug(" Page size Config = ");
|
||||
print_debug_hex32(page_size_config << dimm_shift);
|
||||
print_debug("\r\n");
|
||||
#endif
|
||||
return(page_size_config << dimm_shift);
|
||||
}
|
||||
|
||||
temp = ~(DIMM_PG_SZ << dimm_shift);
|
||||
|
||||
probe_config = getGX2Mem(GX_BASE + MC_BANK_CFG);
|
||||
probe_config &= temp;
|
||||
|
||||
page_size_config -= 0x10;
|
||||
page_size_config <<= dimm_shift;
|
||||
|
||||
probe_config |= page_size_config;
|
||||
|
||||
page_size_config >>= dimm_shift;
|
||||
|
||||
page_test_offset >>= 1;
|
||||
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG, probe_config);
|
||||
do_refresh();
|
||||
} while (page_size_config >= 0);
|
||||
|
||||
return 0x70;
|
||||
}
|
||||
|
||||
static int dimm_detect(int dimm_shift)
|
||||
{
|
||||
unsigned int test;
|
||||
|
||||
print_debug("Probing for DIMM");
|
||||
print_debug_char((dimm_shift >> 4) + 0x30);
|
||||
print_debug("\r\n");
|
||||
|
||||
setGX2Mem(0, TEST_DATA1);
|
||||
setGX2Mem(0x100, 0);
|
||||
test = getGX2Mem(0);
|
||||
setGX2Mem(0, 0);
|
||||
|
||||
if (test != TEST_DATA1)
|
||||
return 0;
|
||||
|
||||
print_debug(" Found DIMM");
|
||||
print_debug_char((dimm_shift >> 4) + 0x30);
|
||||
print_debug("\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int size_memory(int dimm_shift, unsigned int mem_config)
|
||||
static void sdram_set_spd_registers(const struct mem_controller *ctrl)
|
||||
{
|
||||
|
||||
if (!dimm_detect(dimm_shift))
|
||||
return (mem_config);
|
||||
|
||||
mem_config &= (~(DIMM_PG_SZ << dimm_shift));
|
||||
mem_config |= (page_size(dimm_shift));
|
||||
|
||||
print_debug(" Page Size: ");
|
||||
print_debug_hex32(0x400 << ((mem_config & (DIMM_PG_SZ << dimm_shift)) >> (dimm_shift + 4)));
|
||||
print_debug("\r\n");
|
||||
|
||||
/* Now do component banks detection */
|
||||
|
||||
mem_config &= (~(DIMM_COMP_BNK << dimm_shift));
|
||||
mem_config |= (component_banks(dimm_shift));
|
||||
|
||||
print_debug(" Component Banks: ");
|
||||
print_debug_char((((mem_config & (DIMM_COMP_BNK << dimm_shift)) >> (dimm_shift + 12)) ? 4 : 2) + 0x30);
|
||||
print_debug("\r\n");
|
||||
|
||||
/* Now do module banks */
|
||||
|
||||
mem_config &= (~(DIMM_MOD_BNK << dimm_shift));
|
||||
mem_config |= (module_banks(dimm_shift));
|
||||
|
||||
print_debug(" Module Banks: ");
|
||||
print_debug_char((((mem_config & (DIMM_MOD_BNK << dimm_shift)) >> (dimm_shift + 14)) ? 2 : 1) + 0x30);
|
||||
print_debug("\r\n");
|
||||
|
||||
mem_config &= (~(DIMM_SZ << dimm_shift));
|
||||
mem_config |= (size_dimm(dimm_shift));
|
||||
|
||||
print_debug(" DIMM size: ");
|
||||
print_debug_hex32(1 <<
|
||||
((mem_config & (DIMM_SZ << dimm_shift)) >> (dimm_shift + 8)) + 22);
|
||||
print_debug("\r\n");
|
||||
|
||||
return (mem_config);
|
||||
}
|
||||
|
||||
static void sdram_init(void)
|
||||
/* 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)
|
||||
{
|
||||
unsigned int mem_config = 0x00700070;
|
||||
int i;
|
||||
msr_t msr;
|
||||
|
||||
print_debug("Setting up default parameters for memory\r\n");
|
||||
outb(0x70, 0x80);
|
||||
/* 1. Initialize GLMC registers base on SPD values,
|
||||
* Hard coded as XpressROM for now */
|
||||
print_debug("sdram_enable step 1\r\n");
|
||||
msr = rdmsr(0x20000018);
|
||||
msr.hi = 0x10076013;
|
||||
msr.lo = 0x00004800;
|
||||
wrmsr(0x20000018, msr);
|
||||
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL2, 0x000007d8); /* Disable all CLKS, Shift = 3 */
|
||||
setGX2Mem(GX_BASE + MC_MEM_CNTRL1, 0x92140000); /* MD_DS=2, MA_DS=2, CNTL_DS=2 SDCLKRATE=4 */
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG, 0x00700070); /* No DIMMS installed */
|
||||
setGX2Mem(GX_BASE + MC_SYNC_TIM1, 0x3a733225); /* LTMODE=3, RC=10, RAS=7, RP=3, RCD=3, RRD=2, DPL=2 */
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG, 0x57405740); /* Largest DIMM size
|
||||
0x4000 -- 2 module banks
|
||||
0x1000 -- 4 component banks
|
||||
0x0700 -- DIMM size 512MB
|
||||
0x0040 -- Page Size 16kB */
|
||||
msr = rdmsr(0x20000019);
|
||||
msr.hi = 0x18000108;
|
||||
msr.lo = 0x286332a3;
|
||||
wrmsr(0x20000019, msr);
|
||||
|
||||
enable_dimm();
|
||||
/* 2. release from PMode */
|
||||
msr = rdmsr(0x20002004);
|
||||
msr.lo &= !0x04;
|
||||
msr.lo |= 0x01;
|
||||
wrmsr(0x20002004, msr);
|
||||
/* undocmented bits in GX, in LX there are
|
||||
* 8 bits in PM1_UP_DLY */
|
||||
msr = rdmsr(0x2000001a);
|
||||
//msr.lo |= 0xF000;
|
||||
msr.lo = 0x0101;
|
||||
wrmsr(0x2000001a, msr);
|
||||
print_debug("sdram_enable step 2\r\n");
|
||||
|
||||
print_debug("Sizing memory\r\n");
|
||||
/* 3. release CKE mask to enable CKE */
|
||||
msr = rdmsr(0x2000001d);
|
||||
msr.lo &= !(0x03 << 8);
|
||||
wrmsr(0x2000201d, msr);
|
||||
print_debug("sdram_enable step 3\r\n");
|
||||
|
||||
/* 4. set and clear REF_TST 16 times, more shouldn't hurt */
|
||||
for (i = 0; i < 19; i++) {
|
||||
msr = rdmsr(0x20000018);
|
||||
msr.lo |= (0x01 << 3);
|
||||
wrmsr(0x20000018, msr);
|
||||
msr.lo &= !(0x01 << 3);
|
||||
wrmsr(0x20000018, msr);
|
||||
}
|
||||
print_debug("sdram_enable step 4\r\n");
|
||||
|
||||
/* 5. set refresh interval */
|
||||
msr = rdmsr(0x20000018);
|
||||
msr.lo |= (0x48 << 8);
|
||||
wrmsr(0x20000018, msr);
|
||||
|
||||
/* set refresh staggering to 4 SDRAM clocks */
|
||||
msr = rdmsr(0x20000018);
|
||||
msr.lo &= !(0x03 << 6);
|
||||
wrmsr(0x20000018, msr);
|
||||
|
||||
|
||||
/* 6. enable RLL, load Extended Mode Register by set and clear PROG_DRAM */
|
||||
msr = rdmsr(0x20000018);
|
||||
msr.lo |= ((0x01 << 28) | 0x01);
|
||||
wrmsr(0x20000018, msr);
|
||||
msr.lo &= !((0x01 << 28) | 0x01);
|
||||
wrmsr(0x20000018, msr);
|
||||
print_debug("sdram_enable step 7\r\n");
|
||||
|
||||
/* 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 */
|
||||
msr = rdmsr(0x20000018);
|
||||
msr.lo |= ((0x01 << 27) | 0x01);
|
||||
wrmsr(0x20000018, msr);
|
||||
msr.lo &= !((0x01 << 27) | 0x01);
|
||||
wrmsr(0x20000018, msr);
|
||||
print_debug("sdram_enable step 9\r\n");
|
||||
|
||||
|
||||
/* 8. load Mode Register by set and clear PROG_DRAM */
|
||||
msr = rdmsr(0x20000018);
|
||||
msr.lo |= 0x01;
|
||||
wrmsr(0x20000018, msr);
|
||||
msr.lo &= !0x01;
|
||||
wrmsr(0x20000018, msr);
|
||||
print_debug("sdram_enable step 10\r\n");
|
||||
|
||||
/* wait 200 SDCLKs */
|
||||
for (i = 0; i < 200; i++)
|
||||
outb(0xaa, 0x80);
|
||||
|
||||
/* load RDSYNC */
|
||||
msr = rdmsr(0x2000001a);
|
||||
msr.hi = 0x000ff310;
|
||||
wrmsr(0x20000018, msr);
|
||||
print_debug("sdram_enable step 10\r\n");
|
||||
|
||||
/* DRAM working now?? */
|
||||
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG, 0x00705740);
|
||||
do_refresh();
|
||||
mem_config = size_memory(0, mem_config);
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG, 0x57400070);
|
||||
do_refresh();
|
||||
mem_config = size_memory(16, mem_config);
|
||||
|
||||
print_debug("MC_BANK_CFG = ");
|
||||
print_debug_hex32(mem_config);
|
||||
print_debug("\r\n");
|
||||
|
||||
setGX2Mem(GX_BASE + MC_BANK_CFG, mem_config);
|
||||
enable_dimm();
|
||||
outb(0x7e, 0x80);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
#ifndef RAMINIT_H
|
||||
#define RAMINIT_H
|
||||
|
||||
#define DIMM_SOCKETS 4
|
||||
#define DIMM_SOCKETS 2
|
||||
|
||||
struct mem_controller {
|
||||
device_t d0;
|
||||
uint16_t channel0[DIMM_SOCKETS];
|
||||
};
|
||||
|
||||
|
||||
#endif /* RAMINIT_H */
|
||||
|
|
Loading…
Reference in New Issue