diff options
Diffstat (limited to 'resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch')
-rw-r--r-- | resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch | 3454 |
1 files changed, 0 insertions, 3454 deletions
diff --git a/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch b/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch deleted file mode 100644 index c3abdeec..00000000 --- a/resources/libreboot/patch/kgpe-d16/0010-northbridge-amd-amdmct-Fix-broken-AMD-K10-DDR3-memor.patch +++ /dev/null @@ -1,3454 +0,0 @@ -From b79a652d746bc186b0de559aa237462e7ba09109 Mon Sep 17 00:00:00 2001 -From: Timothy Pearson <tpearson@raptorengineeringinc.com> -Date: Sat, 5 Sep 2015 17:55:58 -0500 -Subject: [PATCH 010/143] northbridge/amd/amdmct: Fix broken AMD K10 DDR3 - memory initalization - -Change-Id: Iab690db769e820600693ad1170085623b177b94e -Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com> ---- - src/northbridge/amd/amdfam10/raminit_amdmct.c | 2 + - src/northbridge/amd/amdmct/mct/mct_d.c | 1 - - src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 177 ++++- - src/northbridge/amd/amdmct/mct_ddr3/mct_d.h | 8 +- - src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h | 87 +-- - src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c | 6 +- - src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 806 ++++++++++++----------- - src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c | 6 +- - src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c | 14 +- - src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c | 3 +- - src/northbridge/amd/amdmct/mct_ddr3/mctproc.c | 19 +- - src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c | 5 +- - src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c | 800 +++++++++++----------- - src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c | 18 +- - src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c | 13 +- - src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c | 7 +- - src/northbridge/amd/amdmct/mct_ddr3/mctwl.c | 42 +- - src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 267 ++++---- - src/northbridge/amd/amdmct/wrappers/mcti_d.c | 110 +--- - 19 files changed, 1252 insertions(+), 1139 deletions(-) - -diff --git a/src/northbridge/amd/amdfam10/raminit_amdmct.c b/src/northbridge/amd/amdfam10/raminit_amdmct.c -index a0d47f4..a585fae 100644 ---- a/src/northbridge/amd/amdfam10/raminit_amdmct.c -+++ b/src/northbridge/amd/amdfam10/raminit_amdmct.c -@@ -28,12 +28,14 @@ static void print_tx(const char *strval, u32 val) - } - #endif - -+#if (CONFIG_DIMM_SUPPORT & 0x000F)!=0x0005 /* not needed for AMD_FAM10_DDR3 */ - static void print_t(const char *strval) - { - #if CONFIG_DEBUG_RAM_SETUP - printk(BIOS_DEBUG, "%s", strval); - #endif - } -+#endif - - static void print_tf(const char *func, const char *strval) - { -diff --git a/src/northbridge/amd/amdmct/mct/mct_d.c b/src/northbridge/amd/amdmct/mct/mct_d.c -index 3dec934..88910e2 100644 ---- a/src/northbridge/amd/amdmct/mct/mct_d.c -+++ b/src/northbridge/amd/amdmct/mct/mct_d.c -@@ -542,7 +542,6 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, - pDCTstat = pDCTstatA + Node; - devx = pDCTstat->dev_map; - DramSelBaseAddr = 0; -- pDCTstat = pDCTstatA + Node; - if (!pDCTstat->GangedMode) { - DramSelBaseAddr = pDCTstat->NodeSysLimit - pDCTstat->DCTSysLimit; - /*In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */ -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c -index 71a6be8..fa59d71 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c -@@ -214,6 +214,8 @@ static const u8 Table_DQSRcvEn_Offset[] = {0x00,0x01,0x10,0x11,0x2}; - static const u8 Tab_L1CLKDis[] = {0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04}; - static const u8 Tab_AM3CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; - static const u8 Tab_S1CLKDis[] = {0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -+static const u8 Tab_C32CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; /* Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */ -+static const u8 Tab_G34CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; /* Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */ - static const u8 Tab_ManualCLKDis[]= {0x10, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00}; - - static const u8 Table_Comp_Rise_Slew_20x[] = {7, 3, 2, 2, 0xFF}; -@@ -277,6 +279,11 @@ restartinit: - for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { - struct DCTStatStruc *pDCTstat; - pDCTstat = pDCTstatA + Node; -+ -+ /* Zero out data structures to avoid false detection of DIMMs */ -+ memset(pDCTstat, 0, sizeof(struct DCTStatStruc)); -+ -+ /* Initialize data structures */ - pDCTstat->Node_ID = Node; - pDCTstat->dev_host = PA_HOST(Node); - pDCTstat->dev_map = PA_MAP(Node); -@@ -284,17 +291,22 @@ restartinit: - pDCTstat->dev_nbmisc = PA_NBMISC(Node); - pDCTstat->NodeSysBase = node_sys_base; - -+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_init Node %d\n", Node); - mct_init(pMCTstat, pDCTstat); - mctNodeIDDebugPort_D(); - pDCTstat->NodePresent = NodePresent_D(Node); - if (pDCTstat->NodePresent) { /* See if Node is there*/ -+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: clear_legacy_Mode\n"); - clear_legacy_Mode(pMCTstat, pDCTstat); - pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node); - -+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_InitialMCT_D\n"); - mct_InitialMCT_D(pMCTstat, pDCTstat); - -+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctSMBhub_Init\n"); - mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node*/ - -+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_initDCT\n"); - mct_initDCT(pMCTstat, pDCTstat); - if (pDCTstat->ErrCode == SC_FatalErr) { - goto fatalexit; /* any fatal errors?*/ -@@ -345,6 +357,7 @@ restartinit: - - mct_FinalMCT_D(pMCTstat, pDCTstatA); - printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", pMCTstat->GStatus); -+ - return; - - fatalexit: -@@ -560,7 +573,6 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, - pDCTstat = pDCTstatA + Node; - devx = pDCTstat->dev_map; - DramSelBaseAddr = 0; -- pDCTstat = pDCTstatA + Node; /* ??? */ - if (!pDCTstat->GangedMode) { - DramSelBaseAddr = pDCTstat->NodeSysLimit - pDCTstat->DCTSysLimit; - /*In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */ -@@ -645,6 +657,7 @@ static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, - devx = pDCTstat->dev_map; - - if (pDCTstat->NodePresent) { -+ printk(BIOS_DEBUG, " Copy dram map from Node 0 to Node %02x \n", Node); - reg = 0x40; /*Dram Base 0*/ - do { - val = Get_NB32(dev, reg); -@@ -1162,7 +1175,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat, - - /* Program DRAM Timing values */ - DramTimingLo = 0; /* Dram Timing Low init */ -- val = pDCTstat->CASL - 2; /* pDCTstat.CASL to reg. definition */ -+ val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */ - DramTimingLo |= val; - - val = pDCTstat->Trcd - Bias_TrcdT; -@@ -1406,18 +1419,16 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat, - else if (tCKproposed16x <= 24) { - pDCTstat->TargetFreq = 6; - tCKproposed16x = 24; -- } -- else if (tCKproposed16x <= 30) { -+ } else if (tCKproposed16x <= 30) { - pDCTstat->TargetFreq = 5; - tCKproposed16x = 30; -- } -- else { -+ } else { - pDCTstat->TargetFreq = 4; - tCKproposed16x = 40; - } - /* Running through this loop twice: - - First time find tCL at target frequency -- - Second tim find tCL at 400MHz */ -+ - Second time find tCL at 400MHz */ - - for (;;) { - CLT_Fail = 0; -@@ -1451,7 +1462,7 @@ static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat, - CLT_Fail = 1; - /* get CL and T */ - if (!CLT_Fail) { -- bytex = CLactual - 2; -+ bytex = CLactual; - if (tCKproposed16x == 20) - byte = 7; - else if (tCKproposed16x == 24) -@@ -1632,7 +1643,7 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, - val = 0x0f; /* recommended setting (default) */ - DramConfigHi |= val << 24; - -- if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Bx)) -+ if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx)) - DramConfigHi |= 1 << DcqArbBypassEn; - - /* Build MemClkDis Value from Dram Timing Lo and -@@ -1657,6 +1668,10 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, - p = Tab_L1CLKDis; - else if (byte == PT_M2 || byte == PT_AS) - p = Tab_AM3CLKDis; -+ else if (byte == PT_C3) -+ p = Tab_C32CLKDis; -+ else if (byte == PT_GR) -+ p = Tab_G34CLKDis; - else - p = Tab_S1CLKDis; - -@@ -2102,8 +2117,7 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat, - if (byte == JED_RDIMM || byte == JED_MiniRDIMM) { - RegDIMMPresent |= 1 << i; - pDCTstat->DimmRegistered[i] = 1; -- } -- else { -+ } else { - pDCTstat->DimmRegistered[i] = 0; - } - /* Check ECC capable */ -@@ -2977,9 +2991,9 @@ static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat, - } else { /* For Dx CPU */ - val = 0x0CE00F00 | 1 << 29/* FlushWrOnStpGnt */; - if (!(pDCTstat->GangedMode)) -- val |= 0x20; /* MctWrLimit = 8 for Unganed mode */ -+ val |= 0x20; /* MctWrLimit = 8 for Unganged mode */ - else -- val |= 0x40; /* MctWrLimit = 16 for ganed mode */ -+ val |= 0x40; /* MctWrLimit = 16 for ganged mode */ - Set_NB32(pDCTstat->dev_dct, 0x11C, val); - - val = Get_NB32(pDCTstat->dev_dct, 0x1B0); -@@ -3414,6 +3428,138 @@ static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat, - Set_NB32(dev, 0x98 + reg_off, 0x0D000030); - Set_NB32(dev, 0x9C + reg_off, dword); - Set_NB32(dev, 0x98 + reg_off, 0x4D040F30); -+ -+ /* FIXME -+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel -+ * For now assume a maximum of 2 DIMMs per channel can be installed -+ */ -+ uint8_t MaxDimmsInstallable = 2; -+ -+ /* Obtain number of DIMMs on channel */ -+ uint8_t dimm_count = pDCTstat->MAdimms[i]; -+ uint8_t rank_count_dimm0; -+ uint8_t rank_count_dimm1; -+ uint32_t odt_pattern_0; -+ uint32_t odt_pattern_1; -+ uint32_t odt_pattern_2; -+ uint32_t odt_pattern_3; -+ -+ /* Select appropriate ODT pattern for installed DIMMs -+ * Refer to the BKDG Rev. 3.62, page 120 onwards -+ */ -+ if (pDCTstat->C_DCTPtr[i]->Status[DCT_STATUS_REGISTERED]) { -+ if (MaxDimmsInstallable == 2) { -+ if (dimm_count == 1) { -+ /* 1 DIMM detected */ -+ rank_count_dimm1 = pDCTstat->C_DCTPtr[i]->DimmRanks[1]; -+ if (rank_count_dimm1 == 1) { -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x00020000; -+ } else if (rank_count_dimm1 == 2) { -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x02080000; -+ } else if (rank_count_dimm1 == 4) { -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x020a0000; -+ odt_pattern_3 = 0x080a0000; -+ } else { -+ /* Fallback */ -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x00000000; -+ } -+ } else { -+ /* 2 DIMMs detected */ -+ rank_count_dimm0 = pDCTstat->C_DCTPtr[i]->DimmRanks[0]; -+ rank_count_dimm1 = pDCTstat->C_DCTPtr[i]->DimmRanks[1]; -+ if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) { -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x01010202; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x09030603; -+ } else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4)) { -+ odt_pattern_0 = 0x01010000; -+ odt_pattern_1 = 0x01010a0a; -+ odt_pattern_2 = 0x01090000; -+ odt_pattern_3 = 0x01030e0b; -+ } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4)) { -+ odt_pattern_0 = 0x00000202; -+ odt_pattern_1 = 0x05050202; -+ odt_pattern_2 = 0x00000206; -+ odt_pattern_3 = 0x0d070203; -+ } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 == 4)) { -+ odt_pattern_0 = 0x05050a0a; -+ odt_pattern_1 = 0x05050a0a; -+ odt_pattern_2 = 0x050d0a0e; -+ odt_pattern_3 = 0x05070a0b; -+ } else { -+ /* Fallback */ -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x00000000; -+ } -+ } -+ } else { -+ /* FIXME -+ * 3 DIMMs per channel UNIMPLEMENTED -+ */ -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x00000000; -+ } -+ } else { -+ if (MaxDimmsInstallable == 2) { -+ if (dimm_count == 1) { -+ /* 1 DIMM detected */ -+ rank_count_dimm1 = pDCTstat->C_DCTPtr[i]->DimmRanks[1]; -+ if (rank_count_dimm1 == 1) { -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x00020000; -+ } else if (rank_count_dimm1 == 2) { -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x02080000; -+ } else { -+ /* Fallback */ -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x00000000; -+ } -+ } else { -+ /* 2 DIMMs detected */ -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x01010202; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x09030603; -+ } -+ } else { -+ /* FIXME -+ * 3 DIMMs per channel UNIMPLEMENTED -+ */ -+ odt_pattern_0 = 0x00000000; -+ odt_pattern_1 = 0x00000000; -+ odt_pattern_2 = 0x00000000; -+ odt_pattern_3 = 0x00000000; -+ } -+ } -+ -+ /* Program ODT pattern */ -+ Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x180, odt_pattern_1); -+ Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x181, odt_pattern_0); -+ Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x182, odt_pattern_3); -+ Set_NB32_index_wait(dev, 0xf0 + reg_off, 0x183, odt_pattern_2); - } - } - } -@@ -3657,6 +3803,7 @@ static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat, - } - } - -+/* Erratum 350 */ - static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 dct) - { -@@ -3692,11 +3839,11 @@ static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat, - mct_Read1LTestPattern_D(pMCTstat, pDCTstat, addr); /* cache fills */ - - /* Write 0000_8000h to register F2x[1,0]9C_xD080F0C */ -- Set_NB32_index_wait(dev, 0x98 + reg_off, 0x4D080F0C, 0x00008000); -+ Set_NB32_index_wait(dev, 0x98 + reg_off, 0xD080F0C, 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); -+ Set_NB32_index_wait(dev, 0x98 + reg_off, 0xD080F0C, 0x00000000); - mct_Wait(800); /* wait >= 2us */ - break; - } -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h -index e2d7aa8..219aa42 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h -@@ -499,7 +499,7 @@ struct DCTStatStruc { /* A per Node structure*/ - /* 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] */ -+ u16 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*/ -@@ -509,7 +509,7 @@ struct DCTStatStruc { /* A per Node structure*/ - /* 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]; -+ u16 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*/ -@@ -769,7 +769,7 @@ 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); -+u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, u16 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); -@@ -779,7 +779,7 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTs - 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 mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 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); -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h -index 60f98bc..c40ea1a 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d_gcc.h -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -103,10 +104,10 @@ static void proc_CLFLUSH(u32 addr_hi) - - __asm__ volatile ( - /* clflush fs:[eax] */ -- "outb %%al, $0xed\n\t" /* _EXECFENCE */ -- "clflush %%fs:(%0)\n\t" -+ "outb %%al, $0xed\n\t" /* _EXECFENCE */ -+ "clflush %%fs:(%0)\n\t" - "mfence\n\t" -- ::"a" (addr_hi<<8) -+ ::"a" (addr_hi<<8) - ); - } - -@@ -141,6 +142,24 @@ static u32 read32_fs(u32 addr_lo) - return value; - } - -+static uint64_t read64_fs(uint32_t addr_lo) -+{ -+ uint64_t value = 0; -+ uint32_t value_lo; -+ uint32_t value_hi; -+ -+ __asm__ volatile ( -+ "outb %%al, $0xed\n\t" /* _EXECFENCE */ -+ "mfence\n\t" -+ "movl %%fs:(%2), %0\n\t" -+ "movl %%fs:(%3), %1\n\t" -+ :"=c"(value_lo), "=d"(value_hi): "a" (addr_lo), "b" (addr_lo + 4) : "memory" -+ ); -+ value |= value_lo; -+ value |= ((uint64_t)value_hi) << 32; -+ return value; -+} -+ - #ifdef UNUSED_CODE - static u8 read8_fs(u32 addr_lo) - { -@@ -210,68 +229,6 @@ static __attribute__((noinline)) void FlushDQSTestPattern_L18(u32 addr_lo) - ); - } - --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); -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c b/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c -index ae1654c..99a2628 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctardk6.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -17,7 +18,7 @@ - * Foundation, Inc. - */ - --/* The socket type F (1207), Fr2, G (1207) are not tested. -+/* The socket type Fr2, G (1207) are not tested. - */ - - static void Get_ChannelPS_Cfg0_D(u8 MAAdimms, u8 Speed, u8 MAAload, -@@ -79,8 +80,7 @@ static void Get_ChannelPS_Cfg0_D( u8 MAAdimms, u8 Speed, u8 MAAload, - else - *AddrTmgCTL = 0x00353935; - } -- } -- else { -+ } else { - if(Speed == 4) { - *AddrTmgCTL = 0x00000000; - if (MAAdimms == 3) -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c -index 404727b..cc2f43a 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -22,13 +23,6 @@ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat, - u8 scale, u8 ChipSel); - static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 ChipSel); --static u8 MiddleDQS_D(u8 min, u8 max); --static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start); --static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start); - static void WriteDQSTestPattern_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, - u32 TestAddr_lo); -@@ -43,31 +37,19 @@ static void FlushDQSTestPattern_D(struct DCTStatStruc *pDCTstat, - u32 addr_lo); - static void SetTargetWTIO_D(u32 TestAddr); - static void ResetTargetWTIO_D(void); --static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u32 TestAddr_lo); --static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, u8 ChipSel, -- u8 RnkDlyFilterMin, u8 RnkDlyFilterMax); - void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index); - u8 mct_DisableDimmEccEn_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat); - static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, - u8 ChipSel); --static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start); - u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 Channel, - u8 receiver, u8 *valid); - static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, - u32 *buffer); -- --static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, u8 ChipSel, -- u8 RnkDlyFilterMin, u8 RnkDlyFilterMax); -+static void proc_IOCLFLUSH_D(u32 addr_hi); - - static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 ChipSel); - -@@ -286,20 +268,99 @@ static void CalcEccDQSPos_D(struct MCTStatStruc *pMCTstat, - pDCTstat->DQSDelay = (u8)DQSDelay; - } - -+static void write_dqs_write_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dimm, uint32_t index_reg) -+{ -+ uint32_t dword; -+ -+ /* Lanes 0 - 3 */ -+ dword = Get_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8)); -+ dword &= ~0x7f7f7f7f; -+ dword |= (delay[3] & 0x7f) << 24; -+ dword |= (delay[2] & 0x7f) << 16; -+ dword |= (delay[1] & 0x7f) << 8; -+ dword |= delay[0] & 0x7f; -+ Set_NB32_index_wait(dev, index_reg, 0x1 | (dimm << 8), dword); -+ -+ /* Lanes 4 - 7 */ -+ dword = Get_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8)); -+ dword &= ~0x7f7f7f7f; -+ dword |= (delay[7] & 0x7f) << 24; -+ dword |= (delay[6] & 0x7f) << 16; -+ dword |= (delay[5] & 0x7f) << 8; -+ dword |= delay[4] & 0x7f; -+ Set_NB32_index_wait(dev, index_reg, 0x2 | (dimm << 8), dword); -+ -+ /* Lane 8 (ECC) */ -+ dword = Get_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8)); -+ dword &= ~0x0000007f; -+ dword |= delay[8] & 0x7f; -+ Set_NB32_index_wait(dev, index_reg, 0x3 | (dimm << 8), dword); -+} -+ -+static void write_dqs_read_data_timing_registers(uint16_t* delay, uint32_t dev, uint8_t dimm, uint32_t index_reg) -+{ -+ uint32_t dword; -+ -+ /* Lanes 0 - 3 */ -+ dword = Get_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8)); -+ dword &= ~0x3f3f3f3f; -+ dword |= (delay[3] & 0x3f) << 24; -+ dword |= (delay[2] & 0x3f) << 16; -+ dword |= (delay[1] & 0x3f) << 8; -+ dword |= delay[0] & 0x3f; -+ Set_NB32_index_wait(dev, index_reg, 0x5 | (dimm << 8), dword); -+ -+ /* Lanes 4 - 7 */ -+ dword = Get_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8)); -+ dword &= ~0x3f3f3f3f; -+ dword |= (delay[7] & 0x3f) << 24; -+ dword |= (delay[6] & 0x3f) << 16; -+ dword |= (delay[5] & 0x3f) << 8; -+ dword |= delay[4] & 0x3f; -+ Set_NB32_index_wait(dev, index_reg, 0x6 | (dimm << 8), dword); -+ -+ /* Lane 8 (ECC) */ -+ dword = Get_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8)); -+ dword &= ~0x0000003f; -+ dword |= delay[8] & 0x3f; -+ Set_NB32_index_wait(dev, index_reg, 0x7 | (dimm << 8), dword); -+} -+ -+/* DQS Position Training -+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.3 -+ */ - static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start) -+ struct DCTStatStruc *pDCTstat) - { - u32 Errors; -- u8 Channel, DQSWrDelay; -+ u8 Channel; -+ u8 Receiver; - u8 _DisableDramECC = 0; -- u32 PatternBuffer[292]; -+ u32 PatternBuffer[304]; /* 288 + 16 */ - u8 _Wrap32Dis = 0, _SSE2 = 0; -- u8 dqsWrDelay_end; - -+ u32 dev; - u32 addr; -+ u8 valid; - u32 cr4; - u32 lo, hi; -+ u32 index_reg; -+ uint32_t TestAddr; -+ -+ uint8_t dual_rank; -+ uint8_t iter; -+ uint8_t lane; -+ uint16_t bytelane_test_results; -+ uint16_t current_write_dqs_delay[MAX_BYTE_LANES]; -+ uint16_t current_read_dqs_delay[MAX_BYTE_LANES]; -+ uint16_t write_dqs_delay_stepping_done[MAX_BYTE_LANES]; -+ uint8_t dqs_read_results_array[2][MAX_BYTE_LANES][64]; /* [rank][lane][step] */ -+ uint8_t dqs_write_results_array[2][MAX_BYTE_LANES][128]; /* [rank][lane][step] */ -+ -+ uint8_t last_pos = 0; -+ uint8_t cur_count = 0; -+ uint8_t best_pos = 0; -+ uint8_t best_count = 0; - - print_debug_dqs("\nTrainDQSRdWrPos: Node_ID ", pDCTstat->Node_ID, 0); - cr4 = read_cr4(); -@@ -323,50 +384,363 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat, - SetupDqsPattern_D(pMCTstat, pDCTstat, PatternBuffer); - - /* mct_BeforeTrainDQSRdWrPos_D */ -- dqsWrDelay_end = 0x20; -+ -+ dev = pDCTstat->dev_dct; -+ pDCTstat->Direction = DQS_READDIR; -+ -+ /* 2.8.9.9.3 (2) -+ * Loop over each channel, lane, and rank -+ */ -+ -+ /* NOTE -+ * The BKDG originally stated to iterate over lane, then rank, however this process is quite slow -+ * compared to an equivalent loop over rank, then lane as the latter allows multiple lanes to be -+ * tested simultaneously, thus improving performance by around 8x. -+ */ - - Errors = 0; - for (Channel = 0; Channel < 2; Channel++) { -- print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ",Channel, 1); -+ print_debug_dqs("\tTrainDQSRdWrPos: 1 Channel ", Channel, 1); - pDCTstat->Channel = Channel; - - if (pDCTstat->DIMMValidDCT[Channel] == 0) /* mct_BeforeTrainDQSRdWrPos_D */ - continue; -- pDCTstat->DqsRdWrPos_Saved = 0; -- for ( DQSWrDelay = 0; DQSWrDelay < dqsWrDelay_end; DQSWrDelay++) { -- pDCTstat->DQSDelay = DQSWrDelay; -- pDCTstat->Direction = DQS_WRITEDIR; -- mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start); -- -- print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DQSWrDelay ", DQSWrDelay, 2); -- TrainReadDQS_D(pMCTstat, pDCTstat, cs_start); -- print_debug_dqs("\t\tTrainDQSRdWrPos: 21 DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 2); -- if (pDCTstat->DqsRdWrPos_Saved == 0xFF) -- break; -- -- print_debug_dqs("\t\tTrainDQSRdWrPos: 22 TrainErrors ",pDCTstat->TrainErrors, 2); -- if (pDCTstat->TrainErrors == 0) { -+ -+ index_reg = 0x98 + 0x100 * Channel; -+ -+ dual_rank = 0; -+ Receiver = mct_InitReceiver_D(pDCTstat, Channel); -+ /* There are four receiver pairs, loosely associated with chipselects. -+ * This is essentially looping over each rank of each DIMM. -+ */ -+ for (; Receiver < 8; Receiver++) { -+ if ((Receiver & 0x1) == 0) { -+ /* Even rank of DIMM */ -+ if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver+1)) -+ dual_rank = 1; -+ else -+ dual_rank = 0; -+ } -+ -+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) { -+ continue; -+ } -+ -+ /* Select the base test address for the current rank */ -+ TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, Channel, Receiver, &valid); -+ if (!valid) { /* Address not supported on current CS */ -+ continue; -+ } -+ -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 14 TestAddr ", TestAddr, 4); -+ SetUpperFSbase(TestAddr); /* fs:eax=far ptr to target */ -+ -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 12 Receiver ", Receiver, 2); -+ -+ /* 2.8.9.9.3 (DRAM Write Data Timing Loop) -+ * Iterate over all possible DQS delay values (0x0 - 0x7f) -+ */ -+ uint8_t test_write_dqs_delay = 0; -+ uint8_t test_read_dqs_delay = 0; -+ uint8_t passing_dqs_delay_found[MAX_BYTE_LANES]; -+ -+ /* Initialize variables */ -+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) { -+ current_write_dqs_delay[lane] = 0; -+ passing_dqs_delay_found[lane] = 0; -+ write_dqs_delay_stepping_done[lane] = 0; -+ } -+ -+ for (test_write_dqs_delay = 0; test_write_dqs_delay < 128; test_write_dqs_delay++) { -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 16 test_write_dqs_delay ", test_write_dqs_delay, 6); -+ -+ /* Break out of loop if passing window already found, */ -+ if (write_dqs_delay_stepping_done[0] && write_dqs_delay_stepping_done[1] -+ && write_dqs_delay_stepping_done[2] && write_dqs_delay_stepping_done[3] -+ && write_dqs_delay_stepping_done[4] && write_dqs_delay_stepping_done[5] -+ && write_dqs_delay_stepping_done[6] && write_dqs_delay_stepping_done[7]) - break; -+ -+ /* Commit the current Write Data Timing settings to the hardware registers */ -+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* Write the DRAM training pattern to the base test address */ -+ WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); -+ -+ /* 2.8.9.9.3 (DRAM Read DQS Timing Control Loop) -+ * Iterate over all possible DQS delay values (0x0 - 0x3f) -+ */ -+ for (test_read_dqs_delay = 0; test_read_dqs_delay < 64; test_read_dqs_delay++) { -+ print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 161 test_read_dqs_delay ", test_read_dqs_delay, 6); -+ -+ /* Initialize Read DQS Timing Control settings for this iteration */ -+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) -+ if (!write_dqs_delay_stepping_done[lane]) -+ current_read_dqs_delay[lane] = test_read_dqs_delay; -+ -+ /* Commit the current Read DQS Timing Control settings to the hardware registers */ -+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* Initialize test result variable */ -+ bytelane_test_results = 0xff; -+ -+ /* Read the DRAM training pattern from the base test address three times -+ * NOTE -+ * While the BKDG states to read three times this is probably excessive! -+ * Decrease training time by only reading the test pattern once per iteration -+ */ -+ for (iter = 0; iter < 1; iter++) { -+ /* Flush caches */ -+ SetTargetWTIO_D(TestAddr); -+ FlushDQSTestPattern_D(pDCTstat, TestAddr << 8); -+ ResetTargetWTIO_D(); -+ -+ /* Read and compare pattern */ -+ bytelane_test_results &= (CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8) & 0xff); /* [Lane 7 :: Lane 0] 0=fail, 1=pass */ -+ -+ /* If all lanes have already failed testing bypass remaining re-read attempt(s) */ -+ if (bytelane_test_results == 0x0) -+ break; -+ } -+ -+ /* Store any lanes that passed testing for later use */ -+ for (lane = 0; lane < 8; lane++) -+ if (!write_dqs_delay_stepping_done[lane]) -+ dqs_read_results_array[Receiver & 0x1][lane][test_read_dqs_delay] = (!!(bytelane_test_results & (1 << lane))); -+ -+ print_debug_dqs("\t\t\t\t\tTrainDQSRdWrPos: 162 bytelane_test_results ", bytelane_test_results, 6); -+ } -+ -+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) { -+ if (write_dqs_delay_stepping_done[lane]) -+ continue; -+ -+ /* Determine location and length of longest consecutive string of passing values -+ * Output is stored in best_pos and best_count -+ */ -+ last_pos = 0; -+ cur_count = 0; -+ best_pos = 0; -+ best_count = 0; -+ for (iter = 0; iter < 64; iter++) { -+ if ((dqs_read_results_array[Receiver & 0x1][lane][iter]) && (iter < 63)) { -+ /* Pass */ -+ cur_count++; -+ } else { -+ /* Failure or end of loop */ -+ if (cur_count > best_count) { -+ best_count = cur_count; -+ best_pos = last_pos; -+ } -+ cur_count = 0; -+ last_pos = iter; -+ } -+ } -+ -+ if (best_count > 2) { -+ /* Exit the DRAM Write Data Timing Loop after programming the Read DQS Timing Control -+ * register with the center of the passing window -+ */ -+ current_read_dqs_delay[lane] = (best_pos + (best_count / 2)); -+ passing_dqs_delay_found[lane] = 1; -+ -+ /* Commit the current Read DQS Timing Control settings to the hardware registers */ -+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* Exit the DRAM Write Data Timing Loop */ -+ write_dqs_delay_stepping_done[lane] = 1; -+ -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 142 largest passing region ", best_count, 4); -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 143 largest passing region start ", best_pos, 4); -+ } -+ -+ /* Increment the DQS Write Delay value if needed for the next DRAM Write Data Timing Loop iteration */ -+ if (!write_dqs_delay_stepping_done[lane]) -+ current_write_dqs_delay[lane]++; -+ } - } -- Errors |= pDCTstat->TrainErrors; -- } - -- pDCTstat->DqsRdWrPos_Saved = 0; -- if (DQSWrDelay < dqsWrDelay_end) { -- Errors = 0; -+ /* Flag failure(s) if present */ -+ for (lane = 0; lane < 8; lane++) { -+ if (!passing_dqs_delay_found[lane]) { -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 121 Unable to find passing region for lane ", lane, 2); -+ -+ /* Flag absence of passing window */ -+ Errors |= 1 << SB_NODQSPOS; -+ } -+ } -+ -+ /* Iterate over all possible Write Data Timing values (0x0 - 0x7f) -+ * Note that the Read DQS Timing Control was calibrated / centered in the prior nested loop -+ */ -+ for (test_write_dqs_delay = 0; test_write_dqs_delay < 128; test_write_dqs_delay++) { -+ /* Initialize Write Data Timing settings for this iteration */ -+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) -+ current_write_dqs_delay[lane] = test_write_dqs_delay; -+ -+ /* Commit the current Write Data Timing settings to the hardware registers */ -+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* Write the DRAM training pattern to the base test address */ -+ WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); -+ -+ /* Flush caches */ -+ SetTargetWTIO_D(TestAddr); -+ FlushDQSTestPattern_D(pDCTstat, TestAddr << 8); -+ ResetTargetWTIO_D(); -+ -+ /* Read and compare pattern from the base test address */ -+ bytelane_test_results = (CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8) & 0xff); /* [Lane 7 :: Lane 0] 0=fail, 1=pass */ -+ -+ /* Store any lanes that passed testing for later use */ -+ for (lane = 0; lane < 8; lane++) -+ dqs_write_results_array[Receiver & 0x1][lane][test_write_dqs_delay] = (!!(bytelane_test_results & (1 << lane))); -+ } -+ -+ for (lane = 0; lane < 8; lane++) { -+ if ((!dual_rank) || (dual_rank && (Receiver & 0x1))) { -+ -+#ifdef PRINT_PASS_FAIL_BITMAPS -+ for (iter = 0; iter < 64; iter++) { -+ if (dqs_read_results_array[0][lane][iter]) -+ printk(BIOS_DEBUG, "+"); -+ else -+ printk(BIOS_DEBUG, "."); -+ } -+ printk(BIOS_DEBUG, "\n"); -+ for (iter = 0; iter < 64; iter++) { -+ if (dqs_read_results_array[1][lane][iter]) -+ printk(BIOS_DEBUG, "+"); -+ else -+ printk(BIOS_DEBUG, "."); -+ } -+ printk(BIOS_DEBUG, "\n\n"); -+ for (iter = 0; iter < 128; iter++) { -+ if (dqs_write_results_array[0][lane][iter]) -+ printk(BIOS_DEBUG, "+"); -+ else -+ printk(BIOS_DEBUG, "."); -+ } -+ printk(BIOS_DEBUG, "\n"); -+ for (iter = 0; iter < 128; iter++) { -+ if (dqs_write_results_array[1][lane][iter]) -+ printk(BIOS_DEBUG, "+"); -+ else -+ printk(BIOS_DEBUG, "."); -+ } -+ printk(BIOS_DEBUG, "\n\n"); -+#endif -+ -+ /* Base rank of single-rank DIMM, or odd rank of dual-rank DIMM */ -+ if (dual_rank) { -+ /* Intersect the passing windows of both ranks */ -+ for (iter = 0; iter < 64; iter++) -+ if (!dqs_read_results_array[1][lane][iter]) -+ dqs_read_results_array[0][lane][iter] = 0; -+ for (iter = 0; iter < 128; iter++) -+ if (!dqs_write_results_array[1][lane][iter]) -+ dqs_write_results_array[0][lane][iter] = 0; -+ } -+ -+ /* Determine location and length of longest consecutive string of passing values for read DQS timing -+ * Output is stored in best_pos and best_count -+ */ -+ last_pos = 0; -+ cur_count = 0; -+ best_pos = 0; -+ best_count = 0; -+ for (iter = 0; iter < 64; iter++) { -+ if ((dqs_read_results_array[0][lane][iter]) && (iter < 63)) { -+ /* Pass */ -+ cur_count++; -+ } else { -+ /* Failure or end of loop */ -+ if (cur_count > best_count) { -+ best_count = cur_count; -+ best_pos = last_pos; -+ } -+ cur_count = 0; -+ last_pos = iter; -+ } -+ } -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 144 largest read passing region ", best_count, 4); -+ if (best_count > 0) { -+ if (best_count < MIN_DQS_WNDW) { -+ /* Flag excessively small passing window */ -+ Errors |= 1 << SB_SMALLDQS; -+ } -+ -+ /* Find the center of the passing window */ -+ current_read_dqs_delay[lane] = (best_pos + (best_count / 2)); -+ -+ /* Commit the current Read DQS Timing Control settings to the hardware registers */ -+ write_dqs_read_data_timing_registers(current_read_dqs_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* Save the final Read DQS Timing Control settings for later use */ -+ pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_READDIR][lane] = current_read_dqs_delay[lane]; -+ } else { -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 122 Unable to find read passing region for lane ", lane, 2); -+ -+ /* Flag absence of passing window */ -+ Errors |= 1 << SB_NODQSPOS; -+ } -+ -+ /* Determine location and length of longest consecutive string of passing values for write DQS timing -+ * Output is stored in best_pos and best_count -+ */ -+ last_pos = 0; -+ cur_count = 0; -+ best_pos = 0; -+ best_count = 0; -+ for (iter = 0; iter < 128; iter++) { -+ if ((dqs_write_results_array[0][lane][iter]) && (iter < 127)) { -+ /* Pass */ -+ cur_count++; -+ } else { -+ /* Failure or end of loop */ -+ if (cur_count > best_count) { -+ best_count = cur_count; -+ best_pos = last_pos; -+ } -+ cur_count = 0; -+ last_pos = iter; -+ } -+ } -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 145 largest write passing region ", best_count, 4); -+ if (best_count > 0) { -+ if (best_count < MIN_DQS_WNDW) { -+ /* Flag excessively small passing window */ -+ Errors |= 1 << SB_SMALLDQS; -+ } -+ -+ /* Find the center of the passing window */ -+ current_write_dqs_delay[lane] = (best_pos + (best_count / 2)); -+ -+ /* Commit the current Write Data Timing settings to the hardware registers */ -+ write_dqs_write_data_timing_registers(current_write_dqs_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* Save the final Write Data Timing settings for later use */ -+ pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][DQS_WRITEDIR][lane] = current_write_dqs_delay[lane]; -+ } else { -+ print_debug_dqs("\t\t\t\tTrainDQSRdWrPos: 123 Unable to find write passing region for lane ", lane, 2); -+ -+ /* Flag absence of passing window */ -+ Errors |= 1 << SB_NODQSPOS; -+ } -+ } -+ } - -- print_debug_dqs("\tTrainDQSRdWrPos: 231 DQSWrDelay ", DQSWrDelay, 1); -- TrainWriteDQS_D(pMCTstat, pDCTstat, cs_start); - } -- print_debug_dqs("\tTrainDQSRdWrPos: 232 Errors ", Errors, 1); -- pDCTstat->ErrStatus |= Errors; - } - -+ pDCTstat->TrainErrors |= Errors; -+ pDCTstat->ErrStatus |= Errors; -+ - #if DQS_TRAIN_DEBUG > 0 - { - u8 val; - u8 i; -- u8 Channel, Receiver, Dir; -+ u8 ChannelDTD, ReceiverDTD, Dir; - u8 *p; - - for (Dir = 0; Dir < 2; Dir++) { -@@ -375,14 +749,14 @@ static void TrainDQSRdWrPos_D(struct MCTStatStruc *pMCTstat, - } else { - printk(BIOS_DEBUG, "TrainDQSRdWrPos: CH_D_DIR_B_DQS RD:\n"); - } -- for (Channel = 0; Channel < 2; Channel++) { -- printk(BIOS_DEBUG, "Channel: %02x\n", Channel); -- for (Receiver = cs_start; Receiver < (cs_start + 2); Receiver += 2) { -- printk(BIOS_DEBUG, "\t\tReceiver: %02x: ", Receiver); -- p = pDCTstat->CH_D_DIR_B_DQS[Channel][Receiver >> 1][Dir]; -+ for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) { -+ printk(BIOS_DEBUG, "Channel: %02x\n", ChannelDTD); -+ for (ReceiverDTD = 0; ReceiverDTD < MAX_CS_SUPPORTED; ReceiverDTD += 2) { -+ printk(BIOS_DEBUG, "\t\tReceiver: %02x:", ReceiverDTD); -+ p = pDCTstat->CH_D_DIR_B_DQS[ChannelDTD][ReceiverDTD >> 1][Dir]; - for (i=0;i<8; i++) { - val = p[i]; -- printk(BIOS_DEBUG, "%02x ", val); -+ printk(BIOS_DEBUG, " %02x", val); - } - printk(BIOS_DEBUG, "\n"); - } -@@ -437,225 +811,6 @@ static void SetupDqsPattern_D(struct MCTStatStruc *pMCTstat, - pDCTstat->PtrPatternBufA = (u32)buf; - } - --static void TrainDQSPos_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start) --{ -- u32 Errors; -- u8 ChipSel, DQSDelay; -- u8 RnkDlySeqPassMin=0, RnkDlySeqPassMax=0xFF, RnkDlyFilterMin=0, RnkDlyFilterMax=0xFF; -- u8 RnkDlySeqPassMinTot=0, RnkDlySeqPassMaxTot=0xFF, RnkDlyFilterMinTot=0, RnkDlyFilterMaxTot=0xFF; -- u8 LastTest ,LastTestTot; -- u32 TestAddr; -- u8 ByteLane; -- u8 MutualCSPassW[128]; -- u8 BanksPresent; -- u8 dqsDelay_end; -- u8 tmp, valid, tmp1; -- u16 word; -- -- /* MutualCSPassW: each byte represents a bitmap of pass/fail per -- * ByteLane. The indext within MutualCSPassW is the delay value -- * given the results. -- */ -- print_debug_dqs("\t\t\tTrainDQSPos begin ", 0, 3); -- -- Errors = 0; -- BanksPresent = 0; -- -- dqsDelay_end = 32; -- /* Bitmapped status per delay setting, 0xff=All positions -- * passing (1= PASS). Set the entire array. -- */ -- for (DQSDelay=0; DQSDelay<128; DQSDelay++) { -- MutualCSPassW[DQSDelay] = 0xFF; -- } -- -- for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) { /* logical register chipselects 0..7 */ -- print_debug_dqs("\t\t\t\tTrainDQSPos: 11 ChipSel ", ChipSel, 4); -- -- if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel)) { -- print_debug_dqs("\t\t\t\tmct_RcvrRankEnabled_D CS not enabled ", ChipSel, 4); -- continue; -- } -- -- BanksPresent = 1; /* flag for at least one bank is present */ -- TestAddr = mct_GetMCTSysAddr_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel, &valid); -- if (!valid) { -- print_debug_dqs("\t\t\t\tAddress not supported on current CS ", TestAddr, 4); -- continue; -- } -- -- print_debug_dqs("\t\t\t\tTrainDQSPos: 12 TestAddr ", TestAddr, 4); -- SetUpperFSbase(TestAddr); /* fs:eax=far ptr to target */ -- -- if (pDCTstat->Direction == DQS_READDIR) { -- print_debug_dqs("\t\t\t\tTrainDQSPos: 13 for read ", 0, 4); -- WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); -- } -- -- for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) { -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 141 DQSDelay ", DQSDelay, 5); -- -- tmp = 0xFF; -- tmp1 = DQSDelay; -- if (pDCTstat->Direction == DQS_READDIR) { -- tmp &= MutualCSPassW[DQSDelay]; -- tmp1 += dqsDelay_end; -- } -- tmp &= MutualCSPassW[tmp1]; -- -- if (tmp == 0) { -- continue;/* skip current delay value if other chipselects have failed all 8 bytelanes */ -- } -- -- pDCTstat->DQSDelay = DQSDelay; -- mct_SetDQSDelayAllCSR_D(pMCTstat, pDCTstat, cs_start); -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 142 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); -- -- if (pDCTstat->Direction == DQS_WRITEDIR) { -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 143 for write", 0, 5); -- WriteDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); -- } -- -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 Pattern ", pDCTstat->Pattern, 5); -- ReadDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); -- /* print_debug_dqs("\t\t\t\t\tTrainDQSPos: 145 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); */ -- word = CompareDQSTestPattern_D(pMCTstat, pDCTstat, TestAddr << 8); /* 0=fail, 1=pass */ -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 1 ", word, 3); -- -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 DqsRdWrPos_Saved ", pDCTstat->DqsRdWrPos_Saved, 3); -- word &= ~(pDCTstat->DqsRdWrPos_Saved); /* mask out bytelanes that already passed */ -- word &= ~(pDCTstat->DqsRdWrPos_Saved << 8); -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 144 compare 2 ", word, 3); -- -- tmp = DQSDelay; -- if (pDCTstat->Direction == DQS_READDIR) { -- MutualCSPassW[tmp] &= word >> 8; -- tmp += dqsDelay_end; -- } -- MutualCSPassW[tmp] &= word & 0xFF; -- -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 146 \tMutualCSPassW ", MutualCSPassW[DQSDelay], 5); -- -- SetTargetWTIO_D(TestAddr); -- FlushDQSTestPattern_D(pDCTstat, TestAddr << 8); -- ResetTargetWTIO_D(); -- } -- -- } -- -- if (pDCTstat->Direction == DQS_READDIR) { -- dqsDelay_end <<= 1; -- } -- -- if (BanksPresent) { -- #if 0 /* show the bitmap */ -- for (ByteLane = 0; ByteLane < 8; ByteLane++) { /* just print ByteLane 0 */ -- for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) { -- if (!(MutualCSPassW[DQSDelay] &(1 << ByteLane))) { -- printk(BIOS_DEBUG, "."); -- } else { -- printk(BIOS_DEBUG, "*"); -- } -- } -- printk(BIOS_DEBUG, "\n"); -- } -- #endif -- for (ByteLane = 0; ByteLane < 8; ByteLane++) { -- print_debug_dqs("\t\t\t\tTrainDQSPos: 31 ByteLane ",ByteLane, 4); -- if (!(pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane))) { -- pDCTstat->ByteLane = ByteLane; -- LastTest = DQS_FAIL; /* Analyze the results */ -- LastTestTot = DQS_FAIL; -- /* RnkDlySeqPassMin = 0; */ -- /* RnkDlySeqPassMax = 0; */ -- RnkDlyFilterMax = 0; -- RnkDlyFilterMin = 0; -- RnkDlyFilterMaxTot = 0; -- RnkDlyFilterMinTot = 0; -- for (DQSDelay = 0; DQSDelay < dqsDelay_end; DQSDelay++) { -- if (MutualCSPassW[DQSDelay] & (1 << ByteLane)) { -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 321 DQSDelay ", DQSDelay, 5); -- print_debug_dqs("\t\t\t\t\tTrainDQSPos: 322 MutualCSPassW ", MutualCSPassW[DQSDelay], 5); -- if (pDCTstat->Direction == DQS_READDIR) -- tmp = 0x20; -- else -- tmp = 0; -- if (DQSDelay >= tmp) { -- RnkDlySeqPassMax = DQSDelay; -- if (LastTest == DQS_FAIL) { -- RnkDlySeqPassMin = DQSDelay; /* start sequential run */ -- } -- if ((RnkDlySeqPassMax - RnkDlySeqPassMin)>(RnkDlyFilterMax-RnkDlyFilterMin)){ -- RnkDlyFilterMin = RnkDlySeqPassMin; -- RnkDlyFilterMax = RnkDlySeqPassMax; -- } -- LastTest = DQS_PASS; -- } -- -- if (pDCTstat->Direction == DQS_READDIR) { -- RnkDlySeqPassMaxTot = DQSDelay; -- if (LastTestTot == DQS_FAIL) -- RnkDlySeqPassMinTot = DQSDelay; -- if ((RnkDlySeqPassMaxTot - RnkDlySeqPassMinTot)>(RnkDlyFilterMaxTot-RnkDlyFilterMinTot)){ -- RnkDlyFilterMinTot = RnkDlySeqPassMinTot; -- RnkDlyFilterMaxTot = RnkDlySeqPassMaxTot; -- } -- LastTestTot = DQS_PASS; -- } -- } else { -- LastTest = DQS_FAIL; -- LastTestTot = DQS_FAIL; -- } -- } -- print_debug_dqs("\t\t\t\tTrainDQSPos: 33 RnkDlySeqPassMax ", RnkDlySeqPassMax, 4); -- if (RnkDlySeqPassMax == 0) { -- Errors |= 1 << SB_NODQSPOS; /* no passing window */ -- } else { -- print_debug_dqs_pair("\t\t\t\tTrainDQSPos: 34 RnkDlyFilter: ", RnkDlyFilterMin, " ", RnkDlyFilterMax, 4); -- if (((RnkDlyFilterMax - RnkDlyFilterMin) < MIN_DQS_WNDW)){ -- Errors |= 1 << SB_SMALLDQS; -- } else { -- u8 middle_dqs; -- /* mctEngDQSwindow_Save_D Not required for arrays */ -- if (pDCTstat->Direction == DQS_READDIR) -- middle_dqs = MiddleDQS_D(RnkDlyFilterMinTot, RnkDlyFilterMaxTot); -- else -- middle_dqs = MiddleDQS_D(RnkDlyFilterMin, RnkDlyFilterMax); -- pDCTstat->DQSDelay = middle_dqs; -- mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, cs_start); /* load the register with the value */ -- if (pDCTstat->Direction == DQS_READDIR) -- StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMinTot, RnkDlyFilterMaxTot); /* store the value into the data structure */ -- else -- StoreWrRdDQSDatStrucVal_D(pMCTstat, pDCTstat, cs_start, RnkDlyFilterMin, RnkDlyFilterMax); /* store the value into the data structure */ -- print_debug_dqs("\t\t\t\tTrainDQSPos: 42 middle_dqs : ",middle_dqs, 4); -- pDCTstat->DqsRdWrPos_Saved |= 1 << ByteLane; -- } -- } -- } -- } /* if (pDCTstat->DqsRdWrPos_Saved &(1 << ByteLane)) */ -- } --/* skipLocMiddle: */ -- pDCTstat->TrainErrors = Errors; -- -- print_debug_dqs("\t\t\tTrainDQSPos: Errors ", Errors, 3); --} -- --static void mctEngDQSwindow_Save_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, u8 ChipSel, -- u8 RnkDlyFilterMin, u8 RnkDlyFilterMax) --{ -- pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel] -- [pDCTstat->Direction] -- [0] -- [pDCTstat->ByteLane] = RnkDlyFilterMin; -- pDCTstat->CH_D_DIR_MaxMin_B_Dly[pDCTstat->Channel] -- [pDCTstat->Direction] -- [1] -- [pDCTstat->ByteLane] = RnkDlyFilterMax; --} -- - static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 ChipSel) - { -@@ -679,26 +834,6 @@ static void StoreDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, - pDCTstat->DQSDelay; - } - --static void StoreWrRdDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, u8 ChipSel, -- u8 RnkDlyFilterMin, u8 RnkDlyFilterMax) --{ -- u8 dn; -- -- if (pDCTstat->Direction == DQS_WRITEDIR) { -- dn = ChipSel >> 1; -- RnkDlyFilterMin += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane]; -- RnkDlyFilterMax += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane]; -- pDCTstat->DQSDelay += pDCTstat->CH_D_B_TxDqs[pDCTstat->Channel][dn][pDCTstat->ByteLane]; -- } else { -- RnkDlyFilterMin <<= 1; -- RnkDlyFilterMax <<= 1; -- pDCTstat->DQSDelay <<= 1; -- } -- mctEngDQSwindow_Save_D(pMCTstat, pDCTstat, ChipSel, RnkDlyFilterMin, RnkDlyFilterMax); -- StoreDQSDatStrucVal_D(pMCTstat, pDCTstat, ChipSel); --} -- - static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 ChipSel) - { -@@ -720,33 +855,6 @@ static void GetDQSDatStrucVal_D(struct MCTStatStruc *pMCTstat, - - /* FindDQSDatDimmVal_D is not required since we use an array */ - --static u8 MiddleDQS_D(u8 min, u8 max) --{ -- u8 size; -- size = max-min; -- if (size % 2) -- size++; /* round up if the size isn't even. */ -- return ( min + (size >> 1)); --} -- --static void TrainReadDQS_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start) --{ -- print_debug_dqs("\t\tTrainReadPos ", 0, 2); -- pDCTstat->Direction = DQS_READDIR; -- TrainDQSPos_D(pMCTstat, pDCTstat, cs_start); --} -- --static void TrainWriteDQS_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start) --{ -- pDCTstat->Direction = DQS_WRITEDIR; -- print_debug_dqs("\t\tTrainWritePos", 0, 2); -- TrainDQSPos_D(pMCTstat, pDCTstat, cs_start); --} -- - static void proc_IOCLFLUSH_D(u32 addr_hi) - { - SetTargetWTIO_D(addr_hi); -@@ -963,30 +1071,6 @@ static void ResetTargetWTIO_D(void) - _WRMSR(0xc0010017, lo, hi); /* IORR0 Mask */ - } - --static void ReadDQSTestPattern_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u32 TestAddr_lo) --{ -- /* Read a pattern of 72 bit times (per DQ), to test dram functionality. -- * The pattern is a stress pattern which exercises both ISI and -- * crosstalk. The number of cache lines to fill is dependent on DCT -- * width mode and burstlength. -- * Mode BL Lines Pattern no. -- * ----+---+------------------- -- * 64 4 9 0 -- * 64 8 9 0 -- * 64M 4 9 0 -- * 64M 8 9 0 -- * 128 4 18 1 -- * 128 8 N/A - -- */ -- if (pDCTstat->Pattern == 0) -- ReadL9TestPattern(TestAddr_lo); -- else -- ReadL18TestPattern(TestAddr_lo); -- _MFENCE; --} -- - u32 SetUpperFSbase(u32 addr_hi) - { - /* Set the upper 32-bits of the Base address, 4GB aligned) for the -@@ -1009,8 +1093,6 @@ void ResetDCTWrPtr_D(u32 dev, u32 index_reg, u32 index) - Set_NB32_index_wait(dev, index_reg, index, val); - } - --/* mctEngDQSwindow_Save_D not required with arrays */ -- - void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstatA) - { -@@ -1021,8 +1103,8 @@ void mct_TrainDQSPos_D(struct MCTStatStruc *pMCTstat, - for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { - pDCTstat = pDCTstatA + Node; - if (pDCTstat->DCTSysLimit) { -+ TrainDQSRdWrPos_D(pMCTstat, pDCTstat); - for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) { -- TrainDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel); - SetEccDQSRdWrPos_D(pMCTstat, pDCTstat, ChipSel); - } - } -@@ -1137,27 +1219,6 @@ static void mct_SetDQSDelayCSR_D(struct MCTStatStruc *pMCTstat, - } - } - --/* -- * mct_SetDQSDelayAllCSR_D: -- * Write the Delay value to all eight byte lanes. -- */ --static void mct_SetDQSDelayAllCSR_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u8 cs_start) --{ -- u8 ByteLane; -- u8 ChipSel = cs_start; -- -- for (ChipSel = cs_start; ChipSel < (cs_start + 2); ChipSel++) { -- if ( mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, pDCTstat->Channel, ChipSel)) { -- for (ByteLane = 0; ByteLane < 8; ByteLane++) { -- pDCTstat->ByteLane = ByteLane; -- mct_SetDQSDelayCSR_D(pMCTstat, pDCTstat, ChipSel); -- } -- } -- } --} -- - u8 mct_RcvrRankEnabled_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, - u8 Channel, u8 ChipSel) -@@ -1196,7 +1257,7 @@ u32 mct_GetMCTSysAddr_D(struct MCTStatStruc *pMCTstat, - reg = 0x40 + (receiver << 2) + reg_off; - val = Get_NB32(dev, reg); - -- val &= ~0x0F; -+ val &= ~0xe007c01f; - - /* unganged mode DCT0+DCT1, sys addr of DCT1=node - * base+DctSelBaseAddr+local ca base*/ -@@ -1277,6 +1338,7 @@ exitGetAddrWNoError: - 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: SysBase ", pDCTstat->DCTSysBase, 2); - print_debug_dqs("mct_GetMCTSysAddr_D: HoleBase ", pDCTstat->DCTHoleBase, 2); - print_debug_dqs("mct_GetMCTSysAddr_D: Cachetop ", pMCTstat->Sub4GCacheTop, 2); - -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c -index 528c782..60bc01d 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcthwl.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -25,7 +26,6 @@ static void EnableZQcalibration(struct MCTStatStruc *pMCTstat, struct DCTStatStr - 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); - -@@ -154,7 +154,6 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat, - 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); -@@ -162,6 +161,9 @@ static void PhyWLPass2(struct MCTStatStruc *pMCTstat, - } - } - -+/* Write Levelization Training -+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.1 -+ */ - static void WriteLevelization_HW(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat) - { -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c -index 3d625de..596fb23 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctmtr_d.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -201,12 +202,13 @@ static void SetMTRRrange_D(u32 Base, u32 *pLimit, u32 *pMtrrAddr, u16 MtrrType) - - 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 --*/ -+ /* 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; -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c -index 013a1b9..6f97061 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctndi_d.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -140,7 +141,7 @@ void InterleaveNodes_D(struct MCTStatStruc *pMCTstat, - } - - if (DoIntlv) { -- MCTMemClr_D(pMCTstat,pDCTstatA); -+ 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); -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c -index da2f372..cda9c6b 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -36,10 +37,10 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2) - val = Get_NB32(pDCTstat->dev_dct, dct * 0x100 + 0x78); - - val &= 7; -- val = ((~val) & 0xFF) + 1; -+ val = ((~val) & 0xff) + 1; - val += 6; -- val &= 0xFF; -- misc2 &= 0xFFF8FFFF; -+ val &= 0x7; -+ misc2 &= 0xfff8ffff; - misc2 |= val << 16; /* DataTxFifoWrDly */ - if (pDCTstat->LogicalCPUID & AMD_DR_Dx) - misc2 |= 1 << 7; /* ProgOdtEn */ -@@ -52,11 +53,15 @@ void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat) - u32 val; - - if (pDCTstat->LogicalCPUID & (AMD_DR_Cx)) { -- Set_NB32(pDCTstat->dev_dct, 0x11C, 0x0CE00FC0 | 1 << 29/* FlushWrOnStpGnt */); -+ /* Revision C */ -+ Set_NB32(pDCTstat->dev_dct, 0x11c, 0x0ce00fc0 | 1 << 29/* FlushWrOnStpGnt */); -+ } - -- val = Get_NB32(pDCTstat->dev_dct, 0x1B0); -- val &= 0xFFFFF8C0; -+ if (pDCTstat->LogicalCPUID & (AMD_DR_Cx)) { -+ val = Get_NB32(pDCTstat->dev_dct, 0x1b0); -+ val &= ~0x73f; - val |= 0x101; /* BKDG recommended settings */ -- Set_NB32(pDCTstat->dev_dct, 0x1B0, val); -+ -+ Set_NB32(pDCTstat->dev_dct, 0x1b0, val); - } - } -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c -index 6de2f4e..b21b96a 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -172,6 +173,7 @@ static u32 mct_MR1(struct MCTStatStruc *pMCTstat, - ret |= 1 << 11; - } - -+ /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */ - if (dword & (1 << 13)) - ret |= 1 << 12; - -@@ -199,7 +201,8 @@ static u32 mct_MR0(struct MCTStatStruc *pMCTstat, - /* 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 */ -+ ret |= (dword2 & 0x7) << 4; /* F2x88[2:0] to MrsAddress[6:4] */ -+ ret |= ((dword2 & 0x8) >> 3) << 2; /* F2x88[3] to MrsAddress[2] */ - - /* program MrsAddress[12]=0 (PPD):slow exit */ - if (dword & (1 << 23)) -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c -index 8e5c268..91e8f77 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -24,25 +25,13 @@ - - static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 Pass); --static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat, -- u8 rcvrEnDly, u8 Channel, -- u8 receiver, u8 Pass); --static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u32 addr, u8 channel, -- u8 pattern, u8 Pass); - static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat); - static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 Channel); - static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 Channel); --static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat, -- u8 RcvrEnDly, u8 where, -- u8 Channel, u8 Receiver, -- u32 dev, u32 index_reg, -- u8 Addl_Index, u8 Pass); --static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQSRcvEnDly); -+static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 DQSRcvEnDly); - static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 dct); - static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat); -@@ -50,17 +39,17 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat); - /* Warning: These must be located so they do not cross a logical 16-bit - segment boundary! */ - static const u32 TestPattern0_D[] = { -- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, -- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, -- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, -- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, --}; --static const u32 TestPattern1_D[] = { - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - 0x55555555, 0x55555555, 0x55555555, 0x55555555, - }; -+static const u32 TestPattern1_D[] = { -+ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, -+ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, -+ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, -+ 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, -+}; - static const u32 TestPattern2_D[] = { - 0x12345678, 0x87654321, 0x23456789, 0x98765432, - 0x59385824, 0x30496724, 0x24490795, 0x99938733, -@@ -104,16 +93,87 @@ void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat, - dqsTrainRcvrEn_SW(pMCTstat, pDCTstat, Pass); - } - -+static void read_dqs_write_timing_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg) -+{ -+ uint8_t lane; -+ uint32_t dword; -+ -+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) { -+ uint32_t wdt_reg; -+ if ((lane == 0) || (lane == 1)) -+ wdt_reg = 0x30; -+ if ((lane == 2) || (lane == 3)) -+ wdt_reg = 0x31; -+ if ((lane == 4) || (lane == 5)) -+ wdt_reg = 0x40; -+ if ((lane == 6) || (lane == 7)) -+ wdt_reg = 0x41; -+ if (lane == 8) -+ wdt_reg = 0x32; -+ wdt_reg += dimm * 3; -+ dword = Get_NB32_index_wait(dev, index_reg, wdt_reg); -+ if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) -+ current_total_delay[lane] = (dword & 0x00ff0000) >> 16; -+ if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) -+ current_total_delay[lane] = dword & 0x000000ff; -+ } -+} -+ -+static void write_dqs_receiver_enable_control_registers(uint16_t* current_total_delay, uint32_t dev, uint8_t dimm, uint32_t index_reg) -+{ -+ uint8_t lane; -+ uint32_t dword; -+ -+ for (lane = 0; lane < 8; lane++) { -+ uint32_t ret_reg; -+ if ((lane == 0) || (lane == 1)) -+ ret_reg = 0x10; -+ if ((lane == 2) || (lane == 3)) -+ ret_reg = 0x11; -+ if ((lane == 4) || (lane == 5)) -+ ret_reg = 0x20; -+ if ((lane == 6) || (lane == 7)) -+ ret_reg = 0x21; -+ ret_reg += dimm * 3; -+ dword = Get_NB32_index_wait(dev, index_reg, ret_reg); -+ if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) { -+ dword &= ~(0x1ff << 16); -+ dword |= (current_total_delay[lane] & 0x1ff) << 16; -+ } -+ if ((lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) { -+ dword &= ~0x1ff; -+ dword |= current_total_delay[lane] & 0x1ff; -+ } -+ Set_NB32_index_wait(dev, index_reg, ret_reg, dword); -+ } -+} -+ -+static uint32_t convert_testaddr_and_channel_to_address(struct DCTStatStruc *pDCTstat, uint32_t testaddr, uint8_t channel) -+{ -+ SetUpperFSbase(testaddr); -+ testaddr <<= 8; -+ -+ if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) { -+ testaddr += 8; /* second channel */ -+ } -+ -+ return testaddr; -+} -+ -+/* DQS Receiver Enable Training -+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.2 -+ */ - static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat, u8 Pass) - { -- u8 Channel, RcvrEnDly, RcvrEnDlyRmin; -- u8 Test0, Test1, CurrTest, CurrTestSide0, CurrTestSide1; -- u8 CTLRMaxDelay, _2Ranks, PatternA, PatternB; -+ u8 Channel; -+ u8 _2Ranks; - u8 Addl_Index = 0; - u8 Receiver; - u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0; -- u8 RcvrEnDlyLimit, Final_Value, MaxDelay_CH[2]; -+ u8 Final_Value; -+ u16 CTLRMaxDelay; -+ u16 MaxDelay_CH[2]; - u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B; - u32 PatternBuffer[64+4]; /* FIXME: need increase 8? */ - u32 Errors; -@@ -127,9 +187,20 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat, - u32 cr4; - u32 lo, hi; - -+ uint32_t dword; -+ uint8_t rank; -+ uint8_t lane; -+ uint16_t current_total_delay[MAX_BYTE_LANES]; -+ uint16_t candidate_total_delay[8]; -+ uint8_t data_test_pass_sr[2][8]; /* [rank][lane] */ -+ uint8_t data_test_pass[8]; /* [lane] */ -+ uint8_t data_test_pass_prev[8]; /* [lane] */ -+ uint8_t window_det_toggle[8]; -+ uint8_t trained[8]; -+ uint64_t result_qword1; -+ uint64_t result_qword2; -+ - u8 valid; -- u32 tmp; -- u8 LastTest; - - print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0); - print_debug_dqs("TrainRcvEn: Pass", Pass, 0); -@@ -181,33 +252,103 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat, - - Errors = 0; - dev = pDCTstat->dev_dct; -- CTLRMaxDelay = 0; - - for (Channel = 0; Channel < 2; Channel++) { - print_debug_dqs("\tTrainRcvEn51: Node ", pDCTstat->Node_ID, 1); - print_debug_dqs("\tTrainRcvEn51: Channel ", Channel, 1); - pDCTstat->Channel = Channel; - -+ CTLRMaxDelay = 0; - MaxDelay_CH[Channel] = 0; - index_reg = 0x98 + 0x100 * Channel; - - Receiver = mct_InitReceiver_D(pDCTstat, Channel); -- /* There are four receiver pairs, loosely associated with chipselects. */ -+ /* There are four receiver pairs, loosely associated with chipselects. -+ * This is essentially looping over each DIMM. -+ */ - for (; Receiver < 8; Receiver += 2) { - Addl_Index = (Receiver >> 1) * 3 + 0x10; -- LastTest = DQS_FAIL; -- -- /* mct_ModifyIndex_D */ -- RcvrEnDlyRmin = RcvrEnDlyLimit = 0xff; - - print_debug_dqs("\t\tTrainRcvEnd52: index ", Addl_Index, 2); - -- if(!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) { -+ if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) { - continue; - } - -+ /* Clear data structures */ -+ for (lane = 0; lane < 8; lane++) { -+ data_test_pass_prev[lane] = 0; -+ trained[lane] = 0; -+ } -+ -+ /* 2.8.9.9.2 (1, 6) -+ * Retrieve gross and fine timing fields from write DQS registers -+ */ -+ read_dqs_write_timing_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* 2.8.9.9.2 (1) -+ * Program the Write Data Timing and Write ECC Timing register to -+ * the values stored in the DQS Write Timing Control register -+ * for each lane -+ */ -+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) { -+ uint32_t wdt_reg; -+ -+ /* Calculate Write Data Timing register location */ -+ if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3)) -+ wdt_reg = 0x1; -+ if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7)) -+ wdt_reg = 0x2; -+ if (lane == 8) -+ wdt_reg = 0x3; -+ wdt_reg |= ((Receiver / 2) << 8); -+ -+ /* Set Write Data Timing register values */ -+ dword = Get_NB32_index_wait(dev, index_reg, wdt_reg); -+ if ((lane == 7) || (lane == 3)) { -+ dword &= ~(0x7f << 24); -+ dword |= (current_total_delay[lane] & 0x7f) << 24; -+ } -+ if ((lane == 6) || (lane == 2)) { -+ dword &= ~(0x7f << 16); -+ dword |= (current_total_delay[lane] & 0x7f) << 16; -+ } -+ if ((lane == 5) || (lane == 1)) { -+ dword &= ~(0x7f << 8); -+ dword |= (current_total_delay[lane] & 0x7f) << 8; -+ } -+ if ((lane == 8) || (lane == 4) || (lane == 0)) { -+ dword &= ~0x7f; -+ dword |= current_total_delay[lane] & 0x7f; -+ } -+ Set_NB32_index_wait(dev, index_reg, wdt_reg, dword); -+ } -+ -+ /* 2.8.9.9.2 (2) -+ * Program the Read DQS Timing Control and the Read DQS ECC Timing Control registers -+ * to 1/2 MEMCLK for all lanes -+ */ -+ for (lane = 0; lane < MAX_BYTE_LANES; lane++) { -+ uint32_t rdt_reg; -+ if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3)) -+ rdt_reg = 0x5; -+ if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7)) -+ rdt_reg = 0x6; -+ if (lane == 8) -+ rdt_reg = 0x7; -+ rdt_reg |= ((Receiver / 2) << 8); -+ if (lane == 8) -+ dword = 0x0000003f; -+ else -+ dword = 0x3f3f3f3f; -+ Set_NB32_index_wait(dev, index_reg, rdt_reg, dword); -+ } -+ -+ /* 2.8.9.9.2 (3) -+ * Select two test addresses for each rank present -+ */ - TestAddr0 = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, Channel, Receiver, &valid); -- if(!valid) { /* Address not supported on current CS */ -+ if (!valid) { /* Address not supported on current CS */ - continue; - } - -@@ -229,171 +370,214 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat, - print_debug_dqs("\t\tTrainRcvEn53: TestAddr1 ", TestAddr1, 2); - print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", TestAddr1B, 2); - -- /* -- * Get starting RcvrEnDly value -+ /* 2.8.9.9.2 (4, 5) -+ * Write 1 cache line of the appropriate test pattern to each test addresse - */ -- RcvrEnDly = mct_Get_Start_RcvrEnDly_1Pass(Pass); -+ mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, 0); /* rank 0 of DIMM, testpattern 0 */ -+ mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0B, 1); /* rank 0 of DIMM, testpattern 1 */ -+ if (_2Ranks) { -+ mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1, 0); /*rank 1 of DIMM, testpattern 0 */ -+ mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1B, 1); /*rank 1 of DIMM, testpattern 1 */ -+ } - -- /* mct_GetInitFlag_D*/ -- if (Pass == FirstPass) { -- pDCTstat->DqsRcvEn_Pass = 0; -- } else { -- pDCTstat->DqsRcvEn_Pass=0xFF; -+#if DQS_TRAIN_DEBUG > 0 -+ for (lane = 0; lane < 8; lane++) { -+ print_debug_dqs("\t\tTrainRcvEn54: lane: ", lane, 2); -+ print_debug_dqs("\t\tTrainRcvEn54: current_total_delay ", current_total_delay[lane], 2); - } -- pDCTstat->DqsRcvEn_Saved = 0; -+#endif - -+ /* 2.8.9.9.2 (6) -+ * Write gross and fine timing fields to read DQS registers -+ */ -+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg); -+ -+ /* 2.8.9.9.2 (7) -+ * Loop over all delay values up to 1 MEMCLK (0x40 delay steps) from the initial delay values -+ * -+ * FIXME -+ * It is not clear if training should be discontinued if any test failures occur in the first -+ * 1 MEMCLK window, or if it should be discontinued if no successes occur in the first 1 MEMCLK -+ * window. Therefore, loop over up to 2 MEMCLK (0x80 delay steps) to be on the safe side. -+ */ -+ uint16_t current_delay_step; - -- while(RcvrEnDly < RcvrEnDlyLimit) { /* sweep Delay value here */ -- print_debug_dqs("\t\t\tTrainRcvEn541: RcvrEnDly ", RcvrEnDly, 3); -+ for (current_delay_step = 0; current_delay_step < 0x80; current_delay_step++) { -+ print_debug_dqs("\t\t\tTrainRcvEn541: current_delay_step ", current_delay_step, 3); - -- /* callback not required -- if(mct_AdjustDelay_D(pDCTstat, RcvrEnDly)) -- goto skipDly; -+ /* 2.8.9.9.2 (7 D) -+ * Terminate if all lanes are trained - */ -+ uint8_t all_lanes_trained = 1; -+ for (lane = 0; lane < 8; lane++) -+ if (!trained[lane]) -+ all_lanes_trained = 0; - -- /* Odd steps get another pattern such that even -- and odd steps alternate. The pointers to the -- patterns will be swaped at the end of the loop -- so that they correspond. */ -- if(RcvrEnDly & 1) { -- PatternA = 1; -- PatternB = 0; -- } else { -- /* Even step */ -- PatternA = 0; -- PatternB = 1; -- } -- -- mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0, PatternA); /* rank 0 of DIMM, testpattern 0 */ -- mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0B, PatternB); /* rank 0 of DIMM, testpattern 1 */ -- if(_2Ranks) { -- mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1, PatternA); /*rank 1 of DIMM, testpattern 0 */ -- mct_Write1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1B, PatternB); /*rank 1 of DIMM, testpattern 1 */ -- } -- -- mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, 0, Channel, Receiver, dev, index_reg, Addl_Index, Pass); -- -- CurrTest = DQS_FAIL; -- CurrTestSide0 = DQS_FAIL; -- CurrTestSide1 = DQS_FAIL; -- -- mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0); /*cache fills */ -- Test0 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr0, Channel, PatternA, Pass);/* ROM vs cache compare */ -- proc_IOCLFLUSH_D(TestAddr0); -- ResetDCTWrPtr_D(dev, index_reg, Addl_Index); -- -- print_debug_dqs("\t\t\tTrainRcvEn542: Test0 result ", Test0, 3); -- -- /* != 0x00 mean pass */ -- -- if(Test0 == DQS_PASS) { -- mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0B); /*cache fills */ -- /* ROM vs cache compare */ -- Test1 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr0B, Channel, PatternB, Pass); -- proc_IOCLFLUSH_D(TestAddr0B); -- ResetDCTWrPtr_D(dev, index_reg, Addl_Index); -- -- print_debug_dqs("\t\t\tTrainRcvEn543: Test1 result ", Test1, 3); -+ if (all_lanes_trained) -+ break; - -- if(Test1 == DQS_PASS) { -- CurrTestSide0 = DQS_PASS; -+ /* 2.8.9.9.2 (7 A) -+ * Loop over all ranks -+ */ -+ for (rank = 0; rank < (_2Ranks + 1); rank++) { -+ /* 2.8.9.9.2 (7 A a-d) -+ * Read the first test address of the current rank -+ * Store the first data beat for analysis -+ * Reset read pointer in the DRAM controller FIFO -+ * Read the second test address of the current rank -+ * Store the first data beat for analysis -+ * Reset read pointer in the DRAM controller FIFO -+ */ -+ if (rank & 1) { -+ /* 2.8.9.9.2 (7 D) -+ * Invert read instructions to alternate data read order on the bus -+ */ -+ proc_IOCLFLUSH_D((rank == 0)?TestAddr0B:TestAddr1B); -+ result_qword2 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0B:TestAddr1B, Channel)); -+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg); -+ proc_IOCLFLUSH_D((rank == 0)?TestAddr0:TestAddr1); -+ result_qword1 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0:TestAddr1, Channel)); -+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg); -+ } else { -+ proc_IOCLFLUSH_D((rank == 0)?TestAddr0:TestAddr1); -+ result_qword1 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0:TestAddr1, Channel)); -+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg); -+ proc_IOCLFLUSH_D((rank == 0)?TestAddr0B:TestAddr1B); -+ result_qword2 = read64_fs(convert_testaddr_and_channel_to_address(pDCTstat, (rank == 0)?TestAddr0B:TestAddr1B, Channel)); -+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg); - } -- } -- if(_2Ranks) { -- mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1); /*cache fills */ -- /* ROM vs cache compare */ -- Test0 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1, Channel, PatternA, Pass); -- proc_IOCLFLUSH_D(TestAddr1); -- ResetDCTWrPtr_D(dev, index_reg, Addl_Index); -- -- print_debug_dqs("\t\t\tTrainRcvEn544: Test0 result ", Test0, 3); -- -- if(Test0 == DQS_PASS) { -- mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr1B); /*cache fills */ -- /* ROM vs cache compare */ -- Test1 = mct_CompareTestPatternQW0_D(pMCTstat, pDCTstat, TestAddr1B, Channel, PatternB, Pass); -- proc_IOCLFLUSH_D(TestAddr1B); -- ResetDCTWrPtr_D(dev, index_reg, Addl_Index); -- -- print_debug_dqs("\t\t\tTrainRcvEn545: Test1 result ", Test1, 3); -- if(Test1 == DQS_PASS) { -- CurrTestSide1 = DQS_PASS; -+ /* 2.8.9.9.2 (7 A e) -+ * Compare both read patterns and flag passing ranks/lanes -+ */ -+ uint8_t result_lane_byte1; -+ uint8_t result_lane_byte2; -+ for (lane = 0; lane < 8; lane++) { -+ if (trained[lane] == 1) { -+#if DQS_TRAIN_DEBUG > 0 -+ print_debug_dqs("\t\t\t\t\t\t\t\t lane already trained: ", lane, 4); -+#endif -+ continue; - } -+ -+ result_lane_byte1 = (result_qword1 >> (lane * 8)) & 0xff; -+ result_lane_byte2 = (result_qword2 >> (lane * 8)) & 0xff; -+ if ((result_lane_byte1 == 0x55) && (result_lane_byte2 == 0xaa)) -+ data_test_pass_sr[rank][lane] = 1; -+ else -+ data_test_pass_sr[rank][lane] = 0; -+#if DQS_TRAIN_DEBUG > 0 -+ print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", 0x55, " | ", result_lane_byte1, 4); -+ print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", 0xaa, " | ", result_lane_byte2, 4); -+#endif - } - } - -- if(_2Ranks) { -- if ((CurrTestSide0 == DQS_PASS) && (CurrTestSide1 == DQS_PASS)) { -- CurrTest = DQS_PASS; -+ /* 2.8.9.9.2 (7 B) -+ * If DIMM is dual rank, only use delays that pass testing for both ranks -+ */ -+ for (lane = 0; lane < 8; lane++) { -+ if (_2Ranks) { -+ if ((data_test_pass_sr[0][lane]) && (data_test_pass_sr[1][lane])) -+ data_test_pass[lane] = 1; -+ else -+ data_test_pass[lane] = 0; -+ } else { -+ data_test_pass[lane] = data_test_pass_sr[0][lane]; - } -- } else if (CurrTestSide0 == DQS_PASS) { -- CurrTest = DQS_PASS; - } - -- /* record first pass DqsRcvEn to stack */ -- valid = mct_SavePassRcvEnDly_D(pDCTstat, RcvrEnDly, Channel, Receiver, Pass); -+ /* 2.8.9.9.2 (7 E) -+ * For each lane, update the DQS receiver delay setting in support of next iteration -+ */ -+ for (lane = 0; lane < 8; lane++) { -+ if (trained[lane] == 1) -+ continue; -+ -+ /* 2.8.9.9.2 (7 C a) -+ * Save the total delay of the first success after a failure for later use -+ */ -+ if ((data_test_pass[lane] == 1) && (data_test_pass_prev[lane] == 0)) { -+ candidate_total_delay[lane] = current_total_delay[lane]; -+ window_det_toggle[lane] = 0; -+ } - -- /* Break(1:RevF,2:DR) or not(0) FIXME: This comment deosn't make sense */ -- if(valid == 2 || (LastTest == DQS_FAIL && valid == 1)) { -- RcvrEnDlyRmin = RcvrEnDly; -- break; -+ /* 2.8.9.9.2 (7 C b) -+ * If the current delay failed testing add 1/8 UI to the current delay -+ */ -+ if (data_test_pass[lane] == 0) -+ current_total_delay[lane] += 0x4; -+ -+ /* 2.8.9.9.2 (7 C c) -+ * If the current delay passed testing alternately add either 1/32 UI or 1/4 UI to the current delay -+ * If 1.25 UI of delay have been added with no failures the lane is considered trained -+ */ -+ if (data_test_pass[lane] == 1) { -+ /* See if lane is trained */ -+ if ((current_total_delay[lane] - candidate_total_delay[lane]) >= 0x28) { -+ trained[lane] = 1; -+ -+ /* Calculate and set final lane delay value -+ * The final delay is the candidate delay + 7/8 UI -+ */ -+ current_total_delay[lane] = candidate_total_delay[lane] + 0x1c; -+ } else { -+ if (window_det_toggle[lane] == 0) { -+ current_total_delay[lane] += 0x1; -+ window_det_toggle[lane] = 1; -+ } else { -+ current_total_delay[lane] += 0x8; -+ window_det_toggle[lane] = 0; -+ } -+ } -+ } - } - -- LastTest = CurrTest; -- -- /* swap the rank 0 pointers */ -- tmp = TestAddr0; -- TestAddr0 = TestAddr0B; -- TestAddr0B = tmp; -- -- /* swap the rank 1 pointers */ -- tmp = TestAddr1; -- TestAddr1 = TestAddr1B; -- TestAddr1B = tmp; -- -- print_debug_dqs("\t\t\tTrainRcvEn56: RcvrEnDly ", RcvrEnDly, 3); -+ /* Update delays in hardware */ -+ write_dqs_receiver_enable_control_registers(current_total_delay, dev, (Receiver >> 1), index_reg); - -- RcvrEnDly++; -- -- } /* while RcvrEnDly */ -- -- print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDly ", RcvrEnDly, 2); -- print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyRmin ", RcvrEnDlyRmin, 3); -- print_debug_dqs("\t\tTrainRcvEn61: RcvrEnDlyLimit ", RcvrEnDlyLimit, 3); -- if(RcvrEnDlyRmin == RcvrEnDlyLimit) { -- /* no passing window */ -- pDCTstat->ErrStatus |= 1 << SB_NORCVREN; -- Errors |= 1 << SB_NORCVREN; -- pDCTstat->ErrCode = SC_FatalErr; -+ /* Save previous results for comparison in the next iteration */ -+ for (lane = 0; lane < 8; lane++) -+ data_test_pass_prev[lane] = data_test_pass[lane]; - } - -- if(RcvrEnDly > (RcvrEnDlyLimit - 1)) { -- /* passing window too narrow, too far delayed*/ -- pDCTstat->ErrStatus |= 1 << SB_SmallRCVR; -- Errors |= 1 << SB_SmallRCVR; -- pDCTstat->ErrCode = SC_FatalErr; -- RcvrEnDly = RcvrEnDlyLimit - 1; -- pDCTstat->CSTrainFail |= 1 << Receiver; -- pDCTstat->DimmTrainFail |= 1 << (Receiver + Channel); -- } -- -- /* CHB_D0_B0_RCVRDLY set in mct_Average_RcvrEnDly_Pass */ -- mct_Average_RcvrEnDly_Pass(pDCTstat, RcvrEnDly, RcvrEnDlyLimit, Channel, Receiver, Pass); -+#if DQS_TRAIN_DEBUG > 0 -+ for (lane = 0; lane < 8; lane++) -+ print_debug_dqs_pair("\t\tTrainRcvEn55: Lane ", lane, " current_total_delay ", current_total_delay[lane], 2); -+#endif - -- mct_SetFinalRcvrEnDly_D(pDCTstat, RcvrEnDly, Final_Value, Channel, Receiver, dev, index_reg, Addl_Index, Pass); -+ /* Find highest delay value and save for later use */ -+ for (lane = 0; lane < 8; lane++) -+ if (current_total_delay[lane] > CTLRMaxDelay) -+ CTLRMaxDelay = current_total_delay[lane]; - -- if(pDCTstat->ErrStatus & (1 << SB_SmallRCVR)) { -- Errors |= 1 << SB_SmallRCVR; -+ /* See if any lanes failed training, and set error flags appropriately -+ * For all trained lanes, save delay values for later use -+ */ -+ for (lane = 0; lane < 8; lane++) { -+ if (trained[lane]) { -+ pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1][lane] = current_total_delay[lane]; -+ } else { -+ printk(BIOS_WARNING, "TrainRcvrEn: WARNING: Lane %d of receiver %d on channel %d failed training!\n", lane, Receiver, Channel); -+ -+ /* Set error flags */ -+ pDCTstat->ErrStatus |= 1 << SB_NORCVREN; -+ Errors |= 1 << SB_NORCVREN; -+ pDCTstat->ErrCode = SC_FatalErr; -+ pDCTstat->CSTrainFail |= 1 << Receiver; -+ pDCTstat->DimmTrainFail |= 1 << (Receiver + Channel); -+ } - } - -- RcvrEnDly += Pass1MemClkDly; -- if(RcvrEnDly > CTLRMaxDelay) { -- CTLRMaxDelay = RcvrEnDly; -- } -+ /* 2.8.9.9.2 (8) -+ * Flush the receiver FIFO -+ * Write one full cache line of non-0x55/0xaa data to one of the test addresses, then read it back to flush the FIFO -+ */ - -- } /* while Receiver */ -+ WriteLNTestPattern(TestAddr0 << 8, (uint8_t *)TestPattern2_D, 1); -+ mct_Read1LTestPattern_D(pMCTstat, pDCTstat, TestAddr0); -+ } - MaxDelay_CH[Channel] = CTLRMaxDelay; -- } /* for Channel */ -+ } - - CTLRMaxDelay = MaxDelay_CH[0]; - if (MaxDelay_CH[1] > CTLRMaxDelay) -@@ -428,31 +612,31 @@ static void dqsTrainRcvrEn_SW(struct MCTStatStruc *pMCTstat, - - #if DQS_TRAIN_DEBUG > 0 - { -- u8 Channel; -+ u8 ChannelDTD; - printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n"); -- for(Channel = 0; Channel<2; Channel++) { -+ for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) { - printk(BIOS_DEBUG, "Channel:%x: %x\n", -- Channel, pDCTstat->CH_MaxRdLat[Channel]); -+ ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]); - } - } - #endif - - #if DQS_TRAIN_DEBUG > 0 - { -- u8 val; -- u8 Channel, Receiver; -+ u16 valDTD; -+ u8 ChannelDTD, ReceiverDTD; - u8 i; -- u8 *p; -+ u16 *p; - - printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n"); -- for(Channel = 0; Channel < 2; Channel++) { -- printk(BIOS_DEBUG, "Channel:%x\n", Channel); -- for(Receiver = 0; Receiver<8; Receiver+=2) { -- printk(BIOS_DEBUG, "\t\tReceiver:%x:", Receiver); -- p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver>>1]; -+ for(ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) { -+ printk(BIOS_DEBUG, "Channel:%x\n", ChannelDTD); -+ for(ReceiverDTD = 0; ReceiverDTD<8; ReceiverDTD+=2) { -+ printk(BIOS_DEBUG, "\t\tReceiver:%x:", ReceiverDTD); -+ p = pDCTstat->CH_D_B_RCVRDLY[ChannelDTD][ReceiverDTD>>1]; - for (i=0;i<8; i++) { -- val = p[i]; -- printk(BIOS_DEBUG, "%x ", val); -+ valDTD = p[i]; -+ printk(BIOS_DEBUG, " %03x", valDTD); - } - printk(BIOS_DEBUG, "\n"); - } -@@ -475,15 +659,6 @@ u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct) - } - } - --static void mct_SetFinalRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, u8 where, u8 Channel, u8 Receiver, u32 dev, u32 index_reg, u8 Addl_Index, u8 Pass/*, u8 *p*/) --{ -- /* -- * Program final DqsRcvEnDly to additional index for DQS receiver -- * enabled delay -- */ -- mct_SetRcvrEnDly_D(pDCTstat, RcvrEnDly, where, Channel, Receiver, dev, index_reg, Addl_Index, Pass); --} -- - static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat) - { - u8 ch_end, ch; -@@ -514,17 +689,20 @@ static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat) - * Function only used once so it was inlined. - */ - --void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, -+/* Set F2x[1, 0]9C_x[2B:10] DRAM DQS Receiver Enable Timing Control Registers -+ * See BKDG Rev. 3.62 page 268 for more information -+ */ -+void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u16 RcvrEnDly, - u8 FinalValue, u8 Channel, u8 Receiver, u32 dev, - u32 index_reg, u8 Addl_Index, u8 Pass) - { - u32 index; - u8 i; -- u8 *p; -+ u16 *p; - u32 val; - -- if(RcvrEnDly == 0xFE) { -- /*set the boudary flag */ -+ if(RcvrEnDly == 0x1fe) { -+ /*set the boundary flag */ - pDCTstat->Status |= 1 << SB_DQSRcvLimit; - } - -@@ -543,27 +721,57 @@ void mct_SetRcvrEnDly_D(struct DCTStatStruc *pDCTstat, u8 RcvrEnDly, - val = Get_NB32_index_wait(dev, index_reg, index); - if(i & 1) { - /* odd byte lane */ -- val &= ~(0xFF << 16); -- val |= (RcvrEnDly << 16); -+ val &= ~(0x1ff << 16); -+ val |= ((RcvrEnDly & 0x1ff) << 16); - } else { - /* even byte lane */ -- val &= ~0xFF; -- val |= RcvrEnDly; -+ val &= ~0x1ff; -+ val |= (RcvrEnDly & 0x1ff); - } - Set_NB32_index_wait(dev, index_reg, index, val); - } - - } - --static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQSRcvEnDly) -+/* Calculate MaxRdLatency -+ * Algorithm detailed in the Fam10h BKDG Rev. 3.62 section 2.8.9.9.5 -+ */ -+static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 DQSRcvEnDly) - { - u32 dev; - u32 reg; -- u16 SubTotal; -+ u32 SubTotal; - u32 index_reg; - u32 reg_off; - u32 val; -- u32 valx; -+ -+ uint8_t cpu_val_n; -+ uint8_t cpu_val_p; -+ -+ u16 freq_tab[] = {400, 533, 667, 800}; -+ -+ /* Set up processor-dependent values */ -+ if (pDCTstat->LogicalCPUID & AMD_DR_Dx) { -+ /* Revision D and above */ -+ cpu_val_n = 4; -+ cpu_val_p = 29; -+ } else if (pDCTstat->LogicalCPUID & AMD_DR_Cx) { -+ /* Revision C */ -+ uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE); -+ if ((package_type == PT_L1) /* Socket F (1207) */ -+ || (package_type == PT_M2) /* Socket AM3 */ -+ || (package_type == PT_S1)) { /* Socket S1g<x> */ -+ cpu_val_n = 10; -+ cpu_val_p = 11; -+ } else { -+ cpu_val_n = 4; -+ cpu_val_p = 29; -+ } -+ } else { -+ /* Revision B and below */ -+ cpu_val_n = 10; -+ cpu_val_p = 11; -+ } - - if(pDCTstat->GangedMode) - Channel = 0; -@@ -598,49 +806,32 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQ - val = Get_NB32(dev, 0x78 + reg_off); - SubTotal += 8 - (val & 0x0f); - -- /* Convert bits 7-5 (also referred to as the course delay) of -+ /* Convert bits 7-5 (also referred to as the coarse 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 += DQSRcvEnDly >> 5; /* Retrieve gross delay portion of value */ - -- /* Add 5.5 to the sub-total. 5.5 represents part of the -+ /* Add "P" to the sub-total. "P" represents part of the - * processor specific constant delay value in the DRAM - * clock domain. - */ - SubTotal <<= 1; /*scale 1/2 MemClk to 1/4 MemClk */ -- SubTotal += 11; /*add 5.5 1/2MemClk */ -+ SubTotal += cpu_val_p; /*add "P" 1/2MemClk */ -+ SubTotal >>= 1; /*scale 1/4 MemClk back to 1/2 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). -+ * clocks (NCLKs) - */ -+ SubTotal *= 200 * ((Get_NB32(pDCTstat->dev_nbmisc, 0xd4) & 0x1f) + 4); -+ SubTotal /= freq_tab[((Get_NB32(pDCTstat->dev_dct, 0x94 + reg_off) & 0x7) - 3)]; -+ SubTotal = (SubTotal + (2 - 1)) / 2; /* Round up */ - -- /* 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; -- -- val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4); -- SubTotal *= ((val & 0x1f) + 4 ) * 3; -- -- SubTotal /= valx; -- if (SubTotal % valx) { /* round up */ -- SubTotal++; -- } -- -- /* Add 5 NCLKs to the sub-total. 5 represents part of the -+ /* Add "N" NCLKs to the sub-total. "N" represents part of the - * processor specific constant value in the northbridge - * clock domain. - */ -- SubTotal += 5; -+ SubTotal += (cpu_val_n) / 2; - - pDCTstat->CH_MaxRdLat[Channel] = SubTotal; - if(pDCTstat->GangedMode) { -@@ -659,143 +850,6 @@ static void mct_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQ - Set_NB32(dev, reg, val); - } - --static u8 mct_SavePassRcvEnDly_D(struct DCTStatStruc *pDCTstat, -- u8 rcvrEnDly, u8 Channel, -- u8 receiver, u8 Pass) --{ -- u8 i; -- u8 mask_Saved, mask_Pass; -- u8 *p; -- -- /* calculate dimm offset -- * not needed for CH_D_B_RCVRDLY array -- */ -- -- /* cmp if there has new DqsRcvEnDly to be recorded */ -- mask_Pass = pDCTstat->DqsRcvEn_Pass; -- -- if(Pass == SecondPass) { -- mask_Pass = ~mask_Pass; -- } -- -- mask_Saved = pDCTstat->DqsRcvEn_Saved; -- if(mask_Pass != mask_Saved) { -- -- /* find desired stack offset according to channel/dimm/byte */ -- if(Pass == SecondPass) { -- /* FIXME: SecondPass is never used for Barcelona p = pDCTstat->CH_D_B_RCVRDLY_1[Channel][receiver>>1]; */ -- p = 0; /* Keep the compiler happy. */ -- } else { -- mask_Saved &= mask_Pass; -- p = pDCTstat->CH_D_B_RCVRDLY[Channel][receiver>>1]; -- } -- for(i=0; i < 8; i++) { -- /* cmp per byte lane */ -- if(mask_Pass & (1 << i)) { -- if(!(mask_Saved & (1 << i))) { -- /* save RcvEnDly to stack, according to -- the related Dimm/byte lane */ -- p[i] = (u8)rcvrEnDly; -- mask_Saved |= 1 << i; -- } -- } -- } -- pDCTstat->DqsRcvEn_Saved = mask_Saved; -- } -- return mct_SaveRcvEnDly_D_1Pass(pDCTstat, Pass); --} -- --static u8 mct_CompareTestPatternQW0_D(struct MCTStatStruc *pMCTstat, -- struct DCTStatStruc *pDCTstat, -- u32 addr, u8 channel, -- u8 pattern, u8 Pass) --{ -- /* 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. -- */ -- -- u8 *test_buf; -- u8 i; -- u8 result; -- u8 value; -- -- if(Pass == FirstPass) { -- if(pattern==1) { -- test_buf = (u8 *)TestPattern1_D; -- } else { -- test_buf = (u8 *)TestPattern0_D; -- } -- } else { /* Second Pass */ -- test_buf = (u8 *)TestPattern2_D; -- } -- -- SetUpperFSbase(addr); -- addr <<= 8; -- -- if((pDCTstat->Status & (1<<SB_128bitmode)) && channel ) { -- addr += 8; /* second channel */ -- test_buf += 8; -- } -- -- 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++, addr ++) { -- value = read32_fs(addr); -- print_debug_dqs_pair("\t\t\t\t\t\t\t\t ", test_buf[i], " | ", value, 4); -- -- if (value == test_buf[i]) { -- pDCTstat->DqsRcvEn_Pass |= (1<<i); -- } else { -- pDCTstat->DqsRcvEn_Pass &= ~(1<<i); -- } -- } -- -- result = DQS_FAIL; -- -- if (Pass == FirstPass) { -- /* if first pass, at least one byte lane pass -- * ,then DQS_PASS=1 and will set to related reg. -- */ -- if(pDCTstat->DqsRcvEn_Pass != 0) { -- result = DQS_PASS; -- } else { -- result = DQS_FAIL; -- } -- -- } else { -- /* if second pass, at least one byte lane fail -- * ,then DQS_FAIL=1 and will set to related reg. -- */ -- if(pDCTstat->DqsRcvEn_Pass != 0xFF) { -- result = DQS_FAIL; -- } else { -- result = DQS_PASS; -- } -- } -- -- /* 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))) { -- result = DQS_FAIL; -- pDCTstat->DqsRcvEn_Pass = 0; -- } -- -- /* second pass needs to be inverted -- * FIXME? this could be inverted in the above code to start with... -- */ -- if(Pass == SecondPass) { -- if (result == DQS_PASS) { -- result = DQS_FAIL; -- } else if (result == DQS_FAIL) { /* FIXME: doesn't need to be else if */ -- result = DQS_PASS; -- } -- } -- -- -- return result; --} -- - static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstat) - { -@@ -854,7 +908,7 @@ void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel) - u32 index_reg; - u32 index; - u8 ChipSel; -- u8 *p; -+ u16 *p; - u32 val; - - dev = pDCTstat->dev_dct; -@@ -884,7 +938,7 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, - - for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) { - if(mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, ChipSel)) { -- u8 *p; -+ u16 *p; - p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1]; - - /* DQS Delay Value of Data Bytelane -@@ -920,6 +974,10 @@ static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, - SetEccDQSRcvrEn_D(pDCTstat, Channel); - } - -+/* 2.8.9.9.4 -+ * ECC Byte Lane Training -+ * DQS Receiver Enable Delay -+ */ - void mctSetEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat, - struct DCTStatStruc *pDCTstatA) - { -@@ -1017,7 +1075,9 @@ static void fenceDynTraining_D(struct MCTStatStruc *pMCTstat, - avRecValue -= 3; - else - */ -- if (pDCTstat->LogicalCPUID & AMD_DR_Cx) -+ if (pDCTstat->LogicalCPUID & AMD_DR_Dx) -+ avRecValue -= 8; -+ else if (pDCTstat->LogicalCPUID & AMD_DR_Cx) - avRecValue -= 8; - else if (pDCTstat->LogicalCPUID & AMD_DR_Bx) - avRecValue -= 8; -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c -index c009756..f01e011 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc1p.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -36,17 +37,12 @@ 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, -+static u16 mct_Average_RcvrEnDly_1Pass(struct DCTStatStruc *pDCTstat, u8 Channel, u8 Receiver, - u8 Pass) - { -- u8 i, MaxValue; -- u8 *p; -- u8 val; -+ u16 i, MaxValue; -+ u16 *p; -+ u16 val; - - MaxValue = 0; - p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1]; -@@ -76,8 +72,8 @@ u8 mct_SaveRcvEnDly_D_1Pass(struct DCTStatStruc *pDCTstat, u8 pass) - return ret; - } - --u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, -- u8 RcvrEnDly, u8 RcvrEnDlyLimit, -+u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, -+ u16 RcvrEnDly, u16 RcvrEnDlyLimit, - u8 Channel, u8 Receiver, u8 Pass) - - { -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c -index b01889d..796febc 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc2p.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -74,15 +75,15 @@ u8 mct_Get_Start_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, - return RcvrEnDly; - } - --u8 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, -- u8 RcvrEnDly, u8 RcvrEnDlyLimit, -+u16 mct_Average_RcvrEnDly_Pass(struct DCTStatStruc *pDCTstat, -+ u16 RcvrEnDly, u16 RcvrEnDlyLimit, - u8 Channel, u8 Receiver, u8 Pass) - { - u8 i; -- u8 *p; -- u8 *p_1; -- u8 val; -- u8 val_1; -+ u16 *p; -+ u16 *p_1; -+ u16 val; -+ u16 val_1; - u8 valid = 1; - u8 bn; - -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c -index ea5c8c7..920f514 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mcttmrl.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -191,10 +192,10 @@ static void maxRdLatencyTrain_D(struct MCTStatStruc *pMCTstat, - - #if DQS_TRAIN_DEBUG > 0 - { -- u8 Channel; -+ u8 ChannelDTD; - printk(BIOS_DEBUG, "maxRdLatencyTrain: CH_MaxRdLat:\n"); -- for(Channel = 0; Channel<2; Channel++) { -- printk(BIOS_DEBUG, "Channel: %02x: %02x\n", Channel, pDCTstat->CH_MaxRdLat[Channel]); -+ for(ChannelDTD = 0; ChannelDTD<2; ChannelDTD++) { -+ printk(BIOS_DEBUG, "Channel: %02x: %02x\n", ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD]); - } - } - #endif -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c -index cdeae49..1c3e322 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctwl.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -58,9 +59,9 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat, - pDCTstat->C_DCTPtr[dct]->LogicalCPUID = pDCTstat->LogicalCPUID; - - for (dimm = 0; dimm < MAX_DIMMS; dimm++) { -- if (DimmValid & (1 << dimm)) -+ if (DimmValid & (1 << (dimm << 1))) - pDCTstat->C_DCTPtr[dct]->DimmPresent[dimm] = 1; -- if (Dimmx8Present & (1 << dimm)) -+ if (Dimmx8Present & (1 << (dimm << 1))) - pDCTstat->C_DCTPtr[dct]->DimmX8Present[dimm] = 1; - } - -@@ -88,9 +89,9 @@ void PrepareC_DCT(struct MCTStatStruc *pMCTstat, - u8 DimmRanks; - if (DimmValid & (1 << (dimm << 1))) { - DimmRanks = 1; -- if (pDCTstat->DimmDRPresent & (1 << (dimm+dct))) -+ if (pDCTstat->DimmDRPresent & (1 << ((dimm << 1) + dct))) - DimmRanks = 2; -- else if (pDCTstat->DimmQRPresent & (1 << (dimm+dct))) -+ else if (pDCTstat->DimmQRPresent & (1 << ((dimm << 1) + dct))) - DimmRanks = 4; - } else - DimmRanks = 0; -@@ -249,35 +250,6 @@ static void ChangeMemClk(struct MCTStatStruc *pMCTstat, - } - } - --/* 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. - */ -@@ -352,9 +324,9 @@ void SetTargetFreq(struct MCTStatStruc *pMCTstat, - - if (!DCT1Present) - pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0]; -- else if (pDCTstat->GangedMode) { -+ else if (pDCTstat->GangedMode) - pDCTstat->CSPresent = 0; -- } else -+ else - pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[1]; - - FreqChgCtrlWrd(pMCTstat, pDCTstat); -diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c -index 212a348..67d705c 100644 ---- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c -+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c -@@ -2,6 +2,7 @@ - * This file is part of the coreboot project. - * - * Copyright (C) 2010 Advanced Micro Devices, Inc. -+ * Copyright (C) 2015 Timothy Pearson <tpearson@raptorengineeringinc.com>, Raptor Engineering - * - * 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 -@@ -235,6 +236,65 @@ u32 swapBankBits(sDCTStruct *pDCTData, u32 MRSValue) - return MRSValue; - } - -+static uint16_t unbuffered_dimm_nominal_termination_emrs(uint8_t number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank) -+{ -+ uint16_t term; -+ -+ /* FIXME -+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel -+ * For now assume a maximum of 2 DIMMs per channel can be installed -+ */ -+ uint8_t MaxDimmsInstallable = 2; -+ -+ if (number_of_dimms == 1) { -+ if (MaxDimmsInstallable < 3) { -+ term = 0x04; /* Rtt_Nom=RZQ/4=60 Ohm */ -+ } else { -+ if (rank_count == 1) { -+ term = 0x04; /* Rtt_Nom=RZQ/4=60 Ohm */ -+ } else { -+ if (rank == 0) -+ term = 0x04; /* Rtt_Nom=RZQ/4=60 Ohm */ -+ else -+ term = 0x00; /* Rtt_Nom=OFF */ -+ } -+ } -+ } else { -+ if (frequency_index < 5) -+ term = 0x0044; /* Rtt_Nom=RZQ/6=40 Ohm */ -+ else -+ term = 0x0204; /* Rtt_Nom=RZQ/8=30 Ohm */ -+ } -+ -+ return term; -+} -+ -+static uint16_t unbuffered_dimm_dynamic_termination_emrs(uint8_t number_of_dimms, uint8_t frequency_index, uint8_t rank_count, uint8_t rank) -+{ -+ uint16_t term; -+ -+ /* FIXME -+ * Mainboards need to be able to specify the maximum number of DIMMs installable per channel -+ * For now assume a maximum of 2 DIMMs per channel can be installed -+ */ -+ uint8_t MaxDimmsInstallable = 2; -+ -+ if (number_of_dimms == 1) { -+ if (MaxDimmsInstallable < 3) { -+ term = 0x00; /* Rtt_WR=off */ -+ } else { -+ if (rank_count == 1) -+ term = 0x00; /* Rtt_WR=off */ -+ else -+ term = 0x200; /* Rtt_WR=RZQ/4=60 Ohm */ -+ } -+ } else { -+ term = 0x400; /* Rtt_WR=RZQ/2=120 Ohm */ -+ } -+ -+ return term; -+} -+ - /*----------------------------------------------------------------------------- - * void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *DCTData, u8 Dimm, BOOL WL) - * -@@ -295,48 +355,23 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl) - 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 */ -- } -+ if (wl) { -+ if (rank == 0) { -+ /* Get Rtt_WR for the current DIMM and rank */ -+ uint16_t dynamic_term = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank); -+ -+ /* Convert dynamic termination code to corresponding nominal termination code */ -+ if (dynamic_term == 0x200) -+ tempW1 = 0x04; -+ else if (dynamic_term == 0x400) -+ tempW1 = 0x40; - 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 */ -- } -+ tempW1 = 0x0; -+ } else { -+ tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank); - } -+ } else { -+ tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank); - } - } - tempW=tempW|tempW1; -@@ -353,20 +388,22 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl) - else - { - /* Disable the output drivers of all other ranks for -- * the target DIMM. */ -+ * the target DIMM. -+ */ - tempW = bitTestSet(tempW1, Qoff); - } - } -- /* program MrsAddress[5,1]=output driver impedance control (DIC): -- * based on F2x[1,0]84[DrvImpCtrl] */ -+ /* 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);} -+ if (bitTest(tempW1, 1)) -+ tempW = bitTestSet(tempW, 5); -+ if (bitTest(tempW1, 0)) -+ tempW = bitTestSet(tempW, 1); - -- tempW = swapAddrBits_wl(pDCTData,tempW); -+ tempW = swapAddrBits_wl(pDCTData, tempW); - - set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT, - DRAM_INIT, MrsAddressStart, MrsAddressEnd, tempW); -@@ -404,29 +441,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl) - 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]) { -+ 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 */ -- } -- } -- } -- } -+ else -+ tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank); - tempW=tempW|tempW1; - tempW = swapAddrBits_wl(pDCTData,tempW); - set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT, -@@ -483,38 +501,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl) - } - - /* determine Rtt_Nom for WL & Normal mode */ -- if (pDCTData->Status[DCT_STATUS_REGISTERED]) { -+ 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 */ -- } -- } -- } -- } -+ else -+ tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm], rank); - tempW=tempW|tempW1; - /* program MrsAddress[5,1]=output driver impedance control (DIC): - * based on F2x[1,0]84[DrvImpCtrl] */ -@@ -560,22 +550,10 @@ void prepareDimms(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm, BOOL wl) - 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]) { -+ 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 */ -- } -- } -- } -+ else -+ tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm], rank); - tempW=tempW|tempW1; - tempW = swapAddrBits_wl(pDCTData,tempW); - set_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, FUN_DCT, -@@ -646,9 +624,14 @@ void programODT(sMCTStruct *pMCTData, sDCTStruct *pDCTData, u8 dimm) - */ - void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass) - { -- u8 ByteLane, Seed_Gross, Seed_Fine; -+ u8 ByteLane, Seed_Gross, Seed_Fine, MemClkFreq; - u32 Value, Addr; - u16 Addl_Data_Offset, Addl_Data_Port; -+ u16 freq_tab[] = {400, 533, 667, 800}; -+ -+ /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */ -+ MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, -+ FUN_DCT, DRAM_CONFIG_HIGH, 0, 2); - - /* Program F2x[1, 0]9C_x08[WrLvOdt[3:0]] to the proper ODT settings for the - * current memory subsystem configuration. -@@ -656,12 +639,13 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass) - programODT(pMCTData, pDCTData, dimm); - - /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */ -- if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) -+ if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) { - 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*/ -+ /* Program WrLvOdtEn=1 through set bit 12 of D3CSODT reg offset 0 for Rev.B */ - if (pDCTData->DctTrain) - { - Addl_Data_Offset=0x198; -@@ -687,7 +671,6 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass) - - /* Wait 10 MEMCLKs to allow for ODT signal settling. */ - pMCTData->AgesaDelay(10); -- ByteLane = 0; - if (pass == 1) - { - if (pDCTData->Status[DCT_STATUS_REGISTERED]) -@@ -705,10 +688,17 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass) - } - else - { -- Seed_Gross = 0x00; -- Seed_Fine = 0x1A; -+ if (MemClkFreq == 6) { -+ /* DDR-800 */ -+ Seed_Gross = 0x00; -+ Seed_Fine = 0x1a; -+ } else { -+ /* Use settings for DDR-400 (interpolated from BKDG) */ -+ Seed_Gross = 0x00; -+ Seed_Fine = 0x0d; -+ } - } -- while(ByteLane < MAX_BYTE_LANES) -+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) - { - /* 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 -@@ -720,35 +710,32 @@ void procConifg(sMCTStruct *pMCTData,sDCTStruct *pDCTData, u8 dimm, u8 pass) - */ - pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; - pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; -- ByteLane++; - } -- } else if (pDCTData->Status[DCT_STATUS_REGISTERED]) { /* For Pass 2 */ -+ } else { /* Pass 2 */ - /* From BKDG, Write Leveling Seed Value. */ -- /* TODO: The unbuffered DIMMs are unstable on the code below. So temporarily it is -- * only for registered DIMMs. */ - u32 RegisterDelay, SeedTotal; -- u8 MemClkFreq; -- u16 freq_tab[] = {400, 533, 667, 800}; -- while(ByteLane < MAX_BYTE_LANES) -+ for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) - { -- MemClkFreq = get_Bits(pDCTData, pDCTData->CurrDct, pDCTData->NodeId, -- FUN_DCT, DRAM_CONFIG_HIGH, 0, 2); - if (pDCTData->Status[DCT_STATUS_REGISTERED]) - RegisterDelay = 0x20; /* TODO: ((RCW2 & BIT0) == 0) ? 0x20 : 0x30; */ - else - RegisterDelay = 0; -- SeedTotal = (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1F) | -- pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5; -+ SeedTotal = (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) | -+ (pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] << 5); - /* SeedTotalPreScaling = (the total delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization - training) - RegisterDelay. */ -- /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */ -- SeedTotal = (u16) (RegisterDelay + ((((u32) SeedTotal - RegisterDelay) * -- freq_tab[MemClkFreq-3]) / 400)); -- Seed_Gross = (SeedTotal & 0x20) != 0 ? 1 : 2; -- Seed_Fine = SeedTotal & 0x1F; -+ SeedTotal = (uint16_t) (RegisterDelay + ((((uint64_t) SeedTotal - RegisterDelay) * -+ freq_tab[MemClkFreq-3] * 100) / (freq_tab[0] * 100))); -+ Seed_Gross = SeedTotal / 32; -+ Seed_Fine = SeedTotal & 0x1f; -+ if (Seed_Gross == 0) -+ Seed_Gross = 0; -+ else if (Seed_Gross & 0x1) -+ Seed_Gross = 1; -+ else -+ Seed_Gross = 2; - pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; - pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine; -- ByteLane ++; - } - } - -diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c b/src/northbridge/amd/amdmct/wrappers/mcti_d.c -index ea32893..c00cf24 100644 ---- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c -+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c -@@ -59,6 +59,10 @@ static u16 mctGet_NVbits(u8 index) - val = 1; - #elif CONFIG_CPU_SOCKET_TYPE == 0x13 /* ASB2 */ - val = 4; -+#elif CONFIG_CPU_SOCKET_TYPE == 0x14 /* C32 */ -+ val = 5; -+#elif CONFIG_CPU_SOCKET_TYPE == 0x15 /* G34 */ -+ val = 3; - //#elif SYSTEM_TYPE == MOBILE - // val = 2; - #endif -@@ -297,6 +301,8 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc *pDCTstat) - /* Determine the number of installed DIMMs */ - int ch1_count = 0; - int ch2_count = 0; -+ uint8_t ch1_registered = 0; -+ uint8_t ch2_registered = 0; - int i; - for (i = 0; i < 15; i = i + 2) { - if (pDCTstat->DIMMValid & (1 << i)) -@@ -304,6 +310,12 @@ static void mctGet_MaxLoadFreq(struct DCTStatStruc *pDCTstat) - if (pDCTstat->DIMMValid & (1 << (i + 1))) - ch2_count++; - } -+ for (i = 0; i < MAX_DIMMS_SUPPORTED; i = i + 2) { -+ if (pDCTstat->DimmRegistered[i]) -+ ch1_registered = 1; -+ if (pDCTstat->DimmRegistered[i + 1]) -+ ch2_registered = 1; -+ } - if (IS_ENABLED(CONFIG_DEBUG_RAM_SETUP)) { - printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 1: %d DIMM(s) detected\n", ch1_count); - printk(BIOS_DEBUG, "mctGet_MaxLoadFreq: Channel 2: %d DIMM(s) detected\n", ch2_count); -@@ -413,101 +425,6 @@ static void mctHookAfterDramInit(void) - } - - #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */ --static void coreDelay(u32 microseconds) --{ -- msr_t now; -- msr_t end; -- u32 cycles; -- -- /* delay ~40us -- This seems like a hack to me... -- It would be nice to have a central delay function. */ -- -- cycles = (microseconds * 100) << 3; /* x8 (number of 1.25ns ticks) */ -- -- if (!(rdmsr(HWCR).lo & TSC_FREQ_SEL_MASK)) { -- msr_t pstate_msr = rdmsr(CUR_PSTATE_MSR); -- if (!(rdmsr(0xC0010064+pstate_msr.lo).lo & NB_DID_M_ON)) { -- cycles = cycles <<1; // half freq, double cycles -- } -- } // else should we keep p0 freq at the time of setting TSC_FREQ_SEL_MASK somewhere and check it here ? -- -- now = rdmsr(TSC_MSR); -- // avoid overflow when called near 2^32 ticks ~ 5.3 s boundaries -- if (0xffffffff - cycles >= now.lo ) { -- end.hi = now.hi; -- end.lo = now.lo + cycles; -- } else { -- end.hi = now.hi +1; // -- end.lo = cycles - (1+(0xffffffff - now.lo)); -- } -- do { -- now = rdmsr(TSC_MSR); -- } while ((now.hi < end.hi) || ((now.hi == end.hi) && (now.lo < end.lo))); --} -- --/* Erratum 350 */ --static void vErrata350(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) --{ -- u8 u8Channel; -- u8 u8Receiver; -- u32 u32Addr; -- u8 u8Valid; -- u32 u32DctDev; -- -- // 1. dummy read for each installed DIMM */ -- for (u8Channel = 0; u8Channel < 2; u8Channel++) { -- // This will be 0 for vaild DIMMS, eles 8 -- u8Receiver = mct_InitReceiver_D(pDCTstat, u8Channel); -- -- for (; u8Receiver < 8; u8Receiver += 2) { -- u32Addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, u8Channel, u8Receiver, &u8Valid); -- -- if(!u8Valid) { /* Address not supported on current CS */ -- print_t("vErrata350: Address not supported on current CS\n"); -- continue; -- } -- print_t("vErrata350: dummy read \n"); -- read32_fs(u32Addr); -- } -- } -- -- print_t("vErrata350: step 2a\n"); -- -- /* 2. Write 0000_8000h to register F2x[1, 0]9C_xD080F0C. */ -- u32DctDev = pDCTstat->dev_dct; -- Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00008000); -- /* ^--- value -- ^---F2x[1, 0]9C_x0D080F0C, No description in BKDG. -- ^----F2x[1, 0]98 DRAM Controller Additional Data Offset Register */ -- -- if(!pDCTstat->GangedMode) { -- print_t("vErrata350: step 2b\n"); -- Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00008000); -- /* ^--- value -- ^---F2x[1, 0]9C_x0D080F0C, No description in BKDG -- ^----F2x[1, 0]98 DRAM Controller Additional Data Offset Register */ -- } -- -- print_t("vErrata350: step 3\n"); -- /* 3. Wait at least 300 nanoseconds. */ -- coreDelay(1); -- -- print_t("vErrata350: step 4\n"); -- /* 4. Write 0000_0000h to register F2x[1, 0]9C_xD080F0C. */ -- Set_NB32_index_wait(u32DctDev, 0x098, 0xD080F0C, 0x00000000); -- -- if(!pDCTstat->GangedMode) { -- print_t("vErrata350: step 4b\n"); -- Set_NB32_index_wait(u32DctDev, 0x198, 0xD080F0C, 0x00000000); -- } -- -- print_t("vErrata350: step 5\n"); -- /* 5. Wait at least 2 microseconds. */ -- coreDelay(2); -- --} -- - static void vErratum372(struct DCTStatStruc *pDCTstat) - { - msr_t msr = rdmsr(NB_CFG_MSR); -@@ -546,8 +463,7 @@ static void mctHookBeforeAnyTraining(struct MCTStatStruc *pMCTstat, struct DCTSt - { - #if (CONFIG_DIMM_SUPPORT & 0x000F)==0x0005 /* AMD_FAM10_DDR3 */ - /* FIXME : as of 25.6.2010 errata 350 and 372 should apply to ((RB|BL|DA)-C[23])|(HY-D[01])|(PH-E0) but I don't find constants for all of them */ -- if (pDCTstatA->LogicalCPUID & AMD_DRBH_Cx) { -- vErrata350(pMCTstat, pDCTstatA); -+ if (pDCTstatA->LogicalCPUID & (AMD_DRBH_Cx | AMD_DR_Dx)) { - vErratum372(pDCTstatA); - vErratum414(pDCTstatA); - } --- -1.7.9.5 - |