From 9ad810f056c11e994f6de1ba90be728d8bae109b Mon Sep 17 00:00:00 2001 From: Noe Rubinstein Date: Thu, 26 May 2011 18:20:49 +0200 Subject: Rewrite EP80579 RAM init --- src/include/spd_ddr2.h | 89 +- src/mainboard/intel/truxton/romstage.c | 27 +- src/northbridge/intel/i3100/ep80579.h | 306 +++-- src/northbridge/intel/i3100/raminit_ep80579.c | 1715 ++++++++++++++----------- src/northbridge/intel/i3100/raminit_ep80579.h | 131 +- src/northbridge/intel/i3100/wl_cal3.c | 105 ++ 6 files changed, 1427 insertions(+), 946 deletions(-) create mode 100644 src/northbridge/intel/i3100/wl_cal3.c 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 #include -#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 - 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 #include #include -#include +#include #include -#include +#include #include "southbridge/intel/i3100/early_smbus.h" -#include "raminit_ep80579.h" +// #include +// #include +// #include + #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<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<>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<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 + 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 + +#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))); +} + -- cgit v1.2.3