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 fix memory hoisting across nodes ecc memory scrub updates debug print changes minor cleanups Signed-off-by: Marc Jones (marc.jones@amd.com) Index: coreboot-v2/src/northbridge/amd/amdmct/mct/mct_d.c =================================================================== --- coreboot-v2.orig/src/northbridge/amd/amdmct/mct/mct_d.c 2008-04-07 11:28:02.000000000 -0600 +++ coreboot-v2/src/northbridge/amd/amdmct/mct/mct_d.c 2008-04-07 14:45:52.000000000 -0600 @@ -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 @@ -277,12 +277,15 @@ mctHookAfterCPU(); /* Setup external northbridge(s) */ print_t("mctAutoInitMCT_D: DQSTiming_D\n"); - DQSTiming_D(pMCTstat, pDCTstatA); /* Get Receiver Enable and DQS signal timing*/ + 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); - if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st pass of DIMM spare enabled*/ + if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st pass of DIMM spare enabled */ goto restartinit; } @@ -290,7 +293,7 @@ InterleaveChannels_D(pMCTstat, pDCTstatA); print_t("mctAutoInitMCT_D: ECCInit_D\n"); - if (ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/ + if (ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits */ print_t("mctAutoInitMCT_D: MCTMemClr_D\n"); MCTMemClr_D(pMCTstat,pDCTstatA); } @@ -348,10 +351,11 @@ /* 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 @@ u32 val; u32 base; u32 limit; - u32 dev; + u32 dev, devx; struct DCTStatStruc *pDCTstat; _MemHoleRemap = mctGet_NVbits(NV_MemHole); @@ -529,8 +533,9 @@ pDCTstat = pDCTstatA + 0; dev = pDCTstat->dev_map; - 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 +574,7 @@ 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 Register*/ pDCTstat->DCTSysLimit += HoleSize; base = pDCTstat->DCTSysBase; limit = pDCTstat->DCTSysLimit; @@ -598,21 +603,31 @@ pMCTstat->SysLimit = limit; } Set_NB32(dev, 0x40 + (Node << 3), base); /* [Node] + Dram Base 0 */ - val = limit & 0xffff0000; - val |= Node; /* set DstNode*/ - Set_NB32(dev, 0x44 + (Node << 3), val); /* set DstNode */ + 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 +1031,7 @@ 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 +1069,7 @@ /* 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 +1190,10 @@ 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) { /* Calculate by 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 +1823,7 @@ /* 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 +2644,7 @@ 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 exist both, set DctSelBaseAddr[47:27] to the top of DCT0 */ if (dct == 0) { if (pDCTstat->DIMMValidDCT[1] > 0) { dword = pDCTstat->DCTSysLimit + 1; @@ -2641,8 +2654,7 @@ 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 +2665,7 @@ 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 +2677,7 @@ 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 +2693,7 @@ 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 +2886,25 @@ 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 +2969,16 @@ 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 +2987,13 @@ 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 +3002,9 @@ 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 +3102,14 @@ 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 +3119,13 @@ 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 */ @@ -3358,10 +3394,8 @@ /* Tri-state unused ODTs when motherboard termination is available */ // FIXME: skip for Ax - - dev = pDCTstat->dev_dct; - word = 0; - for (cs = 0; cs < 8; cs += 2) { + // FIXME: BUG53109 function can incorrectly program F2x[1,0]9C_x0C[11:8]_ODTTri +/* for (cs = 0; cs < 8; cs += 2) { if (!(pDCTstat->CSPresent & (1 << cs))) { if (!(pDCTstat->CSPresent & (1 << (cs + 1)))) word |= (1 << (cs >> 1)); @@ -3372,6 +3406,7 @@ val = Get_NB32_index_wait(dev, index_reg, index); val |= (word << 8); Set_NB32_index_wait(dev, index_reg, index, val); +*/ } @@ -3414,8 +3449,14 @@ } /* 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 +3774,26 @@ 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 +3802,24 @@ 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 +3840,7 @@ // 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 +3874,9 @@ 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 */ Index: coreboot-v2/src/northbridge/amd/amdmct/mct/mct_d.h =================================================================== --- coreboot-v2.orig/src/northbridge/amd/amdmct/mct/mct_d.h 2008-04-07 11:28:02.000000000 -0600 +++ coreboot-v2/src/northbridge/amd/amdmct/mct/mct_d.h 2008-04-07 14:46:09.000000000 -0600 @@ -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 @@ 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 @@ 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); Index: coreboot-v2/src/northbridge/amd/amdmct/mct/mctchi_d.c =================================================================== --- coreboot-v2.orig/src/northbridge/amd/amdmct/mct/mctchi_d.c 2008-04-07 11:28:02.000000000 -0600 +++ coreboot-v2/src/northbridge/amd/amdmct/mct/mctchi_d.c 2008-04-07 14:46:29.000000000 -0600 @@ -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 @@ /* 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 @@ 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 @@ 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 @@ } 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); } } Index: coreboot-v2/src/northbridge/amd/amdmct/mct/mctdqs_d.c =================================================================== --- coreboot-v2.orig/src/northbridge/amd/amdmct/mct/mctdqs_d.c 2008-04-07 11:28:02.000000000 -0600 +++ coreboot-v2/src/northbridge/amd/amdmct/mct/mctdqs_d.c 2008-04-07 14:46:42.000000000 -0600 @@ -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 @@ -885,10 +885,12 @@ u32 lo, hi; u32 addr; + lo = 0; hi = addr_hi>>24; addr = FS_Base; _WRMSR(addr, lo, hi); + return addr_hi<<8; } @@ -1085,7 +1087,6 @@ *valid = 0; - if (!pDCTstat->GangedMode) { // FIXME: not used. reg_off = 0x100 * Channel; } @@ -1130,6 +1131,9 @@ 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 +1171,13 @@ *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; Index: coreboot-v2/src/northbridge/amd/amdmct/mct/mctecc_d.c =================================================================== --- coreboot-v2.orig/src/northbridge/amd/amdmct/mct/mctecc_d.c 2008-04-07 11:28:02.000000000 -0600 +++ coreboot-v2/src/northbridge/amd/amdmct/mct/mctecc_d.c 2008-04-07 14:47:12.000000000 -0600 @@ -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 @@ -101,7 +101,7 @@ OF_ScrubCTL = 0; /* Scrub CTL for Dcache, L2, and dram */ val = mctGet_NVbits(NV_DCBKScrub); - mct_AdjustScrub_D(pDCTstatA, val); + mct_AdjustScrub_D(pDCTstatA, (u16) &val); OF_ScrubCTL |= val << 16; val = mctGet_NVbits(NV_L2BKScrub); OF_ScrubCTL |= val << 8; @@ -190,7 +190,18 @@ 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 */ Index: coreboot-v2/src/northbridge/amd/amdmct/mct/mctmtr_d.c =================================================================== --- coreboot-v2.orig/src/northbridge/amd/amdmct/mct/mctmtr_d.c 2008-04-07 11:28:02.000000000 -0600 +++ coreboot-v2/src/northbridge/amd/amdmct/mct/mctmtr_d.c 2008-04-07 14:47:30.000000000 -0600 @@ -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 @@ 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 @@ -92,6 +84,7 @@ 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*/ @@ -118,6 +111,8 @@ if(Bottom40bIO) { hi = Bottom40bIO >> 24; lo = Bottom40bIO << 8; + if (mctSetNodeBoundary_D()) + lo &= 0xC0000000; addr += 3; /* TOM2 */ _WRMSR(addr, lo, hi); } @@ -210,4 +205,54 @@ *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 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"); - - 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 + value = read32_fs(addr); + print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", test_buf[i], " | ", value, 4); - /* prevent speculative execution of following instructions */ - _EXECFENCE; - - for (i=0; i<8; i++) { - if(addr_lo_buf[i] == test_buf[i]) { - pDCTstat->DqsRcvEn_Pass |= (1<DqsRcvEn_Pass |= (1 << i); } else { - pDCTstat->DqsRcvEn_Pass &= ~(1<DqsRcvEn_Pass &= ~(1 << i); } } + result = DQS_FAIL; if (Pass == FirstPass) { /* if first pass, at least one byte lane pass @@ -833,7 +813,7 @@ /* if second pass, at least one byte lane fail * ,then DQS_FAIL=1 and will set to related reg. */ - if(pDCTstat->DqsRcvEn_Pass != 0xFF) { + if (pDCTstat->DqsRcvEn_Pass != 0xFF) { result = DQS_FAIL; } else { result = DQS_PASS; @@ -843,7 +823,7 @@ /* if second pass, we can't find the fail until FFh, * then let it fail to save the final delay */ - if((Pass == SecondPass) && (pDCTstat->Status & (1 << SB_DQSRcvLimit))) { + if ((Pass == SecondPass) && (pDCTstat->Status & (1 << SB_DQSRcvLimit))) { result = DQS_FAIL; pDCTstat->DqsRcvEn_Pass = 0; } @@ -851,7 +831,7 @@ /* second pass needs to be inverted * FIXME? this could be inverted in the above code to start with... */ - if(Pass == SecondPass) { + if (Pass == SecondPass) { if (result == DQS_PASS) { result = DQS_FAIL; } else if (result == DQS_FAIL) { /* FIXME: doesn't need to be else if */ @@ -1062,7 +1042,7 @@ Set_NB32_index_wait(dev, index_reg, 0x08, val); /* Wait 200 MEMCLKs. */ - mct_Wait_10ns (20000); /* wait 200us */ + mct_Wait(50000); /* wait 200us */ /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */ val = Get_NB32_index_wait(dev, index_reg, 0x08); @@ -1101,21 +1081,20 @@ } -static void mct_Wait_10ns (u32 cycles) +static void mct_Wait(u32 cycles) { - u32 saved, i; + u32 saved; u32 hi, lo, msr; - /* cycles = number of 10ns cycles(or longer) to delay */ - /* FIXME: Need to calibrate to CPU/NCLK speed? */ + /* Wait # of 50ns cycles + This seems like a hack to me... */ - msr = 0x10; /* TSC */ - for (i = 0; i < cycles; i++) { - _RDMSR(msr, &lo, &hi); - saved = lo; + cycles <<= 3; /* x8 (number of 1.25ns ticks) */ - do { - _RDMSR(msr, &lo, &hi); - } while (lo - saved < 8); /* 8 x 1.25 ns as NCLK is at 1.25ns */ - } + msr = 0x10; /* TSC */ + _RDMSR(msr, &lo, &hi); + saved = lo; + do { + _RDMSR(msr, &lo, &hi); + } while (lo - saved < cycles ); } Index: coreboot-v2/src/northbridge/amd/amdmct/wrappers/mcti_d.c =================================================================== --- coreboot-v2.orig/src/northbridge/amd/amdmct/wrappers/mcti_d.c 2008-04-07 11:28:02.000000000 -0600 +++ coreboot-v2/src/northbridge/amd/amdmct/wrappers/mcti_d.c 2008-04-07 14:48:12.000000000 -0600 @@ -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 @@ -129,11 +129,11 @@ //val = 1; /* enable */ break; case NV_BottomIO: - val = 0xC0; /* address bits [31:24] */ + val = 0xE0; /* address bits [31:24] */ break; case NV_BottomUMA: #if (UMA_SUPPORT == 0) - val = 0xC0; /* address bits [31:24] */ + val = 0xE0; /* address bits [31:24] */ #elif (UMA_SUPPORT == 1) val = 0xB0; /* address bits [31:24] */ #endif @@ -205,7 +205,7 @@ val = 1; /* Enabled */ //val = 0; /* Disabled */ case NV_ChannelIntlv: - val = 5; /* Disabled */ /* Not currently checked in mctchi_d.c */ + val = 5; /* Not currently checked in mctchi_d.c */ /* Bit 0 = 0 - Disable * 1 - Enable * Bits[2:1] = 00b - Address bits 6 @@ -336,3 +336,8 @@ { return mctGetLogicalCPUID(node); } + +u8 mctSetNodeBoundary_D(void) +{ + return 0; +}