summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNoe Rubinstein <nrubinstein@proformatique.com>2011-05-26 18:20:49 +0200
committerNoe Rubinstein <nrubinstein@avencall.com>2012-12-07 12:43:28 +0100
commit9ad810f056c11e994f6de1ba90be728d8bae109b (patch)
treeddb3d86a0b6badadcf07a972ef5d3a8a5fbb4e10
parent4bdb2dc897a375e458187efb1689a30c60c09bb4 (diff)
Rewrite EP80579 RAM init
-rw-r--r--src/include/spd_ddr2.h89
-rw-r--r--src/mainboard/intel/truxton/romstage.c27
-rw-r--r--src/northbridge/intel/i3100/ep80579.h306
-rw-r--r--src/northbridge/intel/i3100/raminit_ep80579.c1715
-rw-r--r--src/northbridge/intel/i3100/raminit_ep80579.h131
-rw-r--r--src/northbridge/intel/i3100/wl_cal3.c105
6 files changed, 1427 insertions, 946 deletions
diff --git a/src/include/spd_ddr2.h b/src/include/spd_ddr2.h
index 09851f971..93f89ccdb 100644
--- a/src/include/spd_ddr2.h
+++ b/src/include/spd_ddr2.h
@@ -23,38 +23,8 @@
#define SPD_MEM_TYPE_SDRAM_DDR 0x07
#define SPD_MEM_TYPE_SDRAM_DDR2 0x08
-#define SPD_DIMM_TYPE 20 /* x bit0 or bit4 =1 mean registered*/
- #define SPD_DIMM_TYPE_RDIMM (1<<0)
- #define SPD_DIMM_TYPE_UDIMM (1<<1)
- #define SPD_DIMM_TYPE_SODIMM (1<<2)
- #define SPD_DIMM_TYPE_uDIMM (1<<3)
- #define SPD_DIMM_TYPE_mRDIMM (1<<4)
- #define SPD_DIMM_TYPE_mUDIMM (1<<5)
-
-#define SPD_MOD_ATTRIB 21
- #define SPD_MOD_ATTRIB_DIFCK 0x20
- #define SPD_MOD_ATTRIB_REGADC 0x11 /* x */
- #define SPD_MOD_ATTRIB_PROBE 0x40
-
-#define SPD_DEV_ATTRIB 22 /* Device attributes --- general */
-#define SPD_DIMM_CONF_TYPE 11
- #define SPD_DIMM_CONF_TYPE_ECC 0x02
- #define SPD_DIMM_CONF_TYPE_ADDR_PARITY 0x04 /* ? */
-
-#define SPD_CAS_LAT_MIN_X_1 23
-#define SPD_CAS_LAT_MAX_X_1 24
-#define SPD_CAS_LAT_MIN_X_2 25
-#define SPD_CAS_LAT_MAX_X_2 26
-
-#define SPD_BURST_LENGTHS 16
- #define SPD_BURST_LENGTHS_4 (1<<2)
- #define SPD_BURST_LENGTHS_8 (1<<3)
-
#define SPD_ROW_NUM 3 /* Number of Row addresses */
#define SPD_COL_NUM 4 /* Number of Column addresses */
-#define SPD_BANK_NUM 17 /* SDRAM Device attributes - Number of Banks on
- SDRAM device, it could be 0x4, 0x8, so address
- lines for that would be 2, and 3 */
/* Number of Ranks bit [2:0], Package (bit4, 1=stack, 0=planr), Height bit[7:5] */
#define SPD_MOD_ATTRIB_RANK 5
@@ -64,20 +34,25 @@
#define SPD_MOD_ATTRIB_RANK_NUM_MIN 1
#define SPD_MOD_ATTRIB_RANK_NUM_MAX 8
-#define SPD_RANK_SIZE 31 /* Only one bit is set */
- #define SPD_RANK_SIZE_1GB (1<<0)
- #define SPD_RANK_SIZE_2GB (1<<1)
- #define SPD_RANK_SIZE_4GB (1<<2)
- #define SPD_RANK_SIZE_8GB (1<<3)
- #define SPD_RANK_SIZE_16GB (1<<4)
- #define SPD_RANK_SIZE_128MB (1<<5)
- #define SPD_RANK_SIZE_256MB (1<<6)
- #define SPD_RANK_SIZE_512MB (1<<7)
-
#define SPD_DATA_WIDTH 6 /* valid value 0, 32, 33, 36, 64, 72, 80, 128, 144, 254, 255 */
+
+#define SPD_DIMM_CONF_TYPE 11
+ #define SPD_DIMM_CONF_TYPE_ECC 0x02
+ #define SPD_DIMM_CONF_TYPE_ADDR_PARITY 0x04 /* ? */
+
+#define SPD_TREF 12
+
#define SPD_PRI_WIDTH 13 /* Primary SDRAM Width, it could be 0x08 or 0x10 */
#define SPD_ERR_WIDTH 14 /* Error Checking SDRAM Width, it could be 0x08 or 0x10 */
+#define SPD_BURST_LENGTHS 16
+ #define SPD_BURST_LENGTHS_4 (1<<2)
+ #define SPD_BURST_LENGTHS_8 (1<<3)
+
+#define SPD_BANK_NUM 17 /* SDRAM Device attributes - Number of Banks on
+ SDRAM device, it could be 0x4, 0x8, so address
+ lines for that would be 2, and 3 */
+
#define SPD_CAS_LAT 18 /* SDRAM Device Attributes -- CAS Latency */
#define SPD_CAS_LAT_2 (1<<2)
#define SPD_CAS_LAT_3 (1<<3)
@@ -85,10 +60,43 @@
#define SPD_CAS_LAT_5 (1<<5)
#define SPD_CAS_LAT_6 (1<<6)
+#define SPD_DIMM_TYPE 20 /* x bit0 or bit4 =1 mean registered*/
+ #define SPD_DIMM_TYPE_RDIMM 0x01
+ #define SPD_DIMM_TYPE_UDIMM 0x02
+ #define SPD_DIMM_TYPE_SODIMM 0x04
+ #define SPD_DIMM_TYPE_SOCDIMM 0x06
+ #define SPD_DIMM_TYPE_SORDIMM 0x07
+ #define SPD_DIMM_TYPE_uDIMM 0x08
+ #define SPD_DIMM_TYPE_mRDIMM 0x10
+ #define SPD_DIMM_TYPE_mUDIMM 0x20
+
+#define SPD_MOD_ATTRIB 21
+ #define SPD_MOD_ATTRIB_DIFCK 0x20
+ #define SPD_MOD_ATTRIB_REGADC 0x11 /* x */
+ #define SPD_MOD_ATTRIB_PROBE 0x40
+
+#define SPD_DEV_ATTRIB 22 /* Device attributes --- general */
+
+#define SPD_CAS_LAT_MIN_X_1 23
+#define SPD_CAS_LAT_MAX_X_1 24
+#define SPD_CAS_LAT_MIN_X_2 25
+#define SPD_CAS_LAT_MAX_X_2 26
+
#define SPD_TRP 27 /* bit [7:2] = 1-63 ns, bit [1:0] 0.25ns+, final value ((val>>2) + (val & 3) * 0.25)ns */
#define SPD_TRRD 28
#define SPD_TRCD 29
#define SPD_TRAS 30
+
+#define SPD_RANK_SIZE 31 /* Only one bit is set */
+ #define SPD_RANK_SIZE_1GB (1<<0)
+ #define SPD_RANK_SIZE_2GB (1<<1)
+ #define SPD_RANK_SIZE_4GB (1<<2)
+ #define SPD_RANK_SIZE_8GB (1<<3)
+ #define SPD_RANK_SIZE_16GB (1<<4)
+ #define SPD_RANK_SIZE_128MB (1<<5)
+ #define SPD_RANK_SIZE_256MB (1<<6)
+ #define SPD_RANK_SIZE_512MB (1<<7)
+
#define SPD_TWR 36 /* x */
#define SPD_TWTR 37 /* x */
#define SPD_TRTP 38 /* x */
@@ -97,4 +105,3 @@
#define SPD_TRC 41 /* add byte 0x40 bit [3:1] , so final val41+ table[((val40>>1) & 0x7)] ... table[]={0, 0.25, 0.33, 0.5, 0.75, 0, 0}*/
#define SPD_TRFC 42 /* add byte 0x40 bit [6:4] , so final val42+ table[((val40>>4) & 0x7)] + (val40 & 1)*256*/
-#define SPD_TREF 12
diff --git a/src/mainboard/intel/truxton/romstage.c b/src/mainboard/intel/truxton/romstage.c
index c0917004c..d41946ce0 100644
--- a/src/mainboard/intel/truxton/romstage.c
+++ b/src/mainboard/intel/truxton/romstage.c
@@ -36,7 +36,7 @@
#include "cpu/x86/bist.h"
#include <lib.h>
#include <spd.h>
-#include "lib/generic_sdram.c"
+//#include "lib/generic_sdram.c"
/* RCBA registers */
#define RCBA 0xF0
@@ -80,20 +80,12 @@ static void early_config(void)
write16(DEFAULT_RCBA + RCBA_D30IR, 0x3210);
write16(DEFAULT_RCBA + RCBA_D29IR, 0x3237);
write16(DEFAULT_RCBA + RCBA_D28IR, 0x3214);
-
}
#define SERIAL_DEV PNP_DEV(0x4e, I3100_SP1)
void main(unsigned long bist)
{
- const struct mem_controller mch[] = {
- {
- .node_id = 0,
- .f0 = PCI_DEV(0, 0x00, 0),
- .channel0 = { DIMM2, DIMM3 },
- }
- };
if (bist == 0) {
/* Skip this if there was a built in self test failure */
@@ -130,23 +122,16 @@ void main(unsigned long bist)
dump_pci_devices();
#endif
- PRINT_SPD_DUMP();
-
- sdram_initialize(ARRAY_SIZE(mch), mch);
+ //PRINT_SPD_DUMP();
+
+ struct mem_controller mch = { .spd = (u8[]){DIMM2, DIMM3} };
+ sdram_initialize(&mch);
+
#if TRUXTON_DEBUG_PCI
dump_pci_devices();
dump_pci_device(PCI_DEV(0, 0x00, 0));
PRINT_DCAL_DUMP();
#endif
-#if CONFIG_DEBUG_RAM_SETUP
- #include <northbridge/intel/i3100/ep80579.h>
- int tolm=0;
- ram_check(0x00000000, 0x0009FFFF);
- /* Skip VGA and CAR region */
- tolm=(pci_read_config16(mch->f0, TOLM)<<16);
- ram_check(0x000D0000, tolm);
-#endif
-
early_config();
}
diff --git a/src/northbridge/intel/i3100/ep80579.h b/src/northbridge/intel/i3100/ep80579.h
index e80100027..8083a1b85 100644
--- a/src/northbridge/intel/i3100/ep80579.h
+++ b/src/northbridge/intel/i3100/ep80579.h
@@ -21,45 +21,87 @@
#define NORTHBRIDGE_INTEL_I3100_EP80579_H
/* PCI 0:0:0 registers */
-#define SMRBASE 0x14
-#define MCHCFG0 0x50
-#define FDHC 0x58
-#define PAM 0x59
-#define DRB 0x60
-#define DRT1 0x64
-#define DRA 0x70
-#define DRT0 0x78
-#define DRC 0x7c
-#define ECCDIAG 0x84
-#define SDRC 0x88
-#define CKDIS 0x8c
-#define CKEDIS 0x8d
-#define DEVPRES 0x9c
-#define DEVPRES_D0F0 (1 << 0)
-#define DEVPRES_D1F0 (1 << 1)
-#define DEVPRES_D2F0 (1 << 2)
-#define DEVPRES_D3F0 (1 << 3)
-#define DEVPRES_D4F0 (1 << 4)
-#define DEVPRES_D10F0 (1 << 5)
-#define EXSMRC 0x9d
-#define SMRAM 0x9e
-#define EXSMRAMC 0x9f
-#define DDR2ODTC 0xb0
-#define TOLM 0xc4
-#define REMAPBASE 0xc6
-#define REMAPLIMIT 0xc8
-#define REMAPOFFSET 0xca
-#define TOM 0xcc
-#define HECBASE 0xce
-#define DEVPRES1 0xf4
+#define SMRBASE 0x14
+#define MCHCFG0 0x50
+#define FDHC 0x58
+#define PAM 0x59
+#define DRB0 0x60
+#define DRB1 0x61
+#define DRB2 0x62
+#define DRB3 0x63
+#define DRT1 0x64
+#define DRA 0x70
+#define DRT0 0x78
+#define DRC 0x7c
+#define ECCDIAG 0x84
+#define SDRC 0x88
+#define CKDIS 0x8c
+#define CKEDIS 0x8d
+#define DEVPRES 0x9c
+#define DEVPRES_D0F0 (1 << 0)
+#define DEVPRES_D1F0 (1 << 1)
+#define DEVPRES_D2F0 (1 << 2)
+#define DEVPRES_D3F0 (1 << 3)
+#define DEVPRES_D4F0 (1 << 4)
+#define DEVPRES_D10F0 (1 << 5)
+#define EXSMRC 0x9d
+#define SMRAM 0x9e
+#define EXSMRAMC 0x9f
+#define DDR2ODTC 0xb0
+#define TOLM 0xc4
+#define REMAPBASE 0xc6
+#define REMAPLIMIT 0xc8
+#define REMAPOFFSET 0xca
+#define TOM 0xcc
+#define HECBASE 0xce
+#define DIOMON 0xf0
+#define DEVPRES1 0xf4
+#define IMCH_TST2 0xf6
+
+#define MAGIC_A0 0xa0
+#define MAGIC_A4 0xa4
+#define MAGIC_A8 0xa8
+#define MAGIC_AC 0xac
+
+/* PCI 0:0:1 registers */
+#define DRAM_FERR 0x80
+#define DRAM_NERR 0x82
+#define DRAM_SEC_R0 0xb0
+#define DRAM_DED_R0 0xb2
+#define DRAM_SEC_R1 0xb4
+#define DRAM_DED_R1 0xb6
+#define RANKTHREX 0xdc
+
+/* PCI 0:8:0 register */
+#define DDRREFRESH 0xcc
+
+/* PCI 0:10:0 register */
+#define SKU_ID 0x44
/* SMRBASE registers */
+
#define DCALCSR 0x040
#define DCALADDR 0x044
#define DCALDATA 0x048
+#define DRRTC00 0x0a4
+#define DQSFAIL1 0x09c
+#define DQSFAIL0 0x0a0
+#define DRRTC01 0x0a8
+#define DQSOFCS00 0x0b4
+#define DQSOFCS01 0x0b8
+#define DQSOFCS10 0x0bc
+#define DQSOFCS11 0x0c0
+#define DRRTC02 0x0c4
+#define DQSOFCS02 0x0c6
+#define DQSOFCS12 0x0c7
+#define DRAMDLLC 0x0c8
+#define WPTRTC0 0x0cc
+#define WPTRTC1 0x0d0
#define MBCSR 0x140
#define MBADDR 0x144
#define MBDATA 0x148
+#define DDRIOMC0 0x260
+#define DDRIOMC1 0x264
#define DDRIOMC2 0x268
#define WL_CNTL0 0x284
#define WL_CNTL1 0x288
@@ -67,65 +109,173 @@
#define WL_CNTL3 0x290
#define WL_CNTL4 0x294
#define WDLL_MISC 0x298
-/* 32-bit register */
-#define DQSFAIL0 0xa0
-/* 8-bit register */
-#define DQSFAIL1 0x9c
+
/* DQSFAIL mask to skip the DQS08 */
#define DQSFAIL0_ECC_MASK (0x00000000 | (3 << 16))
#define DQSFAIL1_ECC_MASK (0x00 | (3 << 2))
+/* DIOMON Bits */
+#define DSAMP 24
+#define VRESULT 16
+#define DDRIO_ENABLE 15
+#define BIASSEL 11
+#define DQLEGSELOUT 7
+#define DIOPWR 6
+#define CALEGSELOUT 0
+
+/* IMCH_TST2 Bits */
+#define IMCH_TST2_SYSMMREN 6
+#define IMCH_TST2_NSIMMREN 5
+
+/* DDRIOMC1 Bits */
+#define DDRIOMC1_CASLEW 24
+#define DDRIOMC1_DQSLEW 16
+#define DDRIOMC1_DEMPDQ 5
+#define DDRIOMC1_DEMPCA 3
+#define DDRIOMC1_FASTSLEW 0
+
+/* DDRIOMC2 Bits */
+#define DDRIOMC2_PHSEL 26
+#define DDRIOMC2_LEGOVERRIDE 16
+#define DDRIOMC2_FIFOWPTRCLR 15
+#define DDRIOMC2_MASTCNTL 12
+
/* DRT0 Bits */
-#define BTBRWTA 29
-#define BTBRTA 26
-#define BBWRTA 23
-#define Trrd 20
-#define Twr 17
-#define Trc 12
-#define Trcd 9
-#define Trp 6
-#define CL 3
-#define PRGRPD 0
+#define DRT0_BTBRWTA 29
+#define DRT0_BTBRTA 26
+#define DRT0_BBWRTA 23
+#define DRT0_Trrd 20
+#define DRT0_Twr 17
+#define DRT0_Trc 12
+#define DRT0_Trcd 9
+#define DRT0_Trp 6
+#define DRT0_CL 3
+#define DRT0_PRGRPD 0
/* DRT1 Bits */
-#define tRAS 28
-#define tRTP 25
-#define tFAW 20
-#define tCCD 18
-#define tWTR 15
-#define BLEN 13
-#define _2Tor1T 12
-#define NOPCNT 4
-#define BTBWTA 0
+#define DRT1_tRAS 28
+#define DRT1_tRTP 25
+#define DRT1_tFAW 20
+#define DRT1_tCCD 18
+#define DRT1_tWTR 15
+#define DRT1_BLEN 13
+#define DRT1_2Tor1T 12
+#define DRT1_NOPCNT 4
+#define DRT1_BTBWTA 0
/* DRC Bits */
-#define DS 0
-#define CKEPNM 4
-#define ODT0DIS 5
-#define ODT1DIS 6
-#define CS0DIS 10
-#define CS1DIS 11
-#define CADIS 12
-#define HLDDIS 13
-#define ECC 20
-#define INIT_COMP 29
-#define CKE0 30
-#define CKE1 31
+#define DRC_DS 0
+#define DRC_CKEPNM 4
+#define DRC_ODT0DIS 5
+#define DRC_ODT1DIS 6
+#define DRC_CS0DIS 10
+#define DRC_CS1DIS 11
+#define DRC_CADIS 12
+#define DRC_HLDDIS 13
+#define DRC_ECC 20
+#define DRC_INIT_COMP 29
+#define DRC_CKE0 30
+#define DRC_CKE1 31
/* DRA Bits */
-#define NR_ODD 29
-#define NC_ODD 26
-#define NR_EVEN 23
-#define NC_EVEN 20
-#define DTYPE_RANK 17
-#define DTYPE_DDR2 16
-#define DTYPE_ADRSIZE 15
-#define DTYPE 14
-#define DWODD 10
-#define DIMMTECH_ODD 6
-#define DWEVEN 4
-#define DIMMTECH_EVEN 0
+#define DRA_NR_ODD 29
+#define DRA_NC_ODD 26
+#define DRA_NR_EVEN 23
+#define DRA_NC_EVEN 20
+#define DRA_DTYPE_RANK 17
+#define DRA_DTYPE_DDR2 16
+#define DRA_DTYPE_ADRSIZE 15
+#define DRA_DTYPE 14
+#define DRA_DWODD 10
+#define DRA_DIMMTECH_ODD 6
+#define DRA_DWEVEN 4
+#define DRA_DIMMTECH_EVEN 0
+
+/* WL_CNTL bits */
+#define WL_CNTL_WL_CNTRL 8
+#define WL_CNTL_WDLL_CNTL 2
+#define WL_CNTL_WDLL_CLKG 1
+#define WL_CNTL_BYP_WDLL 0
+
+/* WDLL_MISC bits */
+#define WDLL_MISC_WLCKDLY 24
+#define WDLL_MISC_WL_PHSEL_MODE 16
+#define WDLL_MISC_WL_CNTRL 8
+#define WDLL_MISC_WL_CNTRL_A 4
+#define WDLL_MISC_WL_CMD_DLY 0
+
+/* SDRC bits */
+#define SDRC_ODTZENA1 30
+#define SDRC_ODTZENA 28
+#define SDRC_FUSESPEED 20
+#define SDRC_DRRIRR 17
+#define SDRC_DDRDIS 16
+#define SDRC_SCH_WGT 12
+#define SDRC_mu_enable_aioccmd 11
+#define SDRC_mu_enable_bcmd 10
+#define SDRC_mu_enable_eccrrwcmd 9
+#define SDRC_mu_enable_bscrubcmd 8
+#define SDRC_ASU_CMDQSIZE 0
+
+/* DCALCSR bits */
+#define DCALCSR_START 31
+#define DCALCSR_FAIL 28
+#define DCALCSR_BASPAT 27
+#define DCALCSR_RSTREGSS 26
+#define DCALCSR_SGLSTP 23
+#define DCALCSR_CS 21
+#define DCALCSR_PAT 16
+#define DCALCSR_DARWPR 15
+#define DCALCSR_OPMODS 4
+#define DCALCSR_OPCODE 0
+
+/* DCALCSR_OPCODE values */
+enum {
+ DCALCSR_OPCODE_NOP = 0,
+ DCALCSR_OPCODE_REFRESH = 1,
+ DCALCSR_OPCODE_PRECHARGE = 2,
+ DCALCSR_OPCODE_MRS = 3,
+ DCALCSR_OPCODE_SELF_REFRESH_EXIT = 4,
+ DCALCSR_OPCODE_DQS_CAL = 5,
+ DCALCSR_OPCODE_DLL_BIST = 7,
+ DCALCSR_OPCODE_RCVEN = 0xC,
+ DCALCSR_OPCODE_SELF_REFRESH = 0xD,
+ DCALCSR_OPCODE_ERRMON_DDRIO_FIFO = 0xE,
+ DCALCSR_OPCODE_ZQ_CAL = 0xF,
+};
+
+/* DRAMDLLC bits */
+#define DRAMDLLC_SLVBYP 21
+#define DRAMDLLC_SLVLEN4 18
+#define DRAMDLLC_SLVLEN3 15
+#define DRAMDLLC_SLVLEN2 12
+#define DRAMDLLC_SLVLEN1 9
+#define DRAMDLLC_SLVLEN0 6
+
+/* DDRIOMC0 bits */
+#define DDRIOMC0_DQVOXADJ 9
+#define DDRIOMC0_DDRVOXCTL1 8
+#define DDRIOMC0_DDRVOXCTL0 3
+
+/* MBCSR bits */
+#define MBCSR_START 31
+#define MBCSR_PF 30
+#define MBCSR_HALT 29
+#define MBCSR_ABORT 28
+#define MBCSR_SPARE 27
+#define MBCSR_ALGO 24
+#define MBCSR_CS 20
+#define MBCSR_INV 19
+#define MBCSR_FX 16
+#define MBCSR_EN288 15
+#define MBCSR_MBDATA 14
+#define MBCSR_ABAR 13
+#define MBCSR_ADIR 12
+#define MBCSR_FAST 10
+#define MBCSR_DTYPE 8
+#define MBCSR_ATYPE 6
+#define MBCSR_CMD 4
/* DRA Values */
#define DTYPE_REGISTERED 1
diff --git a/src/northbridge/intel/i3100/raminit_ep80579.c b/src/northbridge/intel/i3100/raminit_ep80579.c
index e96860745..7c0a11d11 100644
--- a/src/northbridge/intel/i3100/raminit_ep80579.c
+++ b/src/northbridge/intel/i3100/raminit_ep80579.c
@@ -1,8 +1,7 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2005 Eric W. Biederman and Tom Zimmerman
- * Copyright (C) 2008 Arastra, Inc.
+ * Copyright (C) 2011 Avencall
*
* 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
@@ -23,64 +22,64 @@
#include <arch/io.h>
#include <arch/romcc_io.h>
#include <stdlib.h>
-#include <spd.h>
+#include <spd_ddr2.h>
#include <cpu/x86/msr.h>
-#include <device/pci_def.h>
+#include <arch/hlt.h>
#include "southbridge/intel/i3100/early_smbus.h"
-#include "raminit_ep80579.h"
+// #include <device/pci.h>
+// #include <device/pci_def.h>
+// #include <device/pci_ops.h>
+
#include "ep80579.h"
+#include "raminit_ep80579.h"
-int spd_read_byte(unsigned device, unsigned address)
-{
- return smbus_read_byte(device, address);
-}
+#define BAR 0x90000000
+
+#define dbg_pci_write_config32(dev, reg, val) do { \
+ PRINTK_DEBUG(#reg "=%08x\n", val); \
+ pci_write_config32(dev, reg, val); \
+ } while (0)
+
+#define dbg_pci_write_config16(dev, reg, val) do { \
+ PRINTK_DEBUG(#reg "=%04x\n", val); \
+ pci_write_config16(dev, reg, val); \
+ } while (0)
+
+#define dbg_pci_write_config8(dev, reg, val) do { \
+ PRINTK_DEBUG(#reg "=%02x\n", val); \
+ pci_write_config8(dev, reg, val); \
+ } while (0)
+
+
+#define spd_read_byte smbus_read_byte
#if CONFIG_DEBUG_RAM_SETUP
-static void print_ddrio(void) {
- /* I don't know how long the calibration and measurement takes
- * so give it 16us to come up with an anwser.
- */
- udelay(16);
- write32(BAR + DIOMON, read32(BAR + DIOMON) | (1<<DDRIO_ENABLE));
- udelay(16);
- PRINTK_DEBUG("DDRIO: %08x\n", read32(BAR + DIOMON));
-}
-void dump_dcal_regs(void)
-{
- int i;
- for (i = 0x0; i < 0x2a0; i += 4) {
- if ((i % 16) == 0) {
- PRINTK_DEBUG("\n%04x: ", i);
- }
- PRINTK_DEBUG("%08x ", read32(BAR+i));
- }
- PRINTK_DEBUG("\n");
-}
+# define die(...) do { \
+ printk(BIOS_EMERG, __VA_ARGS__); \
+ \
+ printk(BIOS_DEBUG, "\nRAM STARTUP FAILURE, DUMPING REGS:\n"); \
+ dump_ram_regs(BIOS_DEBUG);\
+ \
+ while(1) hlt(); \
+ } while (0)
-static void dump_dcal_regs_8(void)
-{
- int i;
+#else
- for (i = 0x0; i < 0x2a0; i += 1) {
- if ((i % 16) == 0) {
- printk(BIOS_DEBUG, "\n%04x: ", i);
- }
- printk(BIOS_DEBUG, "%02x", read8(BAR+i));
- if ( (((i+1) % 8) == 0) && (i != 0) && ((i%15) != 0) )
- printk(BIOS_DEBUG, "-");
- else
- printk(BIOS_DEBUG, " ");
- }
- printk(BIOS_DEBUG, "\n");
-}
+# define die(...) do { printk(BIOS_EMERG, __VA_ARGS__); while(1) hlt(); } \
+ while(0)
+
+#endif
+
+#if CONFIG_DEBUG_RAM_SETUP
-void dump_spd_registers(void)
+static void dump_spd_registers(struct mem_controller *mch)
{
unsigned device;
- device = DIMM0;
-
- while(device <= DIMM7) {
+ int j;
+
+ for (j = 0; j < DIMM_SOCKETS; j++) {
+ device = mch->spd[j];
int status = 0;
int i;
printk(BIOS_DEBUG, "\ndimm %02x", device);
@@ -92,7 +91,8 @@ void dump_spd_registers(void)
status = smbus_read_byte(device, i);
if (status < 0) {
- printk(BIOS_DEBUG, "bad device: %02x\n", -status);
+ printk(BIOS_DEBUG, "bad device: %02x\n",
+ -status);
break;
}
printk(BIOS_DEBUG, "%02x ", status);
@@ -101,830 +101,1041 @@ void dump_spd_registers(void)
printk(BIOS_DEBUG, "\n");
}
}
-#endif /* CONFIG_DEBUG_RAM_SETUP */
-void dump_pci_device(u32 dev)
+static void dump_pci_config(int lvl, device_t dev)
{
- int i;
- print_debug_pci_dev(dev);
- printk(BIOS_DEBUG, "\n");
-
- for(i = 0; i <= 255; i++) {
- unsigned char val;
- if ((i & 0x0f) == 0) {
- printk(BIOS_DEBUG, "%02x:", i);
- }
- val = pci_read_config8(dev, i);
- printk(BIOS_DEBUG, " %02x", val);
- if ((i & 0x0f) == 0x0f) {
- printk(BIOS_DEBUG, "\n");
- }
+ int i, j;
+ printk(lvl, " f e d c b a 9 8 7 6 5 4 3 2 1 0");
+ for (i = 0xf; i >= 0; i--) {
+ printk(lvl, "\n%01x", i);
+ for (j = 0xf; j >= 0; j--)
+ printk(lvl, " %02x", pci_read_config8(dev, (i<<4)|j));
}
+ printk(lvl, "\n");
}
-void print_debug_pci_dev(u32 dev)
+static void dump_mmio(int lvl, u32 start, int sz)
{
- printk(BIOS_DEBUG, "PCI: %02x:%02x.%02x", (dev >> 16) & 0xff,
- (dev >> 11) & 0x1f,
- (dev >> 8) & 7);
+ int i, j;
+ printk(lvl, " f e d c b a 9 8 7 6 5 4 3 2 1 0");
+ for (i = (sz>>4); i >= 0; i--) {
+ printk(lvl, "\n%02x ", i);
+ for (j = 0xf; j >= 0; j--)
+ printk(lvl, " %02x", read8(start+(i<<4)+j));
+ }
+ printk(lvl, "\n");
}
-void dump_pci_devices(void)
+static void dump_ram_regs(int lvl)
{
- device_t dev;
- for(dev = PCI_DEV(0, 0, 0);
- dev <= PCI_DEV(0, 0x1f, 0x7);
- dev += PCI_DEV(0,0,1)) {
- uint32_t id;
- id = pci_read_config32(dev, PCI_VENDOR_ID);
- if (((id & 0xffff) == 0x0000) || ((id & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0xffff) ||
- (((id >> 16) & 0xffff) == 0x0000)) {
- continue;
- }
- print_debug_pci_dev(dev);
- printk(BIOS_DEBUG, "\n");
- }
+ printk(lvl, "\nDumping B0:D0:F0\n");
+ dump_pci_config(lvl, PCI_DEV(0,0,0));
+
+ printk(lvl, "\nDumping SMRBASE regs\n");
+ dump_mmio(lvl, BAR, 0x298);
}
-static void clear_fifo_pointers(void) {
- PRINTK_DEBUG("clear read/write fifo pointers\n");
- write32(BAR+DDRIOMC2, read32(BAR+DDRIOMC2) | (1<<15));
+#endif
+
+static void clear_fifo_pointers(void)
+{
+ write32(BAR+DDRIOMC2, read32(BAR+DDRIOMC2) | 1<<DDRIOMC2_FIFOWPTRCLR);
udelay(16);
- write32(BAR+DDRIOMC2, read32(BAR+DDRIOMC2) & ~(1<<15));
+ write32(BAR+DDRIOMC2, read32(BAR+DDRIOMC2)
+ & ~(1<<DDRIOMC2_FIFOWPTRCLR));
udelay(16);
+}
- return;
+inline int memory_initialized(void)
+{
+ return pci_read_config32(PCI_DEV(0, 0x00, 0), DRC) &
+ (1 << DRC_INIT_COMP);
}
-static void clear_dqs_fail(u32 drc) {
-
- /* Don't clear the fail bit if ECC is not enabled. */
- if ( drc & (3 << ECC) ) {
- write32((BAR + DQSFAIL0), 0x0);
- write32((BAR + DQSFAIL1), 0x0);
- }
- else {
- write32(BAR + DQSFAIL0, DQSFAIL0_ECC_MASK);
- write8(BAR + DQSFAIL1, DQSFAIL1_ECC_MASK);
- }
+#include "wl_cal3.c"
+
+static inline unsigned tCK_to_10ps(const u8 x)
+{
+ return 100 * (x>>4) +
+ ((x&0xf) == 0xA ? 25 :
+ (x&0xf) == 0xB ? 33 :
+ (x&0xf) == 0xC ? 66 :
+ (x&0xf) == 0xD ? 75 : 10 * (x&0xf));
}
-void sdram_set_registers(const struct mem_controller *ctrl)
+static inline unsigned tRP_to_10ps(const u8 x)
{
- static const u32 register_values[] = {
- PCI_ADDR(0, 0x00, 0, CKDIS), 0xffff0000, 0x0000ffff,
- PCI_ADDR(0, 0x00, 0, DEVPRES), 0x00000000, 0x07420001 | DEVPRES_CONFIG,
- PCI_ADDR(0, 0x00, 0, PAM-1), 0xcccccc7f, 0x33333000,
- PCI_ADDR(0, 0x00, 0, PAM+3), 0xcccccccc, 0x33333333,
- PCI_ADDR(0, 0x00, 0, DEVPRES1), 0xffffffff, 0x0040003a,
- PCI_ADDR(0, 0x00, 0, SMRBASE), 0x00000fff, BAR | 0,
- };
- int i;
+ return 25 * x;
+}
- for (i = 0; i < ARRAY_SIZE(register_values); i += 3) {
- device_t dev;
- u32 where;
- u32 reg;
- dev = (register_values[i] & ~0xff) - PCI_DEV(0, 0x00, 0) + ctrl->f0;
- 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);
- }
+#define tRCD_to_10ps tRP_to_10ps
+
+static inline unsigned div_ceil(const unsigned a, const unsigned b)
+{
+ return (a+b-1)/b;
}
-struct dimm_size {
- u32 side1;
- u32 side2;
+static const int freq_to_int[] = {
+ [DDR_800] = 800,
+ [DDR_667] = 667,
+ [DDR_533] = 533,
+ [DDR_400] = 400,
};
-static struct dimm_size spd_get_dimm_size(u16 device)
-{
- /* Calculate the log base 2 size of a DIMM in bits */
- struct dimm_size sz;
- int value, low;
- sz.side1 = 0;
- sz.side2 = 0;
-
- /* 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, SPD_NUM_ROWS);
- if (value < 0) goto hw_err;
- if ((value & 0xf) == 0) goto val_err;
- sz.side1 += value & 0xf;
-
- value = spd_read_byte(device, SPD_NUM_COLUMNS);
- if (value < 0) goto hw_err;
- if ((value & 0xf) == 0) goto val_err;
- sz.side1 += value & 0xf;
-
- value = spd_read_byte(device, SPD_NUM_BANKS_PER_SDRAM);
- 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, SPD_MODULE_DATA_WIDTH_MSB);
- if (value < 0) goto hw_err;
- value &= 0xff;
- value <<= 8;
-
- low = spd_read_byte(device, SPD_MODULE_DATA_WIDTH_LSB);
- 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, SPD_NUM_DIMM_BANKS);
-
- if (value < 0) goto hw_err;
- value &= 7;
- 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, SPD_NUM_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, SPD_NUM_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 columns 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:
- PRINTK_DEBUG("dimm %02x size = %02x.%02x\n", device, sz.side1, sz.side2);
- return sz;
+static const int ck_period[] = { /* clock period in 10*picoseconds */
+ [DDR_800] = 250, /* 2.5ns */
+ [DDR_667] = 300, /* 3ns */
+ [DDR_533] = 375, /* 3.75ns */
+ [DDR_400] = 500, /* 5ns */
+};
-}
+static const struct ram_timing speed_bins[] = {
+ [DDR2_1066E] = {DDR_1066, 6, 6, 6},
+ [DDR2_1066F] = {DDR_1066, 7, 7, 7},
+ [DDR2_800C] = {DDR_800, 4, 4, 4},
+ [DDR2_800D] = {DDR_800, 5, 5, 5},
+ [DDR2_800E] = {DDR_800, 6, 6, 6},
+ [DDR2_667C] = {DDR_667, 4, 4, 4},
+ [DDR2_667D] = {DDR_667, 5, 5, 5},
+ [DDR2_533B] = {DDR_533, 3, 3, 3},
+ [DDR2_533C] = {DDR_533, 4, 4, 4},
+ [DDR2_400B] = {DDR_400, 3, 3, 3},
+ [DDR2_400C] = {DDR_400, 4, 4, 4},
+};
-static long spd_set_ram_size(const struct mem_controller *ctrl, u8 dimm_mask)
+/* if speed_bin a is supported, speed_bin b is supported if
+ * (speed_bin_support[a] & 1 << b) */
+static const unsigned int speed_bin_support[] = {
+ [DDR2_1066E] =
+ 1 << DDR2_1066F |
+ 1 << DDR2_1066E |
+ 1 << DDR2_800E |
+ 1 << DDR2_800D |
+ 1 << DDR2_667D |
+ 1 << DDR2_667C |
+ 1 << DDR2_533C |
+ 1 << DDR2_400C,
+ [DDR2_1066F] =
+ 1 << DDR2_1066F |
+ 1 << DDR2_800E |
+ 1 << DDR2_667D |
+ 1 << DDR2_533C |
+ 1 << DDR2_400C,
+ [DDR2_800C] =
+ 1 << DDR2_800D |
+ 1 << DDR2_667D |
+ 1 << DDR2_800C |
+ 1 << DDR2_667C |
+ 1 << DDR2_533C |
+ 1 << DDR2_400C,
+ [DDR2_800D] =
+ 1 << DDR2_800D |
+ 1 << DDR2_667D |
+ 1 << DDR2_533C |
+ 1 << DDR2_400C,
+ [DDR2_800E] =
+ 1 << DDR2_800E |
+ 1 << DDR2_667D |
+ 1 << DDR2_533C |
+ 1 << DDR2_400C,
+ [DDR2_667C] =
+ 1 << DDR2_667D |
+ 1 << DDR2_667C |
+ 1 << DDR2_533C |
+ 1 << DDR2_400C,
+ [DDR2_667D] =
+ 1 << DDR2_667D |
+ 1 << DDR2_533C |
+ 1 << DDR2_400C,
+ [DDR2_533B] =
+ 1 << DDR2_533C |
+ 1 << DDR2_400C |
+ 1 << DDR2_533B |
+ 1 << DDR2_400B,
+ [DDR2_533C] =
+ 1 << DDR2_533C |
+ 1 << DDR2_400C |
+ 1 << DDR2_400B,
+ [DDR2_400B] =
+ 1 << DDR2_400C |
+ 1 << DDR2_400B,
+ [DDR2_400C] =
+ 1 << DDR2_400B,
+};
+
+static void print_ram_timing(int level, const struct ram_timing *conf)
{
- 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);
- pci_write_config8(ctrl->f0, DRB + (i*2), cum);
- pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum);
- if (spd_read_byte(ctrl->channel0[i], SPD_NUM_DIMM_BANKS) & 0x1) {
- cum <<= 1;
- }
- }
- else {
- pci_write_config8(ctrl->f0, DRB + (i*2), cum);
- pci_write_config8(ctrl->f0, DRB+1 + (i*2), cum);
- }
- }
- PRINTK_DEBUG("DRB = %08x\n", pci_read_config32(ctrl->f0, DRB));
-
- cum >>= 1;
- /* set TOM top of memory */
- pci_write_config16(ctrl->f0, TOM, cum);
- PRINTK_DEBUG("TOM = %04x\n", cum);
- /* set TOLM top of low memory */
- if (cum > 0x18) {
- cum = 0x18;
- }
- cum <<= 11;
- pci_write_config16(ctrl->f0, TOLM, cum);
- PRINTK_DEBUG("TOLM = %04x\n", cum);
- return 0;
+ printk(level, "DDR2-%d %d-%d-%d",
+ freq_to_int[conf->speed],
+ conf->CL, conf->tRCD, conf->tRP);
}
-
-static u8 spd_detect_dimms(const struct mem_controller *ctrl)
+static enum ddr_speed get_speed(u8 tCK)
{
- u8 dimm_mask = 0;
- int i;
- for (i = 0; i < DIMM_SOCKETS; i++) {
- int byte;
- u16 device;
- device = ctrl->channel0[i];
- if (device) {
- byte = spd_read_byte(device, SPD_MEMORY_TYPE);
- PRINTK_DEBUG("spd %02x = %02x\n", device, byte);
- if (byte == 8) {
- dimm_mask |= (1 << i);
- }
- }
- }
- return dimm_mask;
+ unsigned tCK_ps = tCK_to_10ps(tCK);
+
+ if (tCK_ps <= ck_period[DDR_800])
+ return DDR_800;
+ if (tCK_ps <= ck_period[DDR_667])
+ return DDR_667;
+ if (tCK_ps <= ck_period[DDR_533])
+ return DDR_533;
+ if (tCK_ps <= ck_period[DDR_400])
+ return DDR_400;
+
+ die("Minimum clock time too high: %dps\n", tCK_ps);
}
-
-static int spd_set_row_attributes(const struct mem_controller *ctrl,
- u8 dimm_mask)
+static inline int timing_to_sb(const struct ram_timing *timing)
{
- int value;
- int i;
+ enum speed_bin sb;
+
+ for (sb = 0; sb < NUM_SPEED_BINS; sb++)
+ if (speed_bins[sb].speed == timing->speed &&
+ speed_bins[sb].CL == timing->CL)
+ return sb;
+ print_ram_timing(BIOS_SPEW, timing);
+ printk(BIOS_SPEW, " is a non-standard speed bin.\n");
+ return -1;
+}
- for (i = 0; i < DIMM_SOCKETS; i++) {
- u32 dra = 0;
- int reg = 0;
+static inline int ram_timing_equal(const struct ram_timing *a,
+ const struct ram_timing *b)
+{
+ return
+ a->speed == b->speed &&
+ a->CL == b->CL &&
+ a->tRCD == b->tRCD &&
+ a->tRP == b->tRP;
+}
- if (!(dimm_mask & (1 << i))) {
- continue;
+static void get_supported_timings(struct mem_controller *mch)
+{
+ int i, j, n;
+ int sb;
+ u8 tRCD, tRP;
+ unsigned required_support;
+
+ for (i = 0; i < mch->dimm_num; i++) {
+ /* Speed bins explicitly supported in SPD */
+ for (j = 0; j < 3 && mch->CL[i][j] != 0; j++) {
+ tRCD = div_ceil(tRCD_to_10ps(mch->tRCD[i]),
+ tCK_to_10ps(mch->tCK[i][j]));
+ tRP = div_ceil(tRP_to_10ps(mch->tRP[i]),
+ tCK_to_10ps(mch->tCK[i][j]));
+
+ mch->support[i][mch->n_support[i]++] =
+ (struct ram_timing){
+ get_speed(mch->tCK[i][j]),
+ mch->CL[i][j], tRCD, tRP };
}
- value = spd_read_byte(ctrl->channel0[i], SPD_NUM_ROWS);
- if (value < 0) die("Bad SPD data\n");
- if ((value & 0xf) == 0) die("Invalid # of rows\n");
- dra |= (((value-13) & 0x7) << NR_EVEN);
- dra |= (((value-13) & 0x7) << NR_ODD);
- reg += value & 0xf;
-
- value = spd_read_byte(ctrl->channel0[i], SPD_NUM_COLUMNS);
- if (value < 0) die("Bad SPD data\n");
- if ((value & 0xf) == 0) die("Invalid # of columns\n");
- dra |= (((value-10) & 0x7) << NC_EVEN);
- dra |= (((value-10) & 0x7) << NC_ODD);
- reg += value & 0xf;
-
- value = spd_read_byte(ctrl->channel0[i], SPD_NUM_BANKS_PER_SDRAM);
- if (value < 0) die("Bad SPD data\n");
- if ((value & 0xff) == 0) die("Invalid # of banks\n");
- reg += log2(value & 0xff);
-
- PRINTK_DEBUG("dimm %02x reg = %02x\n", i, reg);
-
- /* set device density */
- dra |= ((31-reg) << DIMMTECH_EVEN);
- dra |= ((31-reg) << DIMMTECH_ODD);
-
- /* set device width (x8, only option supported) */
- dra |= (1 << DWEVEN);
- dra |= (1 << DWODD);
-
- /* set decice type registered if type RDIMM */
- if ( spd_read_byte(ctrl->channel0[i], 20) & 0x1 ) {
- PRINTK_DEBUG("Using registered (RDIMM) module.\n");
- dra |= (DTYPE_REGISTERED << DTYPE);
- }
+ /* For each speed bin explicitly supported, add other speed
+ * bins required by the standard */
+ n = mch->n_support[i];
+ required_support = 0;
+ for (j = 0; j < n; j++) {
+ sb = timing_to_sb(&mch->support[i][j]);
+ if (sb < 0)
+ continue;
- /* set number of ranks (0=single, 1=dual) */
- value = spd_read_byte(ctrl->channel0[i], SPD_NUM_DIMM_BANKS);
- dra |= ((value & 0x1) << DTYPE_RANK);
+ required_support |= speed_bin_support[sb];
+ }
- PRINTK_DEBUG("DRA %02x = %08x\n", i, dra);
+ for (j = 0; j < NUM_SPEED_BINS; j++)
+ if (required_support & 1 << j)
+ mch->support[i][mch->n_support[i]++] =
+ speed_bins[j];
- pci_write_config32(ctrl->f0, DRA + (i*4), dra);
+#if CONFIG_DEBUG_RAM_SETUP
+ printk(BIOS_DEBUG, "Supported timings on DIMM%d:\n", i);
+ for (j = 0; j < mch->n_support[i]; j++) {
+ printk(BIOS_DEBUG, " - ");
+ print_ram_timing(BIOS_DEBUG, &mch->support[i][j]);
+ printk(BIOS_DEBUG, "\n");
+ }
+#endif
}
- return 0;
}
+#if CONFIG_DEBUG_RAM_SETUP
+#define INCOMPATIBLE(conf, reason) do { \
+ printk(BIOS_DEBUG, "Cannot choose "); \
+ print_ram_timing(BIOS_DEBUG, conf); \
+ printk(BIOS_DEBUG, ", " reason "\n"); \
+ return 0; } while (0)
+#else
+#define INCOMPATIBLE(...) do { return 0; } while (1)
+#endif
-static u32 spd_set_drt_attributes(const struct mem_controller *ctrl,
- u8 dimm_mask, u32 drc)
+static int supported_by_ep80579(struct mem_controller *mch,
+ struct ram_timing *timing)
{
- int i;
- u32 val, val1;
- u32 cl;
- u32 trc = 0;
- u32 trfc = 0;
- u32 tras = 0;
- u32 trtp = 0;
- u32 twtr = 0;
- int index = drc & 0x00000003;
- int ci;
- static const u8 latencies[] = { /* 533, 800, 400, 667 */
- 0x10, 0x60, 0x10, 0x20 };
- static const u32 drt0[] = { /* 533, 800, 400, 667 */
- 0x24240002, 0x24360002, 0x24220002, 0x24360002 };
- static const u32 drt1[] = { /* 533, 800, 400, 667 */
- 0x00400000, 0x00900000, 0x00200000, 0x00700000 };
- /* Write recovery for autoprecharge mrs[27:25]
- * 533 - 011 - 4
- * 800 - 101 - 6
- * 400 - 010 - 3
- * 667 - 100 - 5
- */
- static const u32 mrs[] = { /* 533, 800, 400, 667 */
- 0x07020000, 0x0b020000, 0x05020000, 0x09020000 };
- static const int cycle[] = { /* 533, 800, 400, 667 */
- 15, 10, 20, 12 }; /* cycle time in 1/4 ns units */
- static const int byte40rem[] = {
- 0, 1, 2, 2, 3, 3, 0, 0 }; /* byte 40 remainder in 1/4 ns units */
-
- /* CAS latency in cycles */
- val = latencies[index];
- for (i = 0; i < DIMM_SOCKETS; i++) {
- if (!(dimm_mask & (1 << i)))
- continue;
- val &= spd_read_byte(ctrl->channel0[i], SPD_ACCEPTABLE_CAS_LATENCIES);
- }
- if (val & 0x10)
- cl = 4;
- else if (val & 0x20)
- cl = 5;
- else if (val & 0x40)
- cl = 6;
- else
- die("CAS latency mismatch\n");
- PRINTK_DEBUG("cl = %02x\n", cl);
-
- ci = cycle[index];
-
- /* Trc, Trfc in cycles */
- for (i = 0; i < DIMM_SOCKETS; i++) {
- if (!(dimm_mask & (1 << i)))
- continue;
- val1 = spd_read_byte(ctrl->channel0[i], SPD_BYTE_41_42_EXTENSION);
- val = spd_read_byte(ctrl->channel0[i], SPD_MIN_ACT_TO_ACT_AUTO_REFRESH);
- val <<= 2; /* convert to 1/4 ns */
- val += byte40rem[(val1 >> 4) & 0x7];
- val = (val + ci - 1) / ci + 1; /* convert to cycles */
- if (trc < val)
- trc = val;
- val = spd_read_byte(ctrl->channel0[i], SPD_MIN_AUTO_REFRESH_TO_ACT);
- val <<= 2; /* convert to 1/4 ns */
- if (val1 & 0x01)
- val += 1024;
- val += byte40rem[(val1 >> 1) & 0x7];
- val = (val + ci - 1) / ci; /* convert to cycles */
- if (trfc < val)
- trfc = val;
- }
- PRINTK_DEBUG("trc = %02x\n", trc);
- PRINTK_DEBUG("trfc = %02x\n", trfc);
-
- /* Tras, Trtp, Twtr in cycles */
- for (i = 0; i < DIMM_SOCKETS; i++) {
- if (!(dimm_mask & (1 << i)))
- continue;
- val = spd_read_byte(ctrl->channel0[i], SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY);
- val <<= 2; /* convert to 1/4 ns */
- val = (val + ci - 1) / ci; /* convert to cycles */
- if (tras < val)
- tras = val;
- val = spd_read_byte(ctrl->channel0[i], SPD_INT_READ_TO_PRECHARGE_DELAY);
- val = (val + ci - 1) / ci; /* convert to cycles */
- if (trtp < val)
- trtp = val;
- val = spd_read_byte(ctrl->channel0[i], SPD_INT_WRITE_TO_READ_DELAY);
- val = (val + ci - 1) / ci; /* convert to cycles */
- if (twtr < val)
- twtr = val;
- }
- PRINTK_DEBUG("tras = %02x\n", tras);
- PRINTK_DEBUG("trtp = %02x\n", trtp);
- PRINTK_DEBUG("twtr = %02x\n", twtr);
-
- val = (drt0[index] | ((trc - 11) << Trc) | ((cl - 3) << Trcd)
- | ((cl - 3) << Trp) | ((cl - 3) << CL));
- PRINTK_DEBUG("drt0 = %08x\n", val);
- pci_write_config32(ctrl->f0, DRT0, val);
-
- val = (drt1[index] | ((tras - 8) << tRAS) | ((trtp - 2) << tRTP)
- | (twtr << tWTR));
-
- /* There are two cases where 2T is required:
- * - 800 Mhz DDR2
- * - 2 Unbuffered DIMMs
- */
- /* FIXME: This does not need to turn on 2T timing for RDIMM modules */
- if ( (index == 1) || (dimm_mask != 1) ) {
- printk(BIOS_DEBUG, "Forcing 2T timing: dimm_mask=0x%x || index=0x%x\n", dimm_mask, index);
- val |= (1 << 12);
- }
- PRINTK_DEBUG("drt1 = %08x\n", val);
- pci_write_config32(ctrl->f0, DRT1, val);
+ if (timing->speed > mch->max_speed)
+ INCOMPATIBLE(timing, "speed not supported by SKU");
+ if (timing->speed == DDR_800 && mch->dimm_num == 2)
+ INCOMPATIBLE(timing, "not supported for two DIMMs");
+ if (timing->CL <= 3) /* xref2 */
+ INCOMPATIBLE(timing, "CL=2 and CL=3 not supported on systems "
+ "with ODT");
+
+/* XXX tAC should maybe be tested somewhere as follows:
+ static const int ac_max[] = {
+ [DDR_800] = 0x40,
+ [DDR_667] = 0x45,
+ [DDR_533] = 0x50,
+ [DDR_400] = 0x60,
+ };
- val = (mrs[index] | (cl << 20));
- PRINTK_DEBUG("mrs = %08x\n", val);
+ if (ac_max[conf->speed] < mch->tAC[j][n])
+ INCOMPATIBLE_DIMM("data access time from clock "
+ "too high", j);
+*/
- return val;
+ return 1;
}
-static void set_magic(u32 drc) {
+static int compare_speed_bins(struct ram_timing *a, struct ram_timing *b)
+{
+ if (a->CL == 0)
+ return 1;
+ if (b->CL == 0)
+ return 0;
- u32 index = (drc & 0x00000003);
- u32 val;
+ if (a->speed < b->speed)
+ return 1;
+ if (a->speed > b->speed)
+ return 0;
- static const u32 magic[] = { /* 533, 800, 400, 667 */
- 0x007b8001, 0x00b94001, 0x005ca001, 0x009a6001 };
+ return a->CL + a->tRCD + a->tRP >= b->CL + b->tRCD + b->tRP;
+}
- /* 533, 800, 400, 667 */
- static const u8 magic2[4][4] = {
- /* 256Mb */
- { 0x14, 0x1e, 0x0f, 0x18 },
- /* 512Mb */
- { 0x1c, 0x2a, 0x15, 0x22 },
- /* 1024Mb */
- { 0x22, 0x33, 0x1a, 0x29 },
- /* 2048Mb */
- { 0x34, 0x4e, 0x27, 0x2b } };
+static struct ram_timing get_common_timing(
+ const struct ram_timing *a,
+ const struct ram_timing *b)
+{
+ return (struct ram_timing){
+ a->speed,
+ a->CL,
+ MAX(a->tRCD, b->tRCD),
+ MAX(a->tRP, b->tRP)};
+}
- val = (magic[drc & 0x00] | (magic2[index][3] << 4));
- PRINTK_DEBUG("magic = %08x\n", val);
- pci_write_config32(PCI_DEV(0, 0x08, 0), 0xcc, val);
+static void maybe_select_timing(
+ struct mem_controller *mch,
+ struct ram_timing t)
+{
+ if (supported_by_ep80579(mch, &t) &&
+ compare_speed_bins(&mch->timing, &t))
+ mch->timing = t;
}
-static int spd_set_dram_controller_mode(const struct mem_controller *ctrl,
- u8 dimm_mask)
+static void choose_common_supported_timing(struct mem_controller *mch)
{
- int value;
- int drc = 0;
- int i;
- msr_t msr;
- u8 cycle = 0x25;
- int ranks = 0;
-
- for (i = 0; i < DIMM_SOCKETS; i++) {
- if (!(dimm_mask & (1 << i)))
- continue;
- if ((spd_read_byte(ctrl->channel0[i], SPD_MODULE_DATA_WIDTH_LSB) & 0xf0) != 0x40)
- die("ERROR: Only 64-bit DIMMs supported\n");
- if ((spd_read_byte(ctrl->channel0[i], SPD_DIMM_CONFIG_TYPE) & 0x02)) {
- printk(BIOS_INFO, "ECC enabled.\n");
- drc |= (1 << ECC );
- }
- if (spd_read_byte(ctrl->channel0[i], SPD_PRIMARY_SDRAM_WIDTH) != 0x08)
- die("ERROR: Only x8 DIMMs supported\n");
-
- value = spd_read_byte(ctrl->channel0[i], SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
- /* 0 is 1 rank, 1 is 2 rank */
- ranks = (spd_read_byte(ctrl->channel0[i], SPD_NUM_DIMM_BANKS) & 0x07);
- if (value > cycle)
- cycle = value;
- }
- PRINTK_DEBUG("cycle = %02x\n", cycle);
-
- /* Only enable CKE for slots with memory */
- drc |= (1 << CKE0);
- drc |= (1 << CKE1);
- /* Disable CKE[1] ODT[1] cs[1] for one DIMM, one rank */
- if (!ranks && (dimm_mask < 3)) {
- drc |= (1 << ODT1DIS);
- drc |= (1 << CS1DIS);
- drc &= ~(1 << CKE1);
- }
- drc |= (1 << CKEPNM); /* enable CKE globally */
-
- /* TODO check: */
- /* set front side bus speed */
- msr = rdmsr(0xcd); /* returns 0 on Pentium M 90nm */
- PRINTK_DEBUG("msr 0xcd = %08x%08x\n", msr.hi, msr.lo);
-
- /* TODO check that this msr really indicates fsb speed! */
- if (msr.lo & 0x07) {
- printk(BIOS_INFO, "533 MHz FSB\n");
- if (cycle <= 0x25) {
- drc |= 0x5;
- printk(BIOS_INFO, "400 MHz DDR\n");
- } else if (cycle <= 0x30) {
- drc |= 0x7;
- printk(BIOS_INFO, "333 MHz DDR\n");
- } else if (cycle <= 0x3d) {
- drc |= 0x4;
- printk(BIOS_INFO, "266 MHz DDR\n");
- } else {
- drc |= 0x2;
- printk(BIOS_INFO, "200 MHz DDR\n");
- }
- }
+ int i, j;
+
+ if (mch->dimm_num == 1)
+ for (i = 0; i < mch->n_support[0]; i++)
+ maybe_select_timing(mch, mch->support[0][i]);
else {
- printk(BIOS_INFO, "400 MHz FSB\n");
- if (cycle <= 0x30) {
- drc |= 0x7;
- printk(BIOS_INFO, "333 MHz DDR\n");
- } else if (cycle <= 0x3d) {
- drc |= 0x0;
- printk(BIOS_INFO, "266 MHz DDR\n");
- } else {
- drc |= 0x2;
- printk(BIOS_INFO, "200 MHz DDR\n");
- }
+ for (i = 0; i < mch->n_support[0]; i++)
+ for (j = 0; j < mch->n_support[1]; j++)
+ maybe_select_timing(mch,
+ get_common_timing(
+ &mch->support[0][i],
+ &mch->support[1][j]));
}
+}
- PRINTK_DEBUG("DRC = %08x\n", drc);
+static void warn_if_non_validated(struct ram_timing *timing)
+{
+ static const struct ram_timing conf[] = { /* supported configurations,
+ from fastest to slowest */
+ {DDR_800, 5, 5, 5},
+ {DDR_800, 6, 6, 6},
+ {DDR_667, 5, 5, 5},
+ {DDR_533, 4, 4, 4},
+ {DDR_400, 3, 3, 3}, /* xref2: truxton does not support 3-3-3 */
+ {DDR_400, 4, 4, 4},
+ };
- return drc;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(conf); i++)
+ if (ram_timing_equal(timing, &conf[i]))
+ return;
+
+ printk(BIOS_WARNING, "Using speed ");
+ print_ram_timing(BIOS_WARNING, timing);
+ printk(BIOS_WARNING, " which is not officially validated for use on "
+ "EP80579\n");
}
-void sdram_set_spd_registers(const struct mem_controller *ctrl)
+static void read_timing_info(struct mem_controller *mch)
{
- u8 dimm_mask;
-
- /* Test if we can read the SPD */
- dimm_mask = spd_detect_dimms(ctrl);
- PRINTK_DEBUG("dimm_mask: 0x%x\n", dimm_mask);
- if (!(dimm_mask & ((1 << DIMM_SOCKETS) - 1))) {
- printk(BIOS_ERR, "No memory for this cpu\n");
- return;
+ int i, j, n;
+ u8 cas_lat;
+
+ for (i = 0; i < mch->dimm_num; i++) {
+ mch->tRP[i] = spd_read_byte(mch->spd[i], SPD_TRP);
+ mch->tRCD[i] = spd_read_byte(mch->spd[i], SPD_TRCD);
+
+ cas_lat = spd_read_byte(mch->spd[i], SPD_CAS_LAT);
+ for (j = 7, n = 0; j >= 2 && n < 3; j--)
+ if (cas_lat & 1 << j)
+ mch->CL[i][n++] = j;
+
+ mch->tCK[i][0] = spd_read_byte(mch->spd[i], 9);
+ mch->tAC[i][0] = spd_read_byte(mch->spd[i], 10);
+ mch->tCK[i][1] = spd_read_byte(mch->spd[i], 23);
+ mch->tAC[i][1] = spd_read_byte(mch->spd[i], 24);
+ mch->tCK[i][2] = spd_read_byte(mch->spd[i], 25);
+ mch->tAC[i][2] = spd_read_byte(mch->spd[i], 26);
+ }
+
+#if CONFIG_DEBUG_RAM_SETUP
+ printk(BIOS_DEBUG, "Timings read:\n\tCL tCK tAC\n");
+ for (i = 0; i < mch->dimm_num; i++) {
+ printk(BIOS_DEBUG, "DIMM%d: tRP=%02x tRCD=%02x\n",
+ i, mch->tRP[i], mch->tRCD[i]);
+ for (j = 0; j < 3; j++)
+ printk(BIOS_DEBUG, "\t%d %02x %02x\n",
+ mch->CL[i][j],
+ mch->tCK[i][j],
+ mch->tAC[i][j]);
}
- return;
+#endif
}
-static void send_ram_command(u8 nr_cs, u32 dcaladdr, u32 dcalcsr)
+static void select_timing(struct mem_controller *mch)
{
+ read_timing_info(mch);
+ get_supported_timings(mch);
+ choose_common_supported_timing(mch);
- u8 cs = 0;
- u32 data32 = 0;
+ if (mch->timing.CL == 0)
+ die("No common supported RAM speed found!");
- for (cs = 0; cs < nr_cs; cs++) {
- write32(BAR+DCALADDR, dcaladdr);
- write32(BAR+DCALCSR, (dcalcsr | (1 << 31) | ((cs+1)<<21)));
- data32 = read32(BAR+DCALCSR);
- printk(BIOS_DEBUG, "DCALCSR: 0x%08x DCALADDR: 0x%08x\n", data32, dcaladdr);
- while (data32 & 0x80000000)
- data32 = read32(BAR+DCALCSR);
- }
+ printk(BIOS_DEBUG, "Chosen DRAM speed: ");
+ print_ram_timing(BIOS_DEBUG, &mch->timing);
+ printk(BIOS_DEBUG, "\n");
+ warn_if_non_validated(&mch->timing);
}
-static void set_on_dimm_termination_enable(const struct mem_controller *ctrl)
+static void send_ram_command(u8 nr_cs, u32 dcaladdr, u32 dcalcsr)
{
- u8 c1,c2;
- u32 data32;
- u8 nr_cs;
-
- /* Set up northbridge values */
- /* ODT enable */
- pci_write_config32(ctrl->f0, SDRC, 0xa0002c30);
-
- c1 = pci_read_config8(ctrl->f0, DRB);
- c2 = pci_read_config8(ctrl->f0, DRB+2);
- if (c1 == c2) {
- /* 1 single-rank DIMM */
- data32 = 0x00000010;
- nr_cs = 1;
- }
- else {
- /* 2 single-rank DIMMs or 1 double-rank DIMM */
- data32 = 0x00002010;
- nr_cs = 2;
+ u8 cs = 0;
+ for (cs = 0; cs < nr_cs; cs++) {
+ write32(BAR+DCALADDR, dcaladdr);
+ write32(BAR+DCALCSR, (dcalcsr |
+ (1 << DCALCSR_START) |
+ ((cs+1) << DCALCSR_CS)));
+ while (read32(BAR+DCALCSR) & 1 << DCALCSR_START);
}
-
- PRINTK_DEBUG("ODT Value = %08x\n", data32);
-
- pci_write_config32(ctrl->f0, DDR2ODTC, data32);
-
- /* Set Rtt to 75ohm and maintain OCD setting */
- data32 = (EMR1 & ~(7 << (16+7)));
- /* Rtt = 50ohm
- data32 |= (1 << (16+6));
- data32 |= (1 << (16+2));
- */
- /* Rtt = 75ohm */
- data32 |= (0 << (16+6));
- data32 |= (1 << (16+2));
-
- /* Rtt = 150ohm
- data32 |= (1 << (16+6));
- data32 |= (0 << (16+2));
- */
-
- send_ram_command(nr_cs, data32, 0x00000003);
}
-void sdram_enable(int controllers, const struct mem_controller *ctrl)
+static void jedec_init(int nr_cs, struct ram_timing timing, int sodimm)
{
int i;
- int cs;
- int nr_cs=0;
- long mask;
- u32 drc;
- u32 data32;
- u32 mode_reg;
-
- mask = spd_detect_dimms(ctrl);
- printk(BIOS_INFO, "Starting SDRAM Enable\n");
-
- /* Set DRAM type and Front Side Bus frequency */
- drc = spd_set_dram_controller_mode(ctrl, mask);
- if (drc == 0) {
- die("Error calculating DRC\n");
+
+ udelay(200);
+ send_ram_command(nr_cs, 0, DCALCSR_OPCODE_NOP);
+
+ udelay(1);
+ send_ram_command(nr_cs, 0x0400 << 16, DCALCSR_OPCODE_PRECHARGE);
+
+ send_ram_command(nr_cs, DCALADDR_EMR2, DCALCSR_OPCODE_MRS);
+
+ send_ram_command(nr_cs, DCALADDR_EMR3, DCALCSR_OPCODE_MRS);
+
+ u16 emr1 = (sodimm ?
+ EMR1_Rtt0_disable << EMR1_Rtt0 |
+ EMR1_Rtt1_disable << EMR1_Rtt1
+ :
+ EMR1_Rtt0_75ohm << EMR1_Rtt0 |
+ EMR1_Rtt1_75ohm << EMR1_Rtt1);
+
+ send_ram_command(nr_cs, emr1 << 16 | DCALADDR_EMR1, DCALCSR_OPCODE_MRS);
+
+ static const unsigned wr[] = { /* coherent with DRT0 config (xref1) */
+ [DDR_400] = 1,
+ [DDR_533] = 2,
+ [DDR_667] = 3,
+ [DDR_800] = 4,
+ };
+ u16 mr =
+ wr[timing.speed] << MR_WR | /* xref1 */
+ MR_BL_4 << MR_BURST_LENGTH | /* for 64-bit bus */
+ timing.CL << MR_CAS_LAT | /* CAS latency */
+ 0 << MR_PD | /* Fast exit */
+ 0 << MR_TM | /* Normal mode */
+ 0 << MR_BURST_TYPE; /* Sequential */
+ send_ram_command(nr_cs,
+ (mr | 1 << MR_DLL_RST) << 16 | DCALADDR_MR,
+ DCALCSR_OPCODE_MRS);
+
+ send_ram_command(nr_cs, 0x0400 << 16, DCALCSR_OPCODE_PRECHARGE);
+
+ for (i = 0; i < 6; i++) {
+ send_ram_command(nr_cs, 0, DCALCSR_OPCODE_REFRESH);
+ udelay(1);
}
- data32 = drc & ~(3 << ECC); /* clear ECC mode */
- data32 = data32 | (1 << ODT0DIS) | (1 << ODT1DIS); /* temp turn off ODT */
- /* Set DRAM controller mode */
- pci_write_config32(ctrl->f0, DRC, data32);
- if (drc & (1 << CS1DIS))
- nr_cs = 1;
- else
- nr_cs = 2;
+ send_ram_command(nr_cs, mr << 16 | DCALADDR_MR, DCALCSR_OPCODE_MRS);
+
+ send_ram_command(nr_cs,
+ (emr1 | EMR1_OCD_cal_default << EMR1_OCD) << 16 |
+ DCALADDR_EMR1,
+ DCALCSR_OPCODE_MRS);
+ send_ram_command(nr_cs,
+ (emr1 | EMR1_OCD_cal_exit << EMR1_OCD) << 16 |
+ DCALADDR_EMR1,
+ DCALCSR_OPCODE_MRS);
+}
+
+struct membist_param { int val; const char *desc; };
+static void membist(int nr_cs)
+{
+ int h, i, j, k, pf, fail = 0;
- /* Program row size */
- spd_set_ram_size(ctrl, mask);
+ for(h = 0; h < nr_cs; h++) {
+ PRINTK_DEBUG("Beginning MemBIST for rank %d\n", h);
- /* Program row attributes */
- spd_set_row_attributes(ctrl, mask);
+ static const struct membist_param cmd[] = {
+#if CONFIG_DEBUG_RAM_SETUP
+ {3, "Write followed by read with data comparison" },
+#else
+ {1, "Write only" },
+#endif
+ };
- /* Program timing values */
- mode_reg = spd_set_drt_attributes(ctrl, mask, drc);
+ static const struct membist_param pat[] = {
+#if CONFIG_DEBUG_RAM_SETUP
+ {1, "1111"},
+ {2, "1010"},
+ {3, "0101"},
+ {4, "1100"},
+ {5, "0011"},
+ {6, "1001"},
+ {7, "0110"},
+#endif
+ {0, "0000 (clear memory)"},
+ };
- if (! (drc & (3 << ECC))) {
- write32(BAR+WL_CNTL0, 0x00000b62);
- write32(BAR+WL_CNTL1, 0x00000b62);
- write32(BAR+WL_CNTL2, 0x00000b62);
- write32(BAR+WL_CNTL3, 0x00000b62);
- write32(BAR+WL_CNTL4, 0x00000b60);
- write32(BAR+WDLL_MISC, 0x01000000);
+ static const struct membist_param dir[] = {
+#if CONFIG_DEBUG_RAM_SETUP
+ {1, "decrements"},
+#endif
+ {0, "increments"},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(cmd); i++)
+ for (j = 0; j < ARRAY_SIZE(pat); j++)
+ for (k = 0; k < ARRAY_SIZE(dir); k++)
+ {
+ u32 mbcsr = 0;
+ mbcsr |= 0 << MBCSR_DTYPE; /* Fixed data pattern */
+ mbcsr |= 3 << MBCSR_ATYPE; /* Full address range => not
+ programming MB_START_ADDR
+ nor MB_START_END */
+ mbcsr |= (h+1) << MBCSR_CS; /* Select rank */
+ mbcsr |= cmd[i].val << MBCSR_CMD;
+ mbcsr |= dir[k].val << MBCSR_ADIR;
+ mbcsr |= pat[j].val << MBCSR_FX;
+ mbcsr |= 1 << MBCSR_HALT;
+ mbcsr |= 1 << MBCSR_START; /* start MemBIST execution */
+
+ write32(BAR+MBCSR, mbcsr);
+
+ PRINTK_DEBUG("%s with pattern %s, address %s... ",
+ cmd[i].desc, pat[j].desc, dir[k].desc);
+
+ while((mbcsr = read32(BAR+MBCSR)) & 1 << MBCSR_START);
+
+ pf = mbcsr & 1 << MBCSR_PF;
+
+ fail = fail || pf;
+ PRINTK_DEBUG("%s\n", pf ? "FAIL" : cmd[i].val != 1 ?
+ "PASS" : "");
+ }
}
- PRINT_DCAL_DUMP();
+ if (fail)
+ die("Memory test failed.\n");
+
+ clear_fifo_pointers();
+}
- /* ------------------- */
- /* JEDEC init begin */
- /* ------------------- */
+void sdram_initialize(struct mem_controller *mch)
+{
+ int i;
- /* Turn the clocks on */
- pci_write_config8(ctrl->f0, CKDIS, 0x00);
+#if CONFIG_DEBUG_RAM_SETUP
+ dump_spd_registers(mch);
+#endif
+ /* Do this early */
+ pci_write_config8(PCI_DEV(0,0,0), DEVPRES,
+ DEVPRES_D1F0 |
+ DEVPRES_D2F0 |
+ DEVPRES_D3F0 |
+ DEVPRES_D4F0 |
+ DEVPRES_D10F0);
+
+ /* Activate B0:D0:F1 and B0:D8:F0 */
+ pci_write_config8(PCI_DEV(0,0,0), DEVPRES1,
+ pci_read_config8(PCI_DEV(0,0,0), DEVPRES1) | 0x22);
+
+ /* Enable BAR defined by SMRBASE */
+ pci_write_config8(PCI_DEV(0,0,0), IMCH_TST2,
+ pci_read_config8(PCI_DEV(0,0,0), IMCH_TST2) |
+ 1 << IMCH_TST2_SYSMMREN);
+
+ pci_write_config32(PCI_DEV(0,0,0), SMRBASE, BAR);
+
+ u8 fdhc = pci_read_config8(PCI_DEV(0,0,0), FDHC);
+ fdhc &= 0x7f;
+ dbg_pci_write_config8(PCI_DEV(0,0,0), FDHC, fdhc);
+
+ u8 pam = pci_read_config8(PCI_DEV(0,0,0), PAM);
+ pam &= 0xcc;
+ pam |= 0x30;
+ dbg_pci_write_config8(PCI_DEV(0,0,0), PAM, pam);
+
+ for (i = 1; i <= 6; i++) {
+ pam = pci_read_config8(PCI_DEV(0,0,0), PAM+i);
+ pam &= 0xcc;
+ pam |= 0x33;
+ PRINTK_DEBUG("PAM%d=%02x\n", i, pam);
+ pci_write_config8(PCI_DEV(0,0,0), PAM+i, pam);
+ }
- /* Apply 20 NOP with 10us between each cs (400us of delay)*/
- for (i = 0; i < 20; i++) {
- send_ram_command(nr_cs, 0, 0);
- udelay(20);
+ /* Max memory speed is limited by FSB speed and FUSESPEED */
+ enum fsb_speed fsb_speed;
+
+ fsb_speed = (rdmsr(0xcd).lo & 3) ? FSB_133 : FSB_100;
+ PRINTK_DEBUG("%dMHz FSB\n", fsb_speed == FSB_133 ? 133 : 100);
+ switch ((pci_read_config8(PCI_DEV(0,0,0), SDRC) >> SDRC_FUSESPEED)
+ & 3) {
+ case 0: mch->max_speed = (fsb_speed == FSB_133) ? DDR_800 :
+ DDR_667;
+ break;
+ case 1: mch->max_speed = DDR_667; break;
+ case 2: mch->max_speed = DDR_533; break;
+ case 3: mch->max_speed = DDR_400; break;
}
+ PRINTK_DEBUG("Max DRAM speed: %dMTS\n",
+ freq_to_int[mch->max_speed]);
+
+ int nb_registered = 0;
+ int sodimm = 0;
+ u8 is_double_rank = 0;
+ u8 row_num[2];
+ u8 bank_num[2];
+ u8 col_num[2];
+ enum dev_size size[2];
+ mch->ecc = 1;
+
+ mch->dimm_num = 2;
+
+ /* SPD checks */
+ if (spd_read_byte(mch->spd[0], SPD_MEM_TYPE) != SPD_MEM_TYPE_SDRAM_DDR2)
+ die("DIMM0: No DDR2 module found!\n");
+ if (spd_read_byte(mch->spd[1], SPD_MEM_TYPE) != SPD_MEM_TYPE_SDRAM_DDR2)
+ mch->dimm_num = 1;
+ printk(BIOS_DEBUG, "%d DDR2 SDRAM modules found\n", mch->dimm_num);
+
+ select_timing(mch);
+
+ for (i = 0; i < mch->dimm_num; i++) {
+ row_num[i] = spd_read_byte(mch->spd[i], SPD_ROW_NUM) & 0x1f;
+ if (row_num[i] != 13 && row_num[i] != 14 && row_num[i] != 15)
+ die("DIMM%d: Unsupported number of rows %d\n",
+ i, row_num[i]);
+
+ col_num[i] = spd_read_byte(mch->spd[i], SPD_COL_NUM) & 0xf;
+ if (col_num[i] != 10)
+ die("DIMM%d: Unsupported number of cols %d\n",
+ i, col_num[i]);
+
+ is_double_rank =
+ spd_read_byte(mch->spd[i], SPD_MOD_ATTRIB_RANK) & 3;
+ if (is_double_rank) {
+ if (is_double_rank != 1)
+ die("DIMM%d: Unsupported rank number %d",
+ i, is_double_rank + 1);
+ if (mch->dimm_num != 1)
+ die("DIMM%d: Dual rank only supported with one "
+ "module in the first slot.\n",
+ i);
+ }
- /* Worst case timings from Micron:
- * tCK (AVG) <= 8ns
- * tMRD = 2*tCK <= 16ns
- * tRPA <= 20ns
- * tRFC <= 197.5ns
- * 200*tCK <= 1.6us
- */
-
- /* Enable CKE after 200us of NOP. */
- pci_write_config8(ctrl->f0, CKEDIS, 0x00);
-
- /* Micron timing diagram shows one NOP after 200us */
- send_ram_command(nr_cs, 0, 0);
-
- /* Wait a minimum of 400ns then precharge all banks */
- udelay(2);
- send_ram_command(nr_cs, 0x04000000, 0x00000002);
-
- /* Wait tRPA (max 20ns)
- * EMR(1): Enable DLLs all other bits are 0 (Micron) */
- udelay(1);
- send_ram_command(nr_cs, 0x00000001, 0x00000003);
+ u8 data_width = spd_read_byte(mch->spd[i], SPD_DATA_WIDTH);
+ if (data_width < 64)
+ die("DIMM%d: Only 64-bit DIMM supported.\n", i);
+
+ u8 dimm_conf_type =
+ spd_read_byte(mch->spd[i], SPD_DIMM_CONF_TYPE);
+ mch->ecc = mch->ecc && data_width >= 72 &&
+ (dimm_conf_type & 3) == SPD_DIMM_CONF_TYPE_ECC;
+
+ u8 pri_width = spd_read_byte(mch->spd[i], SPD_PRI_WIDTH);
+
+ if (pri_width == 16 || pri_width == 18)
+ printk(BIOS_WARNING, "DIMM%d: use of x%d module "
+ "not validated\n", i, pri_width);
+
+ else if (!(pri_width == 8 || pri_width == 9))
+ die("DIMM%d: invalid primary width x%d.\n",
+ i, pri_width);
+
+ bank_num[i] = spd_read_byte(mch->spd[i], SPD_BANK_NUM);
+ if (bank_num[i] != 4 && bank_num[i] != 8)
+ die("DIMM%d: invalid bank number %d.\n",
+ i, bank_num[i]);
+
+ if (bank_num[i] == 8 && row_num[i] == 15)
+ size[i] = DEV_2Gb;
+ else if (bank_num[i] == 8 && row_num[i] == 14)
+ size[i] = DEV_1Gb;
+ else if (bank_num[i] == 4 && row_num[i] == 14)
+ size[i] = DEV_512Mb;
+ else if (bank_num[i] == 4 && row_num[i] == 13)
+ size[i] = DEV_256Mb;
+ else
+ die("DIMM%d: incorrect number of banks/rows (%d/%d)\n",
+ i, bank_num[i], row_num[i]);
+
+ u8 dimm_type = spd_read_byte(mch->spd[i], SPD_DIMM_TYPE);
+ nb_registered +=
+ dimm_type == SPD_DIMM_TYPE_RDIMM ||
+ dimm_type == SPD_DIMM_TYPE_mRDIMM ||
+ dimm_type == SPD_DIMM_TYPE_SORDIMM;
+ if (i == 1 && nb_registered == 1)
+ die("Only one of the two DIMMs is registered\n");
+ sodimm =
+ dimm_type == SPD_DIMM_TYPE_SODIMM ||
+ dimm_type == SPD_DIMM_TYPE_SOCDIMM ||
+ dimm_type == SPD_DIMM_TYPE_SORDIMM;
+ }
- /* MRS: Reset DLLs must wait at least 200*tCK after this
- * command before issuing a READ command.*/
- udelay(1);
- send_ram_command(nr_cs, mode_reg, 0x00000003);
+ int rank_num = (mch->dimm_num == 2 || is_double_rank) ? 2 : 1;
- /* Precharge all banks */
- udelay(1);
- send_ram_command(nr_cs, 0x04000000, 0x00000002);
+ PRINTK_DEBUG("Configuring gearing ratio\n");
+ u8 sku_id = pci_read_config8(PCI_DEV(0,10,0), SKU_ID);
+ int QuickAssist = sku_id & 1;
+ printk(BIOS_DEBUG, "SKU %d (%s QuickAssist)\n",
+ sku_id, QuickAssist ? "with" : "without");
- /* Do 6 refreshes */
- for (i = 0; i < 6; i++) {
- udelay(1);
- send_ram_command(nr_cs, 0x00000000, 0x00000001);
+ if (QuickAssist) {
+ dbg_pci_write_config32(PCI_DEV(0,0,0), MAGIC_A8, 0x3000d);
+ dbg_pci_write_config32(PCI_DEV(0,0,0), MAGIC_AC, 0x4000f);
}
- /* MRS: Set DLLs to normal */
- udelay(1);
- send_ram_command(nr_cs, (mode_reg & ~(1<<24)), 0x00000003);
+ if (mch->timing.speed == DDR_667) {
+ if (fsb_speed == FSB_100) {
+ dbg_pci_write_config32(PCI_DEV(0,0,0), MAGIC_A0,
+ 0xFDFFF);
+ dbg_pci_write_config32(PCI_DEV(0,0,0), MAGIC_A4,
+ 0x4001D);
+ if (!QuickAssist) {
+ dbg_pci_write_config32(PCI_DEV(0,0,0),
+ MAGIC_A8, 0x700DF);
+ dbg_pci_write_config32(PCI_DEV(0,0,0),
+ MAGIC_AC, 0x4001B);
+ }
+ } else /* 133 MHz */ {
+ dbg_pci_write_config32(PCI_DEV(0,0,0), MAGIC_A0,
+ 0xB0FDF);
+ dbg_pci_write_config32(PCI_DEV(0,0,0), MAGIC_A4,
+ 0x40017);
+ if (!QuickAssist) {
+ dbg_pci_write_config32(PCI_DEV(0,0,0),
+ MAGIC_A8, 0x5001F);
+ dbg_pci_write_config32(PCI_DEV(0,0,0),
+ MAGIC_AC, 0x4001D);
+ }
+ }
+ }
- /* EMRS: Program EMR(1) and set OCD default */
- udelay(1);
- send_ram_command(nr_cs, EMR1, 0x00000003);
+ PRINTK_DEBUG("Put the VOX in reset mode\n");
+ write32(BAR+DDRIOMC0, read32(BAR+DDRIOMC0) |
+ 1 << DDRIOMC0_DDRVOXCTL1 | 1 << DDRIOMC0_DDRVOXCTL0);
- /* EMRS: Program EMR(1) and exit OCD */
- udelay(1);
- send_ram_command(nr_cs, EMR1 & ~(7<<(16+7)), 0x00000003);
+ PRINTK_DEBUG("DQS delay bypass\n");
+ write32(BAR+DRAMDLLC, read32(BAR+DRAMDLLC) | 1 << DRAMDLLC_SLVBYP);
- /* ------------------- */
- /* JEDEC init complete */
- /* ------------------- */
+ u32 drc = pci_read_config32(PCI_DEV(0,0,0), DRC);
+ u8 ds = (mch->timing.speed == DDR_400 ? 2 :
+ mch->timing.speed == DDR_533 ? 0 :
+ mch->timing.speed == DDR_667 ? 7 :
+ /* DDR_800 */ 5);
- udelay(16);
- /* No command */
- write32(BAR+DCALCSR, 0x0000000f);
+ drc = (drc & ~(0xf << DRC_DS)) | ds << DRC_DS;
- write32(BAR, 0x00100000);
+ drc |= 1 << DRC_CKEPNM;
- PRINT_DCAL_DUMP();
+ if (rank_num == 1)
+ drc |= 1 << DRC_ODT1DIS | 1 << DRC_CS1DIS;
+ else
+ drc &= ~(1 << DRC_ODT1DIS | 1 << DRC_CS1DIS);
- PRINT_DEBUG_DDRIO();
+ drc |= 1 << DRC_CKE0;
- /* Receive enable calibration */
- printk(BIOS_INFO, "Perform receive enable calibration\n");
- udelay(16);
- /* Use BASPAT because we run in 2T mode */
- write32(BAR+DCALCSR, (0x8800000c | (1<<21)));
- data32 = read32(BAR+DCALCSR);
- while (data32 & 0x80000000)
- data32 = read32(BAR+DCALCSR);
- if (data32 & 0x40000000) {
- die("receive enable failed!\n");
+ if (rank_num == 2)
+ drc |= 1 << DRC_CKE1;
+ else
+ drc &= ~(1 << DRC_CKE1);
+
+ PRINTK_DEBUG("DRC=%08x\n", drc);
+ pci_write_config32(PCI_DEV(0,0,0), DRC, drc);
+
+ drc = pci_read_config32(PCI_DEV(0,0,0), DRC);
+ if ((drc & 0xf) != ds)
+ die("Impossible to update the DRC_DS ratio\n");
+
+ for (i = 0; i < 5; i++) {
+ u32 wl_cntl = read32(BAR+WL_CNTL0+(i*4));
+ wl_cntl &= ~0x00000fff;
+ wl_cntl |= mch->timing.speed == DDR_400 ? 0x904 :
+ mch->timing.speed == DDR_533 ? 0x92C :
+ mch->timing.speed == DDR_667 ? 0x94C :
+ /* DDR_800 */ 0x918;
+ if (i < 4)
+ wl_cntl |= 1 << WL_CNTL_WDLL_CLKG;
+
+ PRINTK_DEBUG("WL_CNTL%d=%08x\n", i, wl_cntl);
+ write32(BAR+WL_CNTL0+(i*4), wl_cntl);
}
- PRINT_DCAL_DUMP();
- clear_dqs_fail(drc);
-
- /* Adjust RCOMP */
- data32 = read32(BAR+DDRIOMC2);
- data32 &= ~(0xf << 16);
- data32 |= (0xb << 16);
- write32(BAR+DDRIOMC2, data32);
-
- /* DQS Delay calibration */
- /* Procedure is:
- * For each DIMM slot (not rank!):
- * write DCALADDR to select Row 1, Col 1, Rank 0
- * Write 0x88020015 to DCALCSR
- * Wait for completion
- * Check status
- */
-
- /* Hard code one DIMM slot */
- PRINTK_DEBUG("Perform DQS calibration\n");
- udelay(16);
- /* Use BASPAT because we run in 2T mode */
- write32(BAR+DCALCSR, (0x88000005 | (1<<21)));
- data32 = read32(BAR+DCALCSR);
- while (data32 & 0x80000000)
- data32 = read32(BAR+DCALCSR);
- if (data32 & 0x40000000) {
- die("DQS delay failed!\n");
- }
+ u32 wdll_misc = (read32(BAR+WDLL_MISC) & 0xfe80f00f) | 0x1200902;
+ PRINTK_DEBUG("WDLL_MISC=%08x\n", wdll_misc);
+ write32(BAR+WDLL_MISC, wdll_misc);
- PRINT_DCAL_DUMP();
+ u32 ddriomc1;
+ if (nb_registered)
+ ddriomc1 = 0x52 << DDRIOMC1_CASLEW | 0x52 << DDRIOMC1_DQSLEW;
+ else
+ ddriomc1 = 0xFE << DDRIOMC1_CASLEW | 0xF8 << DDRIOMC1_DQSLEW |
+ 1 << 2 | 3 << DDRIOMC1_FASTSLEW;
- /* Clear any errors from previous calibration */
- clear_dqs_fail(drc);
+ PRINTK_DEBUG("DDRIOMC1=%08x\n", ddriomc1);
+ write32(BAR+DDRIOMC1, ddriomc1);
- PRINT_DCAL_DUMP();
+ static const u8 mastcntl_tbl[] = {
+ [DDR_400] = 6,
+ [DDR_533] = 4,
+ [DDR_667] = 4,
+ [DDR_800] = 3,
+ };
- data32 = drc & ~(3 << ECC); /* clear ECC mode */
- pci_write_config32(ctrl->f0, DRC, data32);
- write32(BAR+DCALCSR, 0x0008000f);
+ mch->mastcntl = mastcntl_tbl[mch->timing.speed];
+ u32 ddriomc2 = mch->mastcntl << DDRIOMC2_MASTCNTL |
+ (nb_registered ? 0x20e : 0x294) << DDRIOMC2_LEGOVERRIDE;
+
+ PRINTK_DEBUG("DDRIOMC2=%08x\n", ddriomc2);
+ write32(BAR+DDRIOMC2, ddriomc2);
+
+ PRINTK_DEBUG("Reset DQS delay bypass\n");
+ write32(BAR+DRAMDLLC, read32(BAR+DRAMDLLC) & ~(1 << DRAMDLLC_SLVBYP));
+ mdelay(50);
+
+ u32 ddriomc0 = ((read32(BAR+DDRIOMC0) & ~0x1e00) |
+ (0xB << DDRIOMC0_DQVOXADJ))
+ & ~(1 << DDRIOMC0_DDRVOXCTL1);
+ PRINTK_DEBUG("DDRIOMC0=%08x\n", ddriomc0);
+ write32(BAR+DDRIOMC0, ddriomc0);
+ mdelay(50);
+
+ u8 ckdis = 0;
+ if (mch->dimm_num == 1)
+ ckdis |= (1 << 3) | (1 << 4) | (1 << 5);
+ if (nb_registered)
+ ckdis |= (1 << 1) | (1 << 2) | (1 << 4) | (1 << 5);
+ if (sodimm)
+ ckdis |= (1 << 2);
+ dbg_pci_write_config8(PCI_DEV(0,0,0), CKDIS, ckdis);
+
+ u32 sdrc =
+ 2 << SDRC_ODTZENA1 |
+ 2 << SDRC_ODTZENA |
+ 1 << SDRC_mu_enable_aioccmd |
+ 1 << SDRC_mu_enable_bcmd |
+ 0x30 << SDRC_ASU_CMDQSIZE;
+
+ dbg_pci_write_config32(PCI_DEV(0,0,0), SDRC, sdrc);
+
+ for (i = 0; i < mch->dimm_num; i++) {
+ static const u32 dimmtech[] = {
+ [DEV_2Gb] = 3 << DRA_DIMMTECH_EVEN |
+ 3 << DRA_DIMMTECH_ODD,
+ [DEV_1Gb] = 4 << DRA_DIMMTECH_EVEN |
+ 4 << DRA_DIMMTECH_ODD,
+ [DEV_512Mb] = 5 << DRA_DIMMTECH_EVEN |
+ 5 << DRA_DIMMTECH_ODD,
+ [DEV_256Mb] = 6 << DRA_DIMMTECH_EVEN |
+ 6 << DRA_DIMMTECH_ODD,
+ };
+
+ u32 dra = dimmtech[size[i]];
+ dra |= is_double_rank << 17;
+ dra |= (!!nb_registered) << 14;
+ dra |= 1 << DRA_DWEVEN;
+ dra |= 1 << DRA_DWODD;
+
+ switch(row_num[i]) {
+ case 13: dra |= 0 << DRA_NR_EVEN;
+ dra |= 0 << DRA_NR_ODD;
+ break;
+ case 14: dra |= 1 << DRA_NR_EVEN;
+ dra |= 1 << DRA_NR_ODD;
+ break;
+ case 15: dra |= 2 << DRA_NR_EVEN;
+ dra |= 2 << DRA_NR_ODD;
+ break;
+ }
- /* Enable on-DIMM termination */
- set_on_dimm_termination_enable(ctrl);
+ dra |= 0 << DRA_NC_EVEN;
+ dra |= 0 << DRA_NC_ODD;
- /* Clear memory and init ECC */
- for (cs = 0; cs < nr_cs; cs++) {
- if (!(mask & (1<<cs)))
- continue;
- PRINTK_DEBUG("clear memory CS%x\n", cs);
- write32(BAR+MBCSR, 0xa00000f0 | ((cs+1)<<20) | (0<<16));
- data32 = read32(BAR+MBCSR);
- while (data32 & 0x80000000)
- data32 = read32(BAR+MBCSR);
- if (data32 & 0x40000000) {
- PRINT_DCAL_DUMP();
- die("memory clear failed!\n");
- }
+ PRINTK_DEBUG("DRA%d=%08x\n", i, dra);
+ pci_write_config32(PCI_DEV(0,0,0), DRA+(i*4), dra);
}
- set_magic(drc);
-
- /* Clear read/write FIFO pointers */
+
+ static const u8 drb_tbl[] = {
+ [DEV_2Gb] = 0x20,
+ [DEV_1Gb] = 0x10,
+ [DEV_512Mb] = 0x08,
+ [DEV_256Mb] = 0x04,
+ };
+
+ u8 drb = drb_tbl[size[0]];
+ PRINTK_DEBUG("DRB0=DRB1=%02x\n", drb);
+ pci_write_config8(PCI_DEV(0,0,0), DRB0, drb);
+ pci_write_config8(PCI_DEV(0,0,0), DRB1, drb);
+
+ if (mch->dimm_num == 2)
+ drb += drb_tbl[size[1]];
+ else if (is_double_rank)
+ drb += drb_tbl[size[0]];
+ /* else DRB3 = DRB2 = DRB1 = DRB0 */
+ PRINTK_DEBUG("DRB2=DRB3=%02x\n", drb);
+ pci_write_config8(PCI_DEV(0,0,0), DRB2, drb);
+ pci_write_config8(PCI_DEV(0,0,0), DRB3, drb);
+
+ static const u32 drt0_tbl[] = { /* coherent with MR config (xref1) */
+ [DDR_400] = 0x24222000,
+ [DDR_533] = 0x24245000,
+ [DDR_667] = 0x2436A000,
+ [DDR_800] = 0x2438D000
+ };
+
+ u32 drt0 = drt0_tbl[mch->timing.speed] |
+ (mch->timing.CL - 3) << DRT0_CL |
+ (mch->timing.CL - 3) << DRT0_Trp |
+ (mch->timing.CL - 3) << DRT0_Trcd;
+
+ PRINTK_DEBUG("DRT0=%08x\n", drt0);
+ pci_write_config32(PCI_DEV(0,0,0), DRT0, drt0);
+
+ static const u32 drt1_tbl[] = {
+ [DDR_400] = 0x10210000,
+ [DDR_533] = 0x40410000,
+ [DDR_667] = 0x72618000,
+ [DDR_800] = 0xA2918000
+ };
+ u32 drt1 = drt1_tbl[mch->timing.speed];
+
+ if (nb_registered == 0 &&
+ (mch->dimm_num == 2 || mch->timing.speed == DDR_800))
+ drt1 |= 1 << DRT1_2Tor1T;
+
+ PRINTK_DEBUG("DRT1=%08x\n", drt1);
+ pci_write_config32(PCI_DEV(0,0,0), DRT1, drt1);
+
+ jedec_init(rank_num, mch->timing, sodimm);
+
+ wl_rcven_calibrate(mch);
+
+ u32 dcalcsr;
+ write32(BAR+DCALADDR, 0x10008);
+ write32(BAR+DCALCSR, 0x88020015);
+ while ((dcalcsr = read32(BAR+DCALCSR)) & 1 << DCALCSR_START);
+ if (dcalcsr & 1 << DCALCSR_FAIL)
+ die("DQS calibration failed.\n");
+
clear_fifo_pointers();
- PRINT_DCAL_DUMP();
- printk(BIOS_INFO, "Memory init done...\n");
+ jedec_init(rank_num, mch->timing, sodimm);
+
+ u32 ddr2odtc = (rank_num == 1) ? (sodimm ? 0 : 0x10) : 0x1122;
+ dbg_pci_write_config32(PCI_DEV(0,0,0), DDR2ODTC, ddr2odtc);
+
+ u16 tom = drb / 2;
+ dbg_pci_write_config16(PCI_DEV(0,0,0), TOM, tom);
+ u16 tolm = MIN(tom, 0x18) << 11;
+ dbg_pci_write_config16(PCI_DEV(0,0,0), TOLM, tolm);
+
+ static const u32 ddrrefresh[][4] = {
+ [DDR_400] = {
+ [DEV_256Mb] = 0x005ca0f1,
+ [DEV_512Mb] = 0x005ca151,
+ [DEV_1Gb] = 0x005ca1a1,
+ [DEV_2Gb] = 0x005ca271,
+ },
+ [DDR_533] = {
+ [DEV_256Mb] = 0x007b8141,
+ [DEV_512Mb] = 0x007b81c1,
+ [DEV_1Gb] = 0x007b8221,
+ [DEV_2Gb] = 0x007b8341,
+ },
+ [DDR_667] = {
+ [DEV_256Mb] = 0x00943181,
+ [DEV_512Mb] = 0x00943221,
+ [DEV_1Gb] = 0x00943291,
+ [DEV_2Gb] = 0x009433f1,
+ },
+ [DDR_800] = {
+ [DEV_256Mb] = 0x00b941e1,
+ [DEV_512Mb] = 0x00b942a1,
+ [DEV_1Gb] = 0x00b94331,
+ [DEV_2Gb] = 0x00b944e1,
+ },
+ };
- /* Set initialization complete */
- drc |= (1 << INIT_COMP);
- data32 = drc & ~(3 << ECC); /* clear ECC mode */
- PRINTK_DEBUG("DRC = %08x\n", data32);
- pci_write_config32(ctrl->f0, DRC, data32);
+ enum dev_size highest_rank_sz =
+ mch->dimm_num == 1 ? size[0] : MAX(size[0], size[1]);
+ dbg_pci_write_config32(PCI_DEV(0,8,0), DDRREFRESH,
+ ddrrefresh[mch->timing.speed][highest_rank_sz]);
#if CONFIG_DEBUG_RAM_SETUP
- dump_pci_device(ctrl->f0);
- dump_dcal_regs_8();
+ dump_ram_regs(BIOS_SPEW);
#endif
- /* Set the ECC mode */
- pci_write_config32(ctrl->f0, DRC, drc);
-}
+#if 0 /* Useless because of MemBIST */
+#include <lib.h>
+ printk(BIOS_DEBUG, "\nSoftware RAM check\n");
+ ram_check(0x00100000, 0x00f00000);
+ ram_check(0x01000000, tolm << 16);
+#endif
-inline int memory_initialized(void)
-{
- return pci_read_config32(PCI_DEV(0, 0x00, 0), DRC) & (1 << INIT_COMP);
+ membist(rank_num);
+
+ /* Clear error from previous boots */
+ pci_write_config16(PCI_DEV(0,0,0), DRAM_FERR, 0xFFFF);
+ pci_write_config16(PCI_DEV(0,0,0), DRAM_NERR, 0xFFFF);
+ pci_write_config16(PCI_DEV(0,0,1), DRAM_SEC_R0, 0x0000);
+ pci_write_config16(PCI_DEV(0,0,1), DRAM_DED_R0, 0x0000);
+ pci_write_config16(PCI_DEV(0,0,1), DRAM_SEC_R1, 0x0000);
+ pci_write_config16(PCI_DEV(0,0,1), DRAM_DED_R1, 0x0000);
+ pci_write_config16(PCI_DEV(0,0,1), RANKTHREX, 0xFFFF);
+
+ pci_write_config32(PCI_DEV(0,0,0), DRC,
+ pci_read_config32(PCI_DEV(0, 0, 0), DRC) |
+ 1 << DRC_INIT_COMP |
+ (!!mch->ecc) << DRC_ECC);
+
+ clear_fifo_pointers();
}
+
diff --git a/src/northbridge/intel/i3100/raminit_ep80579.h b/src/northbridge/intel/i3100/raminit_ep80579.h
index 96eca7db5..b816512ae 100644
--- a/src/northbridge/intel/i3100/raminit_ep80579.h
+++ b/src/northbridge/intel/i3100/raminit_ep80579.h
@@ -20,76 +20,99 @@
#ifndef NORTHBRIDGE_INTEL_I3100_RAMINIT_EP80579_H
#define NORTHBRIDGE_INTEL_I3100_RAMINIT_EP80579_H
+#include <stdint.h>
+
+#define __stringify_1(x) #x
+#define __stringify(x) __stringify_1(x)
+#define mdelay(msecs) udelay(1000*(msecs))
+
#define DIMM_SOCKETS 2
#define BAR 0x90000000
-/* EMR(1) settings:
- * 12 11 10 987 6 543 2 1 0 (bit numbers)
- * 000 0 1 0 111 0 000 1 0 0 (value)
- * [0] DLL - enable
- * [1] ODS - full
- * [6,2] Rtt - disable
- * [5:2] Additive CAS - 0
- * [9:7] OCD program: 111 - enable default, 000 - exit (maintain setting)
- * [10] DQS# - Enable
- * [11] RDQS - Disable (only 1 slot, Micron TN-47-12)
- * [12] Outputs - Enabled (req'd by Micron)
- * [15:13] Reserved - must be 0
- * */
-#define EMR1 0x03800001
-/* EMR(2) settings:
- * High temp refresh rate is off
- */
-#define EMR2 0x00000000
-/* EMR(3) settings:
- * All reserved at this time
- */
-#define EMR3 0x00000000
+/* DDR2 SDRAM mode register (MR) */
+#define MR_BURST_LENGTH 0
+#define MR_BL_4 2
+#define MR_BL_8 3
+#define MR_BURST_TYPE 3
+#define MR_CAS_LAT 4
+#define MR_TM 7
+#define MR_DLL_RST 8
+#define MR_WR 9
+#define MR_PD 12
+
+/* DDR2 SDRAM extended mode register 1 (EMR(1)) */
+#define EMR1_Rtt0 2
+#define EMR1_Rtt1 6
+
+#define EMR1_Rtt1_disable 0
+#define EMR1_Rtt0_disable 0
+
+#define EMR1_Rtt1_75ohm 0
+#define EMR1_Rtt0_75ohm 1
-/* DIOMON offset - DDR I/O monitor register */
-#define DIOMON 0xf0
-/* Bit positions in DIOMON */
-#define DSAMP 24
-#define VRESULT 16
-#define DDRIO_ENABLE 15
-#define BIASSEL 11
-#define DQLEGSELOUT 7
-#define DIOPWR 6
-#define CALEGSELOUT 0
+#define EMR1_Rtt1_150ohm 1
+#define EMR1_Rtt0_150ohm 0
-#define DEVPRES_CONFIG (DEVPRES_D1F0 | DEVPRES_D2F0 | DEVPRES_D3F0 | DEVPRES_D4F0)
+#define EMR1_OCD 7
+#define EMR1_OCD_cal_exit 0
+#define EMR1_OCD_cal_default 0
+
+/* DCALADDR values */
+#define DCALADDR_MR 0
+#define DCALADDR_EMR1 1
+#define DCALADDR_EMR2 2
+#define DCALADDR_EMR3 3
/* Debugging macros. */
#if CONFIG_DEBUG_RAM_SETUP
-#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
-#define PRINT_DEBUG_DDRIO() print_ddrio()
-#define PRINT_DCAL_DUMP() dump_dcal_regs()
-#define PRINT_SPD_DUMP() dump_spd_registers()
+#define PRINTK_DEBUG(x...) printk(BIOS_DEBUG, x)
#else
#define PRINTK_DEBUG(x...)
-#define PRINT_DEBUG_DDRIO()
-#define PRINT_DCAL_DUMP()
-#define PRINT_SPD_DUMP()
-
#endif
+enum ddr_speed { DDR_400, DDR_533, DDR_667, DDR_800, DDR_1066 };
+enum dev_size { DEV_2Gb, DEV_1Gb, DEV_512Mb, DEV_256Mb };
+enum fsb_speed { FSB_133, FSB_100 };
+struct ram_timing { enum ddr_speed speed; u8 CL, tRCD, tRP; };
+
+enum speed_bin {
+ DDR2_1066E,
+ DDR2_1066F,
+ DDR2_800C,
+ DDR2_800D,
+ DDR2_800E,
+ DDR2_667C,
+ DDR2_667D,
+ DDR2_533B,
+ DDR2_533C,
+ DDR2_400B,
+ DDR2_400C,
+ NUM_SPEED_BINS
+};
+
struct mem_controller {
- u32 node_id;
- device_t f0;
- u16 channel0[DIMM_SOCKETS];
+ u8* spd;
+ int dimm_num;
+ enum ddr_speed max_speed;
+ int CL[2][3];
+ int tAC[2][3];
+ int tCK[2][3];
+ u8 tRP[2];
+ u8 tRCD[2];
+ /* Max timing confs supported = number of standard speed bins + 3 other
+ * speed bins explicitly supported in SPD */
+ struct ram_timing support[2][NUM_SPEED_BINS+3];
+ struct ram_timing common[NUM_SPEED_BINS+3];
+ int n_support[2];
+ int n_common;
+ struct ram_timing timing;
+ u8 mastcntl;
+ u8 ecc;
};
/* Function prototypes. */
-void sdram_initialize(int controllers, const struct mem_controller *ctrl);
-void sdram_set_registers(const struct mem_controller *ctrl);
-void sdram_set_spd_registers(const struct mem_controller *ctrl);
-void sdram_enable(int controllers, const struct mem_controller *ctrl);
+void sdram_initialize(struct mem_controller *mch);
int memory_initialized(void);
-int spd_read_byte(unsigned int device, unsigned int address);
-void dump_spd_registers(void);
-void dump_pci_device(u32 dev);
-void print_debug_pci_dev(u32 dev);
-void dump_pci_devices(void);
-void dump_dcal_regs(void);
+
#endif /* NORTHBRIDGE_INTEL_I3100_RAMINIT_EP80579_H */
diff --git a/src/northbridge/intel/i3100/wl_cal3.c b/src/northbridge/intel/i3100/wl_cal3.c
new file mode 100644
index 000000000..367d89140
--- /dev/null
+++ b/src/northbridge/intel/i3100/wl_cal3.c
@@ -0,0 +1,105 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Avencall
+ *
+ * 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
+ */
+
+static const u32 wl_cntl_tbl[2][4] = {
+ /* Not ECC */ {
+ [DDR_400] = 0xb90,
+ [DDR_533] = 0xb60,
+ [DDR_667] = 0xb60,
+ [DDR_800] = 0xb48,
+ },
+ /* ECC */ {
+ [DDR_400] = 0xb60,
+ [DDR_533] = 0xb40,
+ [DDR_667] = 0xb40,
+ [DDR_800] = 0xb30,
+ }
+};
+
+static const u32 wdll_misc_val = 0x1200802;
+
+static void wl_rcven_calibrate(struct mem_controller *mch)
+{
+ u32 data32;
+
+ /* Reset VOX Mode */
+ u32 ddriomc0 = read32(BAR+DDRIOMC0) | 0xb << DDRIOMC0_DQVOXADJ |
+ 1 << DDRIOMC0_DDRVOXCTL1 | 1 << DDRIOMC0_DDRVOXCTL0;
+
+ write32(BAR+DDRIOMC0, ddriomc0);
+ mdelay(50);
+
+ /* Reset DRRTC00, which is sticky, to its default value */
+ write32(BAR+DRRTC00, 0x06060606);
+
+ write32(BAR+WDLL_MISC, wdll_misc_val);
+
+ u32 wl_cntl_val = wl_cntl_tbl[mch->ecc][mch->timing.speed];
+
+ write32(BAR+WL_CNTL0, wl_cntl_val | 1 << WL_CNTL_WDLL_CLKG); /* 2: WDLL_CLKG */
+ write32(BAR+WL_CNTL1, wl_cntl_val | 1 << WL_CNTL_WDLL_CLKG);
+ write32(BAR+WL_CNTL2, wl_cntl_val | 1 << WL_CNTL_WDLL_CLKG);
+ write32(BAR+WL_CNTL3, wl_cntl_val | 1 << WL_CNTL_WDLL_CLKG);
+ write32(BAR+WL_CNTL4, wl_cntl_val);
+
+ ddriomc0 &= ~(1 << DDRIOMC0_DDRVOXCTL1);
+ write32(BAR+DDRIOMC0, ddriomc0);
+
+ mdelay(50);
+
+ write32(BAR+DQSFAIL0, 0);
+ write8(BAR+DQSFAIL1, 0);
+
+ write32(BAR+DCALADDR, 0x10008);
+ write32(BAR+DCALCSR, 0x8802001C);
+ while((data32 = read32(BAR+DCALCSR)) & 0x80000000);
+ if (data32 & 0x40000000)
+ die("receive enable failed!\n");
+
+ data32 = read32(BAR+DRRTC00);
+ u8 rcven = (u8)data32;
+ rcven = MAX(rcven, (u8)(data32>>8));
+ rcven = MAX(rcven, (u8)(data32>>16));
+ rcven = MAX(rcven, (u8)(data32>>24));
+
+ data32 = read32(BAR+DRRTC01);
+ rcven = MAX(rcven, (u8)(data32));
+ rcven = MAX(rcven, (u8)(data32>>8));
+ rcven = MAX(rcven, (u8)(data32>>16));
+ rcven = MAX(rcven, (u8)(data32>>24));
+
+ if (mch->ecc) {
+ u8 drrtc02 = read8(BAR+DRRTC02);
+ rcven = MAX(rcven, drrtc02);
+ }
+
+ unsigned prgrpd = (rcven + 0x1f) >> 5; /* ceil and take 3 MSB */
+
+ data32 = (pci_read_config32(PCI_DEV(0,0,0), DRT1) & ~1) | ((prgrpd>>3) & 1);
+ pci_write_config32(PCI_DEV(0,0,0), DRT1, data32);
+
+ data32 = (pci_read_config32(PCI_DEV(0,0,0), DRT0) & ~7) | (prgrpd & 7);
+ pci_write_config32(PCI_DEV(0,0,0), DRT0, data32);
+
+ printk(BIOS_SPEW, "Finished RCVEN calibration and write levelization\n");
+ for (i = 0; i < 5; i++)
+ printk(BIOS_DEBUG, "WL_CNTL%d=%08x\n",
+ i, read32(BAR+WL_CNTL0+(i*4)));
+}
+