From e3aeb93a52d03e1b3dfcf30c66956b18f7f600d7 Mon Sep 17 00:00:00 2001 From: "Marc Jones (marc.jones" Date: Fri, 11 Apr 2008 03:20:28 +0000 Subject: [PATCH] Bring Fam10 memory controller init up to date with the latest AMD BKDG recomendations. Changes include the following: fix > 4GB dqs tests fix channel interleaving ecc memory scrub updates MC tristating updates debug print changes fix memory hoisting across nodes - The DRAM Hole Address Register is set via devx in each node, but the Node number <-> DRAM Base mapping and the Node number <-> DstNode mapping is set in Node 0. The memmap is setup on node0 and copied to the other nodes later. so dev, not devx. The bug was the hole was always being set on the first node. Signed-off-by: Marc Jones (marc.jones@amd.com) Acked-by: Carl-Daniel Hailfinger git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3232 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- src/northbridge/amd/amdmct/mct/mct_d.c | 198 +++++++++++++------ src/northbridge/amd/amdmct/mct/mct_d.h | 5 +- src/northbridge/amd/amdmct/mct/mctchi_d.c | 17 +- src/northbridge/amd/amdmct/mct/mctdqs_d.c | 12 +- src/northbridge/amd/amdmct/mct/mctecc_d.c | 33 +++- src/northbridge/amd/amdmct/mct/mctmtr_d.c | 64 +++++- src/northbridge/amd/amdmct/mct/mctsrc.c | 66 +++---- src/northbridge/amd/amdmct/wrappers/mcti_d.c | 13 +- 8 files changed, 264 insertions(+), 144 deletions(-) diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c b/src/northbridge/amd/amdmct/mct/mct_d.c index 8cea56546b..f29953a5c6 100644 --- a/src/northbridge/amd/amdmct/mct/mct_d.c +++ b/src/northbridge/amd/amdmct/mct/mct_d.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2008 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 @@ -279,6 +279,9 @@ restartinit: print_t("mctAutoInitMCT_D: DQSTiming_D\n"); DQSTiming_D(pMCTstat, pDCTstatA); /* Get Receiver Enable and DQS signal timing*/ + print_t("mctAutoInitMCT_D: UMAMemTyping_D\n"); + UMAMemTyping_D(pMCTstat, pDCTstatA); /* Fix up for UMA sizing */ + print_t("mctAutoInitMCT_D: :OtherTiming\n"); mct_OtherTiming(pMCTstat, pDCTstatA); @@ -348,10 +351,11 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat, /* FIXME: BOZO- DQS training every time*/ nv_DQSTrainCTL = 1; + print_t("DQSTiming_D: mct_BeforeDQSTrain_D:\n"); + mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);; + phyAssistedMemFnceTraining(pMCTstat, pDCTstatA); + if (nv_DQSTrainCTL) { - print_t("DQSTiming_D: mct_BeforeDQSTrain_D:\n"); - mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);; - phyAssistedMemFnceTraining(pMCTstat, pDCTstatA); mctHookBeforeAnyTraining(); print_t("DQSTiming_D: TrainReceiverEn_D FirstPass:\n"); @@ -512,7 +516,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, u32 val; u32 base; u32 limit; - u32 dev; + u32 dev, devx; struct DCTStatStruc *pDCTstat; _MemHoleRemap = mctGet_NVbits(NV_MemHole); @@ -531,6 +535,8 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { + pDCTstat = pDCTstatA + Node; + devx = pDCTstat->dev_map; DramSelBaseAddr = 0; pDCTstat = pDCTstatA + Node; if (!pDCTstat->GangedMode) { @@ -569,7 +575,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, val <<= 8; /* shl 16, rol 24 */ val |= DramHoleBase << 24; val |= 1 << DramHoleValid; - Set_NB32(dev, 0xF0, val); /*Dram Hole Address Register*/ + Set_NB32(devx, 0xF0, val); /* Dram Hole Address Reg */ pDCTstat->DCTSysLimit += HoleSize; base = pDCTstat->DCTSysBase; limit = pDCTstat->DCTSysLimit; @@ -598,21 +604,33 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, pMCTstat->SysLimit = limit; } Set_NB32(dev, 0x40 + (Node << 3), base); /* [Node] + Dram Base 0 */ - val = limit & 0xffff0000; - val |= Node; /* set DstNode*/ + + /* if Node limit > 1GB then set it to 1GB boundary for each node */ + if ((mctSetNodeBoundary_D()) && (limit > 0x00400000)) { + limit++; + limit &= 0xFFC00000; + limit--; + } + val = limit & 0xFFFF0000; + val |= Node; Set_NB32(dev, 0x44 + (Node << 3), val); /* set DstNode */ limit = pDCTstat->DCTSysLimit; if (limit) { - NextBase = (limit & 0xffff0000) + 0x10000; + NextBase = (limit & 0xFFFF0000) + 0x10000; + if ((mctSetNodeBoundary_D()) && (NextBase > 0x00400000)) { + NextBase++; + NextBase &= 0xFFC00000; + NextBase--; + } } } /* Copy dram map from Node 0 to Node 1-7 */ for (Node = 1; Node < MAX_NODES_SUPPORTED; Node++) { - pDCTstat = pDCTstatA + Node; u32 reg; - u32 devx = pDCTstat->dev_map; + pDCTstat = pDCTstatA + Node; + devx = pDCTstat->dev_map; if (pDCTstat->NodePresent) { printk_debug(" Copy dram map from Node 0 to Node %02x \n", Node); @@ -1016,7 +1034,7 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat, if ((val == 0) || (val == 0xFF)) { pDCTstat->ErrStatus |= 1<ErrCode = SC_VarianceErr; - val = Get_DefTrc_k_D(pDCTstat->DIMMAutoSpeed); + val = Get_DefTrc_k_D(pDCTstat->Speed); } else { byte = mctRead_SPD(smbaddr, SPD_TRCRFC); if (byte & 0xF0) { @@ -1054,7 +1072,7 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat, /* Convert DRAM CycleTiming values and store into DCT structure */ DDR2_1066 = 0; - byte = pDCTstat->DIMMAutoSpeed; + byte = pDCTstat->Speed; if (byte == 5) DDR2_1066 = 1; Tk40 = Get_40Tk_D(byte); @@ -1175,12 +1193,10 @@ static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat, dword = Trtp * 10; pDCTstat->DIMMTrtp = dword; val = pDCTstat->Speed; - if (val <= 2) { - val = 2; /* Calculate by 7.75ns / Speed in ns to get clock # */ - } else if (val == 4) { /* Note a speed of 3 will be a Trtp of 3 */ - val = 3; - } else if (val == 5){ - val = 2; + if (val <= 2) { /* 7.75ns / Speed in ns to get clock # */ + val = 2; /* for DDR400/DDR533 */ + } else { /* Note a speed of 3 will be a Trtp of 3 */ + val = 3; /* for DDR667/DDR800/DDR1066 */ } pDCTstat->Trtp = val; @@ -1810,7 +1826,7 @@ static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat, /* SetCKETriState */ SetODTTriState(pMCTstat, pDCTstat, dct); - if ( pDCTstat->Status & 1<Status & (1 << SB_128bitmode)) { SetCSTriState(pMCTstat, pDCTstat, 1); /* force dct1) */ SetODTTriState(pMCTstat, pDCTstat, 1); /* force dct1) */ } @@ -2631,7 +2647,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat, if (!pDCTstat->GangedMode) { dev = pDCTstat->dev_dct; pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit; - /* if DCT0 and DCT1 exist both, set DctSelBaseAddr[47:27] */ + /* if DCT0 and DCT1 both exist, set DctSelBaseAddr[47:27] to the top of DCT0 */ if (dct == 0) { if (pDCTstat->DIMMValidDCT[1] > 0) { dword = pDCTstat->DCTSysLimit + 1; @@ -2641,8 +2657,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat, pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8; val = pMCTstat->HoleBase; val >>= 16; - val &= ~(0xFF); - val |= (((~val) & 0xFF) + 1); + val = (((~val) & 0xFF) + 1); val <<= 8; dword += val; } @@ -2653,6 +2668,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat, val |= 3; /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */ Set_NB32(dev, reg, val); print_tx("AfterStitch DCT0 and DCT1: DRAM Controller Select Low Register = ", val); + print_tx("AfterStitch DCT0 and DCT1: DRAM Controller Select High Register = ", dword); reg = 0x114; val = dword; @@ -2664,7 +2680,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat, if (pDCTstat->DIMMValidDCT[0] == 0) { dword = pDCTstat->NodeSysBase; dword >>= 8; - if (dword >= DramHoleBase) { + if ((dword >= DramHoleBase) && _MemHoleRemap) { pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8; val = pMCTstat->HoleBase; val >>= 8; @@ -2680,6 +2696,7 @@ static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat, val |= 3; /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */ Set_NB32(dev, reg, val); print_tx("AfterStitch DCT1 only: DRAM Controller Select Low Register = ", val); + print_tx("AfterStitch DCT1 only: DRAM Controller Select High Register = ", dword); } } } else { @@ -2872,16 +2889,25 @@ static void Get_Twrwr(struct MCTStatStruc *pMCTstat, static void Get_Twrrd(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) { - u8 byte, bytex; + u8 byte, bytex, val; u32 index_reg = 0x98 + 0x100 * dct; u32 dev = pDCTstat->dev_dct; /* On any given byte lane, the largest WrDatGrossDlyByte delay of any DIMM minus the DqsRcvEnGrossDelay delay of any other DIMM is equal to the Critical Gross Delay Difference (CGDD) for Twrrd.*/ - pDCTstat->Twrrd = 0; + + /* WrDatGrossDlyByte only use one set register when DDR400~DDR667 + DDR800 have two set register for DIMM0 and DIMM1 */ + if (pDCTstat->Speed > 3) { + val = Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg); + } else { + val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 1); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM0 */ + pDCTstat->WrDatGrossH = (u8) val; /* low byte = max value */ + } + Get_DqsRcvEnGross_Diff(pDCTstat, dev, index_reg); - Get_WrDatGross_Diff(pDCTstat, dct, dev, index_reg); + bytex = pDCTstat->DqsRcvEnGrossL; byte = pDCTstat->WrDatGrossH; if (byte > bytex) { @@ -2946,12 +2972,16 @@ static u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat, u8 i; u32 val; u8 byte; + u8 ecc_reg = 0; Smallest_0 = 0xFF; Smallest_1 = 0xFF; Largest_0 = 0; Largest_1 = 0; + if (index == 0x12) + ecc_reg = 1; + for (i=0; i < 8; i+=2) { if ( pDCTstat->DIMMValid & (1 << i)) { val = Get_NB32_index_wait(dev, index_reg, index); @@ -2960,11 +2990,13 @@ static u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat, Smallest_0 = byte; if (byte > Largest_0) Largest_0 = byte; - byte = (val >> 16) & 0xFF; - if (byte < Smallest_1) - Smallest_1 = byte; - if (byte > Largest_1) - Largest_1 = byte; + if (!(ecc_reg)) { + byte = (val >> 16) & 0xFF; + if (byte < Smallest_1) + Smallest_1 = byte; + if (byte > Largest_1) + Largest_1 = byte; + } } index += 3; } /* while ++i */ @@ -2973,8 +3005,9 @@ static u8 Check_DqsRcvEn_Diff(struct DCTStatStruc *pDCTstat, two DIMMs is less than half of a MEMCLK */ if ((Largest_0 - Smallest_0) > 31) return 1; - if ((Largest_1 - Smallest_1) > 31) - return 1; + if (!(ecc_reg)) + if ((Largest_1 - Smallest_1) > 31) + return 1; return 0; } @@ -3072,10 +3105,14 @@ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat, u8 byte; u32 val; u16 word; + u8 ecc_reg = 0; Smallest = 7; Largest = 0; + if (index == 0x12) + ecc_reg = 1; + for (i=0; i < 8; i+=2) { if ( pDCTstat->DIMMValid & (1 << i)) { val = Get_NB32_index_wait(dev, index_reg, index); @@ -3085,11 +3122,13 @@ static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat, Smallest = byte; if (byte > Largest) Largest = byte; - byte = (val >> (16 + 5)) & 0xFF; - if (byte < Smallest) - Smallest = byte; - if (byte > Largest) - Largest = byte; + if (!(ecc_reg)) { + byte = (val >> (16 + 5)) & 0xFF; + if (byte < Smallest) + Smallest = byte; + if (byte > Largest) + Largest = byte; + } } index += 3; } /* while ++i */ @@ -3353,25 +3392,32 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat, u32 index_reg = 0x98 + 0x100 * dct; u8 cs; u32 index; - u16 word; - - /* Tri-state unused ODTs when motherboard termination is available */ + u8 odt; + u8 max_dimms; // FIXME: skip for Ax - dev = pDCTstat->dev_dct; - word = 0; + /* Tri-state unused ODTs when motherboard termination is available */ + max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS); + odt = 0x0F; /* tristate all the pins then clear the used ones. */ + for (cs = 0; cs < 8; cs += 2) { - if (!(pDCTstat->CSPresent & (1 << cs))) { - if (!(pDCTstat->CSPresent & (1 << (cs + 1)))) - word |= (1 << (cs >> 1)); + if (pDCTstat->CSPresent & (1 << cs)) { + odt &= ~(1 << (cs / 2)); + + /* if quad-rank capable platform clear adtitional pins */ + if (max_dimms != MAX_CS_SUPPORTED) { + if (pDCTstat->CSPresent & (1 << (cs + 1))) + odt &= ~(4 << (cs / 2)); + } } } index = 0x0C; val = Get_NB32_index_wait(dev, index_reg, index); - val |= (word << 8); + val |= (odt << 8); Set_NB32_index_wait(dev, index_reg, index, val); + } @@ -3414,8 +3460,14 @@ static void InitPhyCompensation(struct MCTStatStruc *pMCTstat, } /* Override/Exception */ - if ((pDCTstat->Speed == 2) && (pDCTstat->MAdimms[dct] == 4)) - dword &= 0xF18FFF18; + if (!pDCTstat->GangedMode) { + i = 0; /* use i for the dct setting required */ + if (pDCTstat->MAdimms[0] < 4) + i = 1; + if (((pDCTstat->Speed == 2) || (pDCTstat->Speed == 3)) && (pDCTstat->MAdimms[i] == 4)) + dword &= 0xF18FFF18; + index_reg = 0x98; /* force dct = 0 */ + } Set_NB32_index_wait(dev, index_reg, 0x0a, dword); } @@ -3733,12 +3785,26 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) { u8 Receiver; - u32 val; u32 dev = pDCTstat->dev_dct; u32 reg_off = 0x100 * dct; u32 addr; + u32 lo, hi; + u8 wrap32dis = 0; u8 valid = 0; + /* FIXME: Skip reset DLL for B3 */ + + 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 32bit mode */ + _WRMSR(addr, lo, hi); + + pDCTstat->Channel = dct; Receiver = mct_InitReceiver_D(pDCTstat, dct); /* there are four receiver pairs, loosely associated with chipselects.*/ @@ -3747,23 +3813,24 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat, addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, dct, Receiver, &valid); if (valid) { mct_Read1LTestPattern_D(pMCTstat, pDCTstat, addr); /* cache fills */ - Set_NB32(dev, 0x98 + reg_off, 0x0D00000C); - val = Get_NB32(dev, 0x9C + reg_off); - val |= 1 << 15; - Set_NB32(dev, 0x9C + reg_off, val); - Set_NB32(dev, 0x98 + reg_off, 0x4D0F0F0C); - mct_Wait_10ns(60); /* wait >= 300ns */ - Set_NB32(dev, 0x98 + reg_off, 0x0D00000C); - val = Get_NB32(dev, 0x9C + reg_off); - val &= ~(1 << 15); - Set_NB32(dev, 0x9C + reg_off, val); - Set_NB32(dev, 0x98 + reg_off, 0x4D0F0F0C); - mct_Wait_10ns(400); /* wait >= 2us */ + /* Write 0000_8000h to register F2x[1,0]9C_xD080F0C */ + Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00008000); + mct_Wait(80); /* wait >= 300ns */ + + /* Write 0000_0000h to register F2x[1,0]9C_xD080F0C */ + Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00000000); + mct_Wait(800); /* wait >= 2us */ break; } } } + if(!wrap32dis) { + addr = HWCR; + _RDMSR(addr, &lo, &hi); + lo &= ~(1<<17); /* restore HWCR.wrap32dis */ + _WRMSR(addr, lo, hi); + } } @@ -3784,7 +3851,7 @@ static void mct_EnableDatIntlv_D(struct MCTStatStruc *pMCTstat, // FIXME Skip for Cx dev = pDCTstat->dev_nbmisc; val = Get_NB32(dev, 0x8C); // NB Configuration Hi - val |= 36-32; // DisDatMask + val |= 1 << (36-32); // DisDatMask Set_NB32(dev, 0x8C, val); } } @@ -3818,8 +3885,9 @@ static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) { u32 reg_off = 0x100 * dct; u32 dev = pDCTstat->dev_dct; + /* FIXME: Add B3 */ if (pDCTstat->LogicalCPUID & AMD_DR_B2) { - mct_Wait_10ns(5000); /* Wait 50 us*/ + mct_Wait(10000); /* Wait 50 us*/ val = Get_NB32(dev, 0x110); if ( val & (1 << DramEnabled)) { /* If 50 us expires while DramEnable =0 then do the following */ diff --git a/src/northbridge/amd/amdmct/mct/mct_d.h b/src/northbridge/amd/amdmct/mct/mct_d.h index 37939a8488..9542bcb045 100644 --- a/src/northbridge/amd/amdmct/mct/mct_d.h +++ b/src/northbridge/amd/amdmct/mct/mct_d.h @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2008 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 @@ -699,6 +699,7 @@ 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); @@ -730,7 +731,7 @@ void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat, struct DCTStatStr u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass); static void mct_AdjustScrub_D(struct DCTStatStruc *pDCTstat, u16 *scrub_request); static u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct); -static void mct_Wait_10ns (u32 cycles); +static 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); diff --git a/src/northbridge/amd/amdmct/mct/mctchi_d.c b/src/northbridge/amd/amdmct/mct/mctchi_d.c index 425faf7528..ec6aa96c31 100644 --- a/src/northbridge/amd/amdmct/mct/mctchi_d.c +++ b/src/northbridge/amd/amdmct/mct/mctchi_d.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2008 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 @@ -41,11 +41,10 @@ void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, /* call back to wrapper not needed ManualChannelInterleave_D(); */ /* call back - DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv);*/ /* override interleave */ // FIXME: Check for Cx - DctSelIntLvAddr = 5; /* use default: Enable channel interleave */ - enabled = 1; /* with Hash*: exclusive OR of address bits[20:16, 6]. */ + DctSelIntLvAddr = mctGet_NVbits(NV_ChannelIntlv); /* typ=5: Hash*: exclusive OR of address bits[20:16, 6]. */ beforeInterleaveChannels_D(pDCTstatA, &enabled); - if (enabled) { + if (DctSelIntLvAddr & 1) { DctSelIntLvAddr >>= 1; HoleSize = 0; if ((pMCTstat->GStatus & (1 << GSB_SoftHole)) || @@ -84,7 +83,7 @@ void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, dct0_size += DramBase; dct0_size += dct1_size; if (dct0_size >= HoleBase) /* if DctSelBaseAddr > HoleBase */ - dct0_size += HoleBase; + dct0_size += HoleSize; DctSelBase = dct0_size; if (dct1_size == 0) @@ -100,7 +99,7 @@ void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, val |= DctSelHi; val |= (DctSelIntLvAddr << 6) & 0xFF; Set_NB32(pDCTstat->dev_dct, 0x110, val); - print_tx("InterleaveChannels: DRAM Controller Select Low Register = ", val); + print_tx("InterleaveChannels: F2x110 DRAM Controller Select Low Register = ", val); if (HoleValid) { tmp = DramBase; @@ -112,10 +111,10 @@ void InterleaveChannels_D(struct MCTStatStruc *pMCTstat, } tmp += HoleSize; val = Get_NB32(pDCTstat->dev_map, 0xF0); /* DramHoleOffset */ - val &= 0x7F; - val |= (tmp & 0xFF); + val &= 0xFFFF007F; + val |= (tmp & ~0xFFFF007F); Set_NB32(pDCTstat->dev_map, 0xF0, val); -print_tx("InterleaveChannels:0xF0 = ", val); + print_tx("InterleaveChannels: F1xF0 DRAM Hole Address Register = ", val); } } diff --git a/src/northbridge/amd/amdmct/mct/mctdqs_d.c b/src/northbridge/amd/amdmct/mct/mctdqs_d.c index 7078c7004b..59ba09294b 100644 --- a/src/northbridge/amd/amdmct/mct/mctdqs_d.c +++ b/src/northbridge/amd/amdmct/mct/mctdqs_d.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2008 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 @@ -1130,6 +1130,9 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat, val += (1 << (15-8)); /* add 32K */ } + /* Add a node seed */ + val += (((1 * pDCTstat->Node_ID) << 20) >> 8); /* Add 1MB per node to avoid aliases */ + /* HW remap disabled? */ if (!(pDCTstat->Status & (1 << SB_HWHole))) { if (!(pDCTstat->Status & (1 << SB_SWNodeHole))) { @@ -1167,6 +1170,13 @@ exitGetAddrWNoError: *valid = 1; } } + print_debug_dqs("mct_GetMCTSysAddr_D: receiver ", receiver, 2); + print_debug_dqs("mct_GetMCTSysAddr_D: Channel ", Channel, 2); + print_debug_dqs("mct_GetMCTSysAddr_D: base_addr ", val, 2); + print_debug_dqs("mct_GetMCTSysAddr_D: valid ", *valid, 2); + print_debug_dqs("mct_GetMCTSysAddr_D: status ", pDCTstat->Status, 2); + print_debug_dqs("mct_GetMCTSysAddr_D: HoleBase ", pDCTstat->DCTHoleBase, 2); + print_debug_dqs("mct_GetMCTSysAddr_D: Cachetop ", pMCTstat->Sub4GCacheTop, 2); exitGetAddr: return val; diff --git a/src/northbridge/amd/amdmct/mct/mctecc_d.c b/src/northbridge/amd/amdmct/mct/mctecc_d.c index d8d37bad99..36cb7cbea2 100644 --- a/src/northbridge/amd/amdmct/mct/mctecc_d.c +++ b/src/northbridge/amd/amdmct/mct/mctecc_d.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2008 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 @@ -88,6 +88,7 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA) u32 dev; u32 reg; u32 val; + u16 nvbits; mctHookBeforeECC(); @@ -100,14 +101,15 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA) OB_ChipKill = mctGet_NVbits(NV_ChipKill); /* ECC Chip-kill mode */ OF_ScrubCTL = 0; /* Scrub CTL for Dcache, L2, and dram */ - val = mctGet_NVbits(NV_DCBKScrub); - mct_AdjustScrub_D(pDCTstatA, val); - OF_ScrubCTL |= val << 16; - val = mctGet_NVbits(NV_L2BKScrub); - OF_ScrubCTL |= val << 8; + nvbits = mctGet_NVbits(NV_DCBKScrub); + mct_AdjustScrub_D(pDCTstatA, &nvbits); + OF_ScrubCTL |= (u32) nvbits << 16; - val = mctGet_NVbits(NV_DramBKScrub); - OF_ScrubCTL |= val; + nvbits = mctGet_NVbits(NV_L2BKScrub); + OF_ScrubCTL |= (u32) nvbits << 8; + + nvbits = mctGet_NVbits(NV_DramBKScrub); + OF_ScrubCTL |= nvbits; AllECC = 1; MemClrECC = 0; @@ -190,7 +192,20 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA) 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 */ /*set dram background scrubbing to setup value */ + 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 */ diff --git a/src/northbridge/amd/amdmct/mct/mctmtr_d.c b/src/northbridge/amd/amdmct/mct/mctmtr_d.c index d39bfcc8b2..76cf9806af 100644 --- a/src/northbridge/amd/amdmct/mct/mctmtr_d.c +++ b/src/northbridge/amd/amdmct/mct/mctmtr_d.c @@ -1,7 +1,7 @@ /* * This file is part of the coreboot project. * - * Copyright (C) 2007 Advanced Micro Devices, Inc. + * Copyright (C) 2007-2008 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 @@ -61,15 +61,7 @@ void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, Bottom40bIO = val; } - val = mctGet_NVbits(NV_BottomUMA); - if(val == 0) - val++; - - val <<= (24-8); - if(val > Bottom32bIO) - val = Bottom32bIO; - - Cache32bTOP = val; + Cache32bTOP = Bottom32bIO; /*====================================================================== Set default values for CPU registers @@ -118,6 +110,8 @@ void CPUMemTyping_D(struct MCTStatStruc *pMCTstat, if(Bottom40bIO) { hi = Bottom40bIO >> 24; lo = Bottom40bIO << 8; + if (mctSetNodeBoundary_D()) + lo &= 0xC0000000; addr += 3; /* TOM2 */ _WRMSR(addr, lo, hi); } @@ -210,4 +204,54 @@ static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType) *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 + *======================================================================*/ + print_tx("\t UMAMemTyping_D: Cache32bTOP:", Cache32bTOP); + SetMTRRrangeWB_D(0, &Cache32bTOP, &addr); + if(addr == -1) /* ran out of MTRRs?*/ + pMCTstat->GStatus |= 1<Status & (1< 4 - print_debug("\t\t\t\t\t\tQW0 : test_buf = "); - print_debug_hex32((unsigned)test_buf); - print_debug(": "); + print_debug_dqs_pair("\t\t\t\t\t\t test_buf = ", (u32)test_buf, " | addr_lo = ", addr, 4); for (i=0; i<8; i++) { - print_debug_hex8(test_buf[i]); print_debug(" "); - } - print_debug("\n"); + value = read32_fs(addr); + print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", test_buf[i], " | ", value, 4); - print_debug("\t\t\t\t\t\tQW0 : addr_lo_buf = "); - print_debug_hex32((unsigned)addr_lo_buf); - print_debug(": "); - for (i=0; i<8; i++) { - print_debug_hex8(addr_lo_buf[i]); print_debug(" "); - } - print_debug("\n"); -#endif - - /* prevent speculative execution of following instructions */ - _EXECFENCE; - - for (i=0; i<8; i++) { - if(addr_lo_buf[i] == test_buf[i]) { + if (value == test_buf[i]) { pDCTstat->DqsRcvEn_Pass |= (1<DqsRcvEn_Pass &= ~(1<