Files
system76-coreboot/src/northbridge/intel/e7520/raminit.c
Stefan Reinauer 14e2277962 Since some people disapprove of white space cleanups mixed in regular commits
while others dislike them being extra commits, let's clean them up once and
for all for the existing code. If it's ugly, let it only be ugly once :-)

Signed-off-by: Stefan Reinauer <stepan@coresystems.de>
Acked-by: Stefan Reinauer <stepan@coresystems.de>



git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5507 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
2010-04-27 06:56:47 +00:00

1354 lines
32 KiB
C

/*
* This file is part of the coreboot project.
*
* Copyright (C) 2005 Eric W. Biederman and Tom Zimmerman
*
* 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/x86/mtrr.h>
#include <cpu/x86/cache.h>
#include <stdlib.h>
#include "raminit.h"
#include "e7520.h"
#define BAR 0x40000000
static void sdram_set_registers(const struct mem_controller *ctrl)
{
static const unsigned int register_values[] = {
/* CKDIS 0x8c disable clocks */
PCI_ADDR(0, 0x00, 0, CKDIS), 0xffff0000, 0x0000ffff,
/* 0x9c Device present and extended RAM control
* DEVPRES is very touchy, hard code the initialization
* of PCI-E ports here.
*/
PCI_ADDR(0, 0x00, 0, DEVPRES), 0x00000000, 0x07020801 | DEVPRES_CONFIG,
/* 0xc8 Remap RAM base and limit off */
PCI_ADDR(0, 0x00, 0, REMAPLIMIT), 0x00000000, 0x03df0000,
/* ??? */
PCI_ADDR(0, 0x00, 0, 0xd8), 0x00000000, 0xb5930000,
PCI_ADDR(0, 0x00, 0, 0xe8), 0x00000000, 0x00004a2a,
/* 0x50 scrub */
PCI_ADDR(0, 0x00, 0, MCHCFG0), 0xfce0ffff, 0x00006000, /* 6000 */
/* 0x58 0x5c PAM */
PCI_ADDR(0, 0x00, 0, PAM-1), 0xcccccc7f, 0x33333000,
PCI_ADDR(0, 0x00, 0, PAM+3), 0xcccccccc, 0x33333333,
/* 0xf4 */
PCI_ADDR(0, 0x00, 0, DEVPRES1), 0xffbffff, (1<<22)|(6<<2) | DEVPRES1_CONFIG,
/* 0x14 */
PCI_ADDR(0, 0x00, 0, IURBASE), 0x00000fff, BAR |0,
};
int i;
int max;
max = ARRAY_SIZE(register_values);
for(i = 0; i < max; i += 3) {
device_t dev;
unsigned where;
unsigned long reg;
dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x00, 0) + PCI_DEV(0, 0x00, 0);
where = register_values[i] & 0xff;
reg = pci_read_config32(dev, where);
reg &= register_values[i+1];
reg |= register_values[i+2];
pci_write_config32(dev, where, reg);
}
print_spew("done.\n");
}
struct dimm_size {
unsigned long side1;
unsigned long side2;
};
static struct dimm_size spd_get_dimm_size(unsigned device)
{
/* Calculate the log base 2 size of a DIMM in bits */
struct dimm_size sz;
int value, low, ddr2;
sz.side1 = 0;
sz.side2 = 0;
/* test for ddr2 */
ddr2=0;
value = spd_read_byte(device, 2); /* type */
if (value < 0) goto hw_err;
if (value == 8) ddr2 = 1;
/* Note it might be easier to use byte 31 here, it has the DIMM size as
* a multiple of 4MB. The way we do it now we can size both
* sides of an assymetric dimm.
*/
value = spd_read_byte(device, 3); /* rows */
if (value < 0) goto hw_err;
if ((value & 0xf) == 0) goto val_err;
sz.side1 += value & 0xf;
value = spd_read_byte(device, 4); /* columns */
if (value < 0) goto hw_err;
if ((value & 0xf) == 0) goto val_err;
sz.side1 += value & 0xf;
value = spd_read_byte(device, 17); /* banks */
if (value < 0) goto hw_err;
if ((value & 0xff) == 0) goto val_err;
sz.side1 += log2(value & 0xff);
/* Get the module data width and convert it to a power of two */
value = spd_read_byte(device, 7); /* (high byte) */
if (value < 0) goto hw_err;
value &= 0xff;
value <<= 8;
low = spd_read_byte(device, 6); /* (low byte) */
if (low < 0) goto hw_err;
value = value | (low & 0xff);
if ((value != 72) && (value != 64)) goto val_err;
sz.side1 += log2(value);
/* side 2 */
value = spd_read_byte(device, 5); /* number of physical banks */
if (value < 0) goto hw_err;
value &= 7;
if(ddr2) value++;
if (value == 1) goto out;
if (value != 2) goto val_err;
/* Start with the symmetrical case */
sz.side2 = sz.side1;
value = spd_read_byte(device, 3); /* rows */
if (value < 0) goto hw_err;
if ((value & 0xf0) == 0) goto out; /* If symmetrical we are done */
sz.side2 -= (value & 0x0f); /* Subtract out rows on side 1 */
sz.side2 += ((value >> 4) & 0x0f); /* Add in rows on side 2 */
value = spd_read_byte(device, 4); /* columns */
if (value < 0) goto hw_err;
if ((value & 0xff) == 0) goto val_err;
sz.side2 -= (value & 0x0f); /* Subtract out columns on side 1 */
sz.side2 += ((value >> 4) & 0x0f); /* Add in columsn on side 2 */
goto out;
val_err:
die("Bad SPD value\n");
/* If an hw_error occurs report that I have no memory */
hw_err:
sz.side1 = 0;
sz.side2 = 0;
out:
return sz;
}
static long spd_set_ram_size(const struct mem_controller *ctrl, long dimm_mask)
{
int i;
int cum;
for(i = cum = 0; i < DIMM_SOCKETS; i++) {
struct dimm_size sz;
if (dimm_mask & (1 << i)) {
sz = spd_get_dimm_size(ctrl->channel0[i]);
if (sz.side1 < 29) {
return -1; /* Report SPD error */
}
/* convert bits to multiples of 64MB */
sz.side1 -= 29;
cum += (1 << sz.side1);
/* DRB = 0x60 */
pci_write_config8(PCI_DEV(0, 0x00, 0), DRB + (i*2), cum);
if( sz.side2 > 28) {
sz.side2 -= 29;
cum += (1 << sz.side2);
}
pci_write_config8(PCI_DEV(0, 0x00, 0), DRB+1 + (i*2), cum);
}
else {
pci_write_config8(PCI_DEV(0, 0x00, 0), DRB + (i*2), cum);
pci_write_config8(PCI_DEV(0, 0x00, 0), DRB+1 + (i*2), cum);
}
}
/* set TOM top of memory 0xcc */
pci_write_config16(PCI_DEV(0, 0x00, 0), TOM, cum);
/* set TOLM top of low memory */
if(cum > 0x18) {
cum = 0x18;
}
cum <<= 11;
/* 0xc4 TOLM */
pci_write_config16(PCI_DEV(0, 0x00, 0), TOLM, cum);
return 0;
}
static unsigned int spd_detect_dimms(const struct mem_controller *ctrl)
{
unsigned dimm_mask;
int i;
dimm_mask = 0;
for(i = 0; i < DIMM_SOCKETS; i++) {
int byte;
unsigned device;
device = ctrl->channel0[i];
if (device) {
byte = spd_read_byte(device, 2); /* Type */
if ((byte == 7) || (byte == 8)) {
dimm_mask |= (1 << i);
}
}
device = ctrl->channel1[i];
if (device) {
byte = spd_read_byte(device, 2);
if ((byte == 7) || (byte == 8)) {
dimm_mask |= (1 << (i + DIMM_SOCKETS));
}
}
}
return dimm_mask;
}
static int spd_set_row_attributes(const struct mem_controller *ctrl,
long dimm_mask)
{
int value;
int reg;
int dra;
int cnt;
dra = 0;
for(cnt=0; cnt < 4; cnt++) {
if (!(dimm_mask & (1 << cnt))) {
continue;
}
reg =0;
value = spd_read_byte(ctrl->channel0[cnt], 3); /* rows */
if (value < 0) goto hw_err;
if ((value & 0xf) == 0) goto val_err;
reg += value & 0xf;
value = spd_read_byte(ctrl->channel0[cnt], 4); /* columns */
if (value < 0) goto hw_err;
if ((value & 0xf) == 0) goto val_err;
reg += value & 0xf;
value = spd_read_byte(ctrl->channel0[cnt], 17); /* banks */
if (value < 0) goto hw_err;
if ((value & 0xff) == 0) goto val_err;
reg += log2(value & 0xff);
/* Get the device width and convert it to a power of two */
value = spd_read_byte(ctrl->channel0[cnt], 13);
if (value < 0) goto hw_err;
value = log2(value & 0xff);
reg += value;
if(reg < 27) goto hw_err;
reg -= 27;
reg += (value << 2);
dra += reg << (cnt*8);
value = spd_read_byte(ctrl->channel0[cnt], 5);
if (value & 2)
dra += reg << ((cnt*8)+4);
}
/* 0x70 DRA */
pci_write_config32(PCI_DEV(0, 0x00, 0), DRA, dra);
goto out;
val_err:
die("Bad SPD value\n");
/* If an hw_error occurs report that I have no memory */
hw_err:
dra = 0;
out:
return dra;
}
static int spd_set_drt_attributes(const struct mem_controller *ctrl,
long dimm_mask, uint32_t drc)
{
int value;
int reg;
uint32_t drt;
int cnt;
int first_dimm;
int cas_latency=0;
int latency;
uint32_t index = 0;
uint32_t index2 = 0;
static const unsigned char cycle_time[3] = {0x75,0x60,0x50};
static const int latency_indicies[] = { 26, 23, 9 };
/* 0x78 DRT */
drt = pci_read_config32(PCI_DEV(0, 0x00, 0), DRT);
drt &= 3; /* save bits 1:0 */
for(first_dimm = 0; first_dimm < 4; first_dimm++) {
if (dimm_mask & (1 << first_dimm))
break;
}
/* get dimm type */
value = spd_read_byte(ctrl->channel0[first_dimm], 2);
if(value == 8) {
drt |= (3<<5); /* back to bark write turn around & cycle add */
}
drt |= (3<<18); /* Trasmax */
for(cnt=0; cnt < 4; cnt++) {
if (!(dimm_mask & (1 << cnt))) {
continue;
}
reg = spd_read_byte(ctrl->channel0[cnt], 18); /* CAS Latency */
/* Compute the lowest cas latency supported */
latency = log2(reg) -2;
/* Loop through and find a fast clock with a low latency */
for(index = 0; index < 3; index++, latency++) {
if ((latency < 2) || (latency > 4) ||
(!(reg & (1 << latency)))) {
continue;
}
value = spd_read_byte(ctrl->channel0[cnt],
latency_indicies[index]);
if(value <= cycle_time[drc&3]) {
if( latency > cas_latency) {
cas_latency = latency;
}
break;
}
}
}
index = (cas_latency-2);
if((index)==0) cas_latency = 20;
else if((index)==1) cas_latency = 25;
else cas_latency = 30;
for(cnt=0;cnt<4;cnt++) {
if (!(dimm_mask & (1 << cnt))) {
continue;
}
reg = spd_read_byte(ctrl->channel0[cnt], 27)&0x0ff;
if(((index>>8)&0x0ff)<reg) {
index &= ~(0x0ff << 8);
index |= (reg << 8);
}
reg = spd_read_byte(ctrl->channel0[cnt], 28)&0x0ff;
if(((index>>16)&0x0ff)<reg) {
index &= ~(0x0ff << 16);
index |= (reg<<16);
}
reg = spd_read_byte(ctrl->channel0[cnt], 29)&0x0ff;
if(((index2>>0)&0x0ff)<reg) {
index2 &= ~(0x0ff << 0);
index2 |= (reg<<0);
}
reg = spd_read_byte(ctrl->channel0[cnt], 41)&0x0ff;
if(((index2>>8)&0x0ff)<reg) {
index2 &= ~(0x0ff << 8);
index2 |= (reg<<8);
}
reg = spd_read_byte(ctrl->channel0[cnt], 42)&0x0ff;
if(((index2>>16)&0x0ff)<reg) {
index2 &= ~(0x0ff << 16);
index2 |= (reg<<16);
}
}
/* get dimm speed */
value = cycle_time[drc&3];
if(value <= 0x50) { /* 200 MHz */
if((index&7) > 2) {
drt |= (2<<2); /* CAS latency 4 */
cas_latency = 40;
} else {
drt |= (1<<2); /* CAS latency 3 */
cas_latency = 30;
}
if((index&0x0ff00)<=0x03c00) {
drt |= (1<<8); /* Trp RAS Precharg */
} else {
drt |= (2<<8); /* Trp RAS Precharg */
}
/* Trcd RAS to CAS delay */
if((index2&0x0ff)<=0x03c) {
drt |= (0<<10);
} else {
drt |= (1<<10);
}
/* Tdal Write auto precharge recovery delay */
drt |= (1<<12);
/* Trc TRS min */
if((index2&0x0ff00)<=0x03700)
drt |= (0<<14);
else if((index2&0xff00)<=0x03c00)
drt |= (1<<14);
else
drt |= (2<<14); /* spd 41 */
drt |= (2<<16); /* Twr not defined for DDR docs say use 2 */
/* Trrd Row Delay */
if((index&0x0ff0000)<=0x0140000) {
drt |= (0<<20);
} else if((index&0x0ff0000)<=0x0280000) {
drt |= (1<<20);
} else if((index&0x0ff0000)<=0x03c0000) {
drt |= (2<<20);
} else {
drt |= (3<<20);
}
/* Trfc Auto refresh cycle time */
if((index2&0x0ff0000)<=0x04b0000) {
drt |= (0<<22);
} else if((index2&0x0ff0000)<=0x0690000) {
drt |= (1<<22);
} else {
drt |= (2<<22);
}
/* Docs say use 55 for all 200Mhz */
drt |= (0x055<<24);
}
else if(value <= 0x60) { /* 167 Mhz */
/* according to new documentation CAS latency is 00
* for bits 3:2 for all 167 Mhz
drt |= ((index&3)<<2); */ /* set CAS latency */
if((index&0x0ff00)<=0x03000) {
drt |= (1<<8); /* Trp RAS Precharg */
} else {
drt |= (2<<8); /* Trp RAS Precharg */
}
/* Trcd RAS to CAS delay */
if((index2&0x0ff)<=0x030) {
drt |= (0<<10);
} else {
drt |= (1<<10);
}
/* Tdal Write auto precharge recovery delay */
drt |= (2<<12);
/* Trc TRS min */
drt |= (2<<14); /* spd 41, but only one choice */
drt |= (2<<16); /* Twr not defined for DDR docs say 2 */
/* Trrd Row Delay */
if((index&0x0ff0000)<=0x0180000) {
drt |= (0<<20);
} else if((index&0x0ff0000)<=0x0300000) {
drt |= (1<<20);
} else {
drt |= (2<<20);
}
/* Trfc Auto refresh cycle time */
if((index2&0x0ff0000)<=0x0480000) {
drt |= (0<<22);
} else if((index2&0x0ff0000)<=0x0780000) {
drt |= (2<<22);
} else {
drt |= (2<<22);
}
/* Docs state to use 99 for all 167 Mhz */
drt |= (0x099<<24);
}
else if(value <= 0x75) { /* 133 Mhz */
drt |= ((index&3)<<2); /* set CAS latency */
if((index&0x0ff00)<=0x03c00) {
drt |= (1<<8); /* Trp RAS Precharg */
} else {
drt |= (2<<8); /* Trp RAS Precharg */
}
/* Trcd RAS to CAS delay */
if((index2&0x0ff)<=0x03c) {
drt |= (0<<10);
} else {
drt |= (1<<10);
}
/* Tdal Write auto precharge recovery delay */
drt |= (1<<12);
/* Trc TRS min */
drt |= (2<<14); /* spd 41, but only one choice */
drt |= (1<<16); /* Twr not defined for DDR docs say 1 */
/* Trrd Row Delay */
if((index&0x0ff0000)<=0x01e0000) {
drt |= (0<<20);
} else if((index&0x0ff0000)<=0x03c0000) {
drt |= (1<<20);
} else {
drt |= (2<<20);
}
/* Trfc Auto refresh cycle time */
if((index2&0x0ff0000)<=0x04b0000) {
drt |= (0<<22);
} else if((index2&0x0ff0000)<=0x0780000) {
drt |= (2<<22);
} else {
drt |= (2<<22);
}
/* Based on CAS latency */
if(index&7)
drt |= (0x099<<24);
else
drt |= (0x055<<24);
}
else {
die("Invalid SPD 9 bus speed.\n");
}
/* 0x78 DRT */
pci_write_config32(PCI_DEV(0, 0x00, 0), DRT, drt);
return(cas_latency);
}
static int spd_set_dram_controller_mode(const struct mem_controller *ctrl,
long dimm_mask)
{
int value;
int reg;
int drc;
int cnt;
msr_t msr;
unsigned char dram_type = 0xff;
unsigned char ecc = 0xff;
unsigned char rate = 62;
static const unsigned char spd_rates[6] = {15,3,7,7,62,62};
static const unsigned char drc_rates[5] = {0,15,7,62,3};
static const unsigned char fsb_conversion[4] = {3,1,3,2};
/* 0x7c DRC */
drc = pci_read_config32(PCI_DEV(0, 0x00, 0), DRC);
for(cnt=0; cnt < 4; cnt++) {
if (!(dimm_mask & (1 << cnt))) {
continue;
}
value = spd_read_byte(ctrl->channel0[cnt], 11); /* ECC */
reg = spd_read_byte(ctrl->channel0[cnt], 2); /* Type */
if (value == 2) { /* RAM is ECC capable */
if (reg == 8) {
if ( ecc == 0xff ) {
ecc = 2;
}
else if (ecc == 1) {
die("ERROR - Mixed DDR & DDR2 RAM\n");
}
}
else if ( reg == 7 ) {
if ( ecc == 0xff) {
ecc = 1;
}
else if ( ecc > 1 ) {
die("ERROR - Mixed DDR & DDR2 RAM\n");
}
}
else {
die("ERROR - RAM not DDR\n");
}
}
else {
die("ERROR - Non ECC memory dimm\n");
}
value = spd_read_byte(ctrl->channel0[cnt], 12); /*refresh rate*/
value &= 0x0f; /* clip self refresh bit */
if (value > 5) goto hw_err;
if (rate > spd_rates[value])
rate = spd_rates[value];
value = spd_read_byte(ctrl->channel0[cnt], 9); /* cycle time */
if (value > 0x75) goto hw_err;
if (value <= 0x50) {
if (dram_type >= 2) {
if (reg == 8) { /*speed is good, is this ddr2?*/
dram_type = 2;
} else { /* not ddr2 so use ddr333 */
dram_type = 1;
}
}
}
else if (value <= 0x60) {
if (dram_type >= 1) dram_type = 1;
}
else dram_type = 0; /* ddr266 */
}
ecc = 2;
if (read_option(CMOS_VSTART_ECC_memory,CMOS_VLEN_ECC_memory,1) == 0) {
ecc = 0; /* ECC off in CMOS so disable it */
print_debug("ECC off\n");
}
else {
print_debug("ECC on\n");
}
drc &= ~(3 << 20); /* clear the ecc bits */
drc |= (ecc << 20); /* or in the calculated ecc bits */
for ( cnt = 1; cnt < 5; cnt++)
if (drc_rates[cnt] == rate)
break;
if (cnt < 5) {
drc &= ~(7 << 8); /* clear the rate bits */
drc |= (cnt << 8);
}
if (reg == 8) { /* independant clocks */
drc |= (1 << 4);
}
drc |= (1 << 26); /* set the overlap bit - the factory BIOS does */
drc |= (1 << 27); /* set DED retry enable - the factory BIOS does */
/* front side bus */
msr = rdmsr(0x2c);
value = msr.lo >> 16;
value &= 0x03;
drc &= ~(3 << 2); /* set the front side bus */
drc |= (fsb_conversion[value] << 2);
drc &= ~(3 << 0); /* set the dram type */
drc |= (dram_type << 0);
goto out;
val_err:
die("Bad SPD value\n");
/* If an hw_error occurs report that I have no memory */
hw_err:
drc = 0;
out:
return drc;
}
static void sdram_set_spd_registers(const struct mem_controller *ctrl)
{
long dimm_mask;
/* Test if we can read the spd and if ram is ddr or ddr2 */
dimm_mask = spd_detect_dimms(ctrl);
if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
print_err("No memory for this cpu\n");
return;
}
return;
}
static void do_delay(void)
{
int i;
unsigned char b;
for(i=0;i<16;i++)
b=inb(0x80);
}
static void pll_setup(uint32_t drc)
{
unsigned pins;
if(drc&3) { /* DDR 333 or DDR 400 */
if((drc&0x0c) == 0x0c) { /* FSB 200 */
pins = 2 | 1;
}
else if((drc&0x0c) == 0x08) { /* FSB 167 */
pins = 0 | 1;
}
else if(drc&1){ /* FSB 133 DDR 333 */
pins = 2 | 1;
}
else { /* FSB 133 DDR 400 */
pins = 0 | 1;
}
}
else { /* DDR 266 */
if((drc&0x08) == 0x08) { /* FSB 200 or 167 */
pins = 0 | 0;
}
else { /* FSB 133 */
pins = 0 | 1;
}
}
mainboard_set_e7520_pll(pins);
return;
}
#define TIMEOUT_LOOPS 300000
#define DCALCSR 0x100
#define DCALADDR 0x104
#define DCALDATA 0x108
static void set_on_dimm_termination_enable(const struct mem_controller *ctrl)
{
unsigned char c1,c2;
unsigned int dimm,i;
unsigned int data32;
unsigned int t4;
/* Set up northbridge values */
/* ODT enable */
pci_write_config32(PCI_DEV(0, 0x00, 0), 0x88, 0xf0000180);
/* Figure out which slots are Empty, Single, or Double sided */
for(i=0,t4=0,c2=0;i<8;i+=2) {
c1 = pci_read_config8(PCI_DEV(0, 0x00, 0), DRB+i);
if(c1 == c2) continue;
c2 = pci_read_config8(PCI_DEV(0, 0x00, 0), DRB+1+i);
if(c1 == c2)
t4 |= (1 << (i*4));
else
t4 |= (2 << (i*4));
}
for(i=0;i<1;i++) {
if((t4&0x0f) == 1) {
if( ((t4>>8)&0x0f) == 0 ) {
data32 = 0x00000010; /* EEES */
break;
}
if ( ((t4>>16)&0x0f) == 0 ) {
data32 = 0x00003132; /* EESS */
break;
}
if ( ((t4>>24)&0x0f) == 0 ) {
data32 = 0x00335566; /* ESSS */
break;
}
data32 = 0x77bbddee; /* SSSS */
break;
}
if((t4&0x0f) == 2) {
if( ((t4>>8)&0x0f) == 0 ) {
data32 = 0x00003132; /* EEED */
break;
}
if ( ((t4>>8)&0x0f) == 2 ) {
data32 = 0xb373ecdc; /* EEDD */
break;
}
if ( ((t4>>16)&0x0f) == 0 ) {
data32 = 0x00b3a898; /* EESD */
break;
}
data32 = 0x777becdc; /* ESSD */
break;
}
die("Error - First dimm slot empty\n");
}
print_debug("ODT Value = ");
print_debug_hex32(data32);
print_debug("\n");
pci_write_config32(PCI_DEV(0, 0x00, 0), 0xb0, data32);
for(dimm=0;dimm<8;dimm+=1) {
write32(BAR+DCALADDR, 0x0b840001);
write32(BAR+DCALCSR, 0x83000003 | (dimm << 20));
for(i=0;i<1001;i++) {
data32 = read32(BAR+DCALCSR);
if(!(data32 & (1<<31)))
break;
}
}
}
static void set_receive_enable(const struct mem_controller *ctrl)
{
unsigned int i;
unsigned int cnt;
uint32_t recena=0;
uint32_t recenb=0;
{
unsigned int dimm;
unsigned int edge;
int32_t data32;
uint32_t data32_dram;
uint32_t dcal_data32_0;
uint32_t dcal_data32_1;
uint32_t dcal_data32_2;
uint32_t dcal_data32_3;
uint32_t work32l;
uint32_t work32h;
uint32_t data32r;
int32_t recen;
for(dimm=0;dimm<8;dimm+=1) {
if(!(dimm&1)) {
write32(BAR+DCALDATA+(17*4), 0x04020000);
write32(BAR+DCALCSR, 0x83800004 | (dimm << 20));
for(i=0;i<1001;i++) {
data32 = read32(BAR+DCALCSR);
if(!(data32 & (1<<31)))
break;
}
if(i>=1000)
continue;
dcal_data32_0 = read32(BAR+DCALDATA + 0);
dcal_data32_1 = read32(BAR+DCALDATA + 4);
dcal_data32_2 = read32(BAR+DCALDATA + 8);
dcal_data32_3 = read32(BAR+DCALDATA + 12);
}
else {
dcal_data32_0 = read32(BAR+DCALDATA + 16);
dcal_data32_1 = read32(BAR+DCALDATA + 20);
dcal_data32_2 = read32(BAR+DCALDATA + 24);
dcal_data32_3 = read32(BAR+DCALDATA + 28);
}
/* check if bank is installed */
if((dcal_data32_0 == 0) && (dcal_data32_2 == 0))
continue;
/* Calculate the timing value */
{
unsigned int bit;
for(i=0,edge=0,bit=63,cnt=31,data32r=0,
work32l=dcal_data32_1,work32h=dcal_data32_3;
(i<4) && bit; i++) {
for(;;bit--,cnt--) {
if(work32l & (1<<cnt))
break;
if(!cnt) {
work32l = dcal_data32_0;
work32h = dcal_data32_2;
cnt = 32;
}
if(!bit) break;
}
for(;;bit--,cnt--) {
if(!(work32l & (1<<cnt)))
break;
if(!cnt) {
work32l = dcal_data32_0;
work32h = dcal_data32_2;
cnt = 32;
}
if(!bit) break;
}
if(!bit) {
break;
}
data32 = ((bit%8) << 1);
if(work32h & (1<<cnt))
data32 += 1;
if(data32 < 4) {
if(!edge) {
edge = 1;
}
else {
if(edge != 1) {
data32 = 0x0f;
}
}
}
if(data32 > 12) {
if(!edge) {
edge = 2;
}
else {
if(edge != 2) {
data32 = 0x00;
}
}
}
data32r += data32;
}
}
work32l = dcal_data32_0;
work32h = dcal_data32_2;
recen = data32r;
recen += 3;
recen = recen>>2;
for(cnt=5;cnt<24;) {
for(;;cnt++)
if(!(work32l & (1<<cnt)))
break;
for(;;cnt++) {
if(work32l & (1<<cnt))
break;
}
data32 = (((cnt-1)%8)<<1);
if(work32h & (1<<(cnt-1))) {
data32++;
}
/* test for frame edge cross overs */
if((edge == 1) && (data32 > 12) &&
(((recen+16)-data32) < 3)) {
data32 = 0;
cnt += 2;
}
if((edge == 2) && (data32 < 4) &&
((recen - data32) > 12)) {
data32 = 0x0f;
cnt -= 2;
}
if(((recen+3) >= data32) && ((recen-3) <= data32))
break;
}
cnt--;
cnt /= 8;
cnt--;
if(recen&1)
recen+=2;
recen >>= 1;
recen += (cnt*8);
recen+=2; /* this is not in the spec, but matches
the factory output, and has less failure */
recen <<= (dimm/2) * 8;
if(!(dimm&1)) {
recena |= recen;
}
else {
recenb |= recen;
}
}
}
/* Check for Eratta problem */
for(i=cnt=0;i<32;i+=8) {
if (((recena>>i)&0x0f)>7) {
cnt+= 0x101;
}
else {
if((recena>>i)&0x0f) {
cnt++;
}
}
}
if(cnt&0x0f00) {
cnt = (cnt&0x0f) - (cnt>>16);
if(cnt>1) {
for(i=0;i<32;i+=8) {
if(((recena>>i)&0x0f)>7) {
recena &= ~(0x0f<<i);
recena |= (7<<i);
}
}
}
else {
for(i=0;i<32;i+=8) {
if(((recena>>i)&0x0f)<8) {
recena &= ~(0x0f<<i);
recena |= (8<<i);
}
}
}
}
for(i=cnt=0;i<32;i+=8) {
if (((recenb>>i)&0x0f)>7) {
cnt+= 0x101;
}
else {
if((recenb>>i)&0x0f) {
cnt++;
}
}
}
if(cnt & 0x0f00) {
cnt = (cnt&0x0f) - (cnt>>16);
if(cnt>1) {
for(i=0;i<32;i+=8) {
if(((recenb>>i)&0x0f)>7) {
recenb &= ~(0x0f<<i);
recenb |= (7<<i);
}
}
}
else {
for(i=0;i<32;i+=8) {
if(((recenb>>8)&0x0f)<8) {
recenb &= ~(0x0f<<i);
recenb |= (8<<i);
}
}
}
}
print_debug("Receive enable A = ");
print_debug_hex32(recena);
print_debug(", Receive enable B = ");
print_debug_hex32(recenb);
print_debug("\n");
/* clear out the calibration area */
write32(BAR+DCALDATA+(16*4), 0x00000000);
write32(BAR+DCALDATA+(17*4), 0x00000000);
write32(BAR+DCALDATA+(18*4), 0x00000000);
write32(BAR+DCALDATA+(19*4), 0x00000000);
/* No command */
write32(BAR+DCALCSR, 0x0000000f);
write32(BAR+0x150, recena);
write32(BAR+0x154, recenb);
}
static void sdram_enable(int controllers, const struct mem_controller *ctrl)
{
int i;
int cs;
int cnt;
int cas_latency;
long mask;
uint32_t drc;
uint32_t data32;
uint32_t mode_reg;
uint32_t *iptr;
volatile unsigned long *iptrv;
msr_t msr;
uint32_t scratch;
uint8_t byte;
uint16_t data16;
static const struct {
uint32_t clkgr[4];
} gearing [] = {
/* FSB 133 DIMM 266 */
{{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
/* FSB 133 DIMM 333 */
{{ 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
/* FSB 133 DIMM 400 */
{{ 0x00000120, 0x00000000, 0x00000032, 0x00000010}},
/* FSB 167 DIMM 266 */
{{ 0x00005432, 0x00001000, 0x00004325, 0x00000000}},
/* FSB 167 DIMM 333 */
{{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
/* FSB 167 DIMM 400 */
{{ 0x00154320, 0x00000000, 0x00065432, 0x00010000}},
/* FSB 200 DIMM 266 */
{{ 0x00000032, 0x00000010, 0x00000120, 0x00000000}},
/* FSB 200 DIMM 333 */
{{ 0x00065432, 0x00010000, 0x00154320, 0x00000000}},
/* FSB 200 DIMM 400 */
{{ 0x00000001, 0x00000000, 0x00000001, 0x00000000}},
};
static const uint32_t dqs_data[] = {
0xffffffff, 0xffffffff, 0x000000ff,
0xffffffff, 0xffffffff, 0x000000ff,
0xffffffff, 0xffffffff, 0x000000ff,
0xffffffff, 0xffffffff, 0x000000ff,
0xffffffff, 0xffffffff, 0x000000ff,
0xffffffff, 0xffffffff, 0x000000ff,
0xffffffff, 0xffffffff, 0x000000ff,
0xffffffff, 0xffffffff, 0x000000ff};
mask = spd_detect_dimms(ctrl);
print_debug("Starting SDRAM Enable\n");
/* 0x80 */
#ifdef DIMM_MAP_LOGICAL
pci_write_config32(PCI_DEV(0, 0x00, 0), DRM,
0x00210000 | DIMM_MAP_LOGICAL);
#else
pci_write_config32(PCI_DEV(0, 0x00, 0), DRM, 0x00211248);
#endif
/* set dram type and Front Side Bus freq. */
drc = spd_set_dram_controller_mode(ctrl, mask);
if( drc == 0) {
die("Error calculating DRC\n");
}
pll_setup(drc);
data32 = drc & ~(3 << 20); /* clear ECC mode */
data32 = data32 & ~(7 << 8); /* clear refresh rates */
data32 = data32 | (1 << 5); /* temp turn off of ODT */
/* Set gearing, then dram controller mode */
/* drc bits 1:0 = DIMM speed, bits 3:2 = FSB speed */
for(iptr = gearing[(drc&3)+((((drc>>2)&3)-1)*3)].clkgr,cnt=0;
cnt<4;cnt++) {
pci_write_config32(PCI_DEV(0, 0x00, 0), 0xa0+(cnt*4), iptr[cnt]);
}
/* 0x7c DRC */
pci_write_config32(PCI_DEV(0, 0x00, 0), DRC, data32);
/* turn the clocks on */
/* 0x8c CKDIS */
pci_write_config16(PCI_DEV(0, 0x00, 0), CKDIS, 0x0000);
/* 0x9a DDRCSR Take subsystem out of idle */
data16 = pci_read_config16(PCI_DEV(0, 0x00, 0), DDRCSR);
data16 &= ~(7 << 12);
data16 |= (3 << 12); /* use dual channel lock step */
pci_write_config16(PCI_DEV(0, 0x00, 0), DDRCSR, data16);
/* program row size DRB */
spd_set_ram_size(ctrl, mask);
/* program page size DRA */
spd_set_row_attributes(ctrl, mask);
/* program DRT timing values */
cas_latency = spd_set_drt_attributes(ctrl, mask, drc);
for(i=0;i<8;i++) { /* loop throught each dimm to test for row */
print_debug("DIMM ");
print_debug_hex8(i);
print_debug("\n");
/* Apply NOP */
do_delay();
write32(BAR + 0x100, (0x03000000 | (i<<20)));
write32(BAR+0x100, (0x83000000 | (i<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* Apply NOP */
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR + DCALCSR, (0x83000000 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* Precharg all banks */
do_delay();
for(cs=0;cs<8;cs++) {
if ((drc & 3) == 2) /* DDR2 */
write32(BAR+DCALADDR, 0x04000000);
else /* DDR1 */
write32(BAR+DCALADDR, 0x00000000);
write32(BAR+DCALCSR, (0x83000002 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* EMRS dll's enabled */
do_delay();
for(cs=0;cs<8;cs++) {
if ((drc & 3) == 2) /* DDR2 */
/* fixme hard code AL additive latency */
write32(BAR+DCALADDR, 0x0b940001);
else /* DDR1 */
write32(BAR+DCALADDR, 0x00000001);
write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* MRS reset dll's */
do_delay();
if ((drc & 3) == 2) { /* DDR2 */
if(cas_latency == 30)
mode_reg = 0x053a0000;
else
mode_reg = 0x054a0000;
}
else { /* DDR1 */
if(cas_latency == 20)
mode_reg = 0x012a0000;
else /* CAS Latency 2.5 */
mode_reg = 0x016a0000;
}
for(cs=0;cs<8;cs++) {
write32(BAR+DCALADDR, mode_reg);
write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* Precharg all banks */
do_delay();
do_delay();
do_delay();
for(cs=0;cs<8;cs++) {
if ((drc & 3) == 2) /* DDR2 */
write32(BAR+DCALADDR, 0x04000000);
else /* DDR1 */
write32(BAR+DCALADDR, 0x00000000);
write32(BAR+DCALCSR, (0x83000002 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* Do 2 refreshes */
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
do_delay();
/* for good luck do 6 more */
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
}
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
}
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
}
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
}
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
}
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x83000001 | (cs<<20)));
}
do_delay();
/* MRS reset dll's normal */
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALADDR, (mode_reg & ~(1<<24)));
write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* Do only if DDR2 EMRS dll's enabled */
if ((drc & 3) == 2) { /* DDR2 */
do_delay();
for(cs=0;cs<8;cs++) {
write32(BAR+DCALADDR, (0x0b940001));
write32(BAR+DCALCSR, (0x83000003 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
}
do_delay();
/* No command */
write32(BAR+DCALCSR, 0x0000000f);
/* DDR1 This is test code to copy some codes in the factory setup */
write32(BAR, 0x00100000);
if ((drc & 3) == 2) { /* DDR2 */
/* enable on dimm termination */
set_on_dimm_termination_enable(ctrl);
}
else { /* ddr */
pci_write_config32(PCI_DEV(0, 0x00, 0), 0x88, 0xa0000000 );
}
/* receive enable calibration */
set_receive_enable(ctrl);
/* DQS */
pci_write_config32(PCI_DEV(0, 0x00, 0), 0x94, 0x3904a100 );
for(i = 0, cnt = (BAR+0x200); i < 24; i++, cnt+=4) {
write32(cnt, dqs_data[i]);
}
pci_write_config32(PCI_DEV(0, 0x00, 0), 0x94, 0x3904a100 );
/* Enable refresh */
/* 0x7c DRC */
data32 = drc & ~(3 << 20); /* clear ECC mode */
pci_write_config32(PCI_DEV(0, 0x00, 0), DRC, data32);
write32(BAR+DCALCSR, 0x0008000f);
/* clear memory and init ECC */
print_debug("Clearing memory\n");
for(i=0;i<64;i+=4) {
write32(BAR+DCALDATA+i, 0x00000000);
}
for(cs=0;cs<8;cs++) {
write32(BAR+DCALCSR, (0x830831d8 | (cs<<20)));
data32 = read32(BAR+DCALCSR);
while(data32 & 0x80000000)
data32 = read32(BAR+DCALCSR);
}
/* Bring memory subsystem on line */
data32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0x98);
data32 |= (1 << 31);
pci_write_config32(PCI_DEV(0, 0x00, 0), 0x98, data32);
/* wait for completion */
print_debug("Waiting for mem complete\n");
while(1) {
data32 = pci_read_config32(PCI_DEV(0, 0x00, 0), 0x98);
if( (data32 & (1<<31)) == 0)
break;
}
print_debug("Done\n");
/* Set initialization complete */
/* 0x7c DRC */
drc |= (1 << 29);
data32 = drc & ~(3 << 20); /* clear ECC mode */
pci_write_config32(PCI_DEV(0, 0x00, 0), DRC, data32);
/* Set the ecc mode */
pci_write_config32(PCI_DEV(0, 0x00, 0), DRC, drc);
/* Enable memory scrubbing */
/* 0x52 MCHSCRB */
data16 = pci_read_config16(PCI_DEV(0, 0x00, 0), MCHSCRB);
data16 &= ~0x0f;
data16 |= ((2 << 2) | (2 << 0));
pci_write_config16(PCI_DEV(0, 0x00, 0), MCHSCRB, data16);
/* The memory is now setup, use it */
cache_lbmem(MTRR_TYPE_WRBACK);
}