DDR3 support for AMD Fam10.
Signed-off-by: Zheng Bao <zheng.bao@amd.com> Acked-by: Stefan Reinauer <stepan@coresystems.de> git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5481 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
This commit is contained in:
committed by
Stefan Reinauer
parent
fe6c2cda6e
commit
eb75f652d3
@@ -996,7 +996,11 @@ struct mem_info { // pernode
|
||||
u8 rsv[1];
|
||||
} __attribute__((packed));
|
||||
#else
|
||||
#include "../amdmct/mct/mct_d.h"
|
||||
#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
|
||||
#include "../amdmct/mct_ddr3/mct_d.h"
|
||||
#else
|
||||
#include "../amdmct/mct/mct_d.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct link_pair_t {
|
||||
|
@@ -30,6 +30,54 @@ static void print_t(const char *strval)
|
||||
printk(BIOS_DEBUG, "%s", strval);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
|
||||
#include "amdfam10.h"
|
||||
#include "../amdmct/wrappers/mcti.h"
|
||||
#include "../amdmct/amddefs.h"
|
||||
#include "../amdmct/mct_ddr3/mwlc_d.h"
|
||||
#include "../amdmct/mct_ddr3/mct_d.h"
|
||||
#include "../amdmct/mct_ddr3/mct_d_gcc.h"
|
||||
|
||||
#include "../amdmct/wrappers/mcti_d.c"
|
||||
#include "../amdmct/mct_ddr3/mct_d.c"
|
||||
|
||||
#include "../amdmct/mct_ddr3/mctmtr_d.c"
|
||||
#include "../amdmct/mct_ddr3/mctcsi_d.c"
|
||||
#include "../amdmct/mct_ddr3/mctecc_d.c"
|
||||
#include "../amdmct/mct_ddr3/mctdqs_d.c"
|
||||
#include "../amdmct/mct_ddr3/mctsrc.c"
|
||||
#include "../amdmct/mct_ddr3/mctsdi.c"
|
||||
#include "../amdmct/mct_ddr3/mctproc.c"
|
||||
#include "../amdmct/mct_ddr3/mctprob.c"
|
||||
#include "../amdmct/mct_ddr3/mcthwl.c"
|
||||
#include "../amdmct/mct_ddr3/mctwl.c"
|
||||
#include "../amdmct/mct_ddr3/mport_d.c"
|
||||
#include "../amdmct/mct_ddr3/mutilc_d.c"
|
||||
#include "../amdmct/mct_ddr3/modtrdim.c"
|
||||
#include "../amdmct/mct_ddr3/mhwlc_d.c"
|
||||
#include "../amdmct/mct_ddr3/mctrci.c"
|
||||
#include "../amdmct/mct_ddr3/mctsrc1p.c"
|
||||
#include "../amdmct/mct_ddr3/mcttmrl.c"
|
||||
#include "../amdmct/mct_ddr3/mcthdi.c"
|
||||
#include "../amdmct/mct_ddr3/mctndi_d.c"
|
||||
#include "../amdmct/mct_ddr3/mctchi_d.c"
|
||||
|
||||
#if CONFIG_CPU_SOCKET_TYPE == 0x10
|
||||
//TODO: S1G1?
|
||||
#elif CONFIG_CPU_SOCKET_TYPE == 0x11
|
||||
//AM3
|
||||
#include "../amdmct/mct_ddr3/mctardk5.c"
|
||||
#elif CONFIG_CPU_SOCKET_TYPE == 0x12
|
||||
//F (1207), Fr2, G (1207)
|
||||
#include "../amdmct/mct_ddr3/mctardk6.c"
|
||||
#elif CONFIG_CPU_SOCKET_TYPE == 0x13
|
||||
//ASB2
|
||||
#include "../amdmct/mct_ddr3/mctardk5.c"
|
||||
#endif
|
||||
|
||||
#else /* DDR2 */
|
||||
|
||||
#include "amdfam10.h"
|
||||
#include "../amdmct/wrappers/mcti.h"
|
||||
#include "../amdmct/amddefs.h"
|
||||
@@ -65,6 +113,8 @@ static void print_t(const char *strval)
|
||||
|
||||
#include "../amdmct/mct/mct_fd.c"
|
||||
|
||||
#endif /* DDR2 */
|
||||
|
||||
int mctRead_SPD(u32 smaddr, u32 reg)
|
||||
{
|
||||
return spd_read_byte(smaddr, reg);
|
||||
@@ -141,9 +191,15 @@ u32 mctGetLogicalCPUID(u32 Node)
|
||||
case 0x10042:
|
||||
ret = AMD_RB_C2;
|
||||
break;
|
||||
case 0x10043:
|
||||
ret = AMD_RB_C3;
|
||||
break;
|
||||
case 0x10062:
|
||||
ret = AMD_DA_C2;
|
||||
break;
|
||||
case 0x10063:
|
||||
ret = AMD_DA_C3;
|
||||
break;
|
||||
case 0x10080:
|
||||
ret = AMD_HY_D0;
|
||||
break;
|
||||
|
@@ -43,6 +43,8 @@
|
||||
#define AMD_RB_C2 0x01000000 /* Shanghai C2 */
|
||||
#define AMD_DA_C2 0x02000000 /* XXXX C2 */
|
||||
#define AMD_HY_D0 0x04000000 /* Istanbul D0 */
|
||||
#define AMD_RB_C3 0x08000000 /* ??? C3 */
|
||||
#define AMD_DA_C3 0x10000000 /* XXXX C3 */
|
||||
|
||||
/*
|
||||
* Groups - Create as many as you wish, from the above public values
|
||||
@@ -60,8 +62,11 @@
|
||||
#define AMD_DR_LT_B3 (AMD_DR_B0 | AMD_DR_B1 | AMD_DR_B2 | AMD_DR_BA)
|
||||
#define AMD_DR_GT_B0 (AMD_DR_ALL & ~(AMD_DR_B0))
|
||||
#define AMD_DR_ALL (AMD_DR_Bx)
|
||||
#define AMD_FAM10_ALL (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0)
|
||||
#define AMD_FAM10_ALL (AMD_DR_ALL | AMD_RB_C2 | AMD_HY_D0 | AMD_DA_C3 | AMD_DA_C2)
|
||||
#define AMD_FAM10_GT_B0 (AMD_FAM10_ALL & ~(AMD_DR_B0))
|
||||
#define AMD_DR_Cx (AMD_RB_C2 | AMD_DA_C2 | AMD_RB_C3 | AMD_DA_C3)
|
||||
#define AMD_DR_Dx (AMD_HY_D0)
|
||||
|
||||
|
||||
/*
|
||||
* Public Platforms - USE THESE VERSIONS TO MAKE COMPARE WITH CPUPLATFORMTYPE RETURN VALUE
|
||||
|
3725
src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
Normal file
3725
src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
Normal file
File diff suppressed because it is too large
Load Diff
794
src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
Normal file
794
src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
Normal file
@@ -0,0 +1,794 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Description: Include file for all generic DDR 3 MCT files.
|
||||
*/
|
||||
#ifndef MCT_D_H
|
||||
#define MCT_D_H
|
||||
|
||||
/*===========================================================================
|
||||
CPU - K8/FAM10
|
||||
===========================================================================*/
|
||||
#define PT_L1 0 /* CPU Package Type */
|
||||
#define PT_M2 1
|
||||
#define PT_S1 2
|
||||
#define PT_GR 3
|
||||
#define PT_AS 4
|
||||
#define PT_C3 5
|
||||
|
||||
#define J_MIN 0 /* j loop constraint. 1=CL 2.0 T*/
|
||||
#define J_MAX 5 /* j loop constraint. 5=CL 7.0 T*/
|
||||
#define K_MIN 1 /* k loop constraint. 1=200 Mhz*/
|
||||
#define K_MAX 5 /* k loop constraint. 5=533 Mhz*/
|
||||
#define CL_DEF 2 /* Default value for failsafe operation. 2=CL 4.0 T*/
|
||||
#define T_DEF 1 /* Default value for failsafe operation. 1=5ns (cycle time)*/
|
||||
|
||||
#define BSCRate 1 /* reg bit field=rate of dram scrubber for ecc*/
|
||||
/* memory initialization (ecc and check-bits).*/
|
||||
/* 1=40 ns/64 bytes.*/
|
||||
#define FirstPass 1 /* First pass through RcvEn training*/
|
||||
#define SecondPass 2 /* Second pass through Rcven training*/
|
||||
|
||||
#define RCVREN_MARGIN 6 /* number of DLL taps to delay beyond first passing position*/
|
||||
#define MAXASYNCLATCTL_2 2 /* Max Async Latency Control value*/
|
||||
#define MAXASYNCLATCTL_3 3 /* Max Async Latency Control value*/
|
||||
|
||||
#define DQS_FAIL 1
|
||||
#define DQS_PASS 0
|
||||
#define DQS_WRITEDIR 1
|
||||
#define DQS_READDIR 0
|
||||
#define MIN_DQS_WNDW 3
|
||||
#define secPassOffset 6
|
||||
#define Pass1MemClkDly 0x20 /* Add 1/2 Memlock delay */
|
||||
#define MAX_RD_LAT 0x3FF
|
||||
#define MIN_FENCE 14
|
||||
#define MAX_FENCE 20
|
||||
#define MIN_DQS_WR_FENCE 14
|
||||
#define MAX_DQS_WR_FENCE 20
|
||||
#define FenceTrnFinDlySeed 19
|
||||
#define EarlyArbEn 19
|
||||
|
||||
#define PA_HOST(Node) ((((0x18+Node) << 3)+0) << 12) /* Node 0 Host Bus function PCI Address bits [15:0]*/
|
||||
#define PA_MAP(Node) ((((0x18+Node) << 3)+1) << 12) /* Node 0 MAP function PCI Address bits [15:0]*/
|
||||
#define PA_DCT(Node) ((((0x18+Node) << 3)+2) << 12) /* Node 0 DCT function PCI Address bits [15:0]*/
|
||||
/* #define PA_EXT_DCT (((00 << 3)+4) << 8) */ /*Node 0 DCT extended configuration registers*/
|
||||
/* #define PA_DCTADDL (((00 << 3)+2) << 8) */ /*Node x DCT function, Additional Registers PCI Address bits [15:0]*/
|
||||
/* #define PA_EXT_DCTADDL (((00 << 3)+5) << 8) */ /*Node x DCT function, Additional Registers PCI Address bits [15:0]*/
|
||||
|
||||
#define PA_NBMISC(Node) ((((0x18+Node) << 3)+3) << 12) /*Node 0 Misc PCI Address bits [15:0]*/
|
||||
/* #define PA_NBDEVOP (((00 << 3)+3) << 8) */ /*Node 0 Misc PCI Address bits [15:0]*/
|
||||
|
||||
#define DCC_EN 1 /* X:2:0x94[19]*/
|
||||
#define ILD_Lmt 3 /* X:2:0x94[18:16]*/
|
||||
|
||||
#define EncodedTSPD 0x00191709 /* encodes which SPD byte to get T from*/
|
||||
/* versus CL X, CL X-.5, and CL X-1*/
|
||||
|
||||
#define Bias_TrpT 5 /* bias to convert bus clocks to bit field value*/
|
||||
#define Bias_TrrdT 4
|
||||
#define Bias_TrcdT 5
|
||||
#define Bias_TrasT 15
|
||||
#define Bias_TrcT 11
|
||||
#define Bias_TrtpT 4
|
||||
#define Bias_TwrT 4
|
||||
#define Bias_TwtrT 4
|
||||
#define Bias_TfawT 14
|
||||
|
||||
#define Min_TrpT 5 /* min programmable value in busclocks */
|
||||
#define Max_TrpT 12 /* max programmable value in busclocks */
|
||||
#define Min_TrrdT 4
|
||||
#define Max_TrrdT 7
|
||||
#define Min_TrcdT 5
|
||||
#define Max_TrcdT 12
|
||||
#define Min_TrasT 15
|
||||
#define Max_TrasT 30
|
||||
#define Min_TrcT 11
|
||||
#define Max_TrcT 42
|
||||
#define Min_TrtpT 4
|
||||
#define Max_TrtpT 7
|
||||
#define Min_TwrT 5
|
||||
#define Max_TwrT 12
|
||||
#define Min_TwtrT 4
|
||||
#define Max_TwtrT 7
|
||||
#define Min_TfawT 16
|
||||
#define Max_TfawT 32
|
||||
|
||||
/*common register bit names*/
|
||||
#define DramHoleValid 0 /* func 1, offset F0h, bit 0*/
|
||||
#define DramMemHoistValid 1 /* func 1, offset F0h, bit 1*/
|
||||
#define CSEnable 0 /* func 2, offset 40h-5C, bit 0*/
|
||||
#define Spare 1 /* func 2, offset 40h-5C, bit 1*/
|
||||
#define TestFail 2 /* func 2, offset 40h-5C, bit 2*/
|
||||
#define DqsRcvEnTrain 18 /* func 2, offset 78h, bit 18*/
|
||||
#define EnDramInit 31 /* func 2, offset 7Ch, bit 31*/
|
||||
#define DisAutoRefresh 18 /* func 2, offset 8Ch, bit 18*/
|
||||
#define InitDram 0 /* func 2, offset 90h, bit 0*/
|
||||
#define BurstLength32 10 /* func 2, offset 90h, bit 10*/
|
||||
#define Width128 11 /* func 2, offset 90h, bit 11*/
|
||||
#define X4Dimm 12 /* func 2, offset 90h, bit 12*/
|
||||
#define UnBuffDimm 16 /* func 2, offset 90h, bit 16*/
|
||||
#define DimmEcEn 19 /* func 2, offset 90h, bit 19*/
|
||||
#define MemClkFreqVal 3 /* func 2, offset 94h, bit 3*/
|
||||
#define RDqsEn 12 /* func 2, offset 94h, bit 12*/
|
||||
#define DisDramInterface 14 /* func 2, offset 94h, bit 14*/
|
||||
#define DctAccessWrite 30 /* func 2, offset 98h, bit 30*/
|
||||
#define DctAccessDone 31 /* func 2, offset 98h, bit 31*/
|
||||
#define MemClrStatus 0 /* func 2, offset A0h, bit 0*/
|
||||
#define PwrSavingsEn 10 /* func 2, offset A0h, bit 10*/
|
||||
#define Mod64BitMux 4 /* func 2, offset A0h, bit 4*/
|
||||
#define DisableJitter 1 /* func 2, offset A0h, bit 1*/
|
||||
#define MemClrDis 1 /* func 3, offset F8h, FNC 4, bit 1*/
|
||||
#define SyncOnUcEccEn 2 /* func 3, offset 44h, bit 2*/
|
||||
#define Dr_MemClrStatus 10 /* func 3, offset 110h, bit 10*/
|
||||
#define MemClrBusy 9 /* func 3, offset 110h, bit 9*/
|
||||
#define DctGangEn 4 /* func 3, offset 110h, bit 4*/
|
||||
#define MemClrInit 3 /* func 3, offset 110h, bit 3*/
|
||||
#define SendZQCmd 29 /* func 2, offset 7Ch, bit 29 */
|
||||
#define AssertCke 28 /* func 2, offset 7Ch, bit 28*/
|
||||
#define DeassertMemRstX 27 /* func 2, offset 7Ch, bit 27*/
|
||||
#define SendMrsCmd 26 /* func 2, offset 7Ch, bit 26*/
|
||||
#define SendAutoRefresh 25 /* func 2, offset 7Ch, bit 25*/
|
||||
#define SendPchgAll 24 /* func 2, offset 7Ch, bit 24*/
|
||||
#define DisDqsBar 6 /* func 2, offset 90h, bit 6*/
|
||||
#define DramEnabled 8 /* func 2, offset 110h, bit 8*/
|
||||
#define LegacyBiosMode 9 /* func 2, offset 94h, bit 9*/
|
||||
#define PrefDramTrainMode 28 /* func 2, offset 11Ch, bit 28*/
|
||||
#define FlushWr 30 /* func 2, offset 11Ch, bit 30*/
|
||||
#define DisAutoComp 30 /* func 2, offset 9Ch, Index 8, bit 30*/
|
||||
#define DqsRcvTrEn 13 /* func 2, offset 9Ch, Index 8, bit 13*/
|
||||
#define ForceAutoPchg 23 /* func 2, offset 90h, bit 23*/
|
||||
#define ClLinesToNbDis 15 /* Bu_CFG2, bit 15*/
|
||||
#define WbEnhWsbDis_D (48-32)
|
||||
#define PhyFenceTrEn 3 /* func 2, offset 9Ch, Index 8, bit 3 */
|
||||
#define ParEn 8 /* func 2, offset 90h, bit 8 */
|
||||
#define DcqArbBypassEn 19 /* func 2, offset 94h, bit 19 */
|
||||
#define ActiveCmdAtRst 1 /* func 2, offset A8H, bit 1 */
|
||||
#define FlushWrOnStpGnt 29 /* func 2, offset 11Ch, bit 29 */
|
||||
#define BankSwizzleMode 22 /* func 2, offset 94h, bit 22 */
|
||||
#define ChSetupSync 15 /* func 2, offset 78h, bit 15 */
|
||||
|
||||
#define Ddr3Mode 8 /* func 2, offset 94h, bit 8 */
|
||||
#define EnterSelfRef 17 /* func 2, offset 90h, bit 17 */
|
||||
#define onDimmMirror 3 /* func 2, offset 5C:40h, bit 3 */
|
||||
#define OdtSwizzle 6 /* func 2, offset A8h, bit 6 */
|
||||
#define FreqChgInProg 21 /* func 2, offset 94h, bit 21 */
|
||||
#define ExitSelfRef 1 /* func 2, offset 90h, bit 1 */
|
||||
|
||||
#define SubMemclkRegDly 5 /* func 2, offset A8h, bit 5 */
|
||||
#define Ddr3FourSocketCh 2 /* func 2, offset A8h, bit 2 */
|
||||
#define SendControlWord 30 /* func 2, offset 7Ch, bit 30 */
|
||||
|
||||
/*=============================================================================
|
||||
SW Initialization
|
||||
============================================================================*/
|
||||
#define DLL_Enable 1
|
||||
#define OCD_Default 2
|
||||
#define OCD_Exit 3
|
||||
|
||||
/*=============================================================================
|
||||
Jedec DDR II
|
||||
=============================================================================*/
|
||||
#define SPD_ByteUse 0
|
||||
#define SPD_TYPE 2 /*SPD byte read location*/
|
||||
#define JED_DDRSDRAM 0x07 /*Jedec defined bit field*/
|
||||
#define JED_DDR2SDRAM 0x08 /*Jedec defined bit field*/
|
||||
#define JED_DDR3SDRAM 0x0B /* Jedec defined bit field*/
|
||||
|
||||
#define SPD_DIMMTYPE 3
|
||||
#define SPD_ATTRIB 21
|
||||
#define JED_DIFCKMSK 0x20 /*Differential Clock Input*/
|
||||
#define JED_REGADCMSK 0x11 /*Registered Address/Control*/
|
||||
#define JED_PROBEMSK 0x40 /*Analysis Probe installed*/
|
||||
#define JED_RDIMM 0x1 /* RDIMM */
|
||||
#define JED_MiniRDIMM 0x5 /* Mini-RDIMM */
|
||||
#define SPD_Density 4 /* Bank address bits,SDRAM capacity */
|
||||
#define SPD_Addressing 5 /* Row/Column address bits */
|
||||
#define SPD_Organization 7 /* rank#,Device width */
|
||||
#define SPD_BusWidth 8 /* ECC, Bus width */
|
||||
#define JED_ECC 8 /* ECC capability */
|
||||
|
||||
#define SPD_MTBDividend 10
|
||||
#define SPD_MTBDivisor 11
|
||||
#define SPD_tCKmin 12
|
||||
#define SPD_CASLow 14
|
||||
#define SPD_CASHigh 15
|
||||
#define SPD_tAAmin 16
|
||||
|
||||
#define SPD_DEVATTRIB 22
|
||||
#define SPD_EDCTYPE 11
|
||||
#define JED_ADRCPAR 0x04
|
||||
|
||||
#define SPD_tWRmin 17
|
||||
#define SPD_tRCDmin 18
|
||||
#define SPD_tRRDmin 19
|
||||
#define SPD_tRPmin 20
|
||||
#define SPD_Upper_tRAS_tRC 21
|
||||
#define SPD_tRASmin 22
|
||||
#define SPD_tRCmin 23
|
||||
#define SPD_tWTRmin 26
|
||||
#define SPD_tRTPmin 27
|
||||
#define SPD_Upper_tFAW 28
|
||||
#define SPD_tFAWmin 29
|
||||
|
||||
#define SPD_RefRawCard 62
|
||||
#define SPD_AddressMirror 63
|
||||
#define SPD_RegManufactureID_L 65 /* not used */
|
||||
#define SPD_RegManufactureID_H 66 /* not used */
|
||||
#define SPD_RegManRevID 67 /* not used */
|
||||
|
||||
#define SPD_byte_126 126
|
||||
#define SPD_byte_127 127
|
||||
|
||||
#define SPD_ROWSZ 3
|
||||
#define SPD_COLSZ 4
|
||||
#define SPD_LBANKS 17 /*number of [logical] banks on each device*/
|
||||
#define SPD_DMBANKS 5 /*number of physical banks on dimm*/
|
||||
#define SPDPLBit 4 /* Dram package bit*/
|
||||
#define SPD_BANKSZ 31 /*capacity of physical bank*/
|
||||
#define SPD_DEVWIDTH 13
|
||||
#define SPD_CASLAT 18
|
||||
#define SPD_TRP 27
|
||||
#define SPD_TRRD 28
|
||||
#define SPD_TRCD 29
|
||||
#define SPD_TRAS 30
|
||||
#define SPD_TWR 36
|
||||
#define SPD_TWTR 37
|
||||
#define SPD_TRTP 38
|
||||
#define SPD_TRCRFC 40
|
||||
#define SPD_TRC 41
|
||||
#define SPD_TRFC 42
|
||||
|
||||
#define SPD_MANDATEYR 93 /*Module Manufacturing Year (BCD)*/
|
||||
|
||||
#define SPD_MANDATEWK 94 /*Module Manufacturing Week (BCD)*/
|
||||
|
||||
/*-----------------------------
|
||||
Jdec DDR II related equates
|
||||
-----------------------------*/
|
||||
#define MYEAR06 6 /* Manufacturing Year BCD encoding of 2006 - 06d*/
|
||||
#define MWEEK24 0x24 /* Manufacturing Week BCD encoding of June - 24d*/
|
||||
|
||||
/*=============================================================================
|
||||
Macros
|
||||
=============================================================================*/
|
||||
|
||||
#define _2GB_RJ8 (2<<(30-8))
|
||||
#define _4GB_RJ8 (4<<(30-8))
|
||||
#define _4GB_RJ4 (4<<(30-4))
|
||||
|
||||
#define BigPagex8_RJ8 (1<<(17+3-8)) /*128KB * 8 >> 8 */
|
||||
|
||||
/*=============================================================================
|
||||
Global MCT Status Structure
|
||||
=============================================================================*/
|
||||
struct MCTStatStruc {
|
||||
u32 GStatus; /* Global Status bitfield*/
|
||||
u32 HoleBase; /* If not zero, BASE[39:8] (system address)
|
||||
of sub 4GB dram hole for HW remapping.*/
|
||||
u32 Sub4GCacheTop; /* If not zero, the 32-bit top of cacheable memory.*/
|
||||
u32 SysLimit; /* LIMIT[39:8] (system address)*/
|
||||
};
|
||||
|
||||
/*=============================================================================
|
||||
Global MCT Configuration Status Word (GStatus)
|
||||
=============================================================================*/
|
||||
/*These should begin at bit 0 of GStatus[31:0]*/
|
||||
#define GSB_MTRRshort 0 /* Ran out of MTRRs while mapping memory*/
|
||||
#define GSB_ECCDIMMs 1 /* All banks of all Nodes are ECC capable*/
|
||||
#define GSB_DramECCDis 2 /* Dram ECC requested but not enabled.*/
|
||||
#define GSB_SoftHole 3 /* A Node Base gap was created*/
|
||||
#define GSB_HWHole 4 /* A HW dram remap was created*/
|
||||
#define GSB_NodeIntlv 5 /* Node Memory interleaving was enabled*/
|
||||
#define GSB_SpIntRemapHole 16 /* Special condition for Node Interleave and HW remapping*/
|
||||
#define GSB_EnDIMMSpareNW 17 /* Indicates that DIMM Spare can be used without a warm reset */
|
||||
/* NOTE: This is a local bit used by memory code */
|
||||
|
||||
/*===============================================================================
|
||||
Local DCT Status structure (a structure for each DCT)
|
||||
===============================================================================*/
|
||||
#include "mwlc_d.h" /* I have to */
|
||||
|
||||
struct DCTStatStruc { /* A per Node structure*/
|
||||
/* DCTStatStruct_F - start */
|
||||
u8 Node_ID; /* Node ID of current controller*/
|
||||
u8 ErrCode; /* Current error condition of Node
|
||||
0= no error
|
||||
1= Variance Error, DCT is running but not in an optimal configuration.
|
||||
2= Stop Error, DCT is NOT running
|
||||
3= Fatal Error, DCT/MCT initialization has been halted.*/
|
||||
u32 ErrStatus; /* Error Status bit Field */
|
||||
u32 Status; /* Status bit Field*/
|
||||
u8 DIMMAddr[8]; /* SPD address of DIMM controlled by MA0_CS_L[0,1]*/
|
||||
/* SPD address of..MB0_CS_L[0,1]*/
|
||||
/* SPD address of..MA1_CS_L[0,1]*/
|
||||
/* SPD address of..MB1_CS_L[0,1]*/
|
||||
/* SPD address of..MA2_CS_L[0,1]*/
|
||||
/* SPD address of..MB2_CS_L[0,1]*/
|
||||
/* SPD address of..MA3_CS_L[0,1]*/
|
||||
/* SPD address of..MB3_CS_L[0,1]*/
|
||||
u16 DIMMPresent; /*For each bit n 0..7, 1=DIMM n is present.
|
||||
DIMM# Select Signal
|
||||
0 MA0_CS_L[0,1]
|
||||
1 MB0_CS_L[0,1]
|
||||
2 MA1_CS_L[0,1]
|
||||
3 MB1_CS_L[0,1]
|
||||
4 MA2_CS_L[0,1]
|
||||
5 MB2_CS_L[0,1]
|
||||
6 MA3_CS_L[0,1]
|
||||
7 MB3_CS_L[0,1]*/
|
||||
u16 DIMMValid; /* For each bit n 0..7, 1=DIMM n is valid and is/will be configured*/
|
||||
u16 DIMMMismatch; /* For each bit n 0..7, 1=DIMM n is mismatched, channel B is always considered the mismatch */
|
||||
u16 DIMMSPDCSE; /* For each bit n 0..7, 1=DIMM n SPD checksum error*/
|
||||
u16 DimmECCPresent; /* For each bit n 0..7, 1=DIMM n is ECC capable.*/
|
||||
u16 DimmPARPresent; /* For each bit n 0..7, 1=DIMM n is ADR/CMD Parity capable.*/
|
||||
u16 Dimmx4Present; /* For each bit n 0..7, 1=DIMM n contains x4 data devices.*/
|
||||
u16 Dimmx8Present; /* For each bit n 0..7, 1=DIMM n contains x8 data devices.*/
|
||||
u16 Dimmx16Present; /* For each bit n 0..7, 1=DIMM n contains x16 data devices.*/
|
||||
u16 DIMM2Kpage; /* For each bit n 0..7, 1=DIMM n contains 1K page devices.*/
|
||||
u8 MAload[2]; /* Number of devices loading MAA bus*/
|
||||
/* Number of devices loading MAB bus*/
|
||||
u8 MAdimms[2]; /*Number of DIMMs loading CH A*/
|
||||
/* Number of DIMMs loading CH B*/
|
||||
u8 DATAload[2]; /*Number of ranks loading CH A DATA*/
|
||||
/* Number of ranks loading CH B DATA*/
|
||||
u8 DIMMAutoSpeed; /*Max valid Mfg. Speed of DIMMs
|
||||
1=200Mhz
|
||||
2=266Mhz
|
||||
3=333Mhz
|
||||
4=400Mhz
|
||||
5=533Mhz*/
|
||||
u8 DIMMCASL; /* Min valid Mfg. CL bitfield
|
||||
0=2.0
|
||||
1=3.0
|
||||
2=4.0
|
||||
3=5.0
|
||||
4=6.0 */
|
||||
u16 DIMMTrcd; /* Minimax Trcd*40 (ns) of DIMMs*/
|
||||
u16 DIMMTrp; /* Minimax Trp*40 (ns) of DIMMs*/
|
||||
u16 DIMMTrtp; /* Minimax Trtp*40 (ns) of DIMMs*/
|
||||
u16 DIMMTras; /* Minimax Tras*40 (ns) of DIMMs*/
|
||||
u16 DIMMTrc; /* Minimax Trc*40 (ns) of DIMMs*/
|
||||
u16 DIMMTwr; /* Minimax Twr*40 (ns) of DIMMs*/
|
||||
u16 DIMMTrrd; /* Minimax Trrd*40 (ns) of DIMMs*/
|
||||
u16 DIMMTwtr; /* Minimax Twtr*40 (ns) of DIMMs*/
|
||||
u8 Speed; /* Bus Speed (to set Controller)
|
||||
1=200Mhz
|
||||
2=266Mhz
|
||||
3=333Mhz
|
||||
4=400Mhz */
|
||||
u8 CASL; /* CAS latency DCT setting
|
||||
0=2.0
|
||||
1=3.0
|
||||
2=4.0
|
||||
3=5.0
|
||||
4=6.0 */
|
||||
u8 Trcd; /* DCT Trcd (busclocks) */
|
||||
u8 Trp; /* DCT Trp (busclocks) */
|
||||
u8 Trtp; /* DCT Trtp (busclocks) */
|
||||
u8 Tras; /* DCT Tras (busclocks) */
|
||||
u8 Trc; /* DCT Trc (busclocks) */
|
||||
u8 Twr; /* DCT Twr (busclocks) */
|
||||
u8 Trrd; /* DCT Trrd (busclocks) */
|
||||
u8 Twtr; /* DCT Twtr (busclocks) */
|
||||
u8 Trfc[4]; /* DCT Logical DIMM0 Trfc
|
||||
0=75ns (for 256Mb devs)
|
||||
1=105ns (for 512Mb devs)
|
||||
2=127.5ns (for 1Gb devs)
|
||||
3=195ns (for 2Gb devs)
|
||||
4=327.5ns (for 4Gb devs) */
|
||||
/* DCT Logical DIMM1 Trfc (see Trfc0 for format) */
|
||||
/* DCT Logical DIMM2 Trfc (see Trfc0 for format) */
|
||||
/* DCT Logical DIMM3 Trfc (see Trfc0 for format) */
|
||||
u16 CSPresent; /* For each bit n 0..7, 1=Chip-select n is present */
|
||||
u16 CSTestFail; /* For each bit n 0..7, 1=Chip-select n is present but disabled */
|
||||
u32 DCTSysBase; /* BASE[39:8] (system address) of this Node's DCTs. */
|
||||
u32 DCTHoleBase; /* If not zero, BASE[39:8] (system address) of dram hole for HW remapping. Dram hole exists on this Node's DCTs. */
|
||||
u32 DCTSysLimit; /* LIMIT[39:8] (system address) of this Node's DCTs */
|
||||
u16 PresetmaxFreq; /* Maximum OEM defined DDR frequency
|
||||
200=200Mhz (DDR400)
|
||||
266=266Mhz (DDR533)
|
||||
333=333Mhz (DDR667)
|
||||
400=400Mhz (DDR800) */
|
||||
u8 _2Tmode; /* 1T or 2T CMD mode (slow access mode)
|
||||
1=1T
|
||||
2=2T */
|
||||
u8 TrwtTO; /* DCT TrwtTO (busclocks)*/
|
||||
u8 Twrrd; /* DCT Twrrd (busclocks)*/
|
||||
u8 Twrwr; /* DCT Twrwr (busclocks)*/
|
||||
u8 Trdrd; /* DCT Trdrd (busclocks)*/
|
||||
u32 CH_ODC_CTL[2]; /* Output Driver Strength (see BKDG FN2:Offset 9Ch, index 00h*/
|
||||
u32 CH_ADDR_TMG[2]; /* Address Bus Timing (see BKDG FN2:Offset 9Ch, index 04h*/
|
||||
/* Output Driver Strength (see BKDG FN2:Offset 9Ch, index 20h*/
|
||||
/* Address Bus Timing (see BKDG FN2:Offset 9Ch, index 24h*/
|
||||
u16 CH_EccDQSLike[2]; /* CHA DQS ECC byte like...*/
|
||||
u8 CH_EccDQSScale[2]; /* CHA DQS ECC byte scale*/
|
||||
/* CHA DQS ECC byte like...*/
|
||||
/* CHA DQS ECC byte scale*/
|
||||
u8 MaxAsyncLat; /* Max Asynchronous Latency (ns)*/
|
||||
/* NOTE: Not used in Barcelona - u8 CH_D_RCVRDLY[2][4]; */
|
||||
/* CHA DIMM 0 - 4 Receiver Enable Delay*/
|
||||
/* CHB DIMM 0 - 4 Receiver Enable Delay */
|
||||
/* NOTE: Not used in Barcelona - u8 CH_D_B_DQS[2][2][8]; */
|
||||
/* CHA Byte 0-7 Write DQS Delay */
|
||||
/* CHA Byte 0-7 Read DQS Delay */
|
||||
/* CHB Byte 0-7 Write DQS Delay */
|
||||
/* CHB Byte 0-7 Read DQS Delay */
|
||||
u32 PtrPatternBufA; /* Ptr on stack to aligned DQS testing pattern*/
|
||||
u32 PtrPatternBufB; /* Ptr on stack to aligned DQS testing pattern*/
|
||||
u8 Channel; /* Current Channel (0= CH A, 1=CH B)*/
|
||||
u8 ByteLane; /* Current Byte Lane (0..7)*/
|
||||
u8 Direction; /* Current DQS-DQ training write direction (0=read, 1=write)*/
|
||||
u8 Pattern; /* Current pattern*/
|
||||
u8 DQSDelay; /* Current DQS delay value*/
|
||||
u32 TrainErrors; /* Current Training Errors*/
|
||||
|
||||
u32 AMC_TSC_DeltaLo; /* Time Stamp Counter measurement of AMC, Low dword*/
|
||||
u32 AMC_TSC_DeltaHi; /* Time Stamp Counter measurement of AMC, High dword*/
|
||||
/* NOTE: Not used in Barcelona - */
|
||||
u8 CH_D_DIR_MaxMin_B_Dly[2][2][2][8];
|
||||
/* CH A byte lane 0 - 7 minimum filtered window passing DQS delay value*/
|
||||
/* CH A byte lane 0 - 7 maximum filtered window passing DQS delay value*/
|
||||
/* CH B byte lane 0 - 7 minimum filtered window passing DQS delay value*/
|
||||
/* CH B byte lane 0 - 7 maximum filtered window passing DQS delay value*/
|
||||
/* CH A byte lane 0 - 7 minimum filtered window passing DQS delay value*/
|
||||
/* CH A byte lane 0 - 7 maximum filtered window passing DQS delay value*/
|
||||
/* CH B byte lane 0 - 7 minimum filtered window passing DQS delay value*/
|
||||
/* CH B byte lane 0 - 7 maximum filtered window passing DQS delay value*/
|
||||
u32 LogicalCPUID; /* The logical CPUID of the node*/
|
||||
u16 HostBiosSrvc1; /* Word sized general purpose field for use by host BIOS. Scratch space.*/
|
||||
u32 HostBiosSrvc2; /* Dword sized general purpose field for use by host BIOS. Scratch space.*/
|
||||
u16 DimmQRPresent; /* QuadRank DIMM present?*/
|
||||
u16 DimmTrainFail; /* Bitmap showing which dimms failed training*/
|
||||
u16 CSTrainFail; /* Bitmap showing which chipselects failed training*/
|
||||
u16 DimmYr06; /* Bitmap indicating which Dimms have a manufactur's year code <= 2006*/
|
||||
u16 DimmWk2406; /* Bitmap indicating which Dimms have a manufactur's week code <= 24 of 2006 (June)*/
|
||||
u16 DimmDRPresent; /* Bitmap indicating that Dual Rank Dimms are present*/
|
||||
u16 DimmPlPresent; /* Bitmap indicating that Planar (1) or Stacked (0) Dimms are present.*/
|
||||
u16 ChannelTrainFai; /* Bitmap showing the chanel informaiton about failed Chip Selects
|
||||
0 in any bit field indicates Channel 0
|
||||
1 in any bit field indicates Channel 1 */
|
||||
u16 DIMMTfaw; /* Minimax Tfaw*16 (ns) of DIMMs */
|
||||
u8 Tfaw; /* DCT Tfaw (busclocks) */
|
||||
u16 CSUsrTestFail; /* Chip selects excluded by user */
|
||||
/* DCTStatStruct_F - end */
|
||||
|
||||
u16 CH_MaxRdLat[2]; /* Max Read Latency (ns) for DCT 0*/
|
||||
/* Max Read Latency (ns) for DCT 1*/
|
||||
u8 CH_D_DIR_B_DQS[2][4][2][9]; /* [A/B] [DIMM1-4] [R/W] [DQS] */
|
||||
/* CHA DIMM0 Byte 0 - 7 and Check Write DQS Delay*/
|
||||
/* CHA DIMM0 Byte 0 - 7 and Check Read DQS Delay*/
|
||||
/* CHA DIMM1 Byte 0 - 7 and Check Write DQS Delay*/
|
||||
/* CHA DIMM1 Byte 0 - 7 and Check Read DQS Delay*/
|
||||
/* CHB DIMM0 Byte 0 - 7 and Check Write DQS Delay*/
|
||||
/* CHB DIMM0 Byte 0 - 7 and Check Read DQS Delay*/
|
||||
/* CHB DIMM1 Byte 0 - 7 and Check Write DQS Delay*/
|
||||
/* CHB DIMM1 Byte 0 - 7 and Check Read DQS Delay*/
|
||||
u8 CH_D_B_TxDqs[2][4][9]; /* [A/B] [DIMM1-4] [DQS] */
|
||||
/* CHA DIMM0 Byte 0 - 7 TxDqs */
|
||||
/* CHA DIMM0 Byte 0 - 7 TxDqs */
|
||||
/* CHA DIMM1 Byte 0 - 7 TxDqs */
|
||||
/* CHA DIMM1 Byte 0 - 7 TxDqs */
|
||||
/* CHB DIMM0 Byte 0 - 7 TxDqs */
|
||||
/* CHB DIMM0 Byte 0 - 7 TxDqs */
|
||||
/* CHB DIMM1 Byte 0 - 7 TxDqs */
|
||||
/* CHB DIMM1 Byte 0 - 7 TxDqs */
|
||||
u8 CH_D_B_RCVRDLY[2][4][8]; /* [A/B] [DIMM0-3] [DQS] */
|
||||
/* CHA DIMM 0 Receiver Enable Delay*/
|
||||
/* CHA DIMM 1 Receiver Enable Delay*/
|
||||
/* CHA DIMM 2 Receiver Enable Delay*/
|
||||
/* CHA DIMM 3 Receiver Enable Delay*/
|
||||
|
||||
/* CHB DIMM 0 Receiver Enable Delay*/
|
||||
/* CHB DIMM 1 Receiver Enable Delay*/
|
||||
/* CHB DIMM 2 Receiver Enable Delay*/
|
||||
/* CHB DIMM 3 Receiver Enable Delay*/
|
||||
u8 CH_D_BC_RCVRDLY[2][4];
|
||||
/* CHA DIMM 0 - 4 Check Byte Receiver Enable Delay*/
|
||||
/* CHB DIMM 0 - 4 Check Byte Receiver Enable Delay*/
|
||||
u8 DIMMValidDCT[2]; /* DIMM# in DCT0*/
|
||||
/* DIMM# in DCT1*/
|
||||
u16 CSPresent_DCT[2]; /* DCT# CS mapping */
|
||||
u16 MirrPresU_NumRegR; /* Address mapping from edge connect to DIMM present for unbuffered dimm
|
||||
Number of registers on the dimm for registered dimm */
|
||||
u8 MaxDCTs; /* Max number of DCTs in system*/
|
||||
/* NOTE: removed u8 DCT. Use ->dev_ for pci R/W; */ /*DCT pointer*/
|
||||
u8 GangedMode; /* Ganged mode enabled, 0 = disabled, 1 = enabled*/
|
||||
u8 DRPresent; /* Family 10 present flag, 0 = n0t Fam10, 1 = Fam10*/
|
||||
u32 NodeSysLimit; /* BASE[39:8],for DCT0+DCT1 system address*/
|
||||
u8 WrDatGrossH;
|
||||
u8 DqsRcvEnGrossL;
|
||||
/* NOTE: Not used - u8 NodeSpeed */ /* Bus Speed (to set Controller) */
|
||||
/* 1=200Mhz */
|
||||
/* 2=266Mhz */
|
||||
/* 3=333Mhz */
|
||||
/* NOTE: Not used - u8 NodeCASL */ /* CAS latency DCT setting */
|
||||
/* 0=2.0 */
|
||||
/* 1=3.0 */
|
||||
/* 2=4.0 */
|
||||
/* 3=5.0 */
|
||||
/* 4=6.0 */
|
||||
u8 TrwtWB;
|
||||
u8 CurrRcvrCHADelay; /* for keep current RcvrEnDly of chA*/
|
||||
u16 T1000; /* get the T1000 figure (cycle time (ns)*1K)*/
|
||||
u8 DqsRcvEn_Pass; /* for TrainRcvrEn byte lane pass flag*/
|
||||
u8 DqsRcvEn_Saved; /* for TrainRcvrEn byte lane saved flag*/
|
||||
u8 SeedPass1Remainder; /* for Phy assisted DQS receiver enable training*/
|
||||
|
||||
/* for second pass - Second pass should never run for Fam10*/
|
||||
/* NOTE: Not used for Barcelona - u8 CH_D_B_RCVRDLY_1[2][4][8]; */ /* CHA DIMM 0 Receiver Enable Delay */
|
||||
/* CHA DIMM 1 Receiver Enable Delay*/
|
||||
/* CHA DIMM 2 Receiver Enable Delay*/
|
||||
/* CHA DIMM 3 Receiver Enable Delay*/
|
||||
|
||||
/* CHB DIMM 0 Receiver Enable Delay*/
|
||||
/* CHB DIMM 1 Receiver Enable Delay*/
|
||||
/* CHB DIMM 2 Receiver Enable Delay*/
|
||||
/* CHB DIMM 3 Receiver Enable Delay*/
|
||||
|
||||
u8 ClToNB_flag; /* is used to restore ClLinesToNbDis bit after memory */
|
||||
u32 NodeSysBase; /* for channel interleave usage */
|
||||
|
||||
/* New for LB Support */
|
||||
u8 NodePresent;
|
||||
u32 dev_host;
|
||||
u32 dev_map;
|
||||
u32 dev_dct;
|
||||
u32 dev_nbmisc;
|
||||
u8 TargetFreq;
|
||||
u8 TargetCASL;
|
||||
u8 CtrlWrd3;
|
||||
u8 CtrlWrd4;
|
||||
u8 CtrlWrd5;
|
||||
u8 DqsRdWrPos_Saved;
|
||||
u8 DqsRcvEnGrossMax;
|
||||
u8 DqsRcvEnGrossMin;
|
||||
u8 WrDatGrossMax;
|
||||
u8 WrDatGrossMin;
|
||||
|
||||
u16 RegMan1Present; /* DIMM present bitmap of Register manufacture 1 */
|
||||
u16 RegMan2Present; /* DIMM present bitmap of Register manufacture 2 */
|
||||
|
||||
struct _sMCTStruct *C_MCTPtr;
|
||||
struct _sDCTStruct *C_DCTPtr[2];
|
||||
/* struct _sDCTStruct *C_DCT1Ptr; */
|
||||
|
||||
struct _sMCTStruct s_C_MCTPtr;
|
||||
struct _sDCTStruct s_C_DCTPtr[2];
|
||||
/* struct _sDCTStruct s_C_DCT1Ptr[8]; */
|
||||
};
|
||||
|
||||
/*===============================================================================
|
||||
Local Error Status Codes (DCTStatStruc.ErrCode)
|
||||
===============================================================================*/
|
||||
#define SC_RunningOK 0
|
||||
#define SC_VarianceErr 1 /* Running non-optimally*/
|
||||
#define SC_StopError 2 /* Not Running*/
|
||||
#define SC_FatalErr 3 /* Fatal Error, MCTB has exited immediately*/
|
||||
|
||||
/*===============================================================================
|
||||
Local Error Status (DCTStatStruc.ErrStatus[31:0])
|
||||
===============================================================================*/
|
||||
#define SB_NoDimms 0
|
||||
#define SB_DIMMChkSum 1
|
||||
#define SB_DimmMismatchM 2 /* dimm module type(buffer) mismatch*/
|
||||
#define SB_DimmMismatchT 3 /* dimm CL/T mismatch*/
|
||||
#define SB_DimmMismatchO 4 /* dimm organization mismatch (128-bit)*/
|
||||
#define SB_NoTrcTrfc 5 /* SPD missing Trc or Trfc info*/
|
||||
#define SB_NoCycTime 6 /* SPD missing byte 23 or 25*/
|
||||
#define SB_BkIntDis 7 /* Bank interleave requested but not enabled*/
|
||||
#define SB_DramECCDis 8 /* Dram ECC requested but not enabled*/
|
||||
#define SB_SpareDis 9 /* Online spare requested but not enabled*/
|
||||
#define SB_MinimumMode 10 /* Running in Minimum Mode*/
|
||||
#define SB_NORCVREN 11 /* No DQS Receiver Enable pass window found*/
|
||||
#define SB_CHA2BRCVREN 12 /* DQS Rcvr En pass window CHA to CH B too large*/
|
||||
#define SB_SmallRCVR 13 /* DQS Rcvr En pass window too small (far right of dynamic range)*/
|
||||
#define SB_NODQSPOS 14 /* No DQS-DQ passing positions*/
|
||||
#define SB_SMALLDQS 15 /* DQS-DQ passing window too small*/
|
||||
#define SB_DCBKScrubDis 16 /* DCache scrub requested but not enabled */
|
||||
|
||||
/*===============================================================================
|
||||
Local Configuration Status (DCTStatStruc.Status[31:0])
|
||||
===============================================================================*/
|
||||
#define SB_Registered 0 /* All DIMMs are Registered*/
|
||||
#define SB_ECCDIMMs 1 /* All banks ECC capable*/
|
||||
#define SB_PARDIMMs 2 /* All banks Addr/CMD Parity capable*/
|
||||
#define SB_DiagClks 3 /* Jedec ALL slots clock enable diag mode*/
|
||||
#define SB_128bitmode 4 /* DCT in 128-bit mode operation*/
|
||||
#define SB_64MuxedMode 5 /* DCT in 64-bit mux'ed mode.*/
|
||||
#define SB_2TMode 6 /* 2T CMD timing mode is enabled.*/
|
||||
#define SB_SWNodeHole 7 /* Remapping of Node Base on this Node to create a gap.*/
|
||||
#define SB_HWHole 8 /* Memory Hole created on this Node using HW remapping.*/
|
||||
#define SB_Over400MHz 9 /* DCT freq >= 400MHz flag*/
|
||||
#define SB_DQSPos_Pass2 10 /* Using for TrainDQSPos DIMM0/1, when freq>=400MHz*/
|
||||
#define SB_DQSRcvLimit 11 /* Using for DQSRcvEnTrain to know we have reached to upper bound.*/
|
||||
#define SB_ExtConfig 12 /* Indicator the default setting for extend PCI configuration support*/
|
||||
|
||||
|
||||
/*===============================================================================
|
||||
NVRAM/run-time-configurable Items
|
||||
===============================================================================*/
|
||||
/*Platform Configuration*/
|
||||
#define NV_PACK_TYPE 0 /* CPU Package Type (2-bits)
|
||||
0=NPT L1
|
||||
1=NPT M2
|
||||
2=NPT S1*/
|
||||
#define NV_MAX_NODES 1 /* Number of Nodes/Sockets (4-bits)*/
|
||||
#define NV_MAX_DIMMS 2 /* Number of DIMM slots for the specified Node ID (4-bits)*/
|
||||
#define NV_MAX_MEMCLK 3 /* Maximum platform demonstrated Memclock (10-bits)
|
||||
200=200Mhz (DDR400)
|
||||
266=266Mhz (DDR533)
|
||||
333=333Mhz (DDR667)
|
||||
400=400Mhz (DDR800)*/
|
||||
#define NV_ECC_CAP 4 /* Bus ECC capable (1-bits)
|
||||
0=Platform not capable
|
||||
1=Platform is capable*/
|
||||
#define NV_4RANKType 5 /* Quad Rank DIMM slot type (2-bits)
|
||||
0=Normal
|
||||
1=R4 (4-Rank Registered DIMMs in AMD server configuration)
|
||||
2=S4 (Unbuffered SO-DIMMs)*/
|
||||
#define NV_BYPMAX 6 /* Value to set DcqBypassMax field (See Function 2, Offset 94h, [27:24] of BKDG for field definition).
|
||||
4=4 times bypass (normal for non-UMA systems)
|
||||
7=7 times bypass (normal for UMA systems)*/
|
||||
#define NV_RDWRQBYP 7 /* Value to set RdWrQByp field (See Function 2, Offset A0h, [3:2] of BKDG for field definition).
|
||||
2=8 times (normal for non-UMA systems)
|
||||
3=16 times (normal for UMA systems)*/
|
||||
|
||||
|
||||
/*Dram Timing*/
|
||||
#define NV_MCTUSRTMGMODE 10 /* User Memclock Mode (2-bits)
|
||||
0=Auto, no user limit
|
||||
1=Auto, user limit provided in NV_MemCkVal
|
||||
2=Manual, user value provided in NV_MemCkVal*/
|
||||
#define NV_MemCkVal 11 /* Memory Clock Value (2-bits)
|
||||
0=200Mhz
|
||||
1=266Mhz
|
||||
2=333Mhz
|
||||
3=400Mhz*/
|
||||
|
||||
/*Dram Configuration*/
|
||||
#define NV_BankIntlv 20 /* Dram Bank (chip-select) Interleaving (1-bits)
|
||||
0=disable
|
||||
1=enable*/
|
||||
#define NV_AllMemClks 21 /* Turn on All DIMM clocks (1-bits)
|
||||
0=normal
|
||||
1=enable all memclocks*/
|
||||
#define NV_SPDCHK_RESTRT 22 /* SPD Check control bitmap (1-bits)
|
||||
0=Exit current node init if any DIMM has SPD checksum error
|
||||
1=Ignore faulty SPD checksums (Note: DIMM cannot be enabled)*/
|
||||
#define NV_DQSTrainCTL 23 /* DQS Signal Timing Training Control
|
||||
0=skip DQS training
|
||||
1=perform DQS training*/
|
||||
#define NV_NodeIntlv 24 /* Node Memory Interleaving (1-bits)
|
||||
0=disable
|
||||
1=enable*/
|
||||
#define NV_BurstLen32 25 /* BurstLength32 for 64-bit mode (1-bits)
|
||||
0=disable (normal)
|
||||
1=enable (4 beat burst when width is 64-bits)*/
|
||||
|
||||
/*Dram Power*/
|
||||
#define NV_CKE_PDEN 30 /* CKE based power down mode (1-bits)
|
||||
0=disable
|
||||
1=enable*/
|
||||
#define NV_CKE_CTL 31 /* CKE based power down control (1-bits)
|
||||
0=per Channel control
|
||||
1=per Chip select control*/
|
||||
#define NV_CLKHZAltVidC3 32 /* Memclock tri-stating during C3 and Alt VID (1-bits)
|
||||
0=disable
|
||||
1=enable*/
|
||||
|
||||
/*Memory Map/Mgt.*/
|
||||
#define NV_BottomIO 40 /* Bottom of 32-bit IO space (8-bits)
|
||||
NV_BottomIO[7:0]=Addr[31:24]*/
|
||||
#define NV_BottomUMA 41 /* Bottom of shared graphics dram (8-bits)
|
||||
NV_BottomUMA[7:0]=Addr[31:24]*/
|
||||
#define NV_MemHole 42 /* Memory Hole Remapping (1-bits)
|
||||
0=disable
|
||||
1=enable */
|
||||
|
||||
/*ECC*/
|
||||
#define NV_ECC 50 /* Dram ECC enable*/
|
||||
#define NV_NBECC 52 /* ECC MCE enable*/
|
||||
#define NV_ChipKill 53 /* Chip-Kill ECC Mode enable*/
|
||||
#define NV_ECCRedir 54 /* Dram ECC Redirection enable*/
|
||||
#define NV_DramBKScrub 55 /* Dram ECC Background Scrubber CTL*/
|
||||
#define NV_L2BKScrub 56 /* L2 ECC Background Scrubber CTL*/
|
||||
#define NV_DCBKScrub 57 /* DCache ECC Background Scrubber CTL*/
|
||||
#define NV_CS_SpareCTL 58 /* Chip Select Spare Control bit 0:
|
||||
0=disable Spare
|
||||
1=enable Spare */
|
||||
/* Chip Select Spare Control bit 1-4:
|
||||
Reserved, must be zero*/
|
||||
#define NV_SyncOnUnEccEn 61 /* SyncOnUnEccEn control
|
||||
0=disable
|
||||
1=enable*/
|
||||
#define NV_Unganged 62
|
||||
|
||||
#define NV_ChannelIntlv 63 /* Channel Interleaving (3-bits)
|
||||
xx0b = disable
|
||||
yy1b = enable with DctSelIntLvAddr set to yyb */
|
||||
|
||||
|
||||
#ifndef MAX_NODES_SUPPORTED
|
||||
#define MAX_NODES_SUPPORTED 8
|
||||
#endif
|
||||
|
||||
#ifndef MAX_DIMMS_SUPPORTED
|
||||
#define MAX_DIMMS_SUPPORTED 8
|
||||
#endif
|
||||
|
||||
#ifndef MAX_CS_SUPPORTED
|
||||
#define MAX_CS_SUPPORTED 8
|
||||
#endif
|
||||
|
||||
#ifndef MCT_DIMM_SPARE_NO_WARM
|
||||
#define MCT_DIMM_SPARE_NO_WARM 0
|
||||
#endif
|
||||
|
||||
u32 Get_NB32(u32 dev, u32 reg);
|
||||
void Set_NB32(u32 dev, u32 reg, u32 val);
|
||||
u32 Get_NB32_index(u32 dev, u32 index_reg, u32 index);
|
||||
void Set_NB32_index(u32 dev, u32 index_reg, u32 index, u32 data);
|
||||
u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index);
|
||||
void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 index, u32 data);
|
||||
u32 OtherTiming_A_D(struct DCTStatStruc *pDCTstat, u32 val);
|
||||
void mct_ForceAutoPrecharge_D(struct DCTStatStruc *pDCTstat, u32 dct);
|
||||
u32 Modify_D3CMP(struct DCTStatStruc *pDCTstat, u32 dct, u32 value);
|
||||
u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass);
|
||||
u32 SetupDqsPattern_1PassA(u8 Pass);
|
||||
u32 SetupDqsPattern_1PassB(u8 Pass);
|
||||
u8 mct_Get_Start_RcvrEnDly_1Pass(u8 Pass);
|
||||
u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 RcvrEnDlyLimit, u8 Channel, u8 Receiver, u8 Pass);
|
||||
void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
u32 mctGetLogicalCPUID(u32 Node);
|
||||
u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
void TrainReceiverEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u8 Pass);
|
||||
void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
void mct_EndDQSTraining_D(struct MCTStatStruc *pMCTstat,struct DCTStatStruc *pDCTstatA);
|
||||
void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 FinalValue, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 Pass);
|
||||
void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel);
|
||||
void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 dct);
|
||||
void InterleaveBanks_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
|
||||
void mct_SetDramConfigHi_D(struct DCTStatStruc *pDCTstat, u32 dct, u32 DramConfigHi);
|
||||
void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
|
||||
void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 Pass);
|
||||
void mct_EnableDimmEccEn_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 _DisableDramECC);
|
||||
u32 procOdtWorkaround(struct DCTStatStruc *pDCTstat, u32 dct, u32 val);
|
||||
void mct_BeforeDramInit_D(struct DCTStatStruc *pDCTstat, u32 dct);
|
||||
void mctGet_DIMMAddr(struct DCTStatStruc *pDCTstat, u32 node);
|
||||
void mctSMBhub_Init(u32 node);
|
||||
int mctRead_SPD(u32 smaddr, u32 reg);
|
||||
void InterleaveNodes_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
void mct_BeforeDQSTrain_Samp_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
|
||||
void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA);
|
||||
u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass);
|
||||
u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct);
|
||||
void mct_Wait(u32 cycles);
|
||||
u8 mct_RcvrRankEnabled_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 Channel, u8 ChipSel);
|
||||
u32 mct_GetRcvrSysAddr_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 channel, u8 receiver, u8 *valid);
|
||||
void mct_Read1LTestPattern_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u32 addr);
|
||||
|
||||
#endif
|
370
src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
Normal file
370
src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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 inline void _WRMSR(u32 addr, u32 lo, u32 hi)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"wrmsr"
|
||||
:
|
||||
:"c"(addr),"a"(lo), "d" (hi)
|
||||
);
|
||||
}
|
||||
|
||||
static inline void _RDMSR(u32 addr, u32 *lo, u32 *hi)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"rdmsr"
|
||||
:"=a"(*lo), "=d" (*hi)
|
||||
:"c"(addr)
|
||||
);
|
||||
}
|
||||
|
||||
static inline void _RDTSC(u32 *lo, u32 *hi)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"rdtsc"
|
||||
: "=a" (*lo), "=d"(*hi)
|
||||
);
|
||||
}
|
||||
|
||||
static inline void _cpu_id(u32 addr, u32 *val)
|
||||
{
|
||||
__asm__ volatile(
|
||||
"cpuid"
|
||||
: "=a" (val[0]),
|
||||
"=b" (val[1]),
|
||||
"=c" (val[2]),
|
||||
"=d" (val[3])
|
||||
: "0" (addr));
|
||||
|
||||
}
|
||||
|
||||
static u32 bsr(u32 x)
|
||||
{
|
||||
u8 i;
|
||||
u32 ret = 0;
|
||||
|
||||
for(i=31; i>0; i--) {
|
||||
if(x & (1<<i)) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static u32 bsf(u32 x)
|
||||
{
|
||||
u8 i;
|
||||
u32 ret = 32;
|
||||
|
||||
for(i=0; i<32; i++) {
|
||||
if(x & (1<<i)) {
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define _MFENCE asm volatile ( "mfence")
|
||||
|
||||
#define _SFENCE asm volatile ( "sfence" )
|
||||
|
||||
/* prevent speculative execution of following instructions */
|
||||
#define _EXECFENCE asm volatile ("outb %al, $0xed")
|
||||
|
||||
static inline u32 read_cr4(void)
|
||||
{
|
||||
u32 cr4;
|
||||
__asm__ volatile ("movl %%cr4, %0" : "=r" (cr4));
|
||||
return cr4;
|
||||
}
|
||||
|
||||
static inline void write_cr4(u32 cr4)
|
||||
{
|
||||
__asm__ volatile ("movl %0, %%cr4" : : "r" (cr4));
|
||||
}
|
||||
|
||||
u32 SetUpperFSbase(u32 addr_hi);
|
||||
|
||||
static void proc_CLFLUSH(u32 addr_hi)
|
||||
{
|
||||
SetUpperFSbase(addr_hi);
|
||||
|
||||
__asm__ volatile (
|
||||
/* clflush fs:[eax] */
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"clflush %%fs:(%0)\n\t"
|
||||
"mfence\n\t"
|
||||
::"a" (addr_hi<<8)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static void WriteLNTestPattern(u32 addr_lo, u8 *buf_a, u32 line_num)
|
||||
{
|
||||
__asm__ volatile (
|
||||
/*prevent speculative execution of following instructions*/
|
||||
/* FIXME: needed ? */
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"1:\n\t"
|
||||
"movdqa (%3), %%xmm0\n\t"
|
||||
"movntdq %%xmm0, %%fs:(%0)\n\t" /* xmm0 is 128 bit */
|
||||
"addl %1, %0\n\t"
|
||||
"addl %1, %3\n\t"
|
||||
"loop 1b\n\t"
|
||||
"mfence\n\t"
|
||||
|
||||
:: "a" (addr_lo), "d" (16), "c" (line_num * 4), "b"(buf_a)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static u32 read32_fs(u32 addr_lo)
|
||||
{
|
||||
u32 value;
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"movl %%fs:(%1), %0\n\t"
|
||||
:"=b"(value): "a" (addr_lo)
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
#ifdef UNUSED_CODE
|
||||
static u8 read8_fs(u32 addr_lo)
|
||||
{
|
||||
u8 byte;
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"movb %%fs:(%1), %b0\n\t"
|
||||
"mfence\n\t"
|
||||
:"=b"(byte): "a" (addr_lo)
|
||||
);
|
||||
return byte;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void FlushDQSTestPattern_L9(u32 addr_lo)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"clflush %%fs:-128(%%ecx)\n\t"
|
||||
"clflush %%fs:-64(%%ecx)\n\t"
|
||||
"clflush %%fs:(%%ecx)\n\t"
|
||||
"clflush %%fs:64(%%ecx)\n\t"
|
||||
|
||||
"clflush %%fs:-128(%%eax)\n\t"
|
||||
"clflush %%fs:-64(%%eax)\n\t"
|
||||
"clflush %%fs:(%%eax)\n\t"
|
||||
"clflush %%fs:64(%%eax)\n\t"
|
||||
|
||||
"clflush %%fs:-128(%%ebx)\n\t"
|
||||
|
||||
:: "b" (addr_lo+128+8*64), "c"(addr_lo+128),
|
||||
"a"(addr_lo+128+4*64)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) void FlushDQSTestPattern_L18(u32 addr_lo)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"clflush %%fs:-128(%%eax)\n\t"
|
||||
"clflush %%fs:-64(%%eax)\n\t"
|
||||
"clflush %%fs:(%%eax)\n\t"
|
||||
"clflush %%fs:64(%%eax)\n\t"
|
||||
|
||||
"clflush %%fs:-128(%%edi)\n\t"
|
||||
"clflush %%fs:-64(%%edi)\n\t"
|
||||
"clflush %%fs:(%%edi)\n\t"
|
||||
"clflush %%fs:64(%%edi)\n\t"
|
||||
|
||||
"clflush %%fs:-128(%%ebx)\n\t"
|
||||
"clflush %%fs:-64(%%ebx)\n\t"
|
||||
"clflush %%fs:(%%ebx)\n\t"
|
||||
"clflush %%fs:64(%%ebx)\n\t"
|
||||
|
||||
"clflush %%fs:-128(%%ecx)\n\t"
|
||||
"clflush %%fs:-64(%%ecx)\n\t"
|
||||
"clflush %%fs:(%%ecx)\n\t"
|
||||
"clflush %%fs:64(%%ecx)\n\t"
|
||||
|
||||
"clflush %%fs:-128(%%edx)\n\t"
|
||||
"clflush %%fs:-64(%%edx)\n\t"
|
||||
|
||||
:: "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
|
||||
"d" (addr_lo +128+16*64), "a"(addr_lo+128),
|
||||
"D"(addr_lo+128+4*64)
|
||||
);
|
||||
}
|
||||
|
||||
static void ReadL18TestPattern(u32 addr_lo)
|
||||
{
|
||||
/* set fs and use fs prefix to access the mem */
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"movl %%fs:-128(%%esi), %%eax\n\t" /* TestAddr cache line */
|
||||
"movl %%fs:-64(%%esi), %%eax\n\t" /* +1 */
|
||||
"movl %%fs:(%%esi), %%eax\n\t" /* +2 */
|
||||
"movl %%fs:64(%%esi), %%eax\n\t" /* +3 */
|
||||
|
||||
"movl %%fs:-128(%%edi), %%eax\n\t" /* +4 */
|
||||
"movl %%fs:-64(%%edi), %%eax\n\t" /* +5 */
|
||||
"movl %%fs:(%%edi), %%eax\n\t" /* +6 */
|
||||
"movl %%fs:64(%%edi), %%eax\n\t" /* +7 */
|
||||
|
||||
"movl %%fs:-128(%%ebx), %%eax\n\t" /* +8 */
|
||||
"movl %%fs:-64(%%ebx), %%eax\n\t" /* +9 */
|
||||
"movl %%fs:(%%ebx), %%eax\n\t" /* +10 */
|
||||
"movl %%fs:64(%%ebx), %%eax\n\t" /* +11 */
|
||||
|
||||
"movl %%fs:-128(%%ecx), %%eax\n\t" /* +12 */
|
||||
"movl %%fs:-64(%%ecx), %%eax\n\t" /* +13 */
|
||||
"movl %%fs:(%%ecx), %%eax\n\t" /* +14 */
|
||||
"movl %%fs:64(%%ecx), %%eax\n\t" /* +15 */
|
||||
|
||||
"movl %%fs:-128(%%edx), %%eax\n\t" /* +16 */
|
||||
"movl %%fs:-64(%%edx), %%eax\n\t" /* +17 */
|
||||
"mfence\n\t"
|
||||
|
||||
:: "a"(0), "b" (addr_lo+128+8*64), "c" (addr_lo+128+12*64),
|
||||
"d" (addr_lo +128+16*64), "S"(addr_lo+128),
|
||||
"D"(addr_lo+128+4*64)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static void ReadL9TestPattern(u32 addr_lo)
|
||||
{
|
||||
|
||||
/* set fs and use fs prefix to access the mem */
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
|
||||
"movl %%fs:-128(%%ecx), %%eax\n\t" /* TestAddr cache line */
|
||||
"movl %%fs:-64(%%ecx), %%eax\n\t" /* +1 */
|
||||
"movl %%fs:(%%ecx), %%eax\n\t" /* +2 */
|
||||
"movl %%fs:64(%%ecx), %%eax\n\t" /* +3 */
|
||||
|
||||
"movl %%fs:-128(%%edx), %%eax\n\t" /* +4 */
|
||||
"movl %%fs:-64(%%edx), %%eax\n\t" /* +5 */
|
||||
"movl %%fs:(%%edx), %%eax\n\t" /* +6 */
|
||||
"movl %%fs:64(%%edx), %%eax\n\t" /* +7 */
|
||||
|
||||
"movl %%fs:-128(%%ebx), %%eax\n\t" /* +8 */
|
||||
"mfence\n\t"
|
||||
|
||||
:: "a"(0), "b" (addr_lo+128+8*64), "c"(addr_lo+128),
|
||||
"d"(addr_lo+128+4*64)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static void ReadMaxRdLat1CLTestPattern_D(u32 addr)
|
||||
{
|
||||
SetUpperFSbase(addr);
|
||||
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"movl %%fs:-128(%%esi), %%eax\n\t" /* TestAddr cache line */
|
||||
"movl %%fs:-64(%%esi), %%eax\n\t" /* +1 */
|
||||
"movl %%fs:(%%esi), %%eax\n\t" /* +2 */
|
||||
"mfence\n\t"
|
||||
:: "a"(0), "S"((addr<<8)+128)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
static void WriteMaxRdLat1CLTestPattern_D(u32 buf, u32 addr)
|
||||
{
|
||||
SetUpperFSbase(addr);
|
||||
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"1:\n\t"
|
||||
"movdqa (%3), %%xmm0\n\t"
|
||||
"movntdq %%xmm0, %%fs:(%0)\n\t" /* xmm0 is 128 bit */
|
||||
"addl %1, %0\n\t"
|
||||
"addl %1, %3\n\t"
|
||||
"loop 1b\n\t"
|
||||
"mfence\n\t"
|
||||
|
||||
:: "a" (addr<<8), "d" (16), "c" (3 * 4), "b"(buf)
|
||||
);
|
||||
}
|
||||
|
||||
static void FlushMaxRdLatTestPattern_D(u32 addr)
|
||||
{
|
||||
/* Flush a pattern of 72 bit times (per DQ) from cache.
|
||||
* This procedure is used to ensure cache miss on the next read training.
|
||||
*/
|
||||
|
||||
SetUpperFSbase(addr);
|
||||
|
||||
__asm__ volatile (
|
||||
"outb %%al, $0xed\n\t" /* _EXECFENCE */
|
||||
"clflush %%fs:-128(%%esi)\n\t" /* TestAddr cache line */
|
||||
"clflush %%fs:-64(%%esi)\n\t" /* +1 */
|
||||
"clflush %%fs:(%%esi)\n\t" /* +2 */
|
||||
"mfence\n\t"
|
||||
|
||||
:: "S"((addr<<8)+128)
|
||||
);
|
||||
}
|
||||
|
||||
static u32 stream_to_int(u8 *p)
|
||||
{
|
||||
int i;
|
||||
u32 val;
|
||||
u32 valx;
|
||||
|
||||
val = 0;
|
||||
|
||||
for(i=3; i>=0; i--) {
|
||||
val <<= 8;
|
||||
valx = *(p+i);
|
||||
val |= valx;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#ifdef UNUSED_CODE
|
||||
static void oemSet_NB32(u32 addr, u32 val, u8 *valid)
|
||||
{
|
||||
}
|
||||
|
||||
static u32 oemGet_NB32(u32 addr, u8 *valid)
|
||||
{
|
||||
*valid = 0;
|
||||
return 0xffffffff;
|
||||
}
|
||||
#endif
|
||||
|
||||
static u8 oemNodePresent_D(u8 Node, u8 *ret)
|
||||
{
|
||||
*ret = 0;
|
||||
return 0;
|
||||
}
|
87
src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
Normal file
87
src/northbridge/amd/amdmct/mct_ddr3/mctardk5.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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 void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
|
||||
u32 *AddrTmgCTL, u32 *ODC_CTL,
|
||||
u8 *CMDmode);
|
||||
|
||||
void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u32 dct)
|
||||
{
|
||||
Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
|
||||
pDCTstat->MAload[dct],
|
||||
&(pDCTstat->CH_ADDR_TMG[dct]), &(pDCTstat->CH_ODC_CTL[dct]),
|
||||
&pDCTstat->_2Tmode);
|
||||
|
||||
pDCTstat->CH_EccDQSLike[0] = 0x0403;
|
||||
pDCTstat->CH_EccDQSScale[0] = 0x70;
|
||||
pDCTstat->CH_EccDQSLike[1] = 0x0403;
|
||||
pDCTstat->CH_EccDQSScale[1] = 0x70;
|
||||
|
||||
pDCTstat->CH_ODC_CTL[dct] |= 0x20000000; /* 60ohms */
|
||||
}
|
||||
|
||||
/*
|
||||
* In: MAAdimms - number of DIMMs on the channel
|
||||
* : Speed - Speed (see DCTStatstruc.Speed for definition)
|
||||
* : MAAload - number of address bus loads on the channel
|
||||
* Out: AddrTmgCTL - Address Timing Control Register Value
|
||||
* : ODC_CTL - Output Driver Compensation Control Register Value
|
||||
* : CMDmode - CMD mode
|
||||
*/
|
||||
static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
|
||||
u32 *AddrTmgCTL, u32 *ODC_CTL,
|
||||
u8 *CMDmode)
|
||||
{
|
||||
*AddrTmgCTL = 0;
|
||||
*ODC_CTL = 0;
|
||||
*CMDmode = 1;
|
||||
|
||||
if(MAAdimms == 1) {
|
||||
if(MAAload >= 16) {
|
||||
if(Speed == 4)
|
||||
*AddrTmgCTL = 0x003B0000;
|
||||
else if (Speed == 5)
|
||||
*AddrTmgCTL = 0x00380000;
|
||||
else if (Speed == 6)
|
||||
*AddrTmgCTL = 0x00360000;
|
||||
else
|
||||
*AddrTmgCTL = 0x00340000;
|
||||
} else {
|
||||
*AddrTmgCTL = 0x00000000;
|
||||
}
|
||||
*ODC_CTL = 0x00113222;
|
||||
*CMDmode = 1;
|
||||
} else /* if(MAAdimms == 0) */ {
|
||||
if(Speed == 4) {
|
||||
*CMDmode = 1;
|
||||
*AddrTmgCTL = 0x00390039;
|
||||
} else if(Speed == 5) {
|
||||
*CMDmode = 1;
|
||||
*AddrTmgCTL = 0x00350037;
|
||||
} else if(Speed == 6) {
|
||||
*CMDmode = 2;
|
||||
*AddrTmgCTL = 0x00000035;
|
||||
} else {
|
||||
*CMDmode = 2;
|
||||
*AddrTmgCTL = 0x00000033;
|
||||
}
|
||||
*ODC_CTL = 0x00223323;
|
||||
}
|
||||
}
|
118
src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
Normal file
118
src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* The socket type F (1207), Fr2, G (1207) are not tested.
|
||||
*/
|
||||
|
||||
static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload,
|
||||
u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL,
|
||||
u8 *CMDmode);
|
||||
|
||||
|
||||
void mctGet_PS_Cfg_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u32 dct)
|
||||
{
|
||||
Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[dct], pDCTstat->Speed,
|
||||
pDCTstat->MAload[dct], pDCTstat->DATAload[dct],
|
||||
&(pDCTstat->CH_ADDR_TMG[dct]), &(pDCTstat->CH_ODC_CTL[dct]),
|
||||
&pDCTstat->_2Tmode);
|
||||
|
||||
if (pDCTstat->GangedMode == 1 && dct == 0)
|
||||
Get_ChannelPS_Cfg0_D(pDCTstat->MAdimms[1], pDCTstat->Speed,
|
||||
pDCTstat->MAload[1], pDCTstat->DATAload[1],
|
||||
&(pDCTstat->CH_ADDR_TMG[1]), &(pDCTstat->CH_ODC_CTL[1]),
|
||||
&pDCTstat->_2Tmode);
|
||||
|
||||
pDCTstat->CH_EccDQSLike[0] = 0x0302;
|
||||
pDCTstat->CH_EccDQSLike[1] = 0x0302;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* In: MAAdimms - number of DIMMs on the channel
|
||||
* : Speed - Speed (see DCTStatstruc.Speed for definition)
|
||||
* : MAAload - number of address bus loads on the channel
|
||||
* : DATAAload - number of ranks on the channel
|
||||
* Out: AddrTmgCTL - Address Timing Control Register Value
|
||||
* : ODC_CTL - Output Driver Compensation Control Register Value
|
||||
* : CMDmode - CMD mode
|
||||
*/
|
||||
static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload,
|
||||
u8 DATAAload, u32 *AddrTmgCTL, u32 *ODC_CTL,
|
||||
u8 *CMDmode)
|
||||
{
|
||||
*AddrTmgCTL = 0;
|
||||
*ODC_CTL = 0;
|
||||
*CMDmode = 1;
|
||||
|
||||
if (mctGet_NVbits(NV_MAX_DIMMS) == 4) {
|
||||
if(Speed == 4) {
|
||||
*AddrTmgCTL = 0x00000000;
|
||||
} else if (Speed == 5) {
|
||||
*AddrTmgCTL = 0x003C3C3C;
|
||||
if (MAAdimms > 1)
|
||||
*AddrTmgCTL = 0x003A3C3A;
|
||||
} else if (Speed == 6) {
|
||||
if (MAAdimms == 1)
|
||||
*AddrTmgCTL = 0x003A3A3A;
|
||||
else
|
||||
*AddrTmgCTL = 0x00383A38;
|
||||
} else {
|
||||
if (MAAdimms == 1)
|
||||
*AddrTmgCTL = 0x00373937;
|
||||
else
|
||||
*AddrTmgCTL = 0x00353935;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(Speed == 4) {
|
||||
*AddrTmgCTL = 0x00000000;
|
||||
if (MAAdimms == 3)
|
||||
*AddrTmgCTL = 0x00380038;
|
||||
} else if (Speed == 5) {
|
||||
if (MAAdimms == 1)
|
||||
*AddrTmgCTL = 0x003C3C3C;
|
||||
else if (MAAdimms == 2)
|
||||
*AddrTmgCTL = 0x003A3C3A;
|
||||
else
|
||||
*AddrTmgCTL = 0x00373C37;
|
||||
} else if (Speed == 6) {
|
||||
if (MAAdimms == 1)
|
||||
*AddrTmgCTL = 0x003A3A3A;
|
||||
else if (MAAdimms == 2)
|
||||
*AddrTmgCTL = 0x00383A38;
|
||||
else
|
||||
*AddrTmgCTL = 0x00343A34;
|
||||
} else {
|
||||
if (MAAdimms == 1)
|
||||
*AddrTmgCTL = 0x00393939;
|
||||
else if (MAAdimms == 2)
|
||||
*AddrTmgCTL = 0x00363936;
|
||||
else
|
||||
*AddrTmgCTL = 0x00303930;
|
||||
}
|
||||
}
|
||||
|
||||
if ((MAAdimms == 1) && (MAAload < 4))
|
||||
*ODC_CTL = 0x20113222;
|
||||
else
|
||||
*ODC_CTL = 0x20223222;
|
||||
|
||||
*CMDmode = 1;
|
||||
}
|
122
src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c
Normal file
122
src/northbridge/amd/amdmct/mct_ddr3/mctchi_d.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
void InterleaveChannels_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
|
||||
u8 Node;
|
||||
u32 DramBase, DctSelBase;
|
||||
u8 DctSelIntLvAddr, DctSelHi;
|
||||
u8 HoleValid = 0;
|
||||
u32 HoleSize, HoleBase = 0;
|
||||
u32 val, tmp;
|
||||
u32 dct0_size, dct1_size;
|
||||
struct DCTStatStruc *pDCTstat;
|
||||
|
||||
/* HoleValid - indicates whether the current Node contains hole.
|
||||
* HoleSize - indicates whether there is IO hole in the whole system
|
||||
* memory.
|
||||
*/
|
||||
|
||||
/* call back to wrapper not needed ManualChannelInterleave_D(); */
|
||||
/* call back - DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv);*/ /* override interleave */
|
||||
/* Manually set: typ=5, otherwise typ=7. */
|
||||
DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv); /* typ=5: Hash*: exclusive OR of address bits[20:16, 6]. */
|
||||
|
||||
if (DctSelIntLvAddr & 1) {
|
||||
DctSelIntLvAddr >>= 1;
|
||||
HoleSize = 0;
|
||||
if ((pMCTstat->GStatus & (1 << GSB_SoftHole)) ||
|
||||
(pMCTstat->GStatus & (1 << GSB_HWHole))) {
|
||||
if (pMCTstat->HoleBase) {
|
||||
HoleBase = pMCTstat->HoleBase >> 8;
|
||||
HoleSize = HoleBase & 0xFFFF0000;
|
||||
HoleSize |= ((~HoleBase) + 1) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
Node = 0;
|
||||
while (Node < MAX_NODES_SUPPORTED) {
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
val = Get_NB32(pDCTstat->dev_map, 0xF0);
|
||||
if (val & (1 << DramHoleValid))
|
||||
HoleValid = 1;
|
||||
if (!pDCTstat->GangedMode && pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1]) {
|
||||
DramBase = pDCTstat->NodeSysBase >> 8;
|
||||
dct1_size = ((pDCTstat->NodeSysLimit) + 2) >> 8;
|
||||
dct0_size = Get_NB32(pDCTstat->dev_dct, 0x114);
|
||||
if (dct0_size >= 0x10000) {
|
||||
dct0_size -= HoleSize;
|
||||
}
|
||||
|
||||
dct0_size -= DramBase;
|
||||
dct1_size -= dct0_size;
|
||||
DctSelHi = 0x05; /* DctSelHiRngEn = 1, DctSelHi = 0 */
|
||||
if (dct1_size == dct0_size) {
|
||||
dct1_size = 0;
|
||||
DctSelHi = 0x04; /* DctSelHiRngEn = 0 */
|
||||
} else if (dct1_size > dct0_size ) {
|
||||
dct1_size = dct0_size;
|
||||
DctSelHi = 0x07; /* DctSelHiRngEn = 1, DctSelHi = 1 */
|
||||
}
|
||||
dct0_size = dct1_size;
|
||||
dct0_size += DramBase;
|
||||
dct0_size += dct1_size;
|
||||
if (dct0_size >= HoleBase) /* if DctSelBaseAddr > HoleBase */
|
||||
dct0_size += HoleSize;
|
||||
DctSelBase = dct0_size;
|
||||
|
||||
if (dct1_size == 0)
|
||||
dct0_size = 0;
|
||||
dct0_size -= dct1_size; /* DctSelBaseOffset = DctSelBaseAddr - Interleaved region */
|
||||
Set_NB32(pDCTstat->dev_dct, 0x114, dct0_size);
|
||||
|
||||
if (dct1_size == 0)
|
||||
dct1_size = DctSelBase;
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x110);
|
||||
val &= 0x7F8;
|
||||
val |= dct1_size;
|
||||
val |= DctSelHi;
|
||||
val |= (DctSelIntLvAddr << 6) & 0xFF;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x110, val);
|
||||
|
||||
if (HoleValid) {
|
||||
tmp = DramBase;
|
||||
val = DctSelBase;
|
||||
if (val < HoleBase) { /* DctSelBaseAddr < DramHoleBase */
|
||||
val -= DramBase;
|
||||
val >>= 1;
|
||||
tmp += val;
|
||||
}
|
||||
tmp += HoleSize;
|
||||
val = Get_NB32(pDCTstat->dev_map, 0xF0); /* DramHoleOffset */
|
||||
val &= 0xFFFF007F;
|
||||
val |= (tmp & ~0xFFFF007F);
|
||||
Set_NB32(pDCTstat->dev_map, 0xF0, val);
|
||||
}
|
||||
}
|
||||
printk(BIOS_DEBUG, "InterleaveChannels_D: Node %x\n", Node);
|
||||
printk(BIOS_DEBUG, "InterleaveChannels_D: Status %x\n", pDCTstat->Status);
|
||||
printk(BIOS_DEBUG, "InterleaveChannels_D: ErrStatus %x\n", pDCTstat->ErrStatus);
|
||||
printk(BIOS_DEBUG, "InterleaveChannels_D: ErrCode %x\n", pDCTstat->ErrCode);
|
||||
Node++;
|
||||
}
|
||||
}
|
||||
printk(BIOS_DEBUG, "InterleaveChannels_D: Done\n\n");
|
||||
}
|
143
src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
Normal file
143
src/northbridge/amd/amdmct/mct_ddr3/mctcsi_d.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* Low swap bit vs bank size encoding (physical, not logical address bit)
|
||||
* ;To calculate the number by hand, add the number of Bank address bits
|
||||
* ;(2 or 3) to the number of column address bits, plus 3 (the logical
|
||||
* ;page size), and subtract 8.
|
||||
*/
|
||||
static const u8 Tab_int_D[] = {6,7,7,8,8,8,8,8,9,9,8,9};
|
||||
|
||||
void InterleaveBanks_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u8 ChipSel, EnChipSels;
|
||||
u32 AddrLoMask, AddrHiMask;
|
||||
u32 AddrLoMaskN, AddrHiMaskN, MemSize = 0;
|
||||
u8 DoIntlv, _CsIntCap;
|
||||
u32 BitDelta, BankEncd = 0;
|
||||
|
||||
u32 dev;
|
||||
u32 reg;
|
||||
u32 reg_off;
|
||||
u32 val;
|
||||
u32 val_lo, val_hi;
|
||||
|
||||
DoIntlv = mctGet_NVbits(NV_BankIntlv);
|
||||
_CsIntCap = 0;
|
||||
EnChipSels = 0;
|
||||
|
||||
dev = pDCTstat->dev_dct;
|
||||
reg_off = 0x100 * dct;
|
||||
|
||||
ChipSel = 0; /* Find out if current configuration is capable */
|
||||
while (DoIntlv && (ChipSel < MAX_CS_SUPPORTED)) {
|
||||
reg = 0x40+(ChipSel<<2) + reg_off; /* Dram CS Base 0 */
|
||||
val = Get_NB32(dev, reg);
|
||||
if ( val & (1<<CSEnable)) {
|
||||
EnChipSels++;
|
||||
reg = 0x60+((ChipSel>>1)<<2)+reg_off; /*Dram CS Mask 0 */
|
||||
val = Get_NB32(dev, reg);
|
||||
val >>= 19;
|
||||
val &= 0x3ff;
|
||||
val++;
|
||||
if (EnChipSels == 1)
|
||||
MemSize = val;
|
||||
else
|
||||
/*If mask sizes not same then skip */
|
||||
if (val != MemSize)
|
||||
break;
|
||||
reg = 0x80 + reg_off; /*Dram Bank Addressing */
|
||||
val = Get_NB32(dev, reg);
|
||||
val >>= (ChipSel>>1)<<2;
|
||||
val &= 0x0f;
|
||||
if(EnChipSels == 1)
|
||||
BankEncd = val;
|
||||
else
|
||||
/*If number of Rows/Columns not equal, skip */
|
||||
if (val != BankEncd)
|
||||
break;
|
||||
}
|
||||
ChipSel++;
|
||||
}
|
||||
if (ChipSel == MAX_CS_SUPPORTED) {
|
||||
if ((EnChipSels == 2) || (EnChipSels == 4) || (EnChipSels == 8))
|
||||
_CsIntCap = 1;
|
||||
}
|
||||
|
||||
if (DoIntlv) {
|
||||
if(!_CsIntCap) {
|
||||
pDCTstat->ErrStatus |= 1<<SB_BkIntDis;
|
||||
DoIntlv = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(DoIntlv) {
|
||||
val = Tab_int_D[BankEncd];
|
||||
if (pDCTstat->Status & (1<<SB_128bitmode))
|
||||
val++;
|
||||
|
||||
AddrLoMask = (EnChipSels - 1) << val;
|
||||
AddrLoMaskN = ~AddrLoMask;
|
||||
|
||||
val = bsf(MemSize) + 19;
|
||||
AddrHiMask = (EnChipSels -1) << val;
|
||||
AddrHiMaskN = ~AddrHiMask;
|
||||
|
||||
BitDelta = bsf(AddrHiMask) - bsf(AddrLoMask);
|
||||
|
||||
for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel++) {
|
||||
reg = 0x40+(ChipSel<<2) + reg_off; /*Dram CS Base 0 */
|
||||
val = Get_NB32(dev, reg);
|
||||
if (val & 3) {
|
||||
val_lo = val & AddrLoMask;
|
||||
val_hi = val & AddrHiMask;
|
||||
val &= AddrLoMaskN;
|
||||
val &= AddrHiMaskN;
|
||||
val_lo <<= BitDelta;
|
||||
val_hi >>= BitDelta;
|
||||
val |= val_lo;
|
||||
val |= val_hi;
|
||||
Set_NB32(dev, reg, val);
|
||||
|
||||
if(ChipSel & 1)
|
||||
continue;
|
||||
|
||||
reg = 0x60 + ((ChipSel>>1)<<2) + reg_off; /*Dram CS Mask 0 */
|
||||
val = Get_NB32(dev, reg);
|
||||
val_lo = val & AddrLoMask;
|
||||
val_hi = val & AddrHiMask;
|
||||
val &= AddrLoMaskN;
|
||||
val &= AddrHiMaskN;
|
||||
val_lo <<= BitDelta;
|
||||
val_hi >>= BitDelta;
|
||||
val |= val_lo;
|
||||
val |= val_hi;
|
||||
Set_NB32(dev, reg, val);
|
||||
}
|
||||
}
|
||||
} /* DoIntlv */
|
||||
|
||||
/* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */
|
||||
|
||||
printk(BIOS_DEBUG, "InterleaveBanks_D: Status %x\n", pDCTstat->Status);
|
||||
printk(BIOS_DEBUG, "InterleaveBanks_D: ErrStatus %x\n", pDCTstat->ErrStatus);
|
||||
printk(BIOS_DEBUG, "InterleaveBanks_D: ErrCode %x\n", pDCTstat->ErrCode);
|
||||
printk(BIOS_DEBUG, "InterleaveBanks_D: Done\n\n");
|
||||
}
|
1312
src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
Normal file
1312
src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
Normal file
File diff suppressed because it is too large
Load Diff
268
src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
Normal file
268
src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "mct_d.h"
|
||||
|
||||
static void setSyncOnUnEccEn_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstatA);
|
||||
static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat);
|
||||
|
||||
/* Initialize ECC modes of Integrated Dram+Memory Controllers of a network of
|
||||
* Hammer processors. Use Dram background scrubber to fast initialize ECC bits
|
||||
* of all dram.
|
||||
*
|
||||
* Notes:
|
||||
*
|
||||
* Order that items are set:
|
||||
* 1. eccen bit in NB
|
||||
* 2. Scrub Base
|
||||
* 3. Temp Node Base
|
||||
* 4. Temp Node Limit
|
||||
* 5. Redir bit in NB
|
||||
* 6. Scrub CTL
|
||||
*
|
||||
* Conditions for setting background scrubber.
|
||||
* 1. node is present
|
||||
* 2. node has dram functioning (WE=RE=1)
|
||||
* 3. all eccdimms (or bit 17 of offset 90,fn 2)
|
||||
* 4. no chip-select gap exists
|
||||
*
|
||||
* The dram background scrubber is used under very controlled circumstances to
|
||||
* initialize all the ECC bits on the DIMMs of the entire dram address map
|
||||
* (including hidden or lost dram and dram above 4GB). We will turn the scrub
|
||||
* rate up to maximum, which should clear 4GB of dram in about 2.7 seconds.
|
||||
* We will activate the scrubbers of all nodes with ecc dram and let them run in
|
||||
* parallel, thereby reducing even further the time required to condition dram.
|
||||
* Finally, we will go through each node and either disable background scrubber,
|
||||
* or set the scrub rate to the user setup specified rate.
|
||||
*
|
||||
* To allow the NB to scrub, we need to wait a time period long enough to
|
||||
* guarantee that the NB scrubs the entire dram on its node. Do do this, we
|
||||
* simply sample the scrub ADDR once, for an initial value, then we sample and poll until the polled value of scrub ADDR
|
||||
* has wrapped around at least once: Scrub ADDRi+1 < Scrub ADDRi. Since we let all
|
||||
* Nodes run in parallel, we need to gaurantee that all nodes have wrapped. To do
|
||||
* this efficiently, we need only to sample one of the nodes, the node with the
|
||||
* largest ammount of dram populated is the one which will take the longest amount
|
||||
* of time (the scrub rate is set to max, the same rate, on all nodes). So,
|
||||
* during setup of scrub Base, we determine how much memory and which node has
|
||||
* the largest memory installed.
|
||||
*
|
||||
* Scrubbing should not ordinarily be enabled on a Node with a chip-select gap
|
||||
* (aka SW memhole, cs hoisting, etc..).To init ECC memory on this node, the
|
||||
* scrubber is used in two steps. First, the Dram Limit for the node is adjusted
|
||||
* down to the bottom of the gap, and that ECC dram is initialized. Second, the
|
||||
* orignal Limit is restored, the Scrub base is set to 4GB, and scrubber is
|
||||
* allowed to run until the Scrub Addr wraps around to zero.
|
||||
*/
|
||||
u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
u8 Node;
|
||||
u8 AllECC;
|
||||
u16 OB_NBECC;
|
||||
u32 curBase;
|
||||
u16 OB_ECCRedir;
|
||||
u32 LDramECC;
|
||||
u32 OF_ScrubCTL;
|
||||
u16 OB_ChipKill;
|
||||
u8 MemClrECC;
|
||||
|
||||
u32 dev;
|
||||
u32 reg;
|
||||
u32 val;
|
||||
u16 nvbits;
|
||||
|
||||
mctHookBeforeECC();
|
||||
|
||||
/* Construct these booleans, based on setup options, for easy handling
|
||||
later in this procedure */
|
||||
OB_NBECC = mctGet_NVbits(NV_NBECC); /* MCA ECC (MCE) enable bit */
|
||||
|
||||
OB_ECCRedir = mctGet_NVbits(NV_ECCRedir); /* ECC Redirection */
|
||||
|
||||
OB_ChipKill = mctGet_NVbits(NV_ChipKill); /* ECC Chip-kill mode */
|
||||
|
||||
OF_ScrubCTL = 0; /* Scrub CTL for Dcache, L2, and dram */
|
||||
nvbits = mctGet_NVbits(NV_DCBKScrub);
|
||||
/* mct_AdjustScrub_D(pDCTstatA, &nvbits); */ /* Need not adjust */
|
||||
OF_ScrubCTL |= (u32) nvbits << 16;
|
||||
|
||||
nvbits = mctGet_NVbits(NV_L2BKScrub);
|
||||
OF_ScrubCTL |= (u32) nvbits << 8;
|
||||
|
||||
nvbits = mctGet_NVbits(NV_DramBKScrub);
|
||||
OF_ScrubCTL |= nvbits;
|
||||
|
||||
AllECC = 1;
|
||||
MemClrECC = 0;
|
||||
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
||||
struct DCTStatStruc *pDCTstat;
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
LDramECC = 0;
|
||||
if (NodePresent_D(Node)) { /*If Node is present */
|
||||
dev = pDCTstat->dev_map;
|
||||
reg = 0x40+(Node << 3); /* Dram Base Node 0 + index */
|
||||
val = Get_NB32(dev, reg);
|
||||
|
||||
/* WE/RE is checked */
|
||||
if((val & 3)==3) { /* Node has dram populated */
|
||||
/* Negate 'all nodes/dimms ECC' flag if non ecc
|
||||
memory populated */
|
||||
if( pDCTstat->Status & (1<<SB_ECCDIMMs)) {
|
||||
LDramECC = isDramECCEn_D(pDCTstat);
|
||||
if(pDCTstat->ErrCode != SC_RunningOK) {
|
||||
pDCTstat->Status &= ~(1 << SB_ECCDIMMs);
|
||||
if (OB_NBECC) {
|
||||
pDCTstat->ErrStatus |= (1 << SB_DramECCDis);
|
||||
}
|
||||
AllECC = 0;
|
||||
LDramECC =0;
|
||||
}
|
||||
} else {
|
||||
AllECC = 0;
|
||||
}
|
||||
if(LDramECC) { /* if ECC is enabled on this dram */
|
||||
if (OB_NBECC) {
|
||||
mct_EnableDatIntlv_D(pMCTstat, pDCTstat);
|
||||
dev = pDCTstat->dev_nbmisc;
|
||||
reg =0x44; /* MCA NB Configuration */
|
||||
val = Get_NB32(dev, reg);
|
||||
val |= 1 << 22; /* EccEn */
|
||||
Set_NB32(dev, reg, val);
|
||||
DCTMemClr_Init_D(pMCTstat, pDCTstat);
|
||||
MemClrECC = 1;
|
||||
}
|
||||
} /* this node has ECC enabled dram */
|
||||
} else {
|
||||
LDramECC = 0;
|
||||
} /* Node has Dram */
|
||||
|
||||
if (MemClrECC) {
|
||||
MCTMemClrSync_D(pMCTstat, pDCTstatA);
|
||||
}
|
||||
} /* if Node present */
|
||||
}
|
||||
|
||||
if(AllECC)
|
||||
pMCTstat->GStatus |= 1<<GSB_ECCDIMMs;
|
||||
else
|
||||
pMCTstat->GStatus &= ~(1<<GSB_ECCDIMMs);
|
||||
|
||||
/* Program the Dram BKScrub CTL to the proper (user selected) value.*/
|
||||
/* Reset MC4_STS. */
|
||||
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
||||
struct DCTStatStruc *pDCTstat;
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
LDramECC = 0;
|
||||
if (NodePresent_D(Node)) { /* If Node is present */
|
||||
reg = 0x40+(Node<<3); /* Dram Base Node 0 + index */
|
||||
val = Get_NB32(pDCTstat->dev_map, reg);
|
||||
curBase = val & 0xffff0000;
|
||||
/*WE/RE is checked because memory config may have been */
|
||||
if((val & 3)==3) { /* Node has dram populated */
|
||||
if (isDramECCEn_D(pDCTstat)) { /* if ECC is enabled on this dram */
|
||||
dev = pDCTstat->dev_nbmisc;
|
||||
val = curBase << 8;
|
||||
if(OB_ECCRedir) {
|
||||
val |= (1<<0); /* enable redirection */
|
||||
}
|
||||
Set_NB32(dev, 0x5C, val); /* Dram Scrub Addr Low */
|
||||
val = curBase>>24;
|
||||
Set_NB32(dev, 0x60, val); /* Dram Scrub Addr High */
|
||||
Set_NB32(dev, 0x58, OF_ScrubCTL); /*Scrub Control */
|
||||
|
||||
/* Divisor should not be set deeper than
|
||||
* divide by 16 when Dcache scrubber or
|
||||
* L2 scrubber is enabled.
|
||||
*/
|
||||
if ((OF_ScrubCTL & (0x1F << 16)) || (OF_ScrubCTL & (0x1F << 8))) {
|
||||
val = Get_NB32(dev, 0x84);
|
||||
if ((val & 0xE0000000) > 0x80000000) { /* Get F3x84h[31:29]ClkDivisor for C1 */
|
||||
val &= 0x1FFFFFFF; /* If ClkDivisor is deeper than divide-by-16 */
|
||||
val |= 0x80000000; /* set it to divide-by-16 */
|
||||
Set_NB32(dev, 0x84, val);
|
||||
}
|
||||
}
|
||||
} /* this node has ECC enabled dram */
|
||||
} /*Node has Dram */
|
||||
} /*if Node present */
|
||||
}
|
||||
|
||||
if(mctGet_NVbits(NV_SyncOnUnEccEn))
|
||||
setSyncOnUnEccEn_D(pMCTstat, pDCTstatA);
|
||||
|
||||
mctHookAfterECC();
|
||||
return MemClrECC;
|
||||
}
|
||||
|
||||
static void setSyncOnUnEccEn_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
u32 Node;
|
||||
u32 reg;
|
||||
u32 dev;
|
||||
u32 val;
|
||||
|
||||
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
||||
struct DCTStatStruc *pDCTstat;
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
if (NodePresent_D(Node)) { /* If Node is present*/
|
||||
reg = 0x40+(Node<<3); /* Dram Base Node 0 + index*/
|
||||
val = Get_NB32(pDCTstat->dev_map, reg);
|
||||
/*WE/RE is checked because memory config may have been*/
|
||||
if((val & 3)==3) { /* Node has dram populated*/
|
||||
if( isDramECCEn_D(pDCTstat)) {
|
||||
/*if ECC is enabled on this dram*/
|
||||
dev = pDCTstat->dev_nbmisc;
|
||||
reg = 0x44; /* MCA NB Configuration*/
|
||||
val = Get_NB32(dev, reg);
|
||||
val |= (1<<SyncOnUcEccEn);
|
||||
Set_NB32(dev, reg, val);
|
||||
}
|
||||
} /* Node has Dram*/
|
||||
} /* if Node present*/
|
||||
}
|
||||
}
|
||||
|
||||
static u8 isDramECCEn_D(struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u32 reg;
|
||||
u32 val;
|
||||
u8 i;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u8 ch_end;
|
||||
u8 isDimmECCEn = 0;
|
||||
|
||||
if(pDCTstat->GangedMode) {
|
||||
ch_end = 1;
|
||||
} else {
|
||||
ch_end = 2;
|
||||
}
|
||||
for(i=0; i<ch_end; i++) {
|
||||
if(pDCTstat->DIMMValidDCT[i] > 0){
|
||||
reg = 0x90 + i * 0x100; /* Dram Config Low */
|
||||
val = Get_NB32(dev, reg);
|
||||
if(val & (1<<DimmEcEn)) {
|
||||
/* set local flag 'dram ecc capable' */
|
||||
isDimmECCEn = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return isDimmECCEn;
|
||||
}
|
32
src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
Normal file
32
src/northbridge/amd/amdmct/mct_ddr3/mcthdi.c
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
void mct_DramInit_Hw_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u32 val;
|
||||
u32 reg;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
|
||||
/*flag for selecting HW/SW DRAM Init HW DRAM Init */
|
||||
reg = 0x90 + 0x100 * dct; /*DRAM Configuration Low */
|
||||
val = Get_NB32(dev, reg);
|
||||
val |= (1<<InitDram);
|
||||
Set_NB32(dev, reg, val);
|
||||
}
|
217
src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
Normal file
217
src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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 void SetTargetFreq(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat);
|
||||
static void AgesaHwWlPhase1(sMCTStruct *pMCTData,
|
||||
sDCTStruct *pDCTData, u8 dimm, u8 pass);
|
||||
static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
static void DisableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
static void PrepareC_MCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
static void PrepareC_DCT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
|
||||
static void MultiplyDelay(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct);
|
||||
static void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
static void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
|
||||
|
||||
static void SetEccWrDQS_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u8 ByteLane, DimmNum, OddByte, Addl_Index, Channel;
|
||||
u8 EccRef1, EccRef2, EccDQSScale;
|
||||
u32 val;
|
||||
u16 word;
|
||||
|
||||
for (Channel = 0; Channel < 2; Channel ++) {
|
||||
for (DimmNum = 0; DimmNum < C_MAX_DIMMS; DimmNum ++) { /* we use DimmNum instead of DimmNumx3 */
|
||||
for (ByteLane = 0; ByteLane < 9; ByteLane ++) {
|
||||
/* Get RxEn initial value from WrDqs */
|
||||
if (ByteLane & 1)
|
||||
OddByte = 1;
|
||||
else
|
||||
OddByte = 0;
|
||||
if (ByteLane < 2)
|
||||
Addl_Index = 0x30;
|
||||
else if (ByteLane < 4)
|
||||
Addl_Index = 0x31;
|
||||
else if (ByteLane < 6)
|
||||
Addl_Index = 0x40;
|
||||
else if (ByteLane < 8)
|
||||
Addl_Index = 0x41;
|
||||
else
|
||||
Addl_Index = 0x32;
|
||||
Addl_Index += DimmNum * 3;
|
||||
|
||||
val = Get_NB32_index_wait(pDCTstat->dev_dct, Channel * 0x100 + 0x98, Addl_Index);
|
||||
if (OddByte)
|
||||
val >>= 16;
|
||||
/* Save WrDqs to stack for later usage */
|
||||
pDCTstat->CH_D_B_TxDqs[Channel][DimmNum][ByteLane] = val & 0xFF;
|
||||
EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
|
||||
word = pDCTstat->CH_EccDQSLike[Channel];
|
||||
if ((word & 0xFF) == ByteLane) EccRef1 = val & 0xFF;
|
||||
if (((word >> 8) & 0xFF) == ByteLane) EccRef2 = val & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void EnableAutoRefresh_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x8C);
|
||||
val &= ~(1 << DisAutoRefresh);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x8C, val);
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
|
||||
val &= ~(1 << DisAutoRefresh);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
|
||||
}
|
||||
|
||||
static void DisableAutoRefresh_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x8C);
|
||||
val |= 1 << DisAutoRefresh;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x8C, val);
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x8C + 0x100);
|
||||
val |= 1 << DisAutoRefresh;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x8C + 0x100, val);
|
||||
}
|
||||
|
||||
|
||||
static void PhyWLPass1(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u8 dimm;
|
||||
u16 DIMMValid;
|
||||
void *DCTPtr;
|
||||
|
||||
dct &= 1;
|
||||
|
||||
DCTPtr = (void *)(pDCTstat->C_DCTPtr[dct]);
|
||||
pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
|
||||
pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
|
||||
|
||||
if (pDCTstat->GangedMode & 1)
|
||||
pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
|
||||
|
||||
if (pDCTstat->DIMMValid) {
|
||||
DIMMValid = pDCTstat->DIMMValid;
|
||||
PrepareC_DCT(pMCTstat, pDCTstat, dct);
|
||||
for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
|
||||
if (DIMMValid & (1 << (dimm << 1)))
|
||||
AgesaHwWlPhase1(pDCTstat->C_MCTPtr, DCTPtr, dimm, FirstPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PhyWLPass2(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u8 dimm;
|
||||
u16 DIMMValid;
|
||||
void *DCTPtr;
|
||||
|
||||
dct &= 1;
|
||||
|
||||
DCTPtr = (void *)&(pDCTstat->C_DCTPtr[dct]); /* todo: */
|
||||
pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct];
|
||||
pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
|
||||
|
||||
if (pDCTstat->GangedMode & 1)
|
||||
pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
|
||||
|
||||
if (pDCTstat->DIMMValid) {
|
||||
DIMMValid = pDCTstat->DIMMValid;
|
||||
PrepareC_DCT(pMCTstat, pDCTstat, dct);
|
||||
pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
|
||||
pDCTstat->CASL = pDCTstat->DIMMCASL = pDCTstat->TargetCASL;
|
||||
SPD2ndTiming(pMCTstat, pDCTstat, dct);
|
||||
ProgDramMRSReg_D(pMCTstat, pDCTstat, dct);
|
||||
PlatformSpec_D(pMCTstat, pDCTstat, dct);
|
||||
fenceDynTraining_D(pMCTstat, pDCTstat, dct);
|
||||
Restore_OnDimmMirror(pMCTstat, pDCTstat);
|
||||
StartupDCT_D(pMCTstat, pDCTstat, dct);
|
||||
Clear_OnDimmMirror(pMCTstat, pDCTstat);
|
||||
SetDllSpeedUp_D(pMCTstat, pDCTstat, dct);
|
||||
DisableAutoRefresh_D(pMCTstat, pDCTstat);
|
||||
MultiplyDelay(pMCTstat, pDCTstat, dct);
|
||||
for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm ++) {
|
||||
if (DIMMValid & (1 << (dimm << 1)))
|
||||
AgesaHwWlPhase1(pDCTstat->C_MCTPtr, pDCTstat->C_DCTPtr[dct], dimm, SecondPass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
pDCTstat->C_MCTPtr = &(pDCTstat->s_C_MCTPtr);
|
||||
pDCTstat->C_DCTPtr[0] = &(pDCTstat->s_C_DCTPtr[0]);
|
||||
pDCTstat->C_DCTPtr[1] = &(pDCTstat->s_C_DCTPtr[1]);
|
||||
|
||||
/* Disable auto refresh by configuring F2x[1, 0]8C[DisAutoRefresh] = 1 */
|
||||
DisableAutoRefresh_D(pMCTstat, pDCTstat);
|
||||
|
||||
/* Disable ZQ calibration short command by F2x[1,0]94[ZqcsInterval]=00b */
|
||||
DisableZQcalibration(pMCTstat, pDCTstat);
|
||||
PrepareC_MCT(pMCTstat, pDCTstat);
|
||||
|
||||
if (pDCTstat->GangedMode & (1 << 0)) {
|
||||
pDCTstat->DIMMValidDCT[1] = pDCTstat->DIMMValidDCT[0];
|
||||
}
|
||||
|
||||
PhyWLPass1(pMCTstat, pDCTstat, 0);
|
||||
PhyWLPass1(pMCTstat, pDCTstat, 1);
|
||||
|
||||
if (pDCTstat->TargetFreq > 4) {
|
||||
/* 8.Prepare the memory subsystem for the target MEMCLK frequency.
|
||||
* Note: BIOS must program both DCTs to the same frequency.
|
||||
*/
|
||||
SetTargetFreq(pMCTstat, pDCTstat);
|
||||
PhyWLPass2(pMCTstat, pDCTstat, 0);
|
||||
PhyWLPass2(pMCTstat, pDCTstat, 1);
|
||||
|
||||
}
|
||||
|
||||
SetEccWrDQS_D(pMCTstat, pDCTstat);
|
||||
EnableAutoRefresh_D(pMCTstat, pDCTstat);
|
||||
EnableZQcalibration(pMCTstat, pDCTstat);
|
||||
}
|
||||
|
||||
void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
u8 Node;
|
||||
|
||||
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
||||
struct DCTStatStruc *pDCTstat;
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
|
||||
if (pDCTstat->NodePresent) {
|
||||
mctSMBhub_Init(Node);
|
||||
Clear_OnDimmMirror(pMCTstat, pDCTstat);
|
||||
WriteLevelization_HW(pMCTstat, pDCTstat);
|
||||
Restore_OnDimmMirror(pMCTstat, pDCTstat);
|
||||
}
|
||||
}
|
||||
}
|
252
src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
Normal file
252
src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "mct_d.h"
|
||||
|
||||
static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr);
|
||||
static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType);
|
||||
|
||||
void CPUMemTyping_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
/* BSP only. Set the fixed MTRRs for common legacy ranges.
|
||||
* Set TOP_MEM and TOM2.
|
||||
* Set some variable MTRRs with WB Uncacheable type.
|
||||
*/
|
||||
|
||||
u32 Bottom32bIO, Bottom40bIO, Cache32bTOP;
|
||||
u32 val;
|
||||
u32 addr;
|
||||
u32 lo, hi;
|
||||
|
||||
/* Set temporary top of memory from Node structure data.
|
||||
* Adjust temp top of memory down to accomodate 32-bit IO space.
|
||||
* Bottom40bIO=top of memory, right justified 8 bits
|
||||
* (defines dram versus IO space type)
|
||||
* Bottom32bIO=sub 4GB top of memory, right justified 8 bits
|
||||
* (defines dram versus IO space type)
|
||||
* Cache32bTOP=sub 4GB top of WB cacheable memory,
|
||||
* right justified 8 bits
|
||||
*/
|
||||
|
||||
val = mctGet_NVbits(NV_BottomIO);
|
||||
if(val == 0)
|
||||
val++;
|
||||
|
||||
Bottom32bIO = val << (24-8);
|
||||
|
||||
val = pMCTstat->SysLimit + 1;
|
||||
if(val <= _4GB_RJ8) {
|
||||
Bottom40bIO = 0;
|
||||
if(Bottom32bIO >= val)
|
||||
Bottom32bIO = val;
|
||||
} else {
|
||||
Bottom40bIO = val;
|
||||
}
|
||||
|
||||
Cache32bTOP = Bottom32bIO;
|
||||
|
||||
/*======================================================================
|
||||
Set default values for CPU registers
|
||||
======================================================================*/
|
||||
|
||||
/* NOTE : For coreboot, we don't need to set mtrr enables here because
|
||||
they are still enable from cache_as_ram.inc */
|
||||
|
||||
addr = 0x250;
|
||||
lo = 0x1E1E1E1E;
|
||||
hi = lo;
|
||||
_WRMSR(addr, lo, hi); /* 0 - 512K = WB Mem */
|
||||
addr = 0x258;
|
||||
_WRMSR(addr, lo, hi); /* 512K - 640K = WB Mem */
|
||||
|
||||
/*======================================================================
|
||||
Set variable MTRR values
|
||||
======================================================================*/
|
||||
/* NOTE: for coreboot change from 0x200 to 0x204: coreboot is using
|
||||
0x200, 0x201 for [1M, CONFIG_TOP_MEM)
|
||||
0x202, 0x203 for ROM Caching
|
||||
*/
|
||||
addr = 0x204; /* MTRR phys base 2*/
|
||||
/* use TOP_MEM as limit*/
|
||||
/* Limit=TOP_MEM|TOM2*/
|
||||
/* Base=0*/
|
||||
printk(BIOS_DEBUG, "\t CPUMemTyping: Cache32bTOP:%x\n", Cache32bTOP);
|
||||
SetMTRRrangeWB_D(0, &Cache32bTOP, &addr);
|
||||
/* Base */
|
||||
/* Limit */
|
||||
/* MtrrAddr */
|
||||
if(addr == -1) /* ran out of MTRRs?*/
|
||||
pMCTstat->GStatus |= 1<<GSB_MTRRshort;
|
||||
|
||||
pMCTstat->Sub4GCacheTop = Cache32bTOP<<8;
|
||||
|
||||
/*======================================================================
|
||||
Set TOP_MEM and TOM2 CPU registers
|
||||
======================================================================*/
|
||||
addr = TOP_MEM;
|
||||
lo = Bottom32bIO<<8;
|
||||
hi = Bottom32bIO>>24;
|
||||
_WRMSR(addr, lo, hi);
|
||||
printk(BIOS_DEBUG, "\t CPUMemTyping: Bottom32bIO:%x\n", Bottom32bIO);
|
||||
printk(BIOS_DEBUG, "\t CPUMemTyping: Bottom40bIO:%x\n", Bottom40bIO);
|
||||
if(Bottom40bIO) {
|
||||
hi = Bottom40bIO >> 24;
|
||||
lo = Bottom40bIO << 8;
|
||||
addr += 3; /* TOM2 */
|
||||
_WRMSR(addr, lo, hi);
|
||||
}
|
||||
addr = 0xC0010010; /* SYS_CFG */
|
||||
_RDMSR(addr, &lo, &hi);
|
||||
if(Bottom40bIO) {
|
||||
lo |= (1<<21); /* MtrrTom2En=1 */
|
||||
lo |= (1<<22); /* Tom2ForceMemTypeWB */
|
||||
} else {
|
||||
lo &= ~(1<<21); /* MtrrTom2En=0 */
|
||||
lo &= ~(1<<22); /* Tom2ForceMemTypeWB */
|
||||
}
|
||||
_WRMSR(addr, lo, hi);
|
||||
}
|
||||
|
||||
static void SetMTRRrangeWB_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr)
|
||||
{
|
||||
/*set WB type*/
|
||||
SetMTRRrange_D(Base, pLimit, pMtrrAddr, 6);
|
||||
}
|
||||
|
||||
static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType)
|
||||
{
|
||||
/* Program MTRRs to describe given range as given cache type.
|
||||
* Use MTRR pairs starting with the given MTRRphys Base address,
|
||||
* and use as many as is required up to (excluding) MSR 020C, which
|
||||
* is reserved for OS.
|
||||
*
|
||||
* "Limit" in the context of this procedure is not the numerically
|
||||
* correct limit, but rather the Last address+1, for purposes of coding
|
||||
* efficiency and readability. Size of a region is then Limit-Base.
|
||||
*
|
||||
* 1. Size of each range must be a power of two
|
||||
* 2. Each range must be naturally aligned (Base is same as size)
|
||||
*
|
||||
* There are two code paths: the ascending path and descending path
|
||||
* (analogous to bsf and bsr), where the next limit is a funtion of the
|
||||
* next set bit in a forward or backward sequence of bits (as a function
|
||||
* of the Limit). We start with the ascending path, to ensure that
|
||||
* regions are naturally aligned, then we switch to the descending path
|
||||
* to maximize MTRR usage efficiency. Base=0 is a special case where we
|
||||
* start with the descending path. Correct Mask for region is
|
||||
* 2comp(Size-1)-1, which is 2comp(Limit-Base-1)-1
|
||||
*/
|
||||
|
||||
u32 curBase, curLimit, curSize;
|
||||
u32 val, valx;
|
||||
u32 addr;
|
||||
|
||||
val = curBase = Base;
|
||||
curLimit = *pLimit;
|
||||
addr = *pMtrrAddr;
|
||||
while((addr >= 0x200) && (addr < 0x20C) && (val < *pLimit)) {
|
||||
/* start with "ascending" code path */
|
||||
/* alignment (largest block size)*/
|
||||
valx = 1 << bsf(curBase);
|
||||
curSize = valx;
|
||||
|
||||
/* largest legal limit, given current non-zero range Base*/
|
||||
valx += curBase;
|
||||
if((curBase == 0) || (*pLimit < valx)) {
|
||||
/* flop direction to "descending" code path*/
|
||||
valx = 1<<bsr(*pLimit - curBase);
|
||||
curSize = valx;
|
||||
valx += curBase;
|
||||
}
|
||||
curLimit = valx; /*eax=curBase, edx=curLimit*/
|
||||
valx = val>>24;
|
||||
val <<= 8;
|
||||
|
||||
/* now program the MTRR */
|
||||
val |= MtrrType; /* set cache type (UC or WB)*/
|
||||
_WRMSR(addr, val, valx); /* prog. MTRR with current region Base*/
|
||||
val = ((~(curSize - 1))+1) - 1; /* Size-1*/ /*Mask=2comp(Size-1)-1*/
|
||||
valx = (val >> 24) | (0xff00); /* GH have 48 bits addr */
|
||||
val <<= 8;
|
||||
val |= ( 1 << 11); /* set MTRR valid*/
|
||||
addr++;
|
||||
_WRMSR(addr, val, valx); /* prog. MTRR with current region Mask*/
|
||||
val = curLimit;
|
||||
curBase = val; /* next Base = current Limit (loop exit)*/
|
||||
addr++; /* next MTRR pair addr */
|
||||
}
|
||||
if(val < *pLimit) {
|
||||
*pLimit = val;
|
||||
addr = -1;
|
||||
}
|
||||
*pMtrrAddr = addr;
|
||||
}
|
||||
|
||||
void UMAMemTyping_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
/* UMA memory size may need splitting the MTRR configuration into two
|
||||
Before training use NB_BottomIO or the physical memory size to set the MTRRs.
|
||||
After training, add UMAMemTyping function to reconfigure the MTRRs based on
|
||||
NV_BottomUMA (for UMA systems only).
|
||||
This two-step process allows all memory to be cached for training
|
||||
*/
|
||||
u32 Bottom32bIO, Cache32bTOP;
|
||||
u32 val;
|
||||
u32 addr;
|
||||
u32 lo, hi;
|
||||
|
||||
/*======================================================================
|
||||
* Adjust temp top of memory down to accomodate UMA memory start
|
||||
*======================================================================*/
|
||||
/* Bottom32bIO=sub 4GB top of memory, right justified 8 bits
|
||||
* (defines dram versus IO space type)
|
||||
* Cache32bTOP=sub 4GB top of WB cacheable memory, right justified 8 bits */
|
||||
|
||||
Bottom32bIO = pMCTstat->Sub4GCacheTop >> 8;
|
||||
|
||||
val = mctGet_NVbits(NV_BottomUMA);
|
||||
if (val == 0)
|
||||
val++;
|
||||
|
||||
val <<= (24-8);
|
||||
if (val < Bottom32bIO) {
|
||||
Cache32bTOP = val;
|
||||
pMCTstat->Sub4GCacheTop = val;
|
||||
|
||||
/*======================================================================
|
||||
* Clear variable MTRR values
|
||||
*======================================================================*/
|
||||
addr = 0x200;
|
||||
lo = 0;
|
||||
hi = lo;
|
||||
while( addr < 0x20C) {
|
||||
_WRMSR(addr, lo, hi); /* prog. MTRR with current region Mask */
|
||||
addr++; /* next MTRR pair addr */
|
||||
}
|
||||
|
||||
/*======================================================================
|
||||
* Set variable MTRR values
|
||||
*======================================================================*/
|
||||
printk(BIOS_DEBUG, "\t UMAMemTyping_D: Cache32bTOP:%x\n", Cache32bTOP);
|
||||
SetMTRRrangeWB_D(0, &Cache32bTOP, &addr);
|
||||
if(addr == -1) /* ran out of MTRRs?*/
|
||||
pMCTstat->GStatus |= 1<<GSB_MTRRshort;
|
||||
}
|
||||
}
|
230
src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
Normal file
230
src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
void InterleaveNodes_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
/* Applies Node memory interleaving if enabled and if all criteria are met. */
|
||||
u8 Node;
|
||||
u32 Base;
|
||||
u32 MemSize, MemSize0 = 0;
|
||||
u32 Dct0MemSize = 0, DctSelBase, DctSelBaseOffset;
|
||||
u8 Nodes;
|
||||
u8 NodesWmem;
|
||||
u8 DoIntlv;
|
||||
u8 _NdIntCap;
|
||||
u8 _SWHole;
|
||||
u32 HWHoleSz;
|
||||
u32 DramHoleAddrReg;
|
||||
u32 HoleBase;
|
||||
u32 dev0;
|
||||
u32 reg0;
|
||||
u32 val;
|
||||
u8 i;
|
||||
struct DCTStatStruc *pDCTstat;
|
||||
|
||||
DoIntlv = mctGet_NVbits(NV_NodeIntlv);
|
||||
|
||||
_NdIntCap = 0;
|
||||
HWHoleSz = 0; /*For HW remapping, NOT Node hoisting. */
|
||||
|
||||
pDCTstat = pDCTstatA + 0;
|
||||
dev0 = pDCTstat->dev_host;
|
||||
Nodes = ((Get_NB32(dev0, 0x60) >> 4) & 0x7) + 1;
|
||||
|
||||
dev0 = pDCTstat->dev_map;
|
||||
reg0 = 0x40;
|
||||
|
||||
NodesWmem = 0;
|
||||
Node = 0;
|
||||
|
||||
while (DoIntlv && (Node < Nodes)) {
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
if (pMCTstat->GStatus & (1 << GSB_SpIntRemapHole)) {
|
||||
pMCTstat->GStatus |= 1 << GSB_HWHole;
|
||||
_SWHole = 0;
|
||||
} else if (pDCTstat->Status & (1 << SB_SWNodeHole)) {
|
||||
_SWHole = 1;
|
||||
} else {
|
||||
_SWHole = 0;
|
||||
}
|
||||
|
||||
if(!_SWHole) {
|
||||
Base = Get_NB32(dev0, reg0);
|
||||
if (Base & 1) {
|
||||
NodesWmem++;
|
||||
Base &= 0xFFFF0000; /* Base[39:8] */
|
||||
|
||||
if (pDCTstat->Status & (1 << SB_HWHole )) {
|
||||
|
||||
/* to get true amount of dram,
|
||||
* subtract out memory hole if HW dram remapping */
|
||||
DramHoleAddrReg = Get_NB32(pDCTstat->dev_map, 0xF0);
|
||||
HWHoleSz = DramHoleAddrReg >> 16;
|
||||
HWHoleSz = (((~HWHoleSz) + 1) & 0xFF);
|
||||
HWHoleSz <<= 24-8;
|
||||
}
|
||||
/* check to see if the amount of memory on each channel
|
||||
* are the same on all nodes */
|
||||
|
||||
DctSelBase = Get_NB32(pDCTstat->dev_dct, 0x114);
|
||||
if(DctSelBase) {
|
||||
DctSelBase <<= 8;
|
||||
if ( pDCTstat->Status & (1 << SB_HWHole)) {
|
||||
if (DctSelBase >= 0x1000000) {
|
||||
DctSelBase -= HWHoleSz;
|
||||
}
|
||||
}
|
||||
DctSelBaseOffset -= Base;
|
||||
if (Node == 0) {
|
||||
Dct0MemSize = DctSelBase;
|
||||
} else if (DctSelBase != Dct0MemSize) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MemSize = Get_NB32(dev0, reg0 + 4);
|
||||
MemSize &= 0xFFFF0000;
|
||||
MemSize += 0x00010000;
|
||||
MemSize -= Base;
|
||||
if ( pDCTstat->Status & (1 << SB_HWHole)) {
|
||||
MemSize -= HWHoleSz;
|
||||
}
|
||||
if (Node == 0) {
|
||||
MemSize0 = MemSize;
|
||||
} else if (MemSize0 != MemSize) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
Node++;
|
||||
reg0 += 8;
|
||||
}
|
||||
|
||||
if (Node == Nodes) {
|
||||
/* if all nodes have memory and no Node had SW memhole */
|
||||
if (Nodes == 2 || Nodes == 4 || Nodes == 8)
|
||||
_NdIntCap = 1;
|
||||
}
|
||||
|
||||
if (!_NdIntCap)
|
||||
DoIntlv = 0;
|
||||
|
||||
if (pMCTstat->GStatus & 1 << (GSB_SpIntRemapHole)) {
|
||||
HWHoleSz = pMCTstat->HoleBase;
|
||||
if (HWHoleSz == 0) {
|
||||
HWHoleSz = mctGet_NVbits(NV_BottomIO) & 0xFF;
|
||||
HWHoleSz <<= 24-8;
|
||||
}
|
||||
HWHoleSz = ((~HWHoleSz) + 1) & 0x00FF0000;
|
||||
}
|
||||
|
||||
if (DoIntlv) {
|
||||
MCTMemClr_D(pMCTstat,pDCTstatA);
|
||||
/* Program Interleaving enabled on Node 0 map only.*/
|
||||
MemSize0 <<= bsf(Nodes); /* MemSize=MemSize*2 (or 4, or 8) */
|
||||
Dct0MemSize <<= bsf(Nodes);
|
||||
MemSize0 += HWHoleSz;
|
||||
Base = ((Nodes - 1) << 8) | 3;
|
||||
reg0 = 0x40;
|
||||
Node = 0;
|
||||
while(Node < Nodes) {
|
||||
Set_NB32(dev0, reg0, Base);
|
||||
MemSize = MemSize0;
|
||||
MemSize--;
|
||||
MemSize &= 0xFFFF0000;
|
||||
MemSize |= Node << 8; /* set IntlvSel[2:0] field */
|
||||
MemSize |= Node; /* set DstNode[2:0] field */
|
||||
Set_NB32(dev0, reg0 + 4, MemSize0);
|
||||
reg0 += 8;
|
||||
Node++;
|
||||
}
|
||||
|
||||
/* set base/limit to F1x120/124 per Node */
|
||||
Node = 0;
|
||||
while(Node < Nodes) {
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
pDCTstat->NodeSysBase = 0;
|
||||
MemSize = MemSize0;
|
||||
MemSize -= HWHoleSz;
|
||||
MemSize--;
|
||||
pDCTstat->NodeSysLimit = MemSize;
|
||||
Set_NB32(pDCTstat->dev_map, 0x120, Node << 21);
|
||||
MemSize = MemSize0;
|
||||
MemSize--;
|
||||
MemSize >>= 19;
|
||||
val = Base;
|
||||
val &= 0x700;
|
||||
val <<= 13;
|
||||
val |= MemSize;
|
||||
Set_NB32(pDCTstat->dev_map, 0x124, val);
|
||||
|
||||
if (pMCTstat->GStatus & (1 << GSB_HWHole)) {
|
||||
HoleBase = pMCTstat->HoleBase;
|
||||
if (Dct0MemSize >= HoleBase) {
|
||||
val = HWHoleSz;
|
||||
if( Node == 0) {
|
||||
val += Dct0MemSize;
|
||||
}
|
||||
} else {
|
||||
val = HWHoleSz + Dct0MemSize;
|
||||
}
|
||||
|
||||
val >>= 8; /* DramHoleOffset */
|
||||
HoleBase <<= 8; /* DramHoleBase */
|
||||
val |= HoleBase;
|
||||
val |= 1 << DramMemHoistValid;
|
||||
val |= 1 << DramHoleValid;
|
||||
Set_NB32(pDCTstat->dev_map, 0xF0, val);
|
||||
}
|
||||
|
||||
Set_NB32(pDCTstat->dev_dct, 0x114, Dct0MemSize >> 8); /* DctSelBaseOffset */
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x110);
|
||||
val &= 0x7FF;
|
||||
val |= Dct0MemSize >> 8;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x110, val); /* DctSelBaseAddr */
|
||||
printk(BIOS_DEBUG, "InterleaveNodes: DRAM Controller Select Low Register = %x\n", val);
|
||||
Node++;
|
||||
}
|
||||
|
||||
/* Copy Node 0 into other Nodes' CSRs */
|
||||
Node = 1;
|
||||
while (Node < Nodes) {
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
|
||||
for (i = 0x40; i <= 0x80; i++) {
|
||||
val = Get_NB32(dev0, i);
|
||||
Set_NB32(pDCTstat->dev_map, i, val);
|
||||
}
|
||||
|
||||
val = Get_NB32(dev0, 0xF0);
|
||||
Set_NB32(pDCTstat->dev_map, 0xF0, val);
|
||||
Node++;
|
||||
}
|
||||
pMCTstat->GStatus = (1 << GSB_NodeIntlv);
|
||||
}
|
||||
printk(BIOS_DEBUG, "InterleaveNodes_D: Status %x\n", pDCTstat->Status);
|
||||
printk(BIOS_DEBUG, "InterleaveNodes_D: ErrStatus %x\n", pDCTstat->ErrStatus);
|
||||
printk(BIOS_DEBUG, "InterleaveNodes_D: ErrCode %x\n", pDCTstat->ErrCode);
|
||||
printk(BIOS_DEBUG, "InterleaveNodes_D: Done\n\n");
|
||||
}
|
37
src/northbridge/amd/amdmct/mct_ddr3/mctprob.c
Normal file
37
src/northbridge/amd/amdmct/mct_ddr3/mctprob.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (pDCTstat->LogicalCPUID & AMD_DR_Bx) {
|
||||
Set_NB32(pDCTstat->dev_dct, 0x98, 0x0D004007);
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x9C);
|
||||
val |= 0x3FF;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x9C, val);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x98, 0x4D0F4F07);
|
||||
|
||||
Set_NB32(pDCTstat->dev_dct, 0x198, 0x0D004007);
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x19C);
|
||||
val |= 0x3FF;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x19C, val);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x198, 0x4D0F4F07);
|
||||
}
|
||||
}
|
45
src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
Normal file
45
src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) {
|
||||
if (pDCTstat->Status & (1 << SB_Registered)) {
|
||||
misc2 |= 1 << SubMemclkRegDly;
|
||||
if (mctGet_NVbits(NV_MAX_DIMMS) == 8)
|
||||
misc2 |= 1 << Ddr3FourSocketCh;
|
||||
else
|
||||
misc2 &= ~(1 << Ddr3FourSocketCh);
|
||||
}
|
||||
|
||||
if (pDCTstat->LogicalCPUID & AMD_DR_Cx)
|
||||
misc2 |= 1 << OdtSwizzle;
|
||||
val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78);
|
||||
|
||||
val &= 7;
|
||||
val = ((~val) & 0xFF) + 1;
|
||||
val += 6;
|
||||
val &= 0xFF;
|
||||
misc2 &= 0xFFF8FFFF;
|
||||
misc2 |= val << 16; /* DataTxFifoWrDly */
|
||||
}
|
||||
return misc2;
|
||||
}
|
190
src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
Normal file
190
src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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 u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum)
|
||||
{
|
||||
u8 Dimms, DimmNum, MaxDimm, Speed;
|
||||
u32 val;
|
||||
|
||||
DimmNum = MrsChipSel >> 20;
|
||||
|
||||
/* assume dct=0; */
|
||||
/* if (dct == 1) */
|
||||
/* DimmNum ++; */
|
||||
/* cl +=8; */
|
||||
|
||||
MaxDimm = mctGet_NVbits(NV_MAX_DIMMS);
|
||||
Speed = pDCTstat->DIMMAutoSpeed;
|
||||
/* if (dct == 0) */
|
||||
Dimms = pDCTstat->MAdimms[0];
|
||||
|
||||
val = 0;
|
||||
if (CtrlWordNum == 0)
|
||||
val |= 1 << 1;
|
||||
else if (CtrlWordNum == 1) {
|
||||
if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 << DimmNum)))
|
||||
val |= 0xC; /* if single rank, set DBA1 and DBA0 */
|
||||
}
|
||||
else if (CtrlWordNum == 2) {
|
||||
if (MaxDimm == 4) {
|
||||
if (Speed == 4) {
|
||||
if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) && (Dimms == 1)) || Dimms == 2)
|
||||
if (!(pDCTstat->MirrPresU_NumRegR & (1 << DimmNum)))
|
||||
val |= 1 << 2;
|
||||
} else {
|
||||
if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
|
||||
val |= 2;
|
||||
}
|
||||
} else {
|
||||
if (Dimms > 1)
|
||||
val |= 2;
|
||||
}
|
||||
} else if (CtrlWordNum == 3) {
|
||||
val = pDCTstat->CtrlWrd3 >> (DimmNum << 2);
|
||||
} else if (CtrlWordNum == 4) {
|
||||
val = pDCTstat->CtrlWrd4 >> (DimmNum << 2);
|
||||
} else if (CtrlWordNum == 5) {
|
||||
val = pDCTstat->CtrlWrd5 >> (DimmNum << 2);
|
||||
} else if (CtrlWordNum == 8) {
|
||||
if (MaxDimm == 4)
|
||||
if (Speed == 4)
|
||||
if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
|
||||
val |= 1 << 2;
|
||||
} else if (CtrlWordNum == 9) {
|
||||
val |= 0xD; /* DBA1, DBA0, DA3 = 0 */
|
||||
}
|
||||
val &= 0xf;
|
||||
|
||||
val = MrsChipSel | ((val >> 2) & 3) << 16 | MrsChipSel | ((val >> 2) & 3);
|
||||
|
||||
/* transfer Control word number to address [BA2,A2,A1,A0] */
|
||||
if (CtrlWordNum > 7) {
|
||||
val |= 1 << 18;
|
||||
CtrlWordNum &= 7;
|
||||
}
|
||||
val |= CtrlWordNum;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u32 val)
|
||||
{
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
|
||||
val |= Get_NB32(dev, 0x7C) & ~0xFFFFFF;
|
||||
val |= 1 << SendControlWord;
|
||||
Set_NB32(dev, 0x7C, val);
|
||||
|
||||
do {
|
||||
val = Get_NB32(dev, 0x7C);
|
||||
} while (val & (1 << SendControlWord));
|
||||
}
|
||||
|
||||
void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u8 MrsChipSel;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 val, cw;
|
||||
|
||||
mct_Wait(1600);
|
||||
|
||||
mct_Wait(1200);
|
||||
|
||||
for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
|
||||
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
|
||||
val = Get_NB32(dev, 0xA8);
|
||||
val &= ~(0xF << 8);
|
||||
|
||||
switch (MrsChipSel) {
|
||||
case 0:
|
||||
case 1:
|
||||
val |= 3 << 8;
|
||||
case 2:
|
||||
case 3:
|
||||
val |= (3 << 2) << 8;
|
||||
case 4:
|
||||
case 5:
|
||||
val |= (3 << 4) << 8;
|
||||
case 6:
|
||||
case 7:
|
||||
val |= (3 << 6) << 8;
|
||||
}
|
||||
Set_NB32(dev, 0xA8, val);
|
||||
|
||||
for (cw=0; cw <=15; cw ++) {
|
||||
mct_Wait(1600);
|
||||
if (!(cw==6 || cw==7)) {
|
||||
val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, cw);
|
||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mct_Wait(1200);
|
||||
}
|
||||
|
||||
void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u32 SaveSpeed = pDCTstat->DIMMAutoSpeed;
|
||||
u32 MrsChipSel;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 val;
|
||||
|
||||
pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
|
||||
for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
|
||||
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
|
||||
val = Get_NB32(dev, 0xA8);
|
||||
val &= ~(0xFF << 8);
|
||||
val |= (0x3 << MrsChipSel) << 8;
|
||||
Set_NB32(dev, 0xA8, val);
|
||||
|
||||
mct_Wait(1600);
|
||||
switch (pDCTstat->TargetFreq) {
|
||||
case 6:
|
||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4000A);
|
||||
break;
|
||||
case 5:
|
||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40012);
|
||||
break;
|
||||
case 7:
|
||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4001A);
|
||||
break;
|
||||
}
|
||||
|
||||
mct_Wait(1600);
|
||||
|
||||
val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 2);
|
||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
|
||||
|
||||
mct_Wait(1600);
|
||||
|
||||
/* Resend control word 8 */
|
||||
val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 8);
|
||||
mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
|
||||
|
||||
mct_Wait(1600);
|
||||
}
|
||||
}
|
||||
pDCTstat->DIMMAutoSpeed = SaveSpeed;
|
||||
}
|
326
src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
Normal file
326
src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
Normal file
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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 void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct);
|
||||
|
||||
static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 val;
|
||||
|
||||
do {
|
||||
val = Get_NB32(dev, reg_off + 0x98);
|
||||
} while (!(val & (1 << DctAccessDone)));
|
||||
}
|
||||
|
||||
static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting, u8 MrsChipSel, u8 dct)
|
||||
{
|
||||
u16 word;
|
||||
u32 ret;
|
||||
|
||||
if (!(pDCTstat->Status & (1 << SB_Registered))) {
|
||||
word = pDCTstat->MirrPresU_NumRegR;
|
||||
if (dct == 0) {
|
||||
word &= 0x55;
|
||||
word <<= 1;
|
||||
} else
|
||||
word &= 0xAA;
|
||||
|
||||
if (word & (1 << MrsChipSel)) {
|
||||
/* A3<->A4,A5<->A6,A7<->A8,BA0<->BA1 */
|
||||
ret = 0;
|
||||
if (MR_register_setting & (1 << 3)) ret |= 1 << 4;
|
||||
if (MR_register_setting & (1 << 4)) ret |= 1 << 3;
|
||||
if (MR_register_setting & (1 << 5)) ret |= 1 << 6;
|
||||
if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
|
||||
if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
|
||||
if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
|
||||
if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
|
||||
if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
|
||||
MR_register_setting &= ~0x301f8;
|
||||
MR_register_setting |= ret;
|
||||
}
|
||||
}
|
||||
return MR_register_setting;
|
||||
}
|
||||
|
||||
static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
|
||||
{
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 val;
|
||||
|
||||
val = Get_NB32(dev, reg_off + 0x7C);
|
||||
val &= ~0xFFFFFF;
|
||||
val |= EMRS;
|
||||
val |= 1 << SendMrsCmd;
|
||||
Set_NB32(dev, reg_off + 0x7C, val);
|
||||
|
||||
do {
|
||||
val = Get_NB32(dev, reg_off + 0x7C);
|
||||
} while (val & (1 << SendMrsCmd));
|
||||
}
|
||||
|
||||
static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
|
||||
{
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 dword, ret;
|
||||
|
||||
ret = 0x20000;
|
||||
ret |= MrsChipSel;
|
||||
|
||||
/* program MrsAddress[5:3]=CAS write latency (CWL):
|
||||
* based on F2x[1,0]84[Tcwl] */
|
||||
dword = Get_NB32(dev, reg_off + 0x84);
|
||||
dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
|
||||
|
||||
ret |= ((dword >> 20) & 7) << 3;
|
||||
|
||||
/* program MrsAddress[6]=auto self refresh method (ASR):
|
||||
based on F2x[1,0]84[ASR]
|
||||
program MrsAddress[7]=self refresh temperature range (SRT):
|
||||
based on F2x[1,0]84[ASR and SRT] */
|
||||
ret |= ((dword >> 18) & 3) << 6;
|
||||
|
||||
/* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
|
||||
based on F2x[1,0]84[DramTermDyn] */
|
||||
ret |= ((dword >> 10) & 3) << 9;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
|
||||
{
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 dword, ret;
|
||||
|
||||
ret = 0x30000;
|
||||
ret |= MrsChipSel;
|
||||
|
||||
/* program MrsAddress[1:0]=multi purpose register address location
|
||||
(MPR Location):based on F2x[1,0]84[MprLoc]
|
||||
program MrsAddress[2]=multi purpose register
|
||||
(MPR):based on F2x[1,0]84[MprEn]
|
||||
*/
|
||||
dword = Get_NB32(dev, reg_off + 0x84);
|
||||
ret |= (dword >> 24) & 7;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
|
||||
{
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 dword, ret;
|
||||
|
||||
ret = 0x10000;
|
||||
ret |= MrsChipSel;
|
||||
|
||||
/* program MrsAddress[5,1]=output driver impedance control (DIC):
|
||||
* based on F2x[1,0]84[DrvImpCtrl] */
|
||||
dword = Get_NB32(dev, reg_off + 0x84);
|
||||
if (dword & (1 << 3))
|
||||
ret |= 1 << 5;
|
||||
if (dword & (1 << 2))
|
||||
ret |= 1 << 1;
|
||||
|
||||
/* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
|
||||
based on F2x[1,0]84[DramTerm] */
|
||||
if (!(pDCTstat->Status & (1 << SB_Registered))) {
|
||||
if (dword & (1 << 9))
|
||||
ret |= 1 << 9;
|
||||
if (dword & (1 << 8))
|
||||
ret |= 1 << 6;
|
||||
if (dword & (1 << 7))
|
||||
ret |= 1 << 2;
|
||||
} else {
|
||||
/* TODO: mct_MR1Odt_RDimm */
|
||||
}
|
||||
|
||||
/* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
|
||||
if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
|
||||
u8 bit;
|
||||
/* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
|
||||
bit = (ret >> 21) << 1;
|
||||
if ((dct & 1) != 0)
|
||||
bit ++;
|
||||
if (pDCTstat->Dimmx8Present & (1 << bit))
|
||||
ret |= 1 << 11;
|
||||
}
|
||||
|
||||
if (dword & (1 << 13))
|
||||
ret |= 1 << 12;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
|
||||
{
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 dword, ret, dword2;
|
||||
|
||||
ret = 0x00000;
|
||||
ret |= MrsChipSel;
|
||||
|
||||
/* program MrsAddress[1:0]=burst length and control method
|
||||
(BL):based on F2x[1,0]84[BurstCtrl] */
|
||||
dword = Get_NB32(dev, reg_off + 0x84);
|
||||
ret |= dword & 3;
|
||||
|
||||
/* program MrsAddress[3]=1 (BT):interleaved */
|
||||
ret |= 1 << 3;
|
||||
|
||||
/* program MrsAddress[6:4,2]=read CAS latency
|
||||
(CL):based on F2x[1,0]88[Tcl] */
|
||||
dword2 = Get_NB32(dev, reg_off + 0x88);
|
||||
ret |= (dword2 & 0xF) << 4; /* F2x88[3:0] to MrsAddress[6:4,2]=xxx0b */
|
||||
|
||||
/* program MrsAddress[12]=0 (PPD):slow exit */
|
||||
if (dword & (1 << 23))
|
||||
ret |= 1 << 12;
|
||||
|
||||
/* program MrsAddress[11:9]=write recovery for auto-precharge
|
||||
(WR):based on F2x[1,0]84[Twr] */
|
||||
ret |= ((dword >> 4) & 7) << 9;
|
||||
|
||||
/* program MrsAddress[8]=1 (DLL):DLL reset
|
||||
just issue DLL reset at first time */
|
||||
ret |= 1 << 8;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
u32 dword;
|
||||
|
||||
/*1.Program MrsAddress[10]=1
|
||||
2.Set SendZQCmd=1
|
||||
*/
|
||||
dword = Get_NB32(dev, reg_off + 0x7C);
|
||||
dword &= ~0xFFFFFF;
|
||||
dword |= 1 << 10;
|
||||
dword |= 1 << SendZQCmd;
|
||||
Set_NB32(dev, reg_off + 0x7C, dword);
|
||||
|
||||
/* Wait for SendZQCmd=0 */
|
||||
do {
|
||||
dword = Get_NB32(dev, reg_off + 0x7C);
|
||||
} while (dword & (1 << SendZQCmd));
|
||||
|
||||
/* 4.Wait 512 MEMCLKs */
|
||||
mct_Wait(300);
|
||||
}
|
||||
|
||||
void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u8 MrsChipSel;
|
||||
u32 dword;
|
||||
u32 reg_off = 0x100 * dct;
|
||||
u32 dev = pDCTstat->dev_dct;
|
||||
|
||||
if (pDCTstat->DIMMAutoSpeed == 4) {
|
||||
/* 3.Program F2x[1,0]7C[EnDramInit]=1 */
|
||||
dword = Get_NB32(dev, reg_off + 0x7C);
|
||||
dword |= 1 << EnDramInit;
|
||||
Set_NB32(dev, reg_off + 0x7C, dword);
|
||||
mct_DCTAccessDone(pDCTstat, dct);
|
||||
|
||||
/* 4.wait 200us */
|
||||
mct_Wait(40000);
|
||||
|
||||
/* 5.On revision C processors, program F2x[1, 0]7C[DeassertMemRstX] = 1. */
|
||||
dword = Get_NB32(dev, reg_off + 0x7C);
|
||||
dword |= 1 << DeassertMemRstX;
|
||||
Set_NB32(dev, reg_off + 0x7C, dword);
|
||||
|
||||
/* 6.wait 500us */
|
||||
mct_Wait(200000);
|
||||
|
||||
/* 7.Program F2x[1,0]7C[AssertCke]=1 */
|
||||
dword = Get_NB32(dev, reg_off + 0x7C);
|
||||
dword |= 1 << AssertCke;
|
||||
Set_NB32(dev, reg_off + 0x7C, dword);
|
||||
|
||||
/* 8.wait 360ns */
|
||||
mct_Wait(80);
|
||||
|
||||
/* The following steps are performed with registered DIMMs only and
|
||||
* must be done for each chip select pair */
|
||||
if (pDCTstat->Status & (1 << SB_Registered))
|
||||
mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
|
||||
}
|
||||
|
||||
/* The following steps are performed once for unbuffered DIMMs and once for each
|
||||
* chip select on registered DIMMs: */
|
||||
for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
|
||||
if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
|
||||
u32 EMRS;
|
||||
/* 13.Send EMRS(2) */
|
||||
EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
|
||||
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
|
||||
mct_SendMrsCmd(pDCTstat, dct, EMRS);
|
||||
/* 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b */
|
||||
EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
|
||||
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
|
||||
mct_SendMrsCmd(pDCTstat, dct, EMRS);
|
||||
/* 15.Send EMRS(1) */
|
||||
EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
|
||||
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
|
||||
mct_SendMrsCmd(pDCTstat, dct, EMRS);
|
||||
/* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
|
||||
EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
|
||||
EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
|
||||
mct_SendMrsCmd(pDCTstat, dct, EMRS);
|
||||
|
||||
if (pDCTstat->DIMMAutoSpeed == 4)
|
||||
if (!(pDCTstat->Status & (1 << SB_Registered)))
|
||||
break; /* For UDIMM, only send MR commands once per channel */
|
||||
}
|
||||
if (pDCTstat->LogicalCPUID & (AMD_DR_Cx/* | AMD_RB_C0 */)) /* We dont support RB_C0 now. need to be added and tested. */
|
||||
if (!(pDCTstat->Status & (1 << SB_Registered)))
|
||||
MrsChipSel ++;
|
||||
}
|
||||
|
||||
mct_Wait(100000);
|
||||
|
||||
if (pDCTstat->DIMMAutoSpeed == 4) {
|
||||
/* 17.Send two ZQCL commands */
|
||||
mct_SendZQCmd(pDCTstat, dct);
|
||||
mct_SendZQCmd(pDCTstat, dct);
|
||||
/* 18.Program F2x[1,0]7C[EnDramInit]=0 */
|
||||
dword = Get_NB32(dev, reg_off + 0x7C);
|
||||
dword &= ~(1 << EnDramInit);
|
||||
Set_NB32(dev, reg_off + 0x7C, dword);
|
||||
mct_DCTAccessDone(pDCTstat, dct);
|
||||
}
|
||||
}
|
1056
src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
Normal file
1056
src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
Normal file
File diff suppressed because it is too large
Load Diff
85
src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
Normal file
85
src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
u8 mct_checkNumberOfDqsRcvEn_1Pass(u8 pass)
|
||||
{
|
||||
u8 ret = 1;
|
||||
if (pass == SecondPass)
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 SetupDqsPattern_1PassA(u8 pass)
|
||||
{
|
||||
return (u32) TestPattern1_D;
|
||||
}
|
||||
|
||||
u32 SetupDqsPattern_1PassB(u8 pass)
|
||||
{
|
||||
return (u32) TestPattern0_D;
|
||||
}
|
||||
|
||||
u8 mct_Get_Start_RcvrEnDly_1Pass(u8 pass)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 mct_Average_RcvrEnDly_1Pass(struct DCTStatStruc *pDCTstat, u8 Channel, u8 Receiver,
|
||||
u8 Pass)
|
||||
{
|
||||
u8 i, MaxValue;
|
||||
u8 *p;
|
||||
u8 val;
|
||||
|
||||
MaxValue = 0;
|
||||
p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1];
|
||||
|
||||
for(i=0; i < 8; i++) {
|
||||
/* get left value from DCTStatStruc.CHA_D0_B0_RCVRDLY*/
|
||||
val = p[i];
|
||||
/* get right value from DCTStatStruc.CHA_D0_B0_RCVRDLY_1*/
|
||||
val += Pass1MemClkDly;
|
||||
/* write back the value to stack */
|
||||
if (val > MaxValue)
|
||||
MaxValue = val;
|
||||
|
||||
p[i] = val;
|
||||
}
|
||||
/* pDCTstat->DimmTrainFail &= ~(1<<Receiver+Channel); */
|
||||
|
||||
return MaxValue;
|
||||
}
|
||||
|
||||
u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass)
|
||||
{
|
||||
u8 ret;
|
||||
ret = 0;
|
||||
if((pDCTstat->DqsRcvEn_Pass == 0xff) && (pass== FirstPass))
|
||||
ret = 2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
|
||||
u8 RcvrEnDly, u8 RcvrEnDlyLimit,
|
||||
u8 Channel, u8 Receiver, u8 Pass)
|
||||
|
||||
{
|
||||
return mct_Average_RcvrEnDly_1Pass(pDCTstat, Channel, Receiver, Pass);
|
||||
}
|
129
src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
Normal file
129
src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
u8 mct_checkNumberOfDqsRcvEn_Pass(u8 pass)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 SetupDqsPattern_PassA(u8 Pass)
|
||||
{
|
||||
u32 ret;
|
||||
if(Pass == FirstPass)
|
||||
ret = (u32) TestPattern1_D;
|
||||
else
|
||||
ret = (u32) TestPattern2_D;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 SetupDqsPattern_PassB(u8 Pass)
|
||||
{
|
||||
u32 ret;
|
||||
if(Pass == FirstPass)
|
||||
ret = (u32) TestPattern0_D;
|
||||
else
|
||||
ret = (u32) TestPattern2_D;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u8 mct_Get_Start_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
|
||||
u8 Channel, u8 Receiver,
|
||||
u8 Pass)
|
||||
{
|
||||
u8 RcvrEnDly;
|
||||
|
||||
if (Pass == FirstPass)
|
||||
RcvrEnDly = 0;
|
||||
else {
|
||||
u8 max = 0;
|
||||
u8 val;
|
||||
u8 i;
|
||||
u8 *p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
|
||||
u8 bn;
|
||||
bn = 8;
|
||||
|
||||
for ( i=0;i<bn; i++) {
|
||||
val = p[i];
|
||||
|
||||
if(val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
RcvrEnDly = max;
|
||||
}
|
||||
|
||||
return RcvrEnDly;
|
||||
}
|
||||
|
||||
u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat,
|
||||
u8 RcvrEnDly, u8 RcvrEnDlyLimit,
|
||||
u8 Channel, u8 Receiver, u8 Pass)
|
||||
{
|
||||
u8 i;
|
||||
u8 *p;
|
||||
u8 *p_1;
|
||||
u8 val;
|
||||
u8 val_1;
|
||||
u8 valid = 1;
|
||||
u8 bn;
|
||||
|
||||
bn = 8;
|
||||
|
||||
p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1];
|
||||
|
||||
if (Pass == SecondPass) { /* second pass must average values */
|
||||
/* FIXME: which byte? */
|
||||
p_1 = pDCTstat->B_RCVRDLY_1;
|
||||
/* p_1 = pDCTstat->CH_D_B_RCVRDLY_1[Channel][Receiver>>1]; */
|
||||
for(i=0; i<bn; i++) {
|
||||
val = p[i];
|
||||
/* left edge */
|
||||
if (val != (RcvrEnDlyLimit - 1)) {
|
||||
val -= Pass1MemClkDly;
|
||||
val_1 = p_1[i];
|
||||
val += val_1;
|
||||
val >>= 1;
|
||||
p[i] = val;
|
||||
} else {
|
||||
valid = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
pDCTstat->ErrStatus |= 1<<SB_NORCVREN;
|
||||
} else {
|
||||
pDCTstat->DimmTrainFail &= ~(1<<(Receiver + Channel));
|
||||
}
|
||||
} else {
|
||||
for(i=0; i < bn; i++) {
|
||||
val = p[i];
|
||||
/* Add 1/2 Memlock delay */
|
||||
/* val += Pass1MemClkDly; */
|
||||
val += 0x5; /* NOTE: middle value with DQSRCVEN_SAVED_GOOD_TIMES */
|
||||
/* val += 0x02; */
|
||||
p[i] = val;
|
||||
pDCTstat->DimmTrainFail &= ~(1<<(Receiver + Channel));
|
||||
}
|
||||
}
|
||||
|
||||
return RcvrEnDly;
|
||||
}
|
399
src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
Normal file
399
src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Description: Max Read Latency Training feature for DDR 3 MCT
|
||||
*/
|
||||
|
||||
static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr);
|
||||
static u32 GetMaxRdLatTestAddr_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 Channel,
|
||||
u8 *MaxRcvrEnDly, u8 *valid);
|
||||
u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 Channel,
|
||||
u8 DQSRcvEnDly, u32 *Margin);
|
||||
static void maxRdLatencyTrain_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat);
|
||||
static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat, u8 Channel,
|
||||
u16 MaxRdLatVal);
|
||||
|
||||
/*Warning: These must be located so they do not cross a logical 16-bit
|
||||
segment boundary!*/
|
||||
static const u32 TestMaxRdLAtPattern_D[] = {
|
||||
0x6E0E3FAC, 0x0C3CFF52,
|
||||
0x4A688181, 0x49C5B613,
|
||||
0x7C780BA6, 0x5C1650E3,
|
||||
0x0C4F9D76, 0x0C6753E6,
|
||||
0x205535A5, 0xBABFB6CA,
|
||||
0x610E6E5F, 0x0C5F1C87,
|
||||
0x488493CE, 0x14C9C383,
|
||||
0xF5B9A5CD, 0x9CE8F615,
|
||||
|
||||
0xAAD714B5, 0xC38F1B4C,
|
||||
0x72ED647C, 0x669F7562,
|
||||
0x5233F802, 0x4A898B30,
|
||||
0x10A40617, 0x3326B465,
|
||||
0x55386E04, 0xC807E3D3,
|
||||
0xAB49E193, 0x14B4E63A,
|
||||
0x67DF2495, 0xEA517C45,
|
||||
0x7624CE51, 0xF8140C51,
|
||||
|
||||
0x4824BD23, 0xB61DD0C9,
|
||||
0x072BCFBE, 0xE8F3807D,
|
||||
0x919EA373, 0x25E30C47,
|
||||
0xFEB12958, 0x4DA80A5A,
|
||||
0xE9A0DDF8, 0x792B0076,
|
||||
0xE81C73DC, 0xF025B496,
|
||||
0x1DB7E627, 0x808594FE,
|
||||
0x82668268, 0x655C7783,
|
||||
};
|
||||
|
||||
static u32 SetupMaxRdPattern(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat,
|
||||
u32 *buffer)
|
||||
{
|
||||
/* 1. Copy the alpha and Beta patterns from ROM to Cache,
|
||||
* aligning on 16 byte boundary
|
||||
* 2. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufA
|
||||
* for Alpha
|
||||
* 3. Set the ptr to Cacheable copy in DCTStatstruc.PtrPatternBufB
|
||||
* for Beta
|
||||
*/
|
||||
u32 *buf;
|
||||
u8 i;
|
||||
|
||||
buf = (u32 *)(((u32)buffer + 0x10) & (0xfffffff0));
|
||||
|
||||
for(i = 0; i < (16 * 3); i++) {
|
||||
buf[i] = TestMaxRdLAtPattern_D[i];
|
||||
}
|
||||
|
||||
return (u32)buf;
|
||||
}
|
||||
|
||||
void TrainMaxReadLatency_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
u8 Node;
|
||||
|
||||
for(Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
|
||||
struct DCTStatStruc *pDCTstat;
|
||||
pDCTstat = pDCTstatA + Node;
|
||||
|
||||
if(!pDCTstat->NodePresent)
|
||||
break;
|
||||
|
||||
if(pDCTstat->DCTSysLimit)
|
||||
maxRdLatencyTrain_D(pMCTstat, pDCTstat);
|
||||
}
|
||||
}
|
||||
|
||||
static void maxRdLatencyTrain_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u8 Channel;
|
||||
u32 TestAddr0;
|
||||
u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
|
||||
u16 MaxRdLatDly;
|
||||
u8 RcvrEnDly = 0;
|
||||
u32 PatternBuffer[60]; /* FIXME: why not 48 + 4 */
|
||||
u32 Margin;
|
||||
u32 addr;
|
||||
u32 cr4;
|
||||
u32 lo, hi;
|
||||
|
||||
u8 valid;
|
||||
u32 pattern_buf;
|
||||
|
||||
cr4 = read_cr4();
|
||||
if(cr4 & (1<<9)) { /* save the old value */
|
||||
_SSE2 = 1;
|
||||
}
|
||||
cr4 |= (1<<9); /* OSFXSR enable SSE2 */
|
||||
write_cr4(cr4);
|
||||
|
||||
addr = HWCR;
|
||||
_RDMSR(addr, &lo, &hi);
|
||||
if(lo & (1<<17)) { /* save the old value */
|
||||
_Wrap32Dis = 1;
|
||||
}
|
||||
lo |= (1<<17); /* HWCR.wrap32dis */
|
||||
lo &= ~(1<<15); /* SSEDIS */
|
||||
/* Setting wrap32dis allows 64-bit memory references in
|
||||
real mode */
|
||||
_WRMSR(addr, lo, hi);
|
||||
|
||||
_DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
|
||||
|
||||
pattern_buf = SetupMaxRdPattern(pMCTstat, pDCTstat, PatternBuffer);
|
||||
|
||||
for (Channel = 0; Channel < 2; Channel++) {
|
||||
print_debug_dqs("\tMaxRdLatencyTrain51: Channel ",Channel, 1);
|
||||
pDCTstat->Channel = Channel;
|
||||
|
||||
if( (pDCTstat->Status & (1 << SB_128bitmode)) && Channel)
|
||||
break; /*if ganged mode, skip DCT 1 */
|
||||
|
||||
TestAddr0 = GetMaxRdLatTestAddr_D(pMCTstat, pDCTstat, Channel, &RcvrEnDly, &valid);
|
||||
if(!valid) /* Address not supported on current CS */
|
||||
continue;
|
||||
/* rank 1 of DIMM, testpattern 0 */
|
||||
WriteMaxRdLat1CLTestPattern_D(pattern_buf, TestAddr0);
|
||||
|
||||
MaxRdLatDly = mct_GetStartMaxRdLat_D(pMCTstat, pDCTstat, Channel, RcvrEnDly, &Margin);
|
||||
print_debug_dqs("\tMaxRdLatencyTrain52: MaxRdLatDly start ", MaxRdLatDly, 2);
|
||||
print_debug_dqs("\tMaxRdLatencyTrain52: MaxRdLatDly Margin ", Margin, 2);
|
||||
while(MaxRdLatDly < MAX_RD_LAT) { /* sweep Delay value here */
|
||||
mct_setMaxRdLatTrnVal_D(pDCTstat, Channel, MaxRdLatDly);
|
||||
ReadMaxRdLat1CLTestPattern_D(TestAddr0);
|
||||
if( CompareMaxRdLatTestPattern_D(pattern_buf, TestAddr0) == DQS_PASS)
|
||||
break;
|
||||
SetTargetWTIO_D(TestAddr0);
|
||||
FlushMaxRdLatTestPattern_D(TestAddr0);
|
||||
ResetTargetWTIO_D();
|
||||
MaxRdLatDly++;
|
||||
}
|
||||
print_debug_dqs("\tMaxRdLatencyTrain53: MaxRdLatDly end ", MaxRdLatDly, 2);
|
||||
mct_setMaxRdLatTrnVal_D(pDCTstat, Channel, MaxRdLatDly + Margin);
|
||||
}
|
||||
|
||||
if(_DisableDramECC) {
|
||||
mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
|
||||
}
|
||||
|
||||
if(!_Wrap32Dis) {
|
||||
addr = HWCR;
|
||||
_RDMSR(addr, &lo, &hi);
|
||||
lo &= ~(1<<17); /* restore HWCR.wrap32dis */
|
||||
_WRMSR(addr, lo, hi);
|
||||
}
|
||||
if(!_SSE2){
|
||||
cr4 = read_cr4();
|
||||
cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
|
||||
write_cr4(cr4);
|
||||
}
|
||||
|
||||
#if DQS_TRAIN_DEBUG > 0
|
||||
{
|
||||
u8 Channel;
|
||||
print_debug("maxRdLatencyTrain: CH_MaxRdLat:\n");
|
||||
for(Channel = 0; Channel<2; Channel++) {
|
||||
print_debug("Channel:"); print_debug_hex8(Channel);
|
||||
print_debug(": ");
|
||||
print_debug_hex8( pDCTstat->CH_MaxRdLat[Channel] );
|
||||
print_debug("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat,
|
||||
u8 Channel, u16 MaxRdLatVal)
|
||||
{
|
||||
u8 i;
|
||||
u32 reg;
|
||||
u32 dev;
|
||||
u32 val;
|
||||
|
||||
if (pDCTstat->GangedMode) {
|
||||
Channel = 0; /* for safe */
|
||||
for (i=0; i<2; i++)
|
||||
pDCTstat->CH_MaxRdLat[i] = MaxRdLatVal;
|
||||
} else {
|
||||
pDCTstat->CH_MaxRdLat[Channel] = MaxRdLatVal;
|
||||
}
|
||||
|
||||
dev = pDCTstat->dev_dct;
|
||||
reg = 0x78 + Channel * 0x100;
|
||||
val = Get_NB32(dev, reg);
|
||||
val &= ~(0x3ff<<22);
|
||||
val |= MaxRdLatVal<<22;
|
||||
/* program MaxRdLatency to correspond with current delay */
|
||||
Set_NB32(dev, reg, val);
|
||||
}
|
||||
|
||||
static u8 CompareMaxRdLatTestPattern_D(u32 pattern_buf, u32 addr)
|
||||
{
|
||||
/* Compare only the first beat of data. Since target addrs are cache
|
||||
* line aligned, the Channel parameter is used to determine which cache
|
||||
* QW to compare.
|
||||
*/
|
||||
|
||||
u32 *test_buf = (u32 *)pattern_buf;
|
||||
u32 addr_lo;
|
||||
u32 val, val_test;
|
||||
int i;
|
||||
u8 ret = DQS_PASS;
|
||||
|
||||
SetUpperFSbase(addr);
|
||||
addr_lo = addr<<8;
|
||||
|
||||
_EXECFENCE;
|
||||
for (i=0; i<(16*3); i++) {
|
||||
val = read32_fs(addr_lo);
|
||||
val_test = test_buf[i];
|
||||
|
||||
print_debug_dqs_pair("\t\t\t\t\t\ttest_buf = ", (u32)test_buf, " value = ", val_test, 5);
|
||||
print_debug_dqs_pair("\t\t\t\t\t\ttaddr_lo = ", addr_lo, " value = ", val, 5);
|
||||
if(val != val_test) {
|
||||
ret = DQS_FAIL;
|
||||
break;
|
||||
}
|
||||
addr_lo += 4;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 GetMaxRdLatTestAddr_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat,
|
||||
u8 Channel, u8 *MaxRcvrEnDly,
|
||||
u8 *valid)
|
||||
{
|
||||
u8 Max = 0;
|
||||
|
||||
u8 Channel_Max = 0;
|
||||
u8 d;
|
||||
u8 d_Max = 0;
|
||||
|
||||
u8 Byte;
|
||||
u32 TestAddr0 = 0;
|
||||
u8 ch, ch_start, ch_end;
|
||||
u8 bn;
|
||||
|
||||
bn = 8;
|
||||
|
||||
if(pDCTstat->Status & (1 << SB_128bitmode)) {
|
||||
ch_start = 0;
|
||||
ch_end = 2;
|
||||
} else {
|
||||
ch_start = Channel;
|
||||
ch_end = Channel + 1;
|
||||
}
|
||||
|
||||
*valid = 0;
|
||||
|
||||
for(ch = ch_start; ch < ch_end; ch++) {
|
||||
for(d=0; d<4; d++) {
|
||||
for(Byte = 0; Byte<bn; Byte++) {
|
||||
u8 tmp;
|
||||
tmp = pDCTstat->CH_D_B_RCVRDLY[ch][d][Byte];
|
||||
if(tmp>Max) {
|
||||
Max = tmp;
|
||||
Channel_Max = Channel;
|
||||
d_Max = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel_Max, d_Max << 1)) {
|
||||
TestAddr0 = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, Channel_Max, d_Max << 1, valid);
|
||||
}
|
||||
|
||||
if(*valid)
|
||||
*MaxRcvrEnDly = Max;
|
||||
|
||||
return TestAddr0;
|
||||
}
|
||||
|
||||
u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat,
|
||||
u8 Channel, u8 DQSRcvEnDly, u32 *Margin)
|
||||
{
|
||||
u32 SubTotal;
|
||||
u32 val;
|
||||
u32 valx;
|
||||
u32 valxx;
|
||||
u32 index_reg;
|
||||
u32 reg_off;
|
||||
u32 dev;
|
||||
|
||||
if(pDCTstat->GangedMode)
|
||||
Channel = 0;
|
||||
|
||||
index_reg = 0x98 + 0x100 * Channel;
|
||||
|
||||
reg_off = 0x100 * Channel;
|
||||
dev = pDCTstat->dev_dct;
|
||||
|
||||
/* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
|
||||
val = Get_NB32(dev, 0x88 + reg_off);
|
||||
SubTotal = ((val & 0x0f) + 1) << 1; /* SubTotal is 1/2 Memclk unit */
|
||||
|
||||
/* If registered DIMMs are being used then add 1 MEMCLK to the sub-total*/
|
||||
val = Get_NB32(dev, 0x90 + reg_off);
|
||||
if(!(val & (1 << UnBuffDimm)))
|
||||
SubTotal += 2;
|
||||
|
||||
/*If the address prelaunch is setup for 1/2 MEMCLKs then add 1,
|
||||
* else add 2 to the sub-total. if (AddrCmdSetup || CsOdtSetup
|
||||
* || CkeSetup) then K := K + 2; */
|
||||
val = Get_NB32_index_wait(dev, index_reg, 0x04);
|
||||
if(!(val & 0x00202020))
|
||||
SubTotal += 1;
|
||||
else
|
||||
SubTotal += 2;
|
||||
|
||||
/* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
|
||||
* then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
|
||||
val = Get_NB32(dev, 0x78 + reg_off);
|
||||
SubTotal += 8 - (val & 0x0f);
|
||||
|
||||
/* Convert bits 7-5 (also referred to as the course delay) of the current
|
||||
* (or worst case) DQS receiver enable delay to 1/2 MEMCLKs units,
|
||||
* rounding up, and add this to the sub-total. */
|
||||
SubTotal += DQSRcvEnDly >> 5; /*BOZO-no rounding up */
|
||||
|
||||
SubTotal <<= 1; /*scale 1/2 MemClk to 1/4 MemClk */
|
||||
|
||||
/* Convert the sub-total (in 1/2 MEMCLKs) to northbridge clocks (NCLKs)
|
||||
* as follows (assuming DDR400 and assuming that no P-state or link speed
|
||||
* changes have occurred). */
|
||||
|
||||
/*New formula:
|
||||
SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */
|
||||
val = Get_NB32(dev, 0x94 + reg_off);
|
||||
/* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
|
||||
val &= 7;
|
||||
if (val >= 3) {
|
||||
val <<= 1;
|
||||
} else
|
||||
val += 3;
|
||||
valx = (val) << 2; /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4);
|
||||
val = ((val & 0x1f) + 4 ) * 3;
|
||||
|
||||
/* Calculate 1 MemClk + 1 NCLK delay in NCLKs for margin */
|
||||
valxx = val << 2;
|
||||
valxx /= valx;
|
||||
if (valxx % valx)
|
||||
valxx++; /* round up */
|
||||
valxx++; /* add 1NCLK */
|
||||
*Margin = valxx; /* one MemClk delay in NCLKs and one additional NCLK */
|
||||
|
||||
val *= SubTotal;
|
||||
|
||||
val /= valx;
|
||||
if (val % valx)
|
||||
val++; /* round up */
|
||||
|
||||
return val;
|
||||
}
|
382
src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
Normal file
382
src/northbridge/amd/amdmct/mct_ddr3/mctwl.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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 void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat);
|
||||
|
||||
|
||||
static void AgesaDelay(u32 msec)
|
||||
{
|
||||
mct_Wait(msec*10);
|
||||
}
|
||||
|
||||
void PrepareC_MCT(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
pDCTstat->C_MCTPtr->AgesaDelay = AgesaDelay;
|
||||
pDCTstat->C_MCTPtr->PlatMaxTotalDimms = mctGet_NVbits(NV_MAX_DIMMS);
|
||||
pDCTstat->C_MCTPtr->PlatMaxDimmsDct = pDCTstat->C_MCTPtr->PlatMaxTotalDimms >> 1;
|
||||
}
|
||||
|
||||
void PrepareC_DCT(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u8 dimm;
|
||||
u16 DimmValid;
|
||||
u16 Dimmx8Present;
|
||||
|
||||
dct &= 1;
|
||||
|
||||
pDCTstat->C_DCTPtr[dct]->DctTrain = dct;
|
||||
|
||||
if (dct == 1) {
|
||||
Dimmx8Present = pDCTstat->Dimmx8Present >> 1;
|
||||
} else
|
||||
Dimmx8Present = pDCTstat->Dimmx8Present;
|
||||
Dimmx8Present &= 0x55;
|
||||
|
||||
pDCTstat->C_DCTPtr[dct]->MaxDimmsInstalled = pDCTstat->MAdimms[dct];
|
||||
DimmValid = pDCTstat->DIMMValidDCT[dct];
|
||||
|
||||
pDCTstat->C_DCTPtr[dct]->NodeId = pDCTstat->Node_ID;
|
||||
pDCTstat->C_DCTPtr[dct]->LogicalCPUID = pDCTstat->LogicalCPUID;
|
||||
|
||||
for (dimm = 0; dimm < MAX_DIMMS; dimm++) {
|
||||
if (DimmValid & (1 << dimm))
|
||||
pDCTstat->C_DCTPtr[dct]->DimmPresent[dimm] = 1;
|
||||
if (Dimmx8Present & (1 << dimm))
|
||||
pDCTstat->C_DCTPtr[dct]->DimmX8Present[dimm] = 1;
|
||||
}
|
||||
|
||||
if (pDCTstat->GangedMode & (1 << 0))
|
||||
pDCTstat->C_DCTPtr[dct]->CurrDct = 0;
|
||||
else
|
||||
pDCTstat->C_DCTPtr[dct]->CurrDct = dct;
|
||||
|
||||
pDCTstat->C_DCTPtr[dct]->DctCSPresent = pDCTstat->CSPresent_DCT[dct];
|
||||
if (!(pDCTstat->GangedMode & (1 << 0)) && (dct == 1))
|
||||
pDCTstat->C_DCTPtr[dct]->DctCSPresent = pDCTstat->CSPresent_DCT[0];
|
||||
|
||||
if (pDCTstat->Status & (1 << SB_Registered)) {
|
||||
pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 1;
|
||||
pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_OnDimmMirror] = 0;
|
||||
} else {
|
||||
if (pDCTstat->MirrPresU_NumRegR > 0)
|
||||
pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_OnDimmMirror] = 1;
|
||||
pDCTstat->C_DCTPtr[dct]->Status[DCT_STATUS_REGISTERED] = 0;
|
||||
}
|
||||
|
||||
pDCTstat->C_DCTPtr[dct]->RegMan1Present = pDCTstat->RegMan1Present;
|
||||
|
||||
for (dimm = 0; dimm < MAX_TOTAL_DIMMS; dimm++) {
|
||||
u8 DimmRanks;
|
||||
if (DimmValid & (1 << dimm)) {
|
||||
DimmRanks = 1;
|
||||
if (pDCTstat->DimmDRPresent & (1 << (dimm+dct)))
|
||||
DimmRanks = 2;
|
||||
else if (pDCTstat->DimmQRPresent & (1 << (dimm+dct)))
|
||||
DimmRanks = 4;
|
||||
} else
|
||||
DimmRanks = 0;
|
||||
pDCTstat->C_DCTPtr[dct]->DimmRanks[dimm] = DimmRanks;
|
||||
}
|
||||
}
|
||||
|
||||
void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94);
|
||||
val |= 1 << 11;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94, val);
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
|
||||
val |= 1 << 11;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
|
||||
}
|
||||
|
||||
void DisableZQcalibration(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94);
|
||||
val &= ~(1 << 11);
|
||||
val &= ~(1 << 10);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94, val);
|
||||
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
|
||||
val &= ~(1 << 11);
|
||||
val &= ~(1 << 10);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
|
||||
}
|
||||
|
||||
static void EnterSelfRefresh(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u8 DCT0Present, DCT1Present;
|
||||
u32 val;
|
||||
|
||||
DCT0Present = pDCTstat->DIMMValidDCT[0];
|
||||
if (pDCTstat->GangedMode)
|
||||
DCT1Present = 0;
|
||||
else
|
||||
DCT1Present = pDCTstat->DIMMValidDCT[1];
|
||||
|
||||
/* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
|
||||
if (DCT0Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90);
|
||||
val |= 1 << EnterSelfRef;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x90, val);
|
||||
}
|
||||
if (DCT1Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
|
||||
val |= 1 << EnterSelfRef;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
|
||||
}
|
||||
/* Wait until the hardware resets F2x[1, 0]90[EnterSelfRefresh]=0. */
|
||||
if (DCT0Present)
|
||||
do {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90);
|
||||
} while (val & (1 <<EnterSelfRef));
|
||||
if (DCT1Present)
|
||||
do {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
|
||||
} while (val & (1 <<EnterSelfRef));
|
||||
}
|
||||
|
||||
/*
|
||||
* Change memclk for write levelization pass 2
|
||||
*/
|
||||
static void ChangeMemClk(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u8 DCT0Present, DCT1Present;
|
||||
u32 val;
|
||||
|
||||
DCT0Present = pDCTstat->DIMMValidDCT[0];
|
||||
if (pDCTstat->GangedMode)
|
||||
DCT1Present = 0;
|
||||
else
|
||||
DCT1Present = pDCTstat->DIMMValidDCT[1];
|
||||
|
||||
/* Program F2x[1, 0]90[EnterSelfRefresh]=1. */
|
||||
if (DCT0Present) {
|
||||
val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
|
||||
val |= 1 << DisAutoComp;
|
||||
Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
|
||||
}
|
||||
if (DCT1Present) {
|
||||
val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
|
||||
val |= 1 << DisAutoComp;
|
||||
Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
|
||||
}
|
||||
|
||||
/* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
|
||||
if (DCT0Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94);
|
||||
val &= ~(1 << MemClkFreqVal);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94, val);
|
||||
}
|
||||
if (DCT1Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
|
||||
val &= ~(1 << MemClkFreqVal);
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
|
||||
}
|
||||
|
||||
/* Program F2x[1, 0]94[MemClkFreq] to specify the target MEMCLK frequency. */
|
||||
if (DCT0Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94);
|
||||
val &= 0xFFFFFFF8;
|
||||
val |= pDCTstat->TargetFreq - 1;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94, val);
|
||||
}
|
||||
if (DCT1Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
|
||||
val &= 0xFFFFFFF8;
|
||||
val |= pDCTstat->TargetFreq - 1;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
|
||||
}
|
||||
|
||||
/* Program F2x[1, 0]94[MemClkFreqVal] = 1. */
|
||||
if (DCT0Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94);
|
||||
val |= 1 << MemClkFreqVal;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94, val);
|
||||
}
|
||||
if (DCT1Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
|
||||
val |= 1 << MemClkFreqVal;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x94 + 0x100, val);
|
||||
}
|
||||
|
||||
/* Wait until F2x[1, 0]94[FreqChgInProg]=0. */
|
||||
if (DCT0Present)
|
||||
do {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94);
|
||||
} while (val & (1 << FreqChgInProg));
|
||||
if (DCT1Present)
|
||||
do {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x94 + 0x100);
|
||||
} while (val & (1 << FreqChgInProg));
|
||||
|
||||
/* Program F2x[1, 0]94[MemClkFreqVal] = 0. */
|
||||
if (DCT0Present) {
|
||||
val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8);
|
||||
val &= ~(1 << DisAutoComp);
|
||||
Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 8, val);
|
||||
}
|
||||
if (DCT1Present) {
|
||||
val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8);
|
||||
val &= ~(1 << DisAutoComp);
|
||||
Set_NB32_index_wait(pDCTstat->dev_dct, 0x98 + 0x100, 8, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* Multiply the previously saved delay values in Pass 1, step #5 by
|
||||
(target frequency)/400 to find the gross and fine delay initialization
|
||||
values at the target frequency.
|
||||
*/
|
||||
void MultiplyDelay(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat, u8 dct)
|
||||
{
|
||||
u16 index;
|
||||
u8 Multiplier;
|
||||
u8 gross, fine;
|
||||
u16 total;
|
||||
|
||||
Multiplier = pDCTstat->TargetFreq;
|
||||
|
||||
for (index=0; index < MAX_BYTE_LANES*MAX_LDIMMS; index ++) {
|
||||
gross = pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index];
|
||||
fine = pDCTstat->C_DCTPtr[dct]->WLFineDelay[index];
|
||||
|
||||
total = gross << 5 | fine;
|
||||
total *= Multiplier;
|
||||
if (total % 3)
|
||||
total = total / 3 + 1;
|
||||
else
|
||||
total = total / 3;
|
||||
pDCTstat->C_DCTPtr[dct]->WLGrossDelay[index] = (total & 0xFF) >> 5;
|
||||
pDCTstat->C_DCTPtr[dct]->WLFineDelay[index] = total & 0x1F;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the DRAM controller to bring the DRAMs out of self refresh mode.
|
||||
*/
|
||||
static void ExitSelfRefresh(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
u8 DCT0Present, DCT1Present;
|
||||
u32 val;
|
||||
|
||||
DCT0Present = pDCTstat->DIMMValidDCT[0];
|
||||
if (pDCTstat->GangedMode)
|
||||
DCT1Present = 0;
|
||||
else
|
||||
DCT1Present = pDCTstat->DIMMValidDCT[1];
|
||||
|
||||
/* Program F2x[1, 0]90[ExitSelfRef]=1 for both DCTs. */
|
||||
if (DCT0Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90);
|
||||
val |= 1 << ExitSelfRef;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x90, val);
|
||||
}
|
||||
if (DCT1Present) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
|
||||
val |= 1 << ExitSelfRef;
|
||||
Set_NB32(pDCTstat->dev_dct, 0x90 + 0x100, val);
|
||||
}
|
||||
/* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0. */
|
||||
if (DCT0Present)
|
||||
do {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90);
|
||||
} while (val & (1 << ExitSelfRef));
|
||||
if (DCT1Present)
|
||||
do {
|
||||
val = Get_NB32(pDCTstat->dev_dct, 0x90 + 0x100);
|
||||
} while (val & (1 << ExitSelfRef));
|
||||
}
|
||||
|
||||
void SetTargetFreq(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
/* Program F2x[1,0]90[EnterSelfRefresh]=1.
|
||||
* Wait until the hardware resets F2x[1,0]90[EnterSelfRefresh]=0.
|
||||
*/
|
||||
EnterSelfRefresh(pMCTstat, pDCTstat);
|
||||
|
||||
/*
|
||||
* Program F2x[1,0]9C_x08[DisAutoComp]=1
|
||||
* Program F2x[1,0]94[MemClkFreqVal] = 0.
|
||||
* Program F2x[1,0]94[MemClkFreq] to specify the target MEMCLK frequency.
|
||||
* Program F2x[1,0]94[MemClkFreqVal] = 1.
|
||||
* Wait until F2x[1,0]94[FreqChgInProg]=0.
|
||||
* Program F2x[1,0]9C_x08[DisAutoComp]=0
|
||||
*/
|
||||
ChangeMemClk(pMCTstat, pDCTstat);
|
||||
|
||||
/* Program F2x[1,0]90[ExitSelfRef]=1 for both DCTs.
|
||||
* Wait until the hardware resets F2x[1, 0]90[ExitSelfRef]=0.
|
||||
*/
|
||||
ExitSelfRefresh(pMCTstat, pDCTstat);
|
||||
|
||||
/* wait for 500 MCLKs after ExitSelfRef, 500*2.5ns=1250ns */
|
||||
mct_Wait(250);
|
||||
|
||||
if (pDCTstat->Status & (1 << SB_Registered)) {
|
||||
/* TODO: Assuming the dct==0. The agesa here is confusing. */
|
||||
FreqChgCtrlWrd(pMCTstat, pDCTstat);
|
||||
}
|
||||
}
|
||||
|
||||
static void Modify_OnDimmMirror(struct DCTStatStruc *pDCTstat, u8 dct, u8 set)
|
||||
{
|
||||
u32 val;
|
||||
u32 reg_off = dct * 0x100 + 0x44;
|
||||
while (reg_off < 0x60) {
|
||||
val = Get_NB32(pDCTstat->dev_dct, reg_off);
|
||||
if (val & (1 << CSEnable))
|
||||
set ? (val |= 1 << onDimmMirror) : (val &= ~(1<<onDimmMirror));
|
||||
Set_NB32(pDCTstat->dev_dct, reg_off, val);
|
||||
reg_off += 8;
|
||||
}
|
||||
}
|
||||
|
||||
void Restore_OnDimmMirror(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
if (pDCTstat->LogicalCPUID & (AMD_DR_Bx /* | AMD_RB_C0 */)) { /* We dont support RB-C0 now */
|
||||
if (pDCTstat->MirrPresU_NumRegR & 0x55)
|
||||
Modify_OnDimmMirror(pDCTstat, 0, 1); /* dct=0, set */
|
||||
if (pDCTstat->MirrPresU_NumRegR & 0xAA)
|
||||
Modify_OnDimmMirror(pDCTstat, 1, 1); /* dct=1, set */
|
||||
}
|
||||
}
|
||||
void Clear_OnDimmMirror(struct MCTStatStruc *pMCTstat,
|
||||
struct DCTStatStruc *pDCTstat)
|
||||
{
|
||||
if (pDCTstat->LogicalCPUID & (AMD_DR_Bx /* | AMD_RB_C0 */)) { /* We dont support RB-C0 now */
|
||||
if (pDCTstat->MirrPresU_NumRegR & 0x55)
|
||||
Modify_OnDimmMirror(pDCTstat, 0, 0); /* dct=0, clear */
|
||||
if (pDCTstat->MirrPresU_NumRegR & 0xAA)
|
||||
Modify_OnDimmMirror(pDCTstat, 1, 0); /* dct=1, clear */
|
||||
}
|
||||
}
|
916
src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
Normal file
916
src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
Normal file
@@ -0,0 +1,916 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* MODULES USED
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* PROTOTYPES OF LOCAL FUNCTIONS
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue);
|
||||
u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue);
|
||||
void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl);
|
||||
void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm);
|
||||
void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass);
|
||||
void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr);
|
||||
void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm);
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* EXPORTED FUNCTIONS
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* void AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct *DCTData,
|
||||
* u8 Dimm, u8 Pass)
|
||||
*
|
||||
* Description:
|
||||
* This function initialized Hardware based write levelization phase 1
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *SPDData - Pointer to buffer with information about each DIMMs
|
||||
* SPD information
|
||||
* *MCTData - Pointer to buffer with runtime parameters,
|
||||
* *DCTData - Pointer to buffer with information about each DCT
|
||||
*
|
||||
* IN DIMM - Logical DIMM number
|
||||
* Pass - First or Second Pass
|
||||
* OUT
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void AgesaHwWlPhase1(sMCTStruct *pMCTData, sDCTStruct *pDCTData,
|
||||
u8 dimm, u8 pass)
|
||||
{
|
||||
u8 ByteLane;
|
||||
u32 Value, Addr;
|
||||
u16 Addl_Data_Offset, Addl_Data_Port;
|
||||
|
||||
pDCTData->WLPass = pass;
|
||||
/* 1. Specify the target DIMM that is to be trained by programming
|
||||
* F2x[1, 0]9C_x08[TrDimmSel].
|
||||
*/
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
|
||||
TrDimmSelEnd,(u32)dimm);
|
||||
/* 2. Prepare the DIMMs for write levelization using DDR3-defined
|
||||
* MR commands. */
|
||||
prepareDimms(pMCTData, pDCTData,dimm, TRUE);
|
||||
/* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
|
||||
* satisfy DDR3-defined internal DRAM timing.
|
||||
*/
|
||||
pMCTData->AgesaDelay(40);
|
||||
/* 4. Configure the processor's DDR phy for write levelization training: */
|
||||
procConifg(pMCTData,pDCTData, dimm, pass);
|
||||
/* 5. Begin write levelization training:
|
||||
* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=1. */
|
||||
if (pDCTData->LogicalCPUID & AMD_DR_Cx)
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 1);
|
||||
else
|
||||
{
|
||||
/* Broadcast write to all D3Dbyte chiplet register offset 0xc
|
||||
* Set bit 0 (wrTrain)
|
||||
* Program bit 4 to nibble being trained (only matters for x4dimms)
|
||||
* retain value of 3:2 (Trdimmsel)
|
||||
* reset bit 5 (FrzPR)
|
||||
*/
|
||||
if (pDCTData->DctTrain)
|
||||
{
|
||||
Addl_Data_Offset=0x198;
|
||||
Addl_Data_Port=0x19C;
|
||||
}
|
||||
else
|
||||
{
|
||||
Addl_Data_Offset=0x98;
|
||||
Addl_Data_Port=0x9C;
|
||||
}
|
||||
Addr=0x0D00000C;
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
|
||||
while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
|
||||
DctAccessDone, DctAccessDone)) == 0);
|
||||
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
|
||||
Value = bitTestSet(Value, 0); /* enable WL training */
|
||||
Value = bitTestReset(Value, 4); /* for x8 only */
|
||||
Value = bitTestReset(Value, 5); /* for harward WL training */
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
|
||||
Addr=0x4D030F0C;
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
|
||||
while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
|
||||
DctAccessDone, DctAccessDone)) == 0);
|
||||
}
|
||||
|
||||
/* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
|
||||
pMCTData->AgesaDelay(140);
|
||||
/* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
|
||||
/* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
|
||||
* to get the gross and fine delay settings
|
||||
* for the target DIMM and save these values. */
|
||||
ByteLane = 0;
|
||||
while (ByteLane < MAX_BYTE_LANES)
|
||||
{
|
||||
getWLByteDelay(pDCTData,ByteLane, dimm);
|
||||
setWLByteDelay(pDCTData,ByteLane, dimm, 1);
|
||||
ByteLane++;
|
||||
}
|
||||
|
||||
/* 6. Configure DRAM Phy Control Register so that the phy stops driving
|
||||
* write levelization ODT. */
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, 0);
|
||||
|
||||
/* Wait 10 MEMCLKs to allow for ODT signal settling. */
|
||||
pMCTData->AgesaDelay(10);
|
||||
|
||||
/* 7. Program the target DIMM back to normal operation by configuring
|
||||
* the following (See section 2.8.5.4.1.1
|
||||
* [Phy Assisted Write Levelization] on page 97 pass 1, step #2):
|
||||
* Configure all ranks of the target DIMM for normal operation.
|
||||
* Enable the output drivers of all ranks of the target DIMM.
|
||||
* For a two DIMM system, program the Rtt value for the target DIMM
|
||||
* to the normal operating termination:
|
||||
*/
|
||||
prepareDimms(pMCTData, pDCTData,dimm,FALSE);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
* LOCAL FUNCTIONS
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
|
||||
*
|
||||
* Description:
|
||||
* This function swaps the bits in MSR register value
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN u32: MRS value
|
||||
* OUT u32: sWAPPED BANK BITS
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
u32 swapAddrBits_wl(sDCTStruct *pDCTData, u32 MRSValue)
|
||||
{
|
||||
u32 tempW, tempW1;
|
||||
|
||||
tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
|
||||
if (tempW1 & 1)
|
||||
{
|
||||
if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
|
||||
{
|
||||
/* swap A3/A4,A5/A6,A7/A8 */
|
||||
tempW = MRSValue;
|
||||
tempW1 = MRSValue;
|
||||
tempW &= 0x0A8;
|
||||
tempW1 &= 0x0150;
|
||||
MRSValue &= 0xFE07;
|
||||
MRSValue |= (tempW<<1);
|
||||
MRSValue |= (tempW1>>1);
|
||||
}
|
||||
}
|
||||
return MRSValue;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
|
||||
*
|
||||
* Description:
|
||||
* This function swaps the bits in MSR register value
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN u32: MRS value
|
||||
* OUT u32: sWAPPED BANK BITS
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue)
|
||||
{
|
||||
u32 tempW, tempW1;
|
||||
|
||||
tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd);
|
||||
if (tempW1 & 1)
|
||||
{
|
||||
if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
|
||||
{
|
||||
/* swap BA0/BA1 */
|
||||
tempW = MRSValue;
|
||||
tempW1 = MRSValue;
|
||||
tempW &= 0x01;
|
||||
tempW1 &= 0x02;
|
||||
MRSValue = 0;
|
||||
MRSValue |= (tempW<<1);
|
||||
MRSValue |= (tempW1>>1);
|
||||
}
|
||||
}
|
||||
return MRSValue;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *DCTData, u8 Dimm, BOOL WL)
|
||||
*
|
||||
* Description:
|
||||
* This function prepares DIMMS for training
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* *SPDData - Pointer to buffer with information about each DIMMs
|
||||
* SPD information
|
||||
* *MCTData - Pointer to buffer with runtime parameters,
|
||||
* IN Dimm - Logical DIMM number
|
||||
* WL - indicates if the routine is used for Write levelization
|
||||
* training
|
||||
*
|
||||
* OUT
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl)
|
||||
{
|
||||
u32 tempW, tempW1, tempW2, MrsBank;
|
||||
u8 rank, currDimm, MemClkFreq;
|
||||
|
||||
MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
|
||||
/* Configure the DCT to send initialization MR commands to the target DIMM
|
||||
* ;by programming the F2x[1,0]7C register using the following steps.
|
||||
*/
|
||||
rank = 0;
|
||||
while ((rank < pDCTData->DimmRanks[dimm]) && (rank < 2))
|
||||
{
|
||||
/* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank to be trained. */
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, dimm*2+rank);
|
||||
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
|
||||
* ;register that defines the required DDR3-defined function for write
|
||||
* ; levelization.
|
||||
*/
|
||||
MrsBank = swapBankBits(pDCTData,1);
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
|
||||
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
|
||||
* ; for write levelization.
|
||||
*/
|
||||
tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0 */
|
||||
|
||||
/* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
|
||||
tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
|
||||
if (tempW2)
|
||||
{
|
||||
if (pDCTData->DimmX8Present[dimm])
|
||||
tempW |= 0x800;
|
||||
}
|
||||
|
||||
/* determine Rtt_Nom for WL & Normal mode */
|
||||
if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
|
||||
tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
|
||||
} else {
|
||||
if (wl)
|
||||
{
|
||||
if (pDCTData->MaxDimmsInstalled == 1)
|
||||
{
|
||||
if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 0))
|
||||
{
|
||||
tempW1 = 0x00; /* Rtt_Nom=OFF */
|
||||
}
|
||||
else
|
||||
{
|
||||
tempW1 = 0x04; /* Rtt_Nom=RZQ/4=60 Ohm */
|
||||
}
|
||||
}
|
||||
else /* 2 Dimms or more per channel */
|
||||
{
|
||||
if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 1))
|
||||
{
|
||||
tempW1 = 0x00; /* Rtt_Nom=OFF */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MemClkFreq == 6) {
|
||||
tempW1 = 0x04; /* Rtt_Nom=RZQ/4=60 Ohm */
|
||||
} else {
|
||||
tempW1 = 0x40;/* Rtt_Nom=RZQ/2=120 Ohm */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* 1 or 4 Dimms per channel */
|
||||
if ((pDCTData->MaxDimmsInstalled == 1) || (pDCTData->MaxDimmsInstalled == 4))
|
||||
{
|
||||
tempW1 = 0x04; /* Rtt_Nom=RZQ/4=60 Ohm */
|
||||
}
|
||||
else /* 2 or 3 Dimms per channel */
|
||||
{
|
||||
if (MemClkFreq < 5) {
|
||||
tempW1 = 0x0044; /* Rtt_Nom=RZQ/6=40 Ohm */
|
||||
} else {
|
||||
tempW1 = 0x0204; /* Rtt_Nom=RZQ/8=30 Ohm */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tempW=tempW|tempW1;
|
||||
|
||||
/* All ranks of the target DIMM are set to write levelization mode. */
|
||||
if (wl)
|
||||
{
|
||||
tempW1 = bitTestSet(tempW, MRS_Level);
|
||||
if (rank == 0)
|
||||
{
|
||||
/* ?Enable the output driver of the first rank of the target DIMM. */
|
||||
tempW = tempW1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Disable the output drivers of all other ranks for
|
||||
* the target DIMM. */
|
||||
tempW = bitTestSet(tempW1, Qoff);
|
||||
}
|
||||
}
|
||||
/* program MrsAddress[5,1]=output driver impedance control (DIC):
|
||||
* based on F2x[1,0]84[DrvImpCtrl] */
|
||||
tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
|
||||
if (bitTest(tempW1,1))
|
||||
{tempW = bitTestSet(tempW, 5);}
|
||||
if (bitTest(tempW1,0))
|
||||
{tempW = bitTestSet(tempW, 1);}
|
||||
|
||||
tempW = swapAddrBits_wl(pDCTData,tempW);
|
||||
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
|
||||
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
|
||||
* ;the specified DIMM.
|
||||
*/
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
|
||||
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
|
||||
while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
|
||||
{
|
||||
}
|
||||
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
|
||||
* ;register that defines the required DDR3-defined function for Rtt_WR.
|
||||
*/
|
||||
MrsBank = swapBankBits(pDCTData,2);
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
|
||||
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
|
||||
* ; for Rtt_WR (DRAMTermDyn).
|
||||
*/
|
||||
tempW = 0;/* PASR = 0,*/
|
||||
/* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
|
||||
* based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
|
||||
tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
|
||||
if (bitTest(tempW1,19))
|
||||
{tempW = bitTestSet(tempW, 7);}
|
||||
if (bitTest(tempW1,18))
|
||||
{tempW = bitTestSet(tempW, 6);}
|
||||
/* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
|
||||
tempW=tempW|((tempW1&0x00700000)>>17);
|
||||
/* workaround for DR-B0 */
|
||||
if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
|
||||
tempW+=0x8;
|
||||
/* determine Rtt_WR for WL & Normal mode */
|
||||
if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
|
||||
tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
|
||||
} else {
|
||||
if (wl)
|
||||
{
|
||||
tempW1 = 0x00; /* Rtt_WR=off */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pDCTData->MaxDimmsInstalled == 1)
|
||||
{
|
||||
tempW1 = 0x00; /* Rtt_WR=off */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MemClkFreq == 6) {
|
||||
tempW1 = 0x200; /* Rtt_WR=RZQ/4=60 Ohm */
|
||||
} else {
|
||||
tempW1 = 0x400; /* Rtt_WR=RZQ/2 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tempW=tempW|tempW1;
|
||||
tempW = swapAddrBits_wl(pDCTData,tempW);
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
|
||||
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
|
||||
the specified DIMM.*/
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
|
||||
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
|
||||
while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
|
||||
{
|
||||
}
|
||||
|
||||
rank++;
|
||||
}
|
||||
|
||||
/* Configure the non-target DIMM normally. */
|
||||
currDimm = 0;
|
||||
while (currDimm < MAX_LDIMMS)
|
||||
{
|
||||
if (pDCTData->DimmPresent[currDimm])
|
||||
{
|
||||
if (currDimm != dimm)
|
||||
{
|
||||
rank = 0;
|
||||
while ((rank < pDCTData->DimmRanks[currDimm]) && (rank < 2))
|
||||
{
|
||||
|
||||
/* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank
|
||||
* ;to be trained.
|
||||
*/
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, MrsChipSelStart, MrsChipSelEnd, currDimm*2+rank);
|
||||
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal
|
||||
* ;DRAM register that defines the required DDR3-defined function
|
||||
* ; for write levelization.
|
||||
*/
|
||||
MrsBank = swapBankBits(pDCTData,1);
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
|
||||
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required
|
||||
* ;DDR3-defined function for write levelization.
|
||||
*/
|
||||
tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0, Level=0, Qoff=0 */
|
||||
|
||||
/* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
|
||||
tempW2 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
|
||||
if (tempW2)
|
||||
{
|
||||
if (pDCTData->DimmX8Present[currDimm])
|
||||
tempW |= 0x800;
|
||||
}
|
||||
|
||||
/* determine Rtt_Nom for WL & Normal mode */
|
||||
if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
|
||||
tempW1 = RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
|
||||
} else {
|
||||
if (wl)
|
||||
{
|
||||
if ((pDCTData->DimmRanks[currDimm] == 2) && (rank == 1))
|
||||
{
|
||||
tempW1 = 0x00; /* Rtt_Nom=OFF */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MemClkFreq < 5) {
|
||||
tempW1 = 0x0044;/* Rtt_Nom=RZQ/6=40 Ohm */
|
||||
} else {
|
||||
tempW1 = 0x0204;/* Rtt_Nom=RZQ/8=30 Ohm */
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* 1 or 4 Dimms per channel */
|
||||
if ((pDCTData->MaxDimmsInstalled == 4))
|
||||
{
|
||||
tempW1 = 0x04; /* Rtt_Nom=RZQ/4=60 Ohm */
|
||||
}
|
||||
else { /* 2 or 3 Dimms per channel */
|
||||
if (MemClkFreq < 5) {
|
||||
tempW1 = 0x0044; /* Rtt_Nom=RZQ/6=40 Ohm */
|
||||
} else {
|
||||
tempW1 = 0x0204; /* Rtt_Nom=RZQ/8=30 Ohm */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tempW=tempW|tempW1;
|
||||
/* program MrsAddress[5,1]=output driver impedance control (DIC):
|
||||
* based on F2x[1,0]84[DrvImpCtrl] */
|
||||
tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
|
||||
if (bitTest(tempW1,1))
|
||||
{tempW = bitTestSet(tempW, 5);}
|
||||
if (bitTest(tempW1,0))
|
||||
{tempW = bitTestSet(tempW, 1);}
|
||||
tempW = swapAddrBits_wl(pDCTData,tempW);
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
|
||||
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command
|
||||
* ; to the specified DIMM.
|
||||
*/
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
|
||||
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
|
||||
while ((get_Bits(pDCTData, pDCTData->CurrDct,
|
||||
pDCTData->NodeId, FUN_DCT, DRAM_INIT,
|
||||
SendMrsCmd, SendMrsCmd)) == 1);
|
||||
/* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
|
||||
* ;register that defines the required DDR3-defined function for Rtt_WR.
|
||||
*/
|
||||
MrsBank = swapBankBits(pDCTData,2);
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, MrsBankStart, MrsBankEnd, MrsBank);
|
||||
/* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
|
||||
* ; for Rtt_WR (DRAMTermDyn).
|
||||
*/
|
||||
tempW = 0;/* PASR = 0,*/
|
||||
/* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
|
||||
* based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
|
||||
tempW1 = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
|
||||
if (bitTest(tempW1,19))
|
||||
{tempW = bitTestSet(tempW, 7);}
|
||||
if (bitTest(tempW1,18))
|
||||
{tempW = bitTestSet(tempW, 6);}
|
||||
/* tempW=tempW|(((tempW1>>20)&0x7)<<3); */
|
||||
tempW=tempW|((tempW1&0x00700000)>>17);
|
||||
/* workaround for DR-B0 */
|
||||
if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
|
||||
tempW+=0x8;
|
||||
/* determine Rtt_WR for WL & Normal mode */
|
||||
if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
|
||||
tempW1 = RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
|
||||
} else {
|
||||
if (wl)
|
||||
{
|
||||
tempW1 = 0x00; /* Rtt_WR=off */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MemClkFreq == 6) {
|
||||
tempW1 = 0x200; /* Rtt_WR=RZQ/4=60 Ohm */
|
||||
} else {
|
||||
tempW1 = 0x400; /* Rtt_WR=RZQ/2 */
|
||||
}
|
||||
}
|
||||
}
|
||||
tempW=tempW|tempW1;
|
||||
tempW = swapAddrBits_wl(pDCTData,tempW);
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW);
|
||||
/* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
|
||||
the specified DIMM.*/
|
||||
set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
|
||||
/* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
|
||||
while ((get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId,
|
||||
FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
|
||||
{
|
||||
}
|
||||
rank++;
|
||||
}
|
||||
}
|
||||
}
|
||||
currDimm++;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* void programODT(sMCTStruct *pMCTData, DCTStruct *DCTData, u8 dimm)
|
||||
*
|
||||
* Description:
|
||||
* This function programs the ODT values for the NB
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN
|
||||
* OUT
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
|
||||
{
|
||||
u8 WrLvOdt1=0;
|
||||
|
||||
if (pDCTData->Status[DCT_STATUS_REGISTERED] == 0) {
|
||||
if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
|
||||
WrLvOdt1 = 0x03;
|
||||
} else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
|
||||
WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
|
||||
} else {
|
||||
WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
|
||||
}
|
||||
} else {
|
||||
WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
|
||||
}
|
||||
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* void procConifg(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass)
|
||||
*
|
||||
* Description:
|
||||
* This function programs the ODT values for the NB
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* *MCTData - Pointer to buffer with runtime parameters,
|
||||
* IN Dimm - Logical DIMM
|
||||
* Pass - First of Second Pass
|
||||
* OUT
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass)
|
||||
{
|
||||
u8 ByteLane, Seed_Gross, Seed_Fine;
|
||||
u32 Value, Addr;
|
||||
u16 Addl_Data_Offset, Addl_Data_Port;
|
||||
|
||||
/* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for the
|
||||
* ;current memory subsystem configuration.
|
||||
*/
|
||||
programODT(pMCTData, pDCTData, dimm);
|
||||
|
||||
/* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
|
||||
if (pDCTData->LogicalCPUID & AMD_DR_Cx)
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn,(u32) 1);
|
||||
else
|
||||
{
|
||||
/* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 0 for Rev.B*/
|
||||
if (pDCTData->DctTrain)
|
||||
{
|
||||
Addl_Data_Offset=0x198;
|
||||
Addl_Data_Port=0x19C;
|
||||
}
|
||||
else
|
||||
{
|
||||
Addl_Data_Offset=0x98;
|
||||
Addl_Data_Port=0x9C;
|
||||
}
|
||||
Addr=0x0D008000;
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
|
||||
while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
|
||||
DctAccessDone, DctAccessDone)) == 0);
|
||||
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
|
||||
Value = bitTestSet(Value, 12);
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
|
||||
Addr=0x4D088F00;
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
|
||||
while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
|
||||
DctAccessDone, DctAccessDone)) == 0);
|
||||
}
|
||||
|
||||
/* Wait 10 MEMCLKs to allow for ODT signal settling. */
|
||||
pMCTData->AgesaDelay(10);
|
||||
ByteLane = 0;
|
||||
if (pass == 1)
|
||||
{
|
||||
if (pDCTData->Status[DCT_STATUS_REGISTERED])
|
||||
{
|
||||
if(pDCTData->RegMan1Present & ((1<<(dimm*2+pDCTData->DctTrain))))
|
||||
{
|
||||
Seed_Gross = 0x02;
|
||||
Seed_Fine = 0x16;
|
||||
}
|
||||
else
|
||||
{
|
||||
Seed_Gross = 0x02;
|
||||
Seed_Fine = 0x00;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Seed_Gross = 0x00;
|
||||
Seed_Fine = 0x1A;
|
||||
}
|
||||
while(ByteLane < MAX_BYTE_LANES)
|
||||
{
|
||||
/* Program an initialization value to registers F2x[1, 0]9C_x[51:50] and
|
||||
* ;F2x[1, 0]9C_x52 to set the gross and fine delay for all the byte lane fields
|
||||
* ; If the target frequency is different than 400MHz, BIOS must
|
||||
* execute two training passes for each DIMM.
|
||||
* For pass 1 at a 400MHz MEMCLK frequency, use an initial total delay value
|
||||
* ; of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined
|
||||
* ;by design.
|
||||
*/
|
||||
pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross;
|
||||
pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
|
||||
ByteLane++;
|
||||
}
|
||||
}
|
||||
setWLByteDelay(pDCTData, ByteLane, dimm, 0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* void setWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm){
|
||||
*
|
||||
* Description:
|
||||
* This function writes the write levelization byte delay for the Phase
|
||||
* Recovery control registers
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN Dimm - Dimm Number
|
||||
* DCTData->WLGrossDelay[index+ByteLane] - gross write delay for each
|
||||
* logical DIMM
|
||||
* DCTData->WLFineDelay[index+ByteLane] - fine write delay for each
|
||||
* logical DIMM
|
||||
* ByteLane - target byte lane to write
|
||||
* targetAddr - 0: write to DRAM phase recovery control register
|
||||
* 1: write to DQS write register
|
||||
* OUT
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void setWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm, u8 targetAddr)
|
||||
{
|
||||
u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr;
|
||||
u32 addr, fineDelayValue, grossDelayValue, ValueLow, ValueHigh, EccValue, tempW;
|
||||
|
||||
if (targetAddr == 0)
|
||||
{
|
||||
index = (u8)(MAX_BYTE_LANES * dimm);
|
||||
ValueLow = 0;
|
||||
ValueHigh = 0;
|
||||
ByteLane = 0;
|
||||
EccValue = 0;
|
||||
while (ByteLane < MAX_BYTE_LANES)
|
||||
{
|
||||
/* This subtract 0xC workaround might be temporary. */
|
||||
if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+pDCTData->DctTrain))))
|
||||
{
|
||||
tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
|
||||
tempW -= 0xC;
|
||||
pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
|
||||
pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
|
||||
}
|
||||
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
|
||||
/* Adjust seed gross delay overflow (greater than 3):
|
||||
* - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
|
||||
* - Keep original seed gross delay for later reference.
|
||||
*/
|
||||
if(grossDelayValue >= 3)
|
||||
{
|
||||
grossDelayValue = (grossDelayValue&1)? 1 : 2;
|
||||
}
|
||||
fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
|
||||
if (ByteLane < 4)
|
||||
ValueLow |= ((grossDelayValue << 5) | fineDelayValue) << 8*ByteLane;
|
||||
else if(ByteLane < 8)
|
||||
ValueHigh |= ((grossDelayValue << 5) | fineDelayValue) << 8*(ByteLane-4);
|
||||
else
|
||||
EccValue = ((grossDelayValue << 5) | fineDelayValue);
|
||||
ByteLane++;
|
||||
}
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_CONT_ADD_PHASE_REC_CTRL_LOW, 0, 31, (u32)ValueLow);
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH, 0, 31, (u32)ValueHigh);
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_CONT_ADD_ECC_PHASE_REC_CTRL, 0, 31, (u32)EccValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = (u8)(MAX_BYTE_LANES * dimm);
|
||||
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
|
||||
fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
|
||||
|
||||
tempB = 0;
|
||||
offsetAddr = (u8)(3 * dimm);
|
||||
if (ByteLane < 2)
|
||||
{
|
||||
tempB = (u8)(16 * ByteLane);
|
||||
addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01;
|
||||
}
|
||||
else if (ByteLane <4)
|
||||
{
|
||||
tempB = (u8)(16 * ByteLane);
|
||||
addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 1;
|
||||
}
|
||||
else if (ByteLane <6)
|
||||
{
|
||||
tempB = (u8)(16 * ByteLane);
|
||||
addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45;
|
||||
}
|
||||
else if (ByteLane <8)
|
||||
{
|
||||
tempB = (u8)(16 * ByteLane);
|
||||
addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempB = 0;
|
||||
addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 2;
|
||||
}
|
||||
addr += offsetAddr;
|
||||
|
||||
fineStartLoc = (u8)(tempB % 32);
|
||||
fineEndLoc = (u8)(fineStartLoc + 4);
|
||||
grossStartLoc = (u8)(fineEndLoc + 1);
|
||||
grossEndLoc = (u8)(grossStartLoc + 1);
|
||||
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
(u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
|
||||
set_DCT_ADDR_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId, FUN_DCT,
|
||||
(u16)addr, grossStartLoc, grossEndLoc, (u32)grossDelayValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* void getWLByteDelay(DCTStruct *DCTData, u8 ByteLane, u8 Dimm)
|
||||
*
|
||||
* Description:
|
||||
* This function reads the write levelization byte delay from the Phase
|
||||
* Recovery control registers
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN Dimm - Dimm Number
|
||||
* ByteLane - target byte lane to read
|
||||
* OUT
|
||||
* DCTData->WLGrossDelay[index+ByteLane] - gross write delay for current
|
||||
* byte for logical DIMM
|
||||
* DCTData->WLFineDelay[index+ByteLane] - fine write delay for current
|
||||
* byte for logical DIMM
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void getWLByteDelay(sDCTStruct *pDCTData, u8 ByteLane, u8 dimm)
|
||||
{
|
||||
u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index;
|
||||
u32 addr, fine, gross;
|
||||
tempB = 0;
|
||||
index = (u8)(MAX_BYTE_LANES*dimm);
|
||||
if (ByteLane < 4)
|
||||
{
|
||||
tempB = (u8)(8 * ByteLane);
|
||||
addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;
|
||||
}
|
||||
else if (ByteLane < 8)
|
||||
{
|
||||
tempB1 = (u8)(ByteLane - 4);
|
||||
tempB = (u8)(8 * tempB1);
|
||||
addr = DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempB = 0;
|
||||
addr = DRAM_CONT_ADD_ECC_PHASE_REC_CTRL;
|
||||
}
|
||||
fineStartLoc = tempB;
|
||||
fineEndLoc = (u8)(fineStartLoc + 4);
|
||||
grossStartLoc = (u8)(fineEndLoc + 1);
|
||||
grossEndLoc = (u8)(grossStartLoc + 1);
|
||||
|
||||
fine = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
|
||||
FUN_DCT, (u16)addr, fineStartLoc, fineEndLoc);
|
||||
gross = get_ADD_DCT_Bits(pDCTData, pDCTData->DctTrain, pDCTData->NodeId,
|
||||
FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
|
||||
/* Adjust seed gross delay overflow (greater than 3):
|
||||
* - Adjust the trained gross delay to the original seed gross delay.
|
||||
*/
|
||||
if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
|
||||
{
|
||||
gross += pDCTData->WLGrossDelay[index+ByteLane];
|
||||
if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
|
||||
gross -= 1;
|
||||
else
|
||||
gross -= 2;
|
||||
}
|
||||
else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
|
||||
{
|
||||
/* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
|
||||
* We will then round the negative number to 0.
|
||||
*/
|
||||
gross = 0;
|
||||
fine = 0;
|
||||
}
|
||||
pDCTData->WLFineDelay[index+ByteLane] = (u8)fine;
|
||||
pDCTData->WLGrossDelay[index+ByteLane] = (u8)gross;
|
||||
}
|
270
src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
Normal file
270
src/northbridge/amd/amdmct/mct_ddr3/modtrdim.c
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* This file contains functions for odt setting on registered DDR3 dimms */
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* MODULES USED
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
/*----------------------------------------------------------------------------
|
||||
* PROTOTYPES OF LOCAL FUNCTIONS
|
||||
*
|
||||
*----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* EXPORTED FUNCTIONS
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
/* -----------------------------------------------------------------------------*/
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This function set Rtt_Nom for registered DDR3 dimms on targeted dimm.
|
||||
*
|
||||
* @param[in] *pDCTData - Pointer to buffer with information about each DCT
|
||||
* dimm - targeted dimm
|
||||
* wl - current mode, either write levelization mode or normal mode
|
||||
* MemClkFreq - current frequency
|
||||
*
|
||||
* @return tempW1 - Rtt_Nom
|
||||
*/
|
||||
static u32 RttNomTargetRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
|
||||
{
|
||||
u32 tempW1;
|
||||
tempW1 = 0;
|
||||
if (wl) {
|
||||
switch (pMCTData->PlatMaxDimmsDct) {
|
||||
case 2:
|
||||
/* 2 dimms per channel */
|
||||
if (pDCTData->MaxDimmsInstalled == 1) {
|
||||
if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 0)) {
|
||||
tempW1 = 0x00; /* Rtt_Nom = OFF */
|
||||
} else if (pDCTData->DimmRanks[dimm] == 4) {
|
||||
if (rank == 1) {
|
||||
tempW1 = 0x00; /* Rtt_Nom = OFF on second and forth rank of QR dimm */
|
||||
} else {
|
||||
if (MemClkFreq == 6) {
|
||||
tempW1 = 0x04; /* Rtt_Nom = 60 ohms */
|
||||
} else {
|
||||
tempW1 = 0x40; /* Rtt_Nom = 120 ohms */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tempW1 = 0x04; /* Rtt_Nom = 60 ohms */
|
||||
}
|
||||
} else if (pDCTData->MaxDimmsInstalled == 2) {
|
||||
if (((pDCTData->DimmRanks[dimm] == 2) || (pDCTData->DimmRanks[dimm] == 4)) && (rank == 1)) {
|
||||
tempW1 = 0x00; /* Rtt_Nom = OFF */
|
||||
} else if ((pDCTData->DimmRanks[dimm] == 4) || (pDCTData->DctCSPresent & 0xF0)) {
|
||||
if (MemClkFreq == 3) {
|
||||
tempW1 = 0x40; /* Rtt_Nom = 120 ohms */
|
||||
} else {
|
||||
tempW1 = 0x04; /* Rtt_Nom = 60 ohms */
|
||||
}
|
||||
} else {
|
||||
if (MemClkFreq == 6) {
|
||||
tempW1 = 0x04; /* Rtt_Nom = 60 ohms */
|
||||
} else {
|
||||
tempW1 = 0x40; /* Rtt_Nom = 120 ohms */
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* 3 dimms per channel */
|
||||
/* QR not supported in this case on L1 package. */
|
||||
if (pDCTData->MaxDimmsInstalled == 1) {
|
||||
if ((pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
|
||||
tempW1 = 0x00; /* Rtt_Nom = OFF */
|
||||
} else {
|
||||
tempW1 = 0x04; /* Rtt_Nom = 60 ohms */
|
||||
}
|
||||
} else {
|
||||
tempW1 = 0x40; /* Rtt_Nom = 120 ohms */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
} else {
|
||||
switch (pMCTData->PlatMaxDimmsDct) {
|
||||
case 2:
|
||||
/* 2 dimms per channel */
|
||||
if ((pDCTData->DimmRanks[dimm] == 4) && (rank == 1)) {
|
||||
tempW1 = 0x00; /* Rtt_Nom = OFF */
|
||||
} else if ((pDCTData->MaxDimmsInstalled == 1) || (pDCTData->DimmRanks[dimm] == 4)) {
|
||||
tempW1 = 0x04; /* Rtt_Nom = 60 ohms */
|
||||
} else {
|
||||
if (pDCTData->DctCSPresent & 0xF0) {
|
||||
tempW1 = 0x0204; /* Rtt_Nom = 30 ohms */
|
||||
} else {
|
||||
if (MemClkFreq < 5) {
|
||||
tempW1 = 0x44; /* Rtt_Nom = 40 ohms */
|
||||
} else {
|
||||
tempW1 = 0x0204; /* Rtt_Nom = 30 ohms */
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
/* 3 dimms per channel */
|
||||
/* L1 package does not support QR dimms this case. */
|
||||
if (rank == 1) {
|
||||
tempW1 = 0x00; /* Rtt_Nom = OFF */
|
||||
} else if (pDCTData->MaxDimmsInstalled == 1) {
|
||||
tempW1 = 0x04; /* Rtt_Nom = 60 ohms */
|
||||
} else if ((MemClkFreq < 5) || (pDCTData->MaxDimmsInstalled == 3)) {
|
||||
tempW1 = 0x44; /* Rtt_Nom = 40 ohms */
|
||||
} else {
|
||||
tempW1 = 0x0204; /* Rtt_Nom = 30 ohms */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
}
|
||||
return tempW1;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------*/
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This function set Rtt_Nom for registered DDR3 dimms on non-targeted dimm.
|
||||
*
|
||||
* @param[in] *pDCTData - Pointer to buffer with information about each DCT
|
||||
* dimm - non-targeted dimm
|
||||
* wl - current mode, either write levelization mode or normal mode
|
||||
* MemClkFreq - current frequency
|
||||
*
|
||||
* @return tempW1 - Rtt_Nom
|
||||
*/
|
||||
static u32 RttNomNonTargetRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
|
||||
{
|
||||
if ((wl) && (pMCTData->PlatMaxDimmsDct == 2) && (pDCTData->DimmRanks[dimm] == 2) && (rank == 1)) {
|
||||
return 0x00; /* for non-target dimm during WL, the second rank of a DR dimm need to have Rtt_Nom = OFF */
|
||||
} else {
|
||||
return RttNomTargetRegDimm (pMCTData, pDCTData, dimm, FALSE, MemClkFreq, rank); /* otherwise, the same as target dimm in normal mode. */
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------*/
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This function set Rtt_Wr for registered DDR3 dimms.
|
||||
*
|
||||
* @param[in] *pDCTData - Pointer to buffer with information about each DCT
|
||||
* dimm - targeted dimm
|
||||
* wl - current mode, either write levelization mode or normal mode
|
||||
* MemClkFreq - current frequency
|
||||
*
|
||||
* @return tempW1 - Rtt_Wr
|
||||
*/
|
||||
static u32 RttWrRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl, u8 MemClkFreq, u8 rank)
|
||||
{
|
||||
u32 tempW1;
|
||||
tempW1 = 0;
|
||||
if (wl) {
|
||||
tempW1 = 0x00; /* Rtt_WR = OFF */
|
||||
} else {
|
||||
switch (pMCTData->PlatMaxDimmsDct) {
|
||||
case 2:
|
||||
if (pDCTData->MaxDimmsInstalled == 1) {
|
||||
if (pDCTData->DimmRanks[dimm] != 4) {
|
||||
tempW1 = 0x00;
|
||||
} else {
|
||||
if (MemClkFreq == 6) {
|
||||
tempW1 = 0x200; /* Rtt_WR = 60 ohms */
|
||||
} else {
|
||||
tempW1 = 0x400; /* Rtt_WR = 120 ohms */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((pDCTData->DimmRanks[dimm] == 4) || (pDCTData->DctCSPresent & 0xF0)) {
|
||||
if (MemClkFreq == 3) {
|
||||
tempW1 = 0x400; /* Rtt_WR = 120 ohms */
|
||||
} else {
|
||||
tempW1 = 0x200; /* Rtt_WR = 60 ohms */
|
||||
}
|
||||
} else {
|
||||
if (MemClkFreq == 6) {
|
||||
tempW1 = 0x200; /* Rtt_WR = 60 ohms */
|
||||
} else {
|
||||
tempW1 = 0x400; /* Rtt_Nom = 120 ohms */
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (pDCTData->MaxDimmsInstalled == 1) {
|
||||
tempW1 = 0x00; /* Rtt_WR = OFF */
|
||||
} else {
|
||||
tempW1 = 0x400; /* Rtt_Nom = 120 ohms */
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ASSERT (FALSE);
|
||||
}
|
||||
}
|
||||
return tempW1;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------*/
|
||||
/**
|
||||
*
|
||||
*
|
||||
* This function set WrLvOdt for registered DDR3 dimms.
|
||||
*
|
||||
* @param[in] *pDCTData - Pointer to buffer with information about each DCT
|
||||
* dimm - targeted dimm
|
||||
*
|
||||
* @return WrLvOdt
|
||||
*/
|
||||
static u8 WrLvOdtRegDimm (sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm)
|
||||
{
|
||||
u8 WrLvOdt1, i;
|
||||
WrLvOdt1 = 0;
|
||||
i = 0;
|
||||
while (i < 8) {
|
||||
if (pDCTData->DctCSPresent & (1 << i)) {
|
||||
WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, i/2);
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
if (pMCTData->PlatMaxDimmsDct == 2) {
|
||||
if ((pDCTData->DimmRanks[dimm] == 4) && (pDCTData->MaxDimmsInstalled != 1)) {
|
||||
if (dimm >= 2) {
|
||||
WrLvOdt1 = (u8)bitTestReset (WrLvOdt1, (dimm - 2));
|
||||
} else {
|
||||
WrLvOdt1 = (u8)bitTestReset (WrLvOdt1, (dimm + 2));
|
||||
}
|
||||
} else if ((pDCTData->DimmRanks[dimm] == 2) && (pDCTData->MaxDimmsInstalled == 1)) {
|
||||
/* the case for one DR on a 2 dimms per channel is special */
|
||||
WrLvOdt1 = 0x8;
|
||||
}
|
||||
}
|
||||
return WrLvOdt1;
|
||||
}
|
39
src/northbridge/amd/amdmct/mct_ddr3/mport_d.c
Normal file
39
src/northbridge/amd/amdmct/mct_ddr3/mport_d.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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 void AmdMemPCIRead(SBDFO loc, u32 *Value)
|
||||
{
|
||||
/* Convert SBDFO into a CF8 Address */
|
||||
loc = (loc >> 4 & 0xFFFFFF00) | (loc & 0xFF) | ((loc & 0xF00) << 16) ;
|
||||
loc |= 0x80000000;
|
||||
|
||||
outl(loc, 0xCF8);
|
||||
|
||||
*Value = inl(0xCFC);
|
||||
}
|
||||
|
||||
static void AmdMemPCIWrite(SBDFO loc, u32 *Value)
|
||||
{
|
||||
/* Convert SBDFO into a CF8 Address */
|
||||
loc = (loc >> 4 & 0xFFFFFF00) | (loc & 0xFF) | ((loc & 0xF00) << 16) ;
|
||||
loc |= 0x80000000;
|
||||
|
||||
outl(loc, 0xCF8);
|
||||
outl(*Value, 0xCFC);
|
||||
}
|
328
src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
Normal file
328
src/northbridge/amd/amdmct/mct_ddr3/mutilc_d.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* This file contains functions for common utility functions */
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* MODULES USED
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
* EXPORTED FUNCTIONS
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void AmdMemPCIReadBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
|
||||
{
|
||||
/* ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0); */
|
||||
|
||||
AmdMemPCIRead(loc, pValue);
|
||||
*pValue = *pValue >> lowbit; /* Shift */
|
||||
|
||||
/* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
|
||||
if ((highbit-lowbit) != 31)
|
||||
*pValue &= (((u32)1 << (highbit-lowbit+1))-1);
|
||||
}
|
||||
|
||||
static void AmdMemPCIWriteBits(SBDFO loc, u8 highbit, u8 lowbit, u32 *pValue)
|
||||
{
|
||||
u32 temp, mask;
|
||||
|
||||
/* ASSERT(highbit < 32 && lowbit < 32 && highbit >= lowbit && (loc & 3) == 0); */
|
||||
|
||||
/* A 1<<32 == 1<<0 due to x86 SHL instruction, so skip if that is the case */
|
||||
if ((highbit-lowbit) != 31)
|
||||
mask = (((u32)1 << (highbit-lowbit+1))-1);
|
||||
else
|
||||
mask = (u32)0xFFFFFFFF;
|
||||
|
||||
AmdMemPCIRead(loc, &temp);
|
||||
temp &= ~(mask << lowbit);
|
||||
temp |= (*pValue & mask) << lowbit;
|
||||
AmdMemPCIWrite(loc, &temp);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* uint 32
|
||||
* u32 bitTestSet(u32 csMask,u32 tempD)
|
||||
*
|
||||
* Description:
|
||||
* This routine sets a bit in a u32
|
||||
*
|
||||
* Parameters:
|
||||
* IN csMask = Target value in which the bit will be set
|
||||
* IN tempD = Bit that will be set
|
||||
* OUT value = Target value with the bit set
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static u32 bitTestSet(u32 csMask,u32 tempD)
|
||||
{
|
||||
u32 localTemp;
|
||||
/* ASSERT(tempD < 32); */
|
||||
localTemp = 1;
|
||||
csMask |= localTemp << tempD;
|
||||
return csMask;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* uint 32
|
||||
* u32 bitTestReset(u32 csMask,u32 tempD)
|
||||
*
|
||||
* Description:
|
||||
* This routine re-sets a bit in a u32
|
||||
*
|
||||
* Parameters:
|
||||
* IN csMask = Target value in which the bit will be re-set
|
||||
* IN tempD = Bit that will be re-set
|
||||
* OUT value = Target value with the bit re-set
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static u32 bitTestReset(u32 csMask,u32 tempD)
|
||||
{
|
||||
u32 temp, localTemp;
|
||||
/* ASSERT(tempD < 32); */
|
||||
localTemp = 1;
|
||||
temp = localTemp << tempD;
|
||||
temp = ~temp;
|
||||
csMask &= temp;
|
||||
return csMask;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* uint 32
|
||||
* u32 get_Bits(DCTStruct *DCTData, u8 DCT, u8 Node, u8 func, u16 offset,
|
||||
* u8 low, u8 high)
|
||||
*
|
||||
* Description:
|
||||
* This routine Gets the PCT bits from the specidfied Node, DCT and PCI address
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN DCT - DCT number
|
||||
* - 1 indicates DCT 1
|
||||
* - 0 indicates DCT 0
|
||||
* - 2 both DCTs
|
||||
* Node - Node number
|
||||
* Func - PCI Function number
|
||||
* Offset - PCI register number
|
||||
* Low - Low bit of the bit field
|
||||
* High - High bit of the bit field
|
||||
*
|
||||
* OUT value = Value read from PCI space
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static u32 get_Bits(sDCTStruct *pDCTData,
|
||||
u8 dct, u8 node, u8 func,
|
||||
u16 offset, u8 low, u8 high)
|
||||
{
|
||||
u32 temp;
|
||||
/* ASSERT(node < MAX_NODES); */
|
||||
if (dct == BOTH_DCTS)
|
||||
{
|
||||
/* Registers exist on DCT0 only */
|
||||
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dct == 1)
|
||||
{
|
||||
/* Write to dct 1 */
|
||||
offset += 0x100;
|
||||
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write to dct 0 */
|
||||
AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* uint 32
|
||||
* void set_Bits(DCTStruct *DCTData,u8 DCT,u8 Node,u8 func, u16 offset,
|
||||
* u8 low, u8 high, u32 value)
|
||||
*
|
||||
* Description:
|
||||
* This routine Sets the PCT bits from the specidfied Node, DCT and PCI address
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN DCT - DCT number
|
||||
* - 1 indicates DCT 1
|
||||
* - 0 indicates DCT 0
|
||||
* - 2 both DCTs
|
||||
* Node - Node number
|
||||
* Func - PCI Function number
|
||||
* Offset - PCI register number
|
||||
* Low - Low bit of the bit field
|
||||
* High - High bit of the bit field
|
||||
*
|
||||
* OUT
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void set_Bits(sDCTStruct *pDCTData,
|
||||
u8 dct, u8 node, u8 func,
|
||||
u16 offset, u8 low, u8 high, u32 value)
|
||||
{
|
||||
u32 temp;
|
||||
temp = value;
|
||||
|
||||
if (dct == BOTH_DCTS)
|
||||
{
|
||||
/* Registers exist on DCT0 only */
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dct == 1)
|
||||
{
|
||||
/* Write to dct 1 */
|
||||
offset += 0x100;
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Write to dct 0 */
|
||||
AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+node,func,offset), high, low, &temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
* uint 32
|
||||
* u32 get_ADD_DCT_Bits(DCTStruct *DCTData,u8 DCT,u8 Node,u8 func,
|
||||
* u16 offset,u8 low, u8 high)
|
||||
*
|
||||
* Description:
|
||||
* This routine gets the Additional PCT register from Function 2 by specidfied
|
||||
* Node, DCT and PCI address
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN DCT - DCT number
|
||||
* - 1 indicates DCT 1
|
||||
* - 0 indicates DCT 0
|
||||
* - 2 both DCTs
|
||||
* Node - Node number
|
||||
* Func - PCI Function number
|
||||
* Offset - Additional PCI register number
|
||||
* Low - Low bit of the bit field
|
||||
* High - High bit of the bit field
|
||||
*
|
||||
* OUT
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
static u32 get_ADD_DCT_Bits(sDCTStruct *pDCTData,
|
||||
u8 dct, u8 node, u8 func,
|
||||
u16 offset, u8 low, u8 high)
|
||||
{
|
||||
u32 tempD;
|
||||
tempD = offset;
|
||||
tempD = bitTestReset(tempD,DctAccessWrite);
|
||||
set_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
|
||||
PCI_MIN_LOW, PCI_MAX_HIGH, offset);
|
||||
while ((get_Bits(pDCTData,dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
|
||||
DctAccessDone, DctAccessDone)) == 0);
|
||||
return (get_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_PORT_REG,
|
||||
low, high));
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
* uint 32
|
||||
* void set_DCT_ADDR_Bits(DCTStruct *DCTData, u8 DCT,u8 Node,u8 func,
|
||||
* u16 offset,u8 low, u8 high, u32 value)
|
||||
*
|
||||
* Description:
|
||||
* This routine sets the Additional PCT register from Function 2 by specidfied
|
||||
* Node, DCT and PCI address
|
||||
*
|
||||
* Parameters:
|
||||
* IN OUT *DCTData - Pointer to buffer with information about each DCT
|
||||
* IN DCT - DCT number
|
||||
* - 1 indicates DCT 1
|
||||
* - 0 indicates DCT 0
|
||||
* - 2 both DCTs
|
||||
* Node - Node number
|
||||
* Func - PCI Function number
|
||||
* Offset - Additional PCI register number
|
||||
* Low - Low bit of the bit field
|
||||
* High - High bit of the bit field
|
||||
*
|
||||
* OUT
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
static void set_DCT_ADDR_Bits(sDCTStruct *pDCTData,
|
||||
u8 dct, u8 node, u8 func,
|
||||
u16 offset, u8 low, u8 high, u32 value)
|
||||
{
|
||||
u32 tempD;
|
||||
|
||||
set_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
|
||||
PCI_MIN_LOW, PCI_MAX_HIGH, offset);
|
||||
while ((get_Bits(pDCTData,dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
|
||||
DctAccessDone, DctAccessDone)) == 0);
|
||||
|
||||
set_Bits(pDCTData, dct, node, FUN_DCT, DRAM_CONTROLLER_ADD_DATA_PORT_REG,
|
||||
low, high, value);
|
||||
tempD = offset;
|
||||
tempD = bitTestSet(tempD,DctAccessWrite);
|
||||
set_Bits(pDCTData, dct, node, FUN_DCT,DRAM_CONTROLLER_ADD_DATA_OFFSET_REG,
|
||||
PCI_MIN_LOW, PCI_MAX_HIGH, tempD);
|
||||
while ((get_Bits(pDCTData,dct, pDCTData->NodeId, FUN_DCT,
|
||||
DRAM_CONTROLLER_ADD_DATA_OFFSET_REG, DctAccessDone,
|
||||
DctAccessDone)) == 0);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
* uint 32
|
||||
* BOOL bitTest(u32 value, u8 bitLoc)
|
||||
*
|
||||
* Description:
|
||||
* This routine tests the value to determine if the bitLoc is set
|
||||
*
|
||||
* Parameters:
|
||||
* IN Value - value to be tested
|
||||
* bitLoc - bit location to be tested
|
||||
* OUT TRUE - bit is set
|
||||
* FALSE - bit is clear
|
||||
*-------------------------------------------------
|
||||
*/
|
||||
static BOOL bitTest(u32 value, u8 bitLoc)
|
||||
{
|
||||
u32 tempD, compD;
|
||||
tempD = value;
|
||||
compD = 0;
|
||||
compD = bitTestSet(compD,bitLoc);
|
||||
tempD &= compD;
|
||||
if (compD == tempD)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
139
src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
Normal file
139
src/northbridge/amd/amdmct/mct_ddr3/mwlc_d.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
/* IBV defined Structure */ /* IBV Specific Options */
|
||||
#ifndef MWLC_D_H
|
||||
#define MWLC_D_H
|
||||
|
||||
#define MAX_TOTAL_DIMMS 8 /* Maximum Number of DIMMs in systems */
|
||||
/* (DCT0 + DCT1) */
|
||||
#define MAX_DIMMS 4 /* Maximum Number of DIMMs on each DCT */
|
||||
#define MAX_LDIMMS 4 /* Maximum number of Logial DIMMs per DCT */
|
||||
|
||||
/*MCT Max variables */
|
||||
#define MAX_ERRORS 32 /* Maximum number of Errors Reported */
|
||||
#define MAX_STATUS 32 /* Maximum number of Status variables*/
|
||||
#define MAX_BYTE_LANES (8+1) /* Maximum number of Byte Lanes - include ECC */
|
||||
|
||||
#define C_MAX_DIMMS 4 /* Maximum Number of DIMMs on each DCT */
|
||||
|
||||
/* STATUS Definition */
|
||||
#define DCT_STATUS_REGISTERED 3 /* Registered DIMMs support */
|
||||
#define DCT_STATUS_OnDimmMirror 24 /* OnDimmMirror support */
|
||||
|
||||
/* PCI Defintions */
|
||||
#define FUN_HT 0 /* Funtion 0 Access */
|
||||
#define FUN_MAP 1 /* Funtion 1 Access */
|
||||
#define FUN_DCT 2 /* Funtion 2 Access */
|
||||
#define FUN_MISC 3 /* Funtion 3 Access */
|
||||
#define FUN_ADD_DCT 0xF /* Funtion 2 Additional Register Access */
|
||||
#define BOTH_DCTS 2 /* The access is independent of DCTs */
|
||||
#define PCI_MIN_LOW 0 /* Lowest possible PCI register location */
|
||||
#define PCI_MAX_HIGH 31 /* Highest possible PCI register location */
|
||||
|
||||
/*Function 2 */
|
||||
/* #define DRAM_INIT 0x7C */
|
||||
#define DRAM_MRS_REGISTER 0x84
|
||||
#define DRAM_CONFIG_HIGH 0x94
|
||||
#define DRAM_CONTROLLER_ADD_DATA_OFFSET_REG 0x98
|
||||
#define DRAM_CONTROLLER_ADD_DATA_PORT_REG 0x9C
|
||||
|
||||
/*Function 2 Additional DRAM control registers */
|
||||
#define DRAM_ADD_DCT_PHY_CONTROL_REG 0x8
|
||||
#define DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 0x30
|
||||
#define DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 0x40
|
||||
#define DRAM_CONT_ADD_PHASE_REC_CTRL_LOW 0x50
|
||||
#define DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH 0x51
|
||||
#define DRAM_CONT_ADD_ECC_PHASE_REC_CTRL 0x52
|
||||
#define DRAM_CONT_ADD_WRITE_LEV_ERROR_REG 0x53
|
||||
|
||||
/* CPU Register defintions */
|
||||
|
||||
/* Register Bit Location */
|
||||
#define DctAccessDone 31
|
||||
#define DctAccessWrite 30
|
||||
#define RDqsEn 12
|
||||
#define TrDimmSelStart 4
|
||||
#define TrDimmSelEnd 5
|
||||
#define WrLvTrMode 1
|
||||
#define TrNibbleSel 2
|
||||
#define WrLvOdtEn 12
|
||||
#define WrLvErrStart 0
|
||||
#define WrLvErrEnd 8
|
||||
#define SendMrsCmd 26
|
||||
#define Qoff 12
|
||||
#define MRS_Level 7
|
||||
#define MrsAddressStart 0
|
||||
#define MrsAddressEnd 15
|
||||
#define MrsBankStart 16
|
||||
#define MrsBankEnd 18
|
||||
#define MrsChipSelStart 20
|
||||
#define MrsChipSelEnd 22
|
||||
#define ASR 18
|
||||
#define SRT 19
|
||||
#define DramTermDynStart 10
|
||||
#define DramTermDynEnd 11
|
||||
#define WrtLvTrMode 1
|
||||
#define TrNibbleSel 2
|
||||
#define TrDimmSelStart 4
|
||||
#define TrDimmSelEnd 5
|
||||
#define WrtLvTrEn 0
|
||||
#define DrvImpCtrlStart 2
|
||||
#define DrvImpCtrlEnd 3
|
||||
#define DramTermNbStart 7
|
||||
#define DramTermNbEnd 9
|
||||
#define onDimmMirror 3
|
||||
|
||||
typedef struct _sMCTStruct
|
||||
{
|
||||
u8 PlatMaxTotalDimms; /* IBV defined total number of DIMMs */
|
||||
/* on a particular node */
|
||||
u8 PlatMaxDimmsDct; /* IBV defined maximum number of */
|
||||
/* DIMMs on a DCT */
|
||||
void (*AgesaDelay)(u32 delayval); /* IBV defined Delay Function */
|
||||
} sMCTStruct;
|
||||
|
||||
/* DCT 0 and DCT 1 Data structure */
|
||||
typedef struct _sDCTStruct
|
||||
{
|
||||
u8 NodeId; /* Node ID */
|
||||
u8 DctTrain; /* Current DCT being trained */
|
||||
u8 CurrDct; /* Current DCT number (0 or 1) */
|
||||
u8 DctCSPresent; /* Current DCT CS mapping */
|
||||
u8 WLGrossDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write Levelization Gross Delay */
|
||||
/* per byte Lane Per Logical DIMM*/
|
||||
u8 WLFineDelay[MAX_BYTE_LANES*MAX_LDIMMS]; /* Write Levelization Fine Delay */
|
||||
/* per byte Lane Per Logical DIMM*/
|
||||
u16 RegMan1Present;
|
||||
u8 DimmPresent[MAX_TOTAL_DIMMS];/* Indicates which DIMMs are present */
|
||||
/* from Total Number of DIMMs(per Node)*/
|
||||
u8 DimmX8Present[MAX_TOTAL_DIMMS]; /* Which DIMMs x8 devices */
|
||||
u8 Status[MAX_STATUS]; /* Status for DCT0 and 1 */
|
||||
u8 ErrCode[MAX_ERRORS]; /* Major Error codes for DCT0 and 1 */
|
||||
u8 ErrStatus[MAX_ERRORS]; /* Minor Error codes for DCT0 and 1 */
|
||||
u8 DimmValid[MAX_TOTAL_DIMMS]; /* Indicates which DIMMs are valid for */
|
||||
/* Total Number of DIMMs(per Node) */
|
||||
u8 WLTotalDelay[MAX_BYTE_LANES];/* Write Levelization Toral Delay */
|
||||
/* per byte lane */
|
||||
u8 MaxDimmsInstalled; /* Max Dimms Installed for current DCT */
|
||||
u8 DimmRanks[MAX_TOTAL_DIMMS]; /* Total Number of Ranks(per Dimm) */
|
||||
u32 LogicalCPUID;
|
||||
u8 WLPass;
|
||||
} sDCTStruct;
|
||||
|
||||
#endif
|
@@ -27,8 +27,10 @@ static u16 mctGet_NVbits(u8 index)
|
||||
case NV_PACK_TYPE:
|
||||
#if CONFIG_CPU_SOCKET_TYPE == 0x10 /* Socket F */
|
||||
val = 0;
|
||||
#elif CONFIG_CPU_SOCKET_TYPE == 0x11 /* AM2r2 */
|
||||
#elif CONFIG_CPU_SOCKET_TYPE == 0x11 /* AM3 */
|
||||
val = 1;
|
||||
#elif CONFIG_CPU_SOCKET_TYPE == 0x13 /* ASB2 */
|
||||
val = 4;
|
||||
//#elif SYSTEM_TYPE == MOBILE
|
||||
// val = 2;
|
||||
#endif
|
||||
@@ -400,9 +402,21 @@ static void vErrata350(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTs
|
||||
|
||||
static void mctHookBeforeAnyTraining(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA)
|
||||
{
|
||||
if (pDCTstatA->LogicalCPUID & (AMD_RB_C2 | AMD_DA_C2)) {
|
||||
#if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */
|
||||
if (pDCTstatA->LogicalCPUID & (AMD_RB_C2 | AMD_DA_C2 | AMD_DA_C3)) {
|
||||
vErrata350(pMCTstat, pDCTstatA);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 mct_AdjustSPDTimings(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA, u32 val)
|
||||
{
|
||||
if (pDCTstatA->LogicalCPUID & AMD_DR_Bx) {
|
||||
if (pDCTstatA->Status & (1 << SB_Registered)) {
|
||||
val ++;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void mctHookAfterAnyTraining(void)
|
||||
@@ -418,3 +432,4 @@ static u8 mctSetNodeBoundary_D(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user