aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c1519
1 files changed, 0 insertions, 1519 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
deleted file mode 100644
index 353aa7a1cf..0000000000
--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+++ /dev/null
@@ -1,1519 +0,0 @@
-/*
- * This file is part of the coreboot project.
- *
- * Copyright (C) 2010 Advanced Micro Devices, Inc.
- * Copyright (C) 2015 - 2016 Raptor Engineering, LLC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <stdint.h>
-#include <assert.h>
-#include <console/console.h>
-#include <northbridge/amd/amdfam10/amdfam10.h>
-
-#include "mct_d.h"
-#include "mct_d_gcc.h"
-#include "mwlc_d.h"
-
-u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t MRSValue);
-u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t MRSValue);
-void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
- u8 dct, u8 dimm, BOOL wl);
-void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm);
-void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble);
-void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass, uint8_t lane_count);
-void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass, uint8_t nibble, uint8_t lane_count);
-
-#define MAX_LANE_COUNT 9
-
-/*-----------------------------------------------------------------------------
- * uint8_t AgesaHwWlPhase1(SPDStruct *SPDData,MCTStruct *MCTData, DCTStruct *DCTData,
- * u8 Dimm, u8 Pass)
- *
- * Description:
- * This function initialized Hardware based write levelization phase 1
- *
- * Parameters:
- * IN OUT *SPDData - Pointer to buffer with information about each DIMMs
- * SPD information
- * *MCTData - Pointer to buffer with runtime parameters,
- * *DCTData - Pointer to buffer with information about each DCT
- *
- * IN DIMM - Logical DIMM number
- * Pass - First or Second Pass
- * OUT
- *-----------------------------------------------------------------------------
- */
-uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
- u8 dct, u8 dimm, u8 pass)
-{
- u8 ByteLane;
- u32 Value, Addr;
- uint8_t nibble = 0;
- uint8_t train_both_nibbles;
- u16 Addl_Data_Offset, Addl_Data_Port;
- sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- uint8_t lane_count;
-
- lane_count = get_available_lane_count(pMCTstat, pDCTstat);
-
- pDCTData->WLPass = pass;
- /* 1. Specify the target DIMM that is to be trained by programming
- * F2x[1, 0]9C_x08[TrDimmSel].
- */
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, TrDimmSelStart,
- TrDimmSelEnd, (u32)dimm);
-
- train_both_nibbles = 0;
- if (pDCTstat->Dimmx4Present)
- if (is_fam15h())
- train_both_nibbles = 1;
-
- for (nibble = 0; nibble < (train_both_nibbles + 1); nibble++) {
- printk(BIOS_SPEW, "AgesaHwWlPhase1: training nibble %d\n", nibble);
-
- if (is_fam15h()) {
- /* Program F2x[1, 0]9C_x08[WrtLvTrEn]=0 */
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
-
- /* Set TrNibbleSel */
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, 2,
- 2, (uint32_t)nibble);
- }
-
- /* 2. Prepare the DIMMs for write levelization using DDR3-defined
- * MR commands. */
- prepareDimms(pMCTstat, pDCTstat, dct, dimm, TRUE);
-
- /* 3. After the DIMMs are configured, BIOS waits 40 MEMCLKs to
- * satisfy DDR3-defined internal DRAM timing.
- */
- if (is_fam15h())
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 40);
- else
- pMCTData->AgesaDelay(40);
-
- /* 4. Configure the processor's DDR phy for write levelization training: */
- procConfig(pMCTstat, pDCTstat, dct, dimm, pass, nibble);
-
- /* 5. Begin write levelization training:
- * Program F2x[1, 0]9C_x08[WrtLvTrEn]=1. */
- if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL))
- {
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 1);
- }
- else
- {
- /* Broadcast write to all D3Dbyte chipset register offset 0xc
- * Set bit 0 (wrTrain)
- * Program bit 4 to nibble being trained (only matters for x4dimms)
- * retain value of 3:2 (Trdimmsel)
- * reset bit 5 (FrzPR)
- */
- if (dct)
- {
- Addl_Data_Offset = 0x198;
- Addl_Data_Port = 0x19C;
- }
- else
- {
- Addl_Data_Offset = 0x98;
- Addl_Data_Port = 0x9C;
- }
- Addr = 0x0D00000C;
- AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
- while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
- DctAccessDone, DctAccessDone)) == 0);
- AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
- Value = bitTestSet(Value, 0); /* enable WL training */
- Value = bitTestReset(Value, 4); /* for x8 only */
- Value = bitTestReset(Value, 5); /* for hardware WL training */
- AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
- Addr = 0x4D030F0C;
- AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
- while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
- DctAccessDone, DctAccessDone)) == 0);
- }
-
- if (is_fam15h())
- proc_MFENCE();
-
- /* Wait 200 MEMCLKs. If executing pass 2, wait 32 MEMCLKs. */
- if (is_fam15h())
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 200);
- else
- pMCTData->AgesaDelay(140);
-
- /* Program F2x[1, 0]9C_x08[WrtLevelTrEn]=0. */
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, WrtLvTrEn, WrtLvTrEn, 0);
-
- /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52
- * to get the gross and fine delay settings
- * for the target DIMM and save these values. */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, nibble, lane_count);
- }
-
- pDCTData->WLCriticalGrossDelayPrevPass = 0x0;
-
- /* Exit nibble training if current DIMM is not x4 */
- if ((pDCTstat->Dimmx4Present & (1 << (dimm + dct))) == 0)
- break;
- }
-
- return 0;
-}
-
-uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
- uint8_t dct, uint8_t dimm, uint8_t pass)
-{
- u8 ByteLane;
- uint8_t status = 0;
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- uint8_t lane_count;
-
- lane_count = get_available_lane_count(pMCTstat, pDCTstat);
-
- assert(lane_count <= MAX_LANE_COUNT);
-
- if (is_fam15h()) {
- int32_t gross_diff[MAX_LANE_COUNT];
- int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
- uint8_t index = (uint8_t)(lane_count * dimm);
-
- printk(BIOS_SPEW, "\toriginal critical gross delay: %d\n", cgd);
-
- /* FIXME
- * For now, disable CGD adjustment as it seems to interfere with registered DIMM training
- */
-
- /* Calculate the Critical Gross Delay */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- /* Calculate the gross delay differential for this lane */
- gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane];
- gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane];
-
- /* WrDqDqsEarly values greater than 2 are reserved */
- if (gross_diff[ByteLane] < -2)
- gross_diff[ByteLane] = -2;
-
- /* Update the Critical Gross Delay */
- if (gross_diff[ByteLane] < cgd)
- cgd = gross_diff[ByteLane];
- }
-
- printk(BIOS_SPEW, "\tnew critical gross delay: %d\n", cgd);
-
- pDCTData->WLCriticalGrossDelayPrevPass = cgd;
-
- if (pDCTstat->Speed != pDCTstat->TargetFreq) {
- /* FIXME
- * Using the Pass 1 training values causes major phy training problems on
- * all Family 15h processors I tested (Pass 1 values are randomly too high,
- * and Pass 2 cannot lock).
- * Figure out why this is and fix it, then remove the bypass code below...
- */
- if (pass == FirstPass) {
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane];
- pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane];
- }
- return 0;
- }
- }
-
- /* Compensate for occasional noise/instability causing sporadic training failure */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- uint8_t faulty_value_detected = 0;
- uint16_t total_delay_seed = ((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f);
- uint16_t total_delay_phy = ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
- if (pass == FirstPass) {
- /* Allow a somewhat higher step threshold on the first pass
- * For the most part, as long as the phy isn't stepping
- * several clocks at once the values are probably valid.
- */
- if (abs(total_delay_phy - total_delay_seed) > 0x30)
- faulty_value_detected = 1;
- } else {
- /* Stepping memory clocks between adjacent allowed frequencies
- * should not yield large phy value differences...
- */
-
- if (abs(total_delay_phy - total_delay_seed) > 0x20)
- faulty_value_detected = 1;
- }
- if (faulty_value_detected) {
- printk(BIOS_INFO, "%s: overriding faulty phy value (seed: %04x phy: %04x step: %04x)\n", __func__,
- total_delay_seed, total_delay_phy, abs(total_delay_phy - total_delay_seed));
- pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane];
- pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane];
- status = 1;
- }
- }
- }
-
- return status;
-}
-
-uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
- u8 dct, u8 dimm, u8 pass)
-{
- u8 ByteLane;
- sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- uint8_t lane_count;
-
- lane_count = get_available_lane_count(pMCTstat, pDCTstat);
-
- assert(lane_count <= MAX_LANE_COUNT);
-
- if (is_fam15h()) {
- uint32_t dword;
- int32_t gross_diff[MAX_LANE_COUNT];
- int32_t cgd = pDCTData->WLCriticalGrossDelayPrevPass;
- uint8_t index = (uint8_t)(lane_count * dimm);
-
- /* Apply offset(s) if needed */
- if (cgd < 0) {
- dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
- dword &= ~(0x3 << 24); /* WrDqDqsEarly = abs(cgd) */
- dword |= ((abs(cgd) & 0x3) << 24);
- Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
-
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- /* Calculate the gross delay differential for this lane */
- gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane];
- gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane];
-
- /* Prevent underflow in the presence of noise / instability */
- if (gross_diff[ByteLane] < cgd)
- gross_diff[ByteLane] = cgd;
-
- pDCTData->WLGrossDelay[index+ByteLane] = (gross_diff[ByteLane] + (abs(cgd) & 0x3));
- }
- } else {
- dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
- dword &= ~(0x3 << 24); /* WrDqDqsEarly = pDCTData->WrDqsGrossDlyBaseOffset */
- dword |= ((pDCTData->WrDqsGrossDlyBaseOffset & 0x3) << 24);
- Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
- }
- }
-
- /* Write the adjusted gross and fine delay settings
- * to the target DIMM. */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass, lane_count);
- }
-
- /* 6. Configure DRAM Phy Control Register so that the phy stops driving
- * write levelization ODT. */
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, 0);
-
- if (is_fam15h())
- proc_MFENCE();
-
- /* Wait 10 MEMCLKs to allow for ODT signal settling. */
- if (is_fam15h())
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
- else
- pMCTData->AgesaDelay(10);
-
- /* 7. Program the target DIMM back to normal operation by configuring
- * the following (See section 2.8.5.4.1.1
- * [Phy Assisted Write Levelization] on page 97 pass 1, step #2):
- * Configure all ranks of the target DIMM for normal operation.
- * Enable the output drivers of all ranks of the target DIMM.
- * For a two DIMM system, program the Rtt value for the target DIMM
- * to the normal operating termination:
- */
- prepareDimms(pMCTstat, pDCTstat, dct, dimm, FALSE);
-
- return 0;
-}
-
-/*----------------------------------------------------------------------------
- * LOCAL FUNCTIONS
- *
- *----------------------------------------------------------------------------
- */
-
-/*-----------------------------------------------------------------------------
- * u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
- *
- * Description:
- * This function swaps the bits in MSR register value
- *
- * Parameters:
- * IN OUT *DCTData - Pointer to buffer with information about each DCT
- * IN u32: MRS value
- * OUT u32: Swapped BANK BITS
- *
- * ----------------------------------------------------------------------------
- */
-u32 swapAddrBits_wl(struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t MRSValue)
-{
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- u32 tempW, tempW1;
-
- if (is_fam15h())
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15);
- else
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10);
- if (tempW1 & 1)
- {
- if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
- {
- /* swap A3/A4,A5/A6,A7/A8 */
- tempW = MRSValue;
- tempW1 = MRSValue;
- tempW &= 0x0A8;
- tempW1 &= 0x0150;
- MRSValue &= 0xFE07;
- MRSValue |= (tempW << 1);
- MRSValue |= (tempW1 >> 1);
- }
- }
- return MRSValue;
-}
-
-/*-----------------------------------------------------------------------------
- * u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
- *
- * Description:
- * This function swaps the bits in MSR register value
- *
- * Parameters:
- * IN OUT *DCTData - Pointer to buffer with information about each DCT
- * IN u32: MRS value
- * OUT u32: Swapped BANK BITS
- *
- * ----------------------------------------------------------------------------
- */
-u32 swapBankBits(struct DCTStatStruc *pDCTstat, uint8_t dct, u32 MRSValue)
-{
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- u32 tempW, tempW1;
-
- if (is_fam15h())
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15);
- else
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10);
- if (tempW1 & 1)
- {
- if ((pDCTData->Status[DCT_STATUS_OnDimmMirror]))
- {
- /* swap BA0/BA1 */
- tempW = MRSValue;
- tempW1 = MRSValue;
- tempW &= 0x01;
- tempW1 &= 0x02;
- MRSValue = 0;
- MRSValue |= (tempW << 1);
- MRSValue |= (tempW1 >> 1);
- }
- }
- return MRSValue;
-}
-
-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;
-
- uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-
- 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)
-{
- uint16_t term;
-
- uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-
- 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)
- *
- * Description:
- * This function prepares DIMMS for training
- * Fam10h: BKDG Rev. 3.62 section 2.8.9.9.1
- * Fam15h: BKDG Rev. 3.14 section 2.10.5.8.1
- * ----------------------------------------------------------------------------
- */
-void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
- u8 dct, u8 dimm, BOOL wl)
-{
- u32 tempW, tempW1, tempW2, MrsBank;
- u8 rank, currDimm, MemClkFreq;
- sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
- uint8_t number_of_dimms = pDCTData->MaxDimmsInstalled;
-
- if (is_fam15h()) {
- MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
- } else {
- MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, 0, 2);
- }
- /* Configure the DCT to send initialization MR commands to the target DIMM
- * by programming the F2x[1,0]7C register using the following steps.
- */
- rank = 0;
- while ((rank < pDCTData->DimmRanks[dimm]) && (rank < 2))
- {
- /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank to be trained. */
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15, dimm*2+rank);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10, dimm*2+rank);
-
- /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
- * register that defines the required DDR3-defined function for write
- * levelization.
- */
- MrsBank = swapBankBits(pDCTstat, dct, 1);
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
-
- /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
- * for write levelization.
- */
- tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0 */
-
- /* Retrieve normal settings of the MRS control word and clear Rtt_Nom */
- if (is_fam15h()) {
- tempW = mct_MR1(pMCTstat, pDCTstat, dct, dimm*2+rank) & 0xffff;
- tempW &= ~(0x0244);
- } else {
- /* Set TDQS = 1b for x8 DIMM, TDQS = 0b for x4 DIMM, when mixed x8 & x4 */
- tempW2 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
- if (tempW2)
- {
- if (pDCTData->DimmX8Present[dimm])
- tempW |= 0x800;
- }
- }
-
- /* determine Rtt_Nom for WL & Normal mode */
- if (is_fam15h()) {
- if (wl) {
- if (number_of_dimms > 1) {
- if (rank == 0) {
- /* Get Rtt_WR for the current DIMM and rank */
- tempW2 = fam15_rttwr(pDCTstat, dct, dimm, rank, package_type);
- } else {
- tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
- }
- } else {
- tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
- }
- } else {
- tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
- }
- tempW1 = 0;
- tempW1 |= ((tempW2 & 0x4) >> 2) << 9;
- tempW1 |= ((tempW2 & 0x2) >> 1) << 6;
- tempW1 |= ((tempW2 & 0x1) >> 0) << 2;
- } else {
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- tempW1 = RttNomTargetRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
- } else {
- if (wl) {
- if (number_of_dimms > 1) {
- 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]);
-
- /* Convert dynamic termination code to corresponding nominal termination code */
- if (dynamic_term == 0x200)
- tempW1 = 0x04;
- else if (dynamic_term == 0x400)
- tempW1 = 0x40;
- else
- 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);
- }
- } else {
- tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm], rank);
- }
- }
- }
-
- /* Apply Rtt_Nom to the MRS control word */
- tempW = tempW|tempW1;
-
- /* All ranks of the target DIMM are set to write levelization mode. */
- if (wl)
- {
- tempW1 = bitTestSet(tempW, MRS_Level);
- if (rank == 0)
- {
- /* Enable the output driver of the first rank of the target DIMM. */
- tempW = tempW1;
- }
- else
- {
- /* Disable the output drivers of all other ranks for
- * the target DIMM.
- */
- tempW = bitTestSet(tempW1, Qoff);
- }
- }
-
- /* Program MrsAddress[5,1]=output driver impedance control (DIC) */
- if (is_fam15h()) {
- tempW1 = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
- } else {
- /* Read DIC from F2x[1,0]84[DrvImpCtrl] */
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
- }
-
- /* Apply DIC to the MRS control word */
- if (bitTest(tempW1, 1))
- tempW = bitTestSet(tempW, 5);
- if (bitTest(tempW1, 0))
- tempW = bitTestSet(tempW, 1);
-
- tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
-
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
-
- /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
- * the specified DIMM.
- */
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
- /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
- {
- }
-
- /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
- * register that defines the required DDR3-defined function for Rtt_WR.
- */
- MrsBank = swapBankBits(pDCTstat, dct, 2);
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
-
- /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
- * for Rtt_WR (DRAMTermDyn).
- */
- tempW = 0;/* PASR = 0,*/
-
- /* Retrieve normal settings of the MRS control word and clear Rtt_WR */
- if (is_fam15h()) {
- tempW = mct_MR2(pMCTstat, pDCTstat, dct, dimm*2+rank) & 0xffff;
- tempW &= ~(0x0600);
- } else {
- /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
- * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
- if (bitTest(tempW1,19))
- {tempW = bitTestSet(tempW, 7);}
- if (bitTest(tempW1,18))
- {tempW = bitTestSet(tempW, 6);}
- /* tempW = tempW|(((tempW1 >> 20) & 0x7)<< 3); */
- tempW = tempW|((tempW1&0x00700000) >> 17);
- /* workaround for DR-B0 */
- if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
- tempW+=0x8;
- }
-
- /* determine Rtt_WR for WL & Normal mode */
- if (is_fam15h()) {
- tempW1 = (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9);
- } else {
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- tempW1 = RttWrRegDimm(pMCTData, pDCTData, dimm, wl, MemClkFreq, rank);
- else
- tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[dimm]);
- }
-
- /* Apply Rtt_WR to the MRS control word */
- tempW = tempW|tempW1;
- tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
-
- /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
- the specified DIMM.*/
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
-
- /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
- {
- }
-
- rank++;
- }
-
- /* Configure the non-target DIMM normally. */
- currDimm = 0;
- while (currDimm < MAX_LDIMMS)
- {
- if (pDCTData->DimmPresent[currDimm])
- {
- if (currDimm != dimm)
- {
- rank = 0;
- while ((rank < pDCTData->DimmRanks[currDimm]) && (rank < 2))
- {
- /* Program F2x[1, 0]7C[MrsChipSel[2:0]] for the current rank
- * to be trained.
- */
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStartFam15, MrsChipSelEndFam15, currDimm*2+rank);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsChipSelStartFam10, MrsChipSelEndFam10, currDimm*2+rank);
-
- /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal
- * DRAM register that defines the required DDR3-defined function
- * for write levelization.
- */
- MrsBank = swapBankBits(pDCTstat, dct, 1);
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
-
- /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required
- * DDR3-defined function for write levelization.
- */
- tempW = 0;/* DLL_DIS = 0, DIC = 0, AL = 0, TDQS = 0, Level = 0, Qoff = 0 */
-
- /* Retrieve normal settings of the MRS control word and clear Rtt_Nom */
- if (is_fam15h()) {
- tempW = mct_MR1(pMCTstat, pDCTstat, dct, currDimm*2+rank) & 0xffff;
- tempW &= ~(0x0244);
- } else {
- /* Set TDQS = 1b for x8 DIMM, TDQS = 0b for x4 DIMM, when mixed x8 & x4 */
- tempW2 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, RDqsEn, RDqsEn);
- if (tempW2)
- {
- if (pDCTData->DimmX8Present[currDimm])
- tempW |= 0x800;
- }
- }
-
- /* determine Rtt_Nom for WL & Normal mode */
- if (is_fam15h()) {
- tempW2 = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type);
- tempW1 = 0;
- tempW1 |= ((tempW2 & 0x4) >> 2) << 9;
- tempW1 |= ((tempW2 & 0x2) >> 1) << 6;
- tempW1 |= ((tempW2 & 0x1) >> 0) << 2;
- } else {
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- tempW1 = RttNomNonTargetRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
- else
- tempW1 = unbuffered_dimm_nominal_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm], rank);
- }
-
- /* Apply Rtt_Nom to the MRS control word */
- tempW = tempW|tempW1;
-
- /* Program MrsAddress[5,1]=output driver impedance control (DIC) */
- if (is_fam15h()) {
- tempW1 = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type);
- } else {
- /* Read DIC from F2x[1,0]84[DrvImpCtrl] */
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, DrvImpCtrlStart, DrvImpCtrlEnd);
- }
-
- /* Apply DIC to the MRS control word */
- if (bitTest(tempW1,1))
- {tempW = bitTestSet(tempW, 5);}
- if (bitTest(tempW1,0))
- {tempW = bitTestSet(tempW, 1);}
-
- tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
-
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
-
- /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command
- * to the specified DIMM.
- */
- set_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
-
- /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, dct,
- pDCTData->NodeId, FUN_DCT, DRAM_INIT,
- SendMrsCmd, SendMrsCmd)) == 1);
-
- /* Program F2x[1, 0]7C[MrsBank[2:0]] for the appropriate internal DRAM
- * register that defines the required DDR3-defined function for Rtt_WR.
- */
- MrsBank = swapBankBits(pDCTstat, dct, 2);
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStartFam15, MrsBankEndFam15, MrsBank);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsBankStartFam10, MrsBankEndFam10, MrsBank);
-
- /* Program F2x[1, 0]7C[MrsAddress[15:0]] to the required DDR3-defined function
- * for Rtt_WR (DRAMTermDyn).
- */
- tempW = 0;/* PASR = 0,*/
-
- /* Retrieve normal settings of the MRS control word and clear Rtt_WR */
- if (is_fam15h()) {
- tempW = mct_MR2(pMCTstat, pDCTstat, dct, currDimm*2+rank) & 0xffff;
- tempW &= ~(0x0600);
- } else {
- /* program MrsAddress[7,6,5:3]=SRT,ASR,CWL,
- * based on F2x[1,0]84[19,18,22:20]=,SRT,ASR,Tcwl */
- tempW1 = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_MRS_REGISTER, PCI_MIN_LOW, PCI_MAX_HIGH);
- if (bitTest(tempW1,19))
- {tempW = bitTestSet(tempW, 7);}
- if (bitTest(tempW1,18))
- {tempW = bitTestSet(tempW, 6);}
- /* tempW = tempW|(((tempW1 >> 20) & 0x7) << 3); */
- tempW = tempW|((tempW1&0x00700000) >> 17);
- /* workaround for DR-B0 */
- if ((pDCTData->LogicalCPUID & AMD_DR_Bx) && (pDCTData->Status[DCT_STATUS_REGISTERED]))
- tempW+=0x8;
- }
-
- /* determine Rtt_WR for WL & Normal mode */
- if (is_fam15h()) {
- tempW1 = (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9);
- } else {
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- tempW1 = RttWrRegDimm(pMCTData, pDCTData, currDimm, wl, MemClkFreq, rank);
- else
- tempW1 = unbuffered_dimm_dynamic_termination_emrs(pDCTData->MaxDimmsInstalled, MemClkFreq, pDCTData->DimmRanks[currDimm]);
- }
-
- /* Apply Rtt_WR to the MRS control word */
- tempW = tempW|tempW1;
- tempW = swapAddrBits_wl(pDCTstat, dct, tempW);
- if (is_fam15h())
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStartFam15, MrsAddressEndFam15, tempW);
- else
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, MrsAddressStartFam10, MrsAddressEndFam10, tempW);
-
- /* Program F2x[1, 0]7C[SendMrsCmd]=1 to initiate the command to
- the specified DIMM.*/
- set_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_INIT, SendMrsCmd, SendMrsCmd, 1);
-
- /* Wait for F2x[1, 0]7C[SendMrsCmd] to be cleared by hardware. */
- while ((get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_INIT, SendMrsCmd, SendMrsCmd)) == 0x1)
- {
- }
- rank++;
- }
- }
- }
- currDimm++;
- }
-}
-
-/*-----------------------------------------------------------------------------
- * void programODT(sMCTStruct *pMCTData, DCTStruct *DCTData, u8 dimm)
- *
- * Description:
- * This function programs the ODT values for the NB
- *
- * Parameters:
- * IN OUT *DCTData - Pointer to buffer with information about each DCT
- * IN
- * OUT
- * ----------------------------------------------------------------------------
- */
-void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm)
-{
- sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
-
- u8 WrLvOdt1 = 0;
-
- if (is_fam15h()) {
- /* On Family15h processors, the value for the specific CS being targeted
- * is taken from F2x238 / F2x23C as appropriate, then loaded into F2x9C_x0000_0008
- */
-
- /* Convert DIMM number to CS */
- uint32_t dword;
- uint8_t cs;
- uint8_t rank = 0;
-
- cs = (dimm * 2) + rank;
-
- /* Fetch preprogammed ODT pattern from configuration registers */
- dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, ((cs > 3)?0x23c:0x238));
- if ((cs == 7) || (cs == 3))
- WrLvOdt1 = ((dword >> 24) & 0xf);
- else if ((cs == 6) || (cs == 2))
- WrLvOdt1 = ((dword >> 16) & 0xf);
- else if ((cs == 5) || (cs == 1))
- WrLvOdt1 = ((dword >> 8) & 0xf);
- else if ((cs == 4) || (cs == 0))
- WrLvOdt1 = (dword & 0xf);
- } else {
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- WrLvOdt1 = WrLvOdtRegDimm(pMCTData, pDCTData, dimm);
- } else {
- if ((pDCTData->DctCSPresent & 0x05) == 0x05) {
- WrLvOdt1 = 0x03;
- } else if (bitTest((u32)pDCTData->DctCSPresent,(u8)(dimm*2+1))) {
- WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm+2);
- } else {
- WrLvOdt1 = (u8)bitTestSet(WrLvOdt1, dimm);
- }
- }
- }
-
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
-
- printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x from DIMM %d data\n", dct, WrLvOdt1, dimm);
-
-}
-
-#ifdef UNUSED_CODE
-static uint16_t fam15h_next_lowest_memclk_freq(uint16_t memclk_freq)
-{
- uint16_t fam15h_next_lowest_freq_tab[] = {0, 0, 0, 0, 0x4, 0, 0x4, 0, 0, 0, 0x6, 0, 0, 0, 0xa, 0, 0, 0, 0xe, 0, 0, 0, 0x12};
- return fam15h_next_lowest_freq_tab[memclk_freq];
-}
-#endif
-
-/*-----------------------------------------------------------------------------
- * void procConfig(MCTStruct *MCTData,DCTStruct *DCTData, u8 Dimm, u8 Pass, u8 Nibble)
- *
- * Description:
- * This function programs the ODT values for the NB
- *
- * Parameters:
- * IN OUT *DCTData - Pointer to buffer with information about each DCT
- * *MCTData - Pointer to buffer with runtime parameters,
- * IN Dimm - Logical DIMM
- * Pass - First of Second Pass
- * OUT
- * ----------------------------------------------------------------------------
- */
-void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble)
-{
- u8 ByteLane, MemClkFreq;
- int32_t Seed_Gross;
- int32_t Seed_Fine;
- uint8_t Seed_PreGross;
- u32 Value, Addr;
- uint32_t dword;
- u16 Addl_Data_Offset, Addl_Data_Port;
- sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800};
- uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933};
- uint8_t lane_count;
-
- lane_count = get_available_lane_count(pMCTstat, pDCTstat);
-
- assert(lane_count <= MAX_LANE_COUNT);
-
- if (is_fam15h()) {
- /* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 667MHz; 0x12: 800MHz; 0x16: 933MHz */
- MemClkFreq = get_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, DRAM_CONFIG_HIGH, 0, 4);
- } else {
- /* MemClkFreq: 3: 400MHz; 4: 533MHz; 5: 667MHz; 6: 800MHz */
- MemClkFreq = get_Bits(pDCTData, dct, 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.
- */
- programODT(pMCTstat, pDCTstat, dct, dimm);
-
- /* Program F2x[1,0]9C_x08[WrLvOdtEn]=1 */
- if (pDCTData->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx | AMD_FAM15_ALL)) {
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_ADD_DCT_PHY_CONTROL_REG, WrLvOdtEn, WrLvOdtEn, (u32)1);
- }
- else
- {
- /* Program WrLvOdtEn = 1 through set bit 12 of D3CSODT reg offset 0 for Rev.B */
- if (dct)
- {
- Addl_Data_Offset = 0x198;
- Addl_Data_Port = 0x19C;
- }
- else
- {
- Addl_Data_Offset = 0x98;
- Addl_Data_Port = 0x9C;
- }
- Addr = 0x0D008000;
- AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
- while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
- DctAccessDone, DctAccessDone)) == 0);
- AmdMemPCIReadBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
- Value = bitTestSet(Value, 12);
- AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Port), 31, 0, &Value);
- Addr = 0x4D088F00;
- AmdMemPCIWriteBits(MAKE_SBDFO(0,0,24+(pDCTData->NodeId),FUN_DCT,Addl_Data_Offset), 31, 0, &Addr);
- while ((get_Bits(pDCTData,FUN_DCT,pDCTData->NodeId, FUN_DCT, Addl_Data_Offset,
- DctAccessDone, DctAccessDone)) == 0);
- }
-
- if (is_fam15h())
- proc_MFENCE();
-
- /* Wait 10 MEMCLKs to allow for ODT signal settling. */
- if (is_fam15h())
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 10);
- else
- pMCTData->AgesaDelay(10);
-
- /* Program write levelling seed values */
- if (pass == 1)
- {
- /* Pass 1 */
- if (is_fam15h()) {
- uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
- uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
- uint16_t Seed_Total = 0;
- pDCTData->WrDqsGrossDlyBaseOffset = 0x0;
- if (package_type == PT_GR) {
- /* Socket G34: Fam15h BKDG v3.14 Table 96 */
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- /* TODO
- * Implement mainboard-specific seed and
- * WrDqsGrossDly base overrides.
- * 0x41 and 0x0 are the "stock" values
- */
- Seed_Total = 0x41;
- pDCTData->WrDqsGrossDlyBaseOffset = 0x2;
- } else if (pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
- Seed_Total = 0x0;
- } else {
- Seed_Total = 0xf;
- }
- } else if (package_type == PT_C3) {
- /* Socket C32: Fam15h BKDG v3.14 Table 97 */
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- Seed_Total = 0x3e;
- } else if (pDCTData->Status[DCT_STATUS_LOAD_REDUCED]) {
- Seed_Total = 0x0;
- } else {
- Seed_Total = 0x12;
- }
- } else if (package_type == PT_M2) {
- /* Socket AM3: Fam15h BKDG v3.14 Table 98 */
- Seed_Total = 0xf;
- } else if (package_type == PT_FM2) {
- /* Socket FM2: Fam15h M10 BKDG 3.12 Table 42 */
- Seed_Total = 0x15;
- }
- if (pDCTData->Status[DCT_STATUS_REGISTERED])
- Seed_Total += ((AddrCmdPrelaunch)?0x10:0x0);
-
- /* Adjust seed for the minimum platform supported frequency */
- Seed_Total = (int32_t) (((((int64_t) Seed_Total) *
- fam15h_freq_tab[MemClkFreq] * 100) / (mctGet_NVbits(NV_MIN_MEMCLK) * 100)));
-
- Seed_Gross = (Seed_Total >> 5) & 0x1f;
- Seed_Fine = Seed_Total & 0x1f;
-
- /* Save seed values for later use */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- pDCTData->WLSeedGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
- pDCTData->WLSeedFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
-
- if (Seed_Gross == 0)
- Seed_PreGross = 0;
- else if (Seed_Gross & 0x1)
- Seed_PreGross = 1;
- else
- Seed_PreGross = 2;
-
- pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane] = Seed_PreGross;
- }
- } else {
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
-
- /* The seed values below assume Pass 1 utilizes a 400MHz clock frequency (DDR3-800) */
- if (AddrCmdPrelaunch == 0) {
- Seed_Gross = 0x02;
- Seed_Fine = 0x01;
- } else {
- Seed_Gross = 0x02;
- Seed_Fine = 0x11;
- }
- } else {
- 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;
- }
- }
- }
- for (ByteLane = 0; ByteLane < lane_count; 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
- * If the target frequency is different than 400MHz, BIOS must
- * execute two training passes for each DIMM.
- * For pass 1 at a 400MHz MEMCLK frequency, use an initial total delay value
- * of 01Fh. This represents a 1UI (UI=.5MEMCLK) delay and is determined
- * by design.
- */
- pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
- pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
- printk(BIOS_SPEW, "\tLane %02x initial seed: %04x\n", ByteLane, ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f));
- }
- } else {
- if (nibble == 0) {
- /* Pass 2 */
- /* From BKDG, Write Leveling Seed Value. */
- if (is_fam15h()) {
- uint32_t RegisterDelay;
- int32_t SeedTotal[MAX_LANE_COUNT];
- int32_t SeedTotalPreScaling[MAX_LANE_COUNT];
- uint32_t WrDqDqsEarly;
- uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
-
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- if (AddrCmdPrelaunch)
- RegisterDelay = 0x30;
- else
- RegisterDelay = 0x20;
- } else {
- RegisterDelay = 0;
- }
-
- /* Retrieve WrDqDqsEarly */
- dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8);
- WrDqDqsEarly = (dword >> 24) & 0x3;
-
- /* FIXME
- * Ignore WrDqDqsEarly for now to work around training issues
- */
- WrDqDqsEarly = 0;
-
- /* Generate new seed values */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- /* Calculate adjusted seed values */
- SeedTotal[ByteLane] = (pDCTData->WLFineDelayPrevPass[lane_count*dimm+ByteLane] & 0x1f) |
- ((pDCTData->WLGrossDelayPrevPass[lane_count*dimm+ByteLane] & 0x1f) << 5);
- SeedTotalPreScaling[ByteLane] = (SeedTotal[ByteLane] - RegisterDelay - (0x20 * WrDqDqsEarly));
- SeedTotal[ByteLane] = (int32_t) (RegisterDelay + ((((int64_t) SeedTotalPreScaling[ByteLane]) *
- fam15h_freq_tab[MemClkFreq] * 100) / (fam15h_freq_tab[pDCTData->WLPrevMemclkFreq[dimm]] * 100)));
- }
-
- /* Generate register values from seeds */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- printk(BIOS_SPEW, "\tLane %02x scaled delay: %04x\n", ByteLane, SeedTotal[ByteLane]);
-
- if (SeedTotal[ByteLane] >= 0) {
- Seed_Gross = SeedTotal[ByteLane] / 32;
- Seed_Fine = SeedTotal[ByteLane] % 32;
- } else {
- Seed_Gross = (SeedTotal[ByteLane] / 32) - 1;
- Seed_Fine = (SeedTotal[ByteLane] % 32) + 32;
- }
-
- /* The BKDG-recommended algorithm causes problems with registered DIMMs on some systems
- * due to the long register delays causing premature total delay wrap-around.
- * Attempt to work around this...
- */
- Seed_PreGross = Seed_Gross;
-
- /* Save seed values for later use */
- pDCTData->WLSeedGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
- pDCTData->WLSeedFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
- pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane] = Seed_PreGross;
-
- pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = Seed_PreGross;
- pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
-
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
- }
- } else {
- uint32_t RegisterDelay;
- uint32_t SeedTotalPreScaling;
- uint32_t SeedTotal;
- uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++)
- {
- if (pDCTData->Status[DCT_STATUS_REGISTERED]) {
- if (AddrCmdPrelaunch == 0)
- RegisterDelay = 0x20;
- else
- RegisterDelay = 0x30;
- } else {
- RegisterDelay = 0;
- }
- SeedTotalPreScaling = ((pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f) |
- (pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] << 5)) - RegisterDelay;
- /* SeedTotalPreScaling = (the total delay value in F2x[1, 0]9C_x[4A:30] from pass 1 of write levelization
- training) - RegisterDelay. */
- SeedTotal = (uint16_t) ((((uint64_t) SeedTotalPreScaling) *
- fam10h_freq_tab[MemClkFreq] * 100) / (fam10h_freq_tab[3] * 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;
-
- /* The BKDG-recommended algorithm causes problems with registered DIMMs on some systems
- * due to the long register delays causing premature total delay wrap-around.
- * Attempt to work around this...
- */
- SeedTotal = ((Seed_Gross & 0x1f) << 5) | (Seed_Fine & 0x1f);
- SeedTotal += RegisterDelay;
- Seed_Gross = SeedTotal / 32;
- Seed_Fine = SeedTotal & 0x1f;
-
- pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = Seed_Gross;
- pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = Seed_Fine;
-
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
- }
- }
-
- /* Save initial seeds for upper nibble pass */
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- pDCTData->WLSeedPreGrossPrevNibble[lane_count*dimm+ByteLane] = pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane];
- pDCTData->WLSeedGrossPrevNibble[lane_count*dimm+ByteLane] = pDCTData->WLGrossDelay[lane_count*dimm+ByteLane];
- pDCTData->WLSeedFinePrevNibble[lane_count*dimm+ByteLane] = pDCTData->WLFineDelay[lane_count*dimm+ByteLane];
- }
- } else {
- /* Restore seed values from lower nibble pass */
- if (is_fam15h()) {
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- pDCTData->WLSeedGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[lane_count*dimm+ByteLane];
- pDCTData->WLSeedFineDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[lane_count*dimm+ByteLane];
- pDCTData->WLSeedPreGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[lane_count*dimm+ByteLane];
-
- pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[lane_count*dimm+ByteLane];
- pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[lane_count*dimm+ByteLane];
-
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
- }
- } else {
- for (ByteLane = 0; ByteLane < lane_count; ByteLane++) {
- pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[lane_count*dimm+ByteLane];
- pDCTData->WLFineDelay[lane_count*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[lane_count*dimm+ByteLane];
-
- printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[lane_count*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[lane_count*dimm+ByteLane] & 0x1f));
- }
- }
- }
- }
-
- pDCTData->WLPrevMemclkFreq[dimm] = MemClkFreq;
- setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass, lane_count);
-}
-
-/*-----------------------------------------------------------------------------
- * void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm, uint8_t lane_count){
- *
- * Description:
- * This function writes the write levelization byte delay for the Phase
- * Recovery control registers
- *
- * Parameters:
- * IN OUT *DCTData - Pointer to buffer with information about each DCT
- * IN Dimm - Dimm Number
- * DCTData->WLGrossDelay[index+ByteLane] - gross write delay for each
- * logical DIMM
- * DCTData->WLFineDelay[index+ByteLane] - fine write delay for each
- * logical DIMM
- * ByteLane - target byte lane to write
- * targetAddr - 0: write to DRAM phase recovery control register
- * 1: write to DQS write register
- * OUT
- *
- *-----------------------------------------------------------------------------
- */
-void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass, uint8_t lane_count)
-{
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr;
- u32 addr, fineDelayValue, grossDelayValue, ValueLow, ValueHigh, EccValue, tempW;
-
- if (targetAddr == 0)
- {
- index = (u8)(lane_count * dimm);
- ValueLow = 0;
- ValueHigh = 0;
- ByteLane = 0;
- EccValue = 0;
- while (ByteLane < lane_count)
- {
- /* This subtract 0xC workaround might be temporary. */
- if ((pDCTData->WLPass == 2) && (pDCTData->RegMan1Present & (1 << (dimm*2+dct)))) {
- tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
- tempW -= 0xC;
- pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
- pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
- }
- grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
- /* Adjust seed gross delay overflow (greater than 3):
- * - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
- * - Keep original seed gross delay for later reference.
- */
- if (grossDelayValue >= 3)
- grossDelayValue = (grossDelayValue&1)? 1 : 2;
- fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
- if (ByteLane < 4)
- ValueLow |= ((grossDelayValue << 5) | fineDelayValue) << 8*ByteLane;
- else if (ByteLane < 8)
- ValueHigh |= ((grossDelayValue << 5) | fineDelayValue) << 8*(ByteLane-4);
- else
- EccValue = ((grossDelayValue << 5) | fineDelayValue);
- ByteLane++;
- }
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_CONT_ADD_PHASE_REC_CTRL_LOW, 0, 31, (u32)ValueLow);
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH, 0, 31, (u32)ValueHigh);
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- DRAM_CONT_ADD_ECC_PHASE_REC_CTRL, 0, 31, (u32)EccValue);
- }
- else
- {
- /* Fam10h BKDG: Rev. 3.62 2.8.9.9.1 (6)
- * Fam15h BKDG: Rev. 3.14 2.10.5.8.1
- */
- index = (u8)(lane_count * dimm);
- grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
- fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
-
- tempB = 0;
- offsetAddr = (u8)(3 * dimm);
- if (ByteLane < 2) {
- tempB = (u8)(16 * ByteLane);
- addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01;
- } else if (ByteLane <4) {
- tempB = (u8)(16 * ByteLane);
- addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 1;
- } else if (ByteLane <6) {
- tempB = (u8)(16 * ByteLane);
- addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45;
- } else if (ByteLane <8) {
- tempB = (u8)(16 * ByteLane);
- addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_45 + 1;
- } else {
- tempB = 0;
- addr = DRAM_CONT_ADD_DQS_TIMING_CTRL_BL_01 + 2;
- }
- addr += offsetAddr;
-
- fineStartLoc = (u8)(tempB % 32);
- fineEndLoc = (u8)(fineStartLoc + 4);
- grossStartLoc = (u8)(fineEndLoc + 1);
- grossEndLoc = (u8)(grossStartLoc + 2);
-
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- (u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
- set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
- (u16)addr, grossStartLoc, grossEndLoc, (u32)grossDelayValue);
-
- pDCTData->WLFineDelayPrevPass[index+ByteLane] = fineDelayValue;
- pDCTData->WLGrossDelayPrevPass[index+ByteLane] = grossDelayValue;
- if (pass == FirstPass) {
- pDCTData->WLFineDelayFirstPass[index+ByteLane] = fineDelayValue;
- pDCTData->WLGrossDelayFirstPass[index+ByteLane] = grossDelayValue;
- pDCTData->WLCriticalGrossDelayFirstPass = pDCTData->WLCriticalGrossDelayPrevPass;
- }
- }
-
-}
-
-/*-----------------------------------------------------------------------------
- * void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm, u8 Nibble, uint8_t lane_count)
- *
- * Description:
- * This function reads the write levelization byte delay from the Phase
- * Recovery control registers
- *
- * Parameters:
- * IN OUT *DCTData - Pointer to buffer with information about each DCT
- * IN Dimm - Dimm Number
- * ByteLane - target byte lane to read
- * OUT
- * DCTData->WLGrossDelay[index+ByteLane] - gross write delay for current
- * byte for logical DIMM
- * DCTData->WLFineDelay[index+ByteLane] - fine write delay for current
- * byte for logical DIMM
- *
- *-----------------------------------------------------------------------------
- */
-void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass, uint8_t nibble, uint8_t lane_count)
-{
- sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
- u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, tempB1, index;
- u32 addr, fine, gross;
- tempB = 0;
- index = (u8)(lane_count*dimm);
- if (ByteLane < 4) {
- tempB = (u8)(8 * ByteLane);
- addr = DRAM_CONT_ADD_PHASE_REC_CTRL_LOW;
- } else if (ByteLane < 8) {
- tempB1 = (u8)(ByteLane - 4);
- tempB = (u8)(8 * tempB1);
- addr = DRAM_CONT_ADD_PHASE_REC_CTRL_HIGH;
- } else {
- tempB = 0;
- addr = DRAM_CONT_ADD_ECC_PHASE_REC_CTRL;
- }
- fineStartLoc = tempB;
- fineEndLoc = (u8)(fineStartLoc + 4);
- grossStartLoc = (u8)(fineEndLoc + 1);
- grossEndLoc = (u8)(grossStartLoc + 1);
-
- fine = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, (u16)addr, fineStartLoc, fineEndLoc);
- gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
- FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
-
- printk(BIOS_SPEW, "\tLane %02x nibble %01x raw readback: %04x\n", ByteLane, nibble, ((gross & 0x1f) << 5) | (fine & 0x1f));
-
- /* Adjust seed gross delay overflow (greater than 3):
- * - Adjust the trained gross delay to the original seed gross delay.
- */
- if (pDCTData->WLGrossDelay[index+ByteLane] >= 3)
- {
- gross += pDCTData->WLGrossDelay[index+ByteLane];
- if (pDCTData->WLGrossDelay[index+ByteLane] & 1)
- gross -= 1;
- else
- gross -= 2;
- }
- else if ((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
- {
- /* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
- * We will then round the negative number to 0.
- */
- gross = 0;
- fine = 0;
- }
- printk(BIOS_SPEW, "\tLane %02x nibble %01x adjusted value (pre nibble): %04x\n", ByteLane, nibble, ((gross & 0x1f) << 5) | (fine & 0x1f));
-
- /* Nibble adjustments */
- if (nibble == 0) {
- pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)fine;
- pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)gross;
- } else {
- uint32_t WLTotalDelay = ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f);
- WLTotalDelay += ((gross & 0x1f) << 5) | (fine & 0x1f);
- WLTotalDelay /= 2;
- pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)(WLTotalDelay & 0x1f);
- pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)((WLTotalDelay >> 5) & 0x1f);
- }
- printk(BIOS_SPEW, "\tLane %02x nibble %01x adjusted value (post nibble): %04x\n", ByteLane, nibble, ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f));
-}