aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c2438
1 files changed, 0 insertions, 2438 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
deleted file mode 100644
index dbb989fe3d..0000000000
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsrc.c
+++ /dev/null
@@ -1,2438 +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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-/******************************************************************************
- Description: Receiver En and DQS Timing Training feature for DDR 3 MCT
-******************************************************************************/
-
-#include <arch/cpu.h>
-#include <stdint.h>
-#include <console/console.h>
-#include <cpu/x86/cr.h>
-#include <string.h>
-#include <cpu/x86/msr.h>
-#include <cpu/amd/msr.h>
-#include "mct_d.h"
-#include "mct_d_gcc.h"
-
-static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u8 Pass);
-static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, 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_SetMaxLatency_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 DQSRcvEnDly);
-static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat);
-
-static uint8_t is_fam15h(void)
-{
- uint8_t fam15h = 0;
- uint32_t family;
-
- family = cpuid_eax(0x80000001);
- family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8);
-
- if (family >= 0x6f)
- /* Family 15h or later */
- fam15h = 1;
-
- return fam15h;
-}
-
-/* Warning: These must be located so they do not cross a logical 16-bit
- segment boundary! */
-const u32 TestPattern0_D[] = {
- 0x55555555, 0x55555555, 0x55555555, 0x55555555,
- 0x55555555, 0x55555555, 0x55555555, 0x55555555,
- 0x55555555, 0x55555555, 0x55555555, 0x55555555,
- 0x55555555, 0x55555555, 0x55555555, 0x55555555,
-};
-const u32 TestPattern1_D[] = {
- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
- 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa,
-};
-const u32 TestPattern2_D[] = {
- 0x12345678, 0x87654321, 0x23456789, 0x98765432,
- 0x59385824, 0x30496724, 0x24490795, 0x99938733,
- 0x40385642, 0x38465245, 0x29432163, 0x05067894,
- 0x12349045, 0x98723467, 0x12387634, 0x34587623,
-};
-
-static void SetupRcvrPattern(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u32 *buffer, u8 pass)
-{
- /*
- * 1. Copy the alpha and Beta patterns from ROM to Cache,
- * aligning on 16 byte boundary
- * 2. Set the ptr to DCTStatstruc.PtrPatternBufA for Alpha
- * 3. Set the ptr to DCTStatstruc.PtrPatternBufB for Beta
- */
- u32 *buf_a;
- u32 *buf_b;
- u32 *p_A;
- u32 *p_B;
- u8 i;
-
- buf_a = (u32 *)(((u32)buffer + 0x10) & (0xfffffff0));
- buf_b = buf_a + 32; /* ?? */
- p_A = (u32 *)SetupDqsPattern_1PassB(pass);
- p_B = (u32 *)SetupDqsPattern_1PassA(pass);
-
- for (i = 0; i < 16; i++) {
- buf_a[i] = p_A[i];
- buf_b[i] = p_B[i];
- }
-
- pDCTstat->PtrPatternBufA = (u32)buf_a;
- pDCTstat->PtrPatternBufB = (u32)buf_b;
-}
-
-void mct_TrainRcvrEn_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u8 Pass)
-{
- if (mct_checkNumberOfDqsRcvEn_1Pass(Pass)) {
- if (is_fam15h())
- dqsTrainRcvrEn_SW_Fam15(pMCTstat, pDCTstat, Pass);
- else
- dqsTrainRcvrEn_SW_Fam10(pMCTstat, pDCTstat, Pass);
- }
-}
-
-static uint16_t fam15_receiver_enable_training_seed(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type)
-{
- uint32_t dword;
- uint16_t seed = 0;
-
- uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
-
- uint8_t channel = dct;
- if (package_type == PT_GR) {
- /* Get the internal node number */
- dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8);
- dword = (dword >> 30) & 0x3;
- if (dword == 1) {
- channel += 2;
- }
- }
-
- if (pDCTstat->Status & (1 << SB_Registered)) {
- if (package_type == PT_GR) {
- /* Socket G34: Fam15h BKDG v3.14 Table 99 */
- if (MaxDimmsInstallable == 1) {
- if (channel == 0)
- seed = 0x43;
- else if (channel == 1)
- seed = 0x3f;
- else if (channel == 2)
- seed = 0x3a;
- else if (channel == 3)
- seed = 0x35;
- } else if (MaxDimmsInstallable == 2) {
- if (channel == 0)
- seed = 0x54;
- else if (channel == 1)
- seed = 0x4d;
- else if (channel == 2)
- seed = 0x45;
- else if (channel == 3)
- seed = 0x40;
- } else if (MaxDimmsInstallable == 3) {
- if (channel == 0)
- seed = 0x6b;
- else if (channel == 1)
- seed = 0x5e;
- else if (channel == 2)
- seed = 0x4b;
- else if (channel == 3)
- seed = 0x3d;
- }
- } else if (package_type == PT_C3) {
- /* Socket C32: Fam15h BKDG v3.14 Table 100 */
- if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable == 2)) {
- if (channel == 0)
- seed = 0x3f;
- else if (channel == 1)
- seed = 0x3e;
- } else if (MaxDimmsInstallable == 3) {
- if (channel == 0)
- seed = 0x47;
- else if (channel == 1)
- seed = 0x38;
- }
- }
- } else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
- if (package_type == PT_GR) {
- /* Socket G34: Fam15h BKDG v3.14 Table 99 */
- if (MaxDimmsInstallable == 1) {
- if (channel == 0)
- seed = 0x123;
- else if (channel == 1)
- seed = 0x122;
- else if (channel == 2)
- seed = 0x112;
- else if (channel == 3)
- seed = 0x102;
- }
- } else if (package_type == PT_C3) {
- /* Socket C32: Fam15h BKDG v3.14 Table 100 */
- if (channel == 0)
- seed = 0x132;
- else if (channel == 1)
- seed = 0x122;
- }
- } else {
- if (package_type == PT_GR) {
- /* Socket G34: Fam15h BKDG v3.14 Table 99 */
- if (MaxDimmsInstallable == 1) {
- if (channel == 0)
- seed = 0x3e;
- else if (channel == 1)
- seed = 0x38;
- else if (channel == 2)
- seed = 0x37;
- else if (channel == 3)
- seed = 0x31;
- } else if (MaxDimmsInstallable == 2) {
- if (channel == 0)
- seed = 0x51;
- else if (channel == 1)
- seed = 0x4a;
- else if (channel == 2)
- seed = 0x46;
- else if (channel == 3)
- seed = 0x3f;
- } else if (MaxDimmsInstallable == 3) {
- if (channel == 0)
- seed = 0x5e;
- else if (channel == 1)
- seed = 0x52;
- else if (channel == 2)
- seed = 0x48;
- else if (channel == 3)
- seed = 0x3c;
- }
- } else if (package_type == PT_C3) {
- /* Socket C32: Fam15h BKDG v3.14 Table 100 */
- if ((MaxDimmsInstallable == 1) || (MaxDimmsInstallable == 2)) {
- if (channel == 0)
- seed = 0x39;
- else if (channel == 1)
- seed = 0x32;
- } else if (MaxDimmsInstallable == 3) {
- if (channel == 0)
- seed = 0x45;
- else if (channel == 1)
- seed = 0x37;
- }
- } else if (package_type == PT_M2) {
- /* Socket AM3: Fam15h BKDG v3.14 Table 101 */
- seed = 0x3a;
- } else if (package_type == PT_FM2) {
- /* Socket FM2: Fam15h Model10 BKDG 3.12 Table 43 */
- seed = 0x32;
- }
- }
-
- printk(BIOS_DEBUG, "%s: using seed: %04x\n", __func__, seed);
-
- return seed;
-}
-
-void read_dqs_write_timing_control_registers(uint16_t *current_total_delay, uint32_t dev, uint8_t dct, 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_DCT(dev, dct, 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;
- }
-}
-
-#ifdef UNUSED_CODE
-static void write_dqs_write_timing_control_registers(uint16_t *current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-{
- uint8_t lane;
- uint32_t dword;
-
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
- uint32_t ret_reg;
- if ((lane == 0) || (lane == 1))
- ret_reg = 0x30;
- if ((lane == 2) || (lane == 3))
- ret_reg = 0x31;
- if ((lane == 4) || (lane == 5))
- ret_reg = 0x40;
- if ((lane == 6) || (lane == 7))
- ret_reg = 0x41;
- if (lane == 8)
- ret_reg = 0x32;
- ret_reg += dimm * 3;
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
- if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
- dword &= ~(0xff << 16);
- dword |= (current_total_delay[lane] & 0xff) << 16;
- }
- if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
- dword &= ~0xff;
- dword |= current_total_delay[lane] & 0xff;
- }
- Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
- }
-}
-#endif
-
-static void write_write_data_timing_control_registers(uint16_t *current_total_delay, uint32_t dev, uint8_t dct, 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;
-
- /* 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 |= (dimm << 8);
-
- /* Set Write Data Timing register values */
- dword = Get_NB32_index_wait_DCT(dev, dct, 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_DCT(dev, dct, index_reg, wdt_reg, dword);
- }
-}
-
-void read_dqs_receiver_enable_control_registers(uint16_t *current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-{
- uint8_t lane;
- uint32_t mask;
- uint32_t dword;
-
- if (is_fam15h())
- mask = 0x3ff;
- else
- mask = 0x1ff;
-
- for (lane = 0; lane < MAX_BYTE_LANES; 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;
- if (lane == 8)
- ret_reg = 0x12;
- ret_reg += dimm * 3;
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
- if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
- current_total_delay[lane] = (dword & (mask << 16)) >> 16;
- }
- if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
- current_total_delay[lane] = dword & mask;
- }
- }
-}
-
-void write_dqs_receiver_enable_control_registers(uint16_t *current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-{
- uint8_t lane;
- uint32_t mask;
- uint32_t dword;
-
- if (is_fam15h())
- mask = 0x3ff;
- else
- mask = 0x1ff;
-
- for (lane = 0; lane < MAX_BYTE_LANES; 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;
- if (lane == 8)
- ret_reg = 0x12;
- ret_reg += dimm * 3;
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg);
- if ((lane == 7) || (lane == 5) || (lane == 3) || (lane == 1)) {
- dword &= ~(mask << 16);
- dword |= (current_total_delay[lane] & mask) << 16;
- }
- if ((lane == 8) || (lane == 6) || (lane == 4) || (lane == 2) || (lane == 0)) {
- dword &= ~mask;
- dword |= current_total_delay[lane] & mask;
- }
- Set_NB32_index_wait_DCT(dev, dct, index_reg, ret_reg, dword);
- }
-}
-
-static void read_dram_phase_recovery_control_registers(uint16_t *current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-{
- uint8_t lane;
- uint32_t dword;
-
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
- uint32_t prc_reg;
-
- /* Calculate DRAM Phase Recovery Control register location */
- if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
- prc_reg = 0x50;
- if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
- prc_reg = 0x51;
- if (lane == 8)
- prc_reg = 0x52;
-
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_reg);
- if ((lane == 7) || (lane == 3)) {
- current_total_delay[lane] = (dword >> 24) & 0x7f;
- }
- if ((lane == 6) || (lane == 2)) {
- current_total_delay[lane] = (dword >> 16) & 0x7f;
- }
- if ((lane == 5) || (lane == 1)) {
- current_total_delay[lane] = (dword >> 8) & 0x7f;
- }
- if ((lane == 8) || (lane == 4) || (lane == 0)) {
- current_total_delay[lane] = dword & 0x7f;
- }
- }
-}
-
-static void write_dram_phase_recovery_control_registers(uint16_t *current_total_delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-{
- uint8_t lane;
- uint32_t dword;
-
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) {
- uint32_t prc_reg;
-
- /* Calculate DRAM Phase Recovery Control register location */
- if ((lane == 0) || (lane == 1) || (lane == 2) || (lane == 3))
- prc_reg = 0x50;
- if ((lane == 4) || (lane == 5) || (lane == 6) || (lane == 7))
- prc_reg = 0x51;
- if (lane == 8)
- prc_reg = 0x52;
-
- /* Set DRAM Phase Recovery Control register values */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, prc_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_DCT(dev, dct, index_reg, prc_reg, dword);
- }
-}
-
-void read_dqs_read_data_timing_registers(uint16_t *delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-{
- uint8_t shift;
- uint32_t dword;
- uint32_t mask;
-
- if (is_fam15h()) {
- mask = 0x3e;
- shift = 1;
- }
- else {
- mask = 0x3f;
- shift = 0;
- }
-
- /* Lanes 0 - 3 */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
- delay[3] = ((dword >> 24) & mask) >> shift;
- delay[2] = ((dword >> 16) & mask) >> shift;
- delay[1] = ((dword >> 8) & mask) >> shift;
- delay[0] = (dword & mask) >> shift;
-
- /* Lanes 4 - 7 */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
- delay[7] = ((dword >> 24) & mask) >> shift;
- delay[6] = ((dword >> 16) & mask) >> shift;
- delay[5] = ((dword >> 8) & mask) >> shift;
- delay[4] = (dword & mask) >> shift;
-
- /* Lane 8 (ECC) */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
- delay[8] = (dword & mask) >> shift;
-}
-
-void write_dqs_read_data_timing_registers(uint16_t *delay, uint32_t dev, uint8_t dct, uint8_t dimm, uint32_t index_reg)
-{
- uint8_t shift;
- uint32_t dword;
- uint32_t mask;
-
- if (is_fam15h()) {
- mask = 0x3e;
- shift = 1;
- }
- else {
- mask = 0x3f;
- shift = 0;
- }
-
- /* Lanes 0 - 3 */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8));
- dword &= ~(mask << 24);
- dword &= ~(mask << 16);
- dword &= ~(mask << 8);
- dword &= ~mask;
- dword |= ((delay[3] << shift) & mask) << 24;
- dword |= ((delay[2] << shift) & mask) << 16;
- dword |= ((delay[1] << shift) & mask) << 8;
- dword |= (delay[0] << shift) & mask;
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x5 | (dimm << 8), dword);
-
- /* Lanes 4 - 7 */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8));
- dword &= ~(mask << 24);
- dword &= ~(mask << 16);
- dword &= ~(mask << 8);
- dword &= ~mask;
- dword |= ((delay[7] << shift) & mask) << 24;
- dword |= ((delay[6] << shift) & mask) << 16;
- dword |= ((delay[5] << shift) & mask) << 8;
- dword |= (delay[4] << shift) & mask;
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x6 | (dimm << 8), dword);
-
- /* Lane 8 (ECC) */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8));
- dword &= ~mask;
- dword |= (delay[8] << shift) & mask;
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x7 | (dimm << 8), 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 (Family 10h)
- * Algorithm detailed in:
- * The Fam10h BKDG Rev. 3.62 section 2.8.9.9.2
- */
-static void dqsTrainRcvrEn_SW_Fam10(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u8 Pass)
-{
- u8 Channel;
- u8 _2Ranks;
- u8 Addl_Index = 0;
- u8 Receiver;
- u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
- u16 CTLRMaxDelay;
- u16 MaxDelay_CH[2];
- u32 TestAddr0, TestAddr1, TestAddr0B, TestAddr1B;
- u32 PatternBuffer[64+4]; /* FIXME: need increase 8? */
- u32 Errors;
-
- u32 val;
- u32 reg;
- u32 dev;
- u32 index_reg;
- u32 ch_start, ch_end, ch;
- msr_t msr;
- CRx_TYPE cr4;
-
- uint32_t dword;
- uint8_t dimm;
- 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;
-
- print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
- print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
-
- dev = pDCTstat->dev_dct;
- ch_start = 0;
- if (!pDCTstat->GangedMode) {
- ch_end = 2;
- } else {
- ch_end = 1;
- }
-
- for (ch = ch_start; ch < ch_end; ch++) {
- reg = 0x78;
- val = Get_NB32_DCT(dev, ch, reg);
- val &= ~(0x3ff << 22);
- val |= (0x0c8 << 22); /* MaxRdLatency = 0xc8 */
- Set_NB32_DCT(dev, ch, reg, val);
- }
-
- if (Pass == FirstPass) {
- mct_InitDQSPos4RcvrEn_D(pMCTstat, pDCTstat);
- } else {
- pDCTstat->DimmTrainFail = 0;
- pDCTstat->CSTrainFail = ~pDCTstat->CSPresent;
- }
-
- cr4 = read_cr4();
- if (cr4 & (1 << 9)) { /* save the old value */
- _SSE2 = 1;
- }
- cr4 |= (1 << 9); /* OSFXSR enable SSE2 */
- write_cr4(cr4);
-
- msr = rdmsr(HWCR_MSR);
- /* FIXME: Why use SSEDIS */
- if (msr.lo & (1 << 17)) { /* save the old value */
- _Wrap32Dis = 1;
- }
- msr.lo |= (1 << 17); /* HWCR.wrap32dis */
- msr.lo &= ~(1 << 15); /* SSEDIS */
- wrmsr(HWCR_MSR, msr); /* Setting wrap32dis allows 64-bit memory
- references in real mode */
-
- _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
-
- SetupRcvrPattern(pMCTstat, pDCTstat, PatternBuffer, Pass);
-
- Errors = 0;
- dev = pDCTstat->dev_dct;
-
- 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;
-
- Receiver = mct_InitReceiver_D(pDCTstat, Channel);
- /* 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;
- dimm = (Receiver >> 1);
-
- print_debug_dqs("\t\tTrainRcvEnd52: index ", Addl_Index, 2);
-
- 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, Channel, dimm, 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
- */
- write_write_data_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
-
- /* 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 |= (dimm << 8);
- if (lane == 8)
- dword = 0x0000003f;
- else
- dword = 0x3f3f3f3f;
- Set_NB32_index_wait_DCT(dev, Channel, 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 */
- continue;
- }
-
- TestAddr0B = TestAddr0 + (BigPagex8_RJ8 << 3);
-
- if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver+1)) {
- TestAddr1 = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, Channel, Receiver+1, &valid);
- if (!valid) { /* Address not supported on current CS */
- continue;
- }
- TestAddr1B = TestAddr1 + (BigPagex8_RJ8 << 3);
- _2Ranks = 1;
- } else {
- _2Ranks = TestAddr1 = TestAddr1B = 0;
- }
-
- print_debug_dqs("\t\tTrainRcvEn53: TestAddr0 ", TestAddr0, 2);
- print_debug_dqs("\t\tTrainRcvEn53: TestAddr0B ", TestAddr0B, 2);
- print_debug_dqs("\t\tTrainRcvEn53: TestAddr1 ", TestAddr1, 2);
- print_debug_dqs("\t\tTrainRcvEn53: TestAddr1B ", TestAddr1B, 2);
-
- /* 2.8.9.9.2 (4, 5)
- * Write 1 cache line of the appropriate test pattern to each test address
- */
- 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 */
- }
-
-#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);
- }
-#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, Channel, dimm, 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;
-
- 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);
-
- /* 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;
-
- if (all_lanes_trained)
- break;
-
- /* 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, Channel, dimm, 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, Channel, dimm, 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, Channel, dimm, 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, Channel, dimm, index_reg);
- }
- /* 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
- }
- }
-
- /* 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];
- }
- }
-
- /* 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;
- }
-
- /* 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;
- }
- }
- }
- }
-
- /* Update delays in hardware */
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
-
- /* 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 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
-
- /* 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];
-
- /* 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);
- }
- }
-
- /* 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
- */
- /* FIXME
- * This does not seem to be needed, and has a tendency to lock up the
- * boot process while attempting to write the test pattern.
- */
- }
- MaxDelay_CH[Channel] = CTLRMaxDelay;
- }
-
- CTLRMaxDelay = MaxDelay_CH[0];
- if (MaxDelay_CH[1] > CTLRMaxDelay)
- CTLRMaxDelay = MaxDelay_CH[1];
-
- for (Channel = 0; Channel < 2; Channel++) {
- mct_SetMaxLatency_D(pDCTstat, Channel, CTLRMaxDelay); /* program Ch A/B MaxAsyncLat to correspond with max delay */
- }
-
- for (Channel = 0; Channel < 2; Channel++) {
- ResetDCTWrPtr_D(dev, Channel, index_reg, Addl_Index);
- }
-
- if (_DisableDramECC) {
- mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
- }
-
- if (Pass == FirstPass) {
- /*Disable DQSRcvrEn training mode */
- mct_DisableDQSRcvEn_D(pDCTstat);
- }
-
- if (!_Wrap32Dis) {
- msr = rdmsr(HWCR_MSR);
- msr.lo &= ~(1<<17); /* restore HWCR.wrap32dis */
- wrmsr(HWCR_MSR, msr);
- }
- if (!_SSE2) {
- cr4 = read_cr4();
- cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
- write_cr4(cr4);
- }
-
-#if DQS_TRAIN_DEBUG > 0
- {
- u8 ChannelDTD;
- printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
- for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
- printk(BIOS_DEBUG, "Channel:%x: %x\n",
- ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD][0]);
- }
- }
-#endif
-
-#if DQS_TRAIN_DEBUG > 0
- {
- u16 valDTD;
- u8 ChannelDTD, ReceiverDTD;
- u8 i;
- u16 *p;
-
- printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
- 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++) {
- valDTD = p[i];
- printk(BIOS_DEBUG, " %03x", valDTD);
- }
- printk(BIOS_DEBUG, "\n");
- }
- }
- }
-#endif
-
- printk(BIOS_DEBUG, "TrainRcvrEn: Status %x\n", pDCTstat->Status);
- printk(BIOS_DEBUG, "TrainRcvrEn: ErrStatus %x\n", pDCTstat->ErrStatus);
- printk(BIOS_DEBUG, "TrainRcvrEn: ErrCode %x\n", pDCTstat->ErrCode);
- printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
-}
-
-/* DQS Receiver Enable Training Pattern Generation (Family 15h)
- * Algorithm detailed in:
- * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2 (4)
- */
-static void generate_dram_receiver_enable_training_pattern_fam15(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t Receiver)
-{
- uint32_t dword;
- uint32_t dev = pDCTstat->dev_dct;
-
- /* 2.10.5.7.1.1
- * It appears that the DCT only supports 8-beat burst length mode,
- * so do nothing here...
- */
-
- /* Wait for CmdSendInProg == 0 */
- do {
- dword = Get_NB32_DCT(dev, dct, 0x250);
- } while (dword & (0x1 << 12));
-
- /* Set CmdTestEnable = 1 */
- dword = Get_NB32_DCT(dev, dct, 0x250);
- dword |= (0x1 << 2);
- Set_NB32_DCT(dev, dct, 0x250, dword);
-
- /* 2.10.5.8.6.1.1 Send Activate Command */
- dword = Get_NB32_DCT(dev, dct, 0x28c);
- dword &= ~(0xff << 22); /* CmdChipSelect = Receiver */
- dword |= ((0x1 << Receiver) << 22);
- dword &= ~(0x7 << 19); /* CmdBank = 0 */
- dword &= ~(0x3ffff); /* CmdAddress = 0 */
- dword |= (0x1 << 31); /* SendActCmd = 1 */
- Set_NB32_DCT(dev, dct, 0x28c, dword);
-
- /* Wait for SendActCmd == 0 */
- do {
- dword = Get_NB32_DCT(dev, dct, 0x28c);
- } while (dword & (0x1 << 31));
-
- /* Wait 75 MEMCLKs. */
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 75);
-
- /* 2.10.5.8.6.1.2 */
- Set_NB32_DCT(dev, dct, 0x274, 0x0); /* DQMask = 0 */
- Set_NB32_DCT(dev, dct, 0x278, 0x0);
-
- dword = Get_NB32_DCT(dev, dct, 0x27c);
- dword &= ~(0xff); /* EccMask = 0 */
- if (pDCTstat->DimmECCPresent == 0)
- dword |= 0xff; /* EccMask = 0xff */
- Set_NB32_DCT(dev, dct, 0x27c, dword);
-
- /* 2.10.5.8.6.1.2 */
- dword = Get_NB32_DCT(dev, dct, 0x270);
- dword &= ~(0x7ffff); /* DataPrbsSeed = 55555 */
- dword |= (0x44443); /* Use AGESA seed */
- Set_NB32_DCT(dev, dct, 0x270, dword);
-
- /* 2.10.5.8.2 (4) */
- dword = Get_NB32_DCT(dev, dct, 0x260);
- dword &= ~(0x1fffff); /* CmdCount = 192 */
- dword |= 192;
- Set_NB32_DCT(dev, dct, 0x260, dword);
-
- /* Configure Target A */
- dword = Get_NB32_DCT(dev, dct, 0x254);
- dword &= ~(0x7 << 24); /* TgtChipSelect = Receiver */
- dword |= (Receiver & 0x7) << 24;
- dword &= ~(0x7 << 21); /* TgtBank = 0 */
- dword &= ~(0x3ff); /* TgtAddress = 0 */
- Set_NB32_DCT(dev, dct, 0x254, dword);
-
- dword = Get_NB32_DCT(dev, dct, 0x250);
- dword |= (0x1 << 3); /* ResetAllErr = 1 */
- dword &= ~(0x1 << 4); /* StopOnErr = 0 */
- dword &= ~(0x3 << 8); /* CmdTgt = 0 (Target A) */
- dword &= ~(0x7 << 5); /* CmdType = 0 (Read) */
- dword |= (0x1 << 11); /* SendCmd = 1 */
- Set_NB32_DCT(dev, dct, 0x250, dword);
-
- /* 2.10.5.8.6.1.2 Wait for TestStatus == 1 and CmdSendInProg == 0 */
- do {
- dword = Get_NB32_DCT(dev, dct, 0x250);
- } while ((dword & (0x1 << 12)) || (!(dword & (0x1 << 10))));
-
- dword = Get_NB32_DCT(dev, dct, 0x250);
- dword &= ~(0x1 << 11); /* SendCmd = 0 */
- Set_NB32_DCT(dev, dct, 0x250, dword);
-
- /* 2.10.5.8.6.1.1 Send Precharge Command */
- /* Wait 25 MEMCLKs. */
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
-
- dword = Get_NB32_DCT(dev, dct, 0x28c);
- dword &= ~(0xff << 22); /* CmdChipSelect = Receiver */
- dword |= ((0x1 << Receiver) << 22);
- dword &= ~(0x7 << 19); /* CmdBank = 0 */
- dword &= ~(0x3ffff); /* CmdAddress = 0x400 */
- dword |= 0x400;
- dword |= (0x1 << 30); /* SendPchgCmd = 1 */
- Set_NB32_DCT(dev, dct, 0x28c, dword);
-
- /* Wait for SendPchgCmd == 0 */
- do {
- dword = Get_NB32_DCT(dev, dct, 0x28c);
- } while (dword & (0x1 << 30));
-
- /* Wait 25 MEMCLKs. */
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 25);
-
- /* Set CmdTestEnable = 0 */
- dword = Get_NB32_DCT(dev, dct, 0x250);
- dword &= ~(0x1 << 2);
- Set_NB32_DCT(dev, dct, 0x250, dword);
-}
-
-/* DQS Receiver Enable Training (Family 15h)
- * Algorithm detailed in:
- * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.2
- * This algorithm runs once at the lowest supported MEMCLK,
- * then once again at the highest supported MEMCLK.
- */
-static void dqsTrainRcvrEn_SW_Fam15(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u8 Pass)
-{
- u8 Channel;
- u8 _2Ranks;
- u8 Addl_Index = 0;
- u8 Receiver;
- u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
- u32 Errors;
-
- u32 val;
- u32 dev;
- u32 index_reg;
- u32 ch_start, ch_end, ch;
- u32 msr;
- CRx_TYPE cr4;
- u32 lo, hi;
-
- uint32_t dword;
- uint8_t dimm;
- uint8_t rank;
- uint8_t lane;
- uint8_t nibble;
- uint8_t mem_clk;
- uint16_t min_mem_clk;
- uint16_t initial_seed;
- uint8_t train_both_nibbles;
- uint16_t current_total_delay[MAX_BYTE_LANES];
- uint16_t nibble0_current_total_delay[MAX_BYTE_LANES];
- uint16_t dqs_ret_pass1_total_delay[MAX_BYTE_LANES];
- uint16_t rank0_current_total_delay[MAX_BYTE_LANES];
- uint16_t phase_recovery_delays[MAX_BYTE_LANES];
- uint16_t seed[MAX_BYTE_LANES];
- uint16_t seed_gross[MAX_BYTE_LANES];
- uint16_t seed_fine[MAX_BYTE_LANES];
- uint16_t seed_pre_gross[MAX_BYTE_LANES];
-
- uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE);
- 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);
-
- print_debug_dqs("\nTrainRcvEn: Node", pDCTstat->Node_ID, 0);
- print_debug_dqs("TrainRcvEn: Pass", Pass, 0);
-
- min_mem_clk = mctGet_NVbits(NV_MIN_MEMCLK);
-
- train_both_nibbles = 0;
- if (pDCTstat->Dimmx4Present)
- if (is_fam15h())
- train_both_nibbles = 1;
-
- dev = pDCTstat->dev_dct;
- index_reg = 0x98;
- ch_start = 0;
- ch_end = 2;
-
- for (ch = ch_start; ch < ch_end; ch++) {
- uint8_t max_rd_latency = 0x55;
- uint8_t p_state;
-
- /* 2.10.5.6 */
- fam15EnableTrainingMode(pMCTstat, pDCTstat, ch, 1);
-
- /* 2.10.5.2 */
- for (p_state = 0; p_state < 3; p_state++) {
- val = Get_NB32_DCT_NBPstate(dev, ch, p_state, 0x210);
- val &= ~(0x3ff << 22); /* MaxRdLatency = max_rd_latency */
- val |= (max_rd_latency & 0x3ff) << 22;
- Set_NB32_DCT_NBPstate(dev, ch, p_state, 0x210, val);
- }
- }
-
- if (Pass != FirstPass) {
- pDCTstat->DimmTrainFail = 0;
- pDCTstat->CSTrainFail = ~pDCTstat->CSPresent;
- }
-
- cr4 = read_cr4();
- if (cr4 & (1 << 9)) { /* save the old value */
- _SSE2 = 1;
- }
- cr4 |= (1 << 9); /* OSFXSR enable SSE2 */
- write_cr4(cr4);
-
- msr = HWCR_MSR;
- _RDMSR(msr, &lo, &hi);
- /* FIXME: Why use SSEDIS */
- if (lo & (1 << 17)) { /* save the old value */
- _Wrap32Dis = 1;
- }
- lo |= (1 << 17); /* HWCR.wrap32dis */
- lo &= ~(1 << 15); /* SSEDIS */
- _WRMSR(msr, lo, hi); /* Setting wrap32dis allows 64-bit memory references in real mode */
-
- _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
-
- Errors = 0;
- dev = pDCTstat->dev_dct;
-
- 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;
-
- mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
-
- Receiver = mct_InitReceiver_D(pDCTstat, Channel);
- /* 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;
- dimm = (Receiver >> 1);
-
- print_debug_dqs("\t\tTrainRcvEnd52: index ", Addl_Index, 2);
-
- if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) {
- continue;
- }
-
- /* Retrieve the total delay values from pass 1 of DQS receiver enable training */
- if (Pass != FirstPass) {
- read_dqs_receiver_enable_control_registers(dqs_ret_pass1_total_delay, dev, Channel, dimm, index_reg);
- }
-
- /* 2.10.5.8.2
- * Loop over all ranks
- */
- if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver+1))
- _2Ranks = 1;
- else
- _2Ranks = 0;
- for (rank = 0; rank < (_2Ranks + 1); rank++) {
- for (nibble = 0; nibble < (train_both_nibbles + 1); nibble++) {
- /* 2.10.5.8.2 (1)
- * Specify the target DIMM and nibble to be trained
- */
- dword = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008);
- dword &= ~(0x3 << 4); /* TrDimmSel = dimm */
- dword |= ((dimm & 0x3) << 4);
- dword &= ~(0x1 << 2); /* TrNibbleSel = nibble */
- dword |= ((nibble & 0x1) << 2);
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008, dword);
-
- /* 2.10.5.8.2 (2)
- * Retrieve gross and fine timing fields from write DQS registers
- */
- read_dqs_write_timing_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
-
- /* 2.10.5.8.2.1
- * Generate the DQS Receiver Enable Training Seed Values
- */
- if (Pass == FirstPass) {
- initial_seed = fam15_receiver_enable_training_seed(pDCTstat, Channel, dimm, rank, package_type);
-
- /* Adjust seed for the minimum platform supported frequency */
- initial_seed = (uint16_t) (((((uint64_t) initial_seed) *
- fam15h_freq_tab[mem_clk] * 100) / (min_mem_clk * 100)));
-
- for (lane = 0; lane < lane_count; lane++) {
- uint16_t wl_pass1_delay;
- wl_pass1_delay = current_total_delay[lane];
-
- seed[lane] = initial_seed + wl_pass1_delay;
- }
- } else {
- uint8_t addr_prelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */
- uint16_t register_delay;
- int16_t seed_prescaling;
-
- memcpy(current_total_delay, dqs_ret_pass1_total_delay, sizeof(current_total_delay));
- if ((pDCTstat->Status & (1 << SB_Registered))) {
- if (addr_prelaunch)
- register_delay = 0x30;
- else
- register_delay = 0x20;
- } else if ((pDCTstat->Status & (1 << SB_LoadReduced))) {
- /* TODO
- * Load reduced DIMM support unimplemented
- */
- register_delay = 0x0;
- } else {
- register_delay = 0x0;
- }
-
- for (lane = 0; lane < lane_count; lane++) {
- seed_prescaling = current_total_delay[lane] - register_delay - 0x20;
- seed[lane] = (uint16_t) (register_delay + ((((uint64_t) seed_prescaling) * fam15h_freq_tab[mem_clk] * 100) / (min_mem_clk * 100)));
- }
- }
-
- for (lane = 0; lane < lane_count; lane++) {
- seed_gross[lane] = (seed[lane] >> 5) & 0x1f;
- seed_fine[lane] = seed[lane] & 0x1f;
-
- /*if (seed_gross[lane] == 0)
- seed_pre_gross[lane] = 0;
- else */if (seed_gross[lane] & 0x1)
- seed_pre_gross[lane] = 1;
- else
- seed_pre_gross[lane] = 2;
-
- /* Calculate phase recovery delays */
- phase_recovery_delays[lane] = ((seed_pre_gross[lane] & 0x1f) << 5) | (seed_fine[lane] & 0x1f);
-
- /* Set the gross delay.
- * NOTE: While the BKDG states to only program DqsRcvEnGrossDelay, this appears
- * to have been a misprint as DqsRcvEnFineDelay should be set to zero as well.
- */
- current_total_delay[lane] = ((seed_gross[lane] & 0x1f) << 5);
- }
-
- /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (5 6)
- * Program PhRecFineDly and PhRecGrossDly
- */
- write_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg);
-
- /* 2.10.5.8.2 (2) / 2.10.5.8.2.1 (7)
- * Program the DQS Receiver Enable delay values for each lane
- */
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
-
- /* 2.10.5.8.2 (3)
- * Program DqsRcvTrEn = 1
- */
- dword = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008);
- dword |= (0x1 << 13);
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008, dword);
-
- /* 2.10.5.8.2 (4)
- * Issue 192 read requests to the target rank
- */
- generate_dram_receiver_enable_training_pattern_fam15(pMCTstat, pDCTstat, Channel, Receiver + (rank & 0x1));
-
- /* 2.10.5.8.2 (5)
- * Program DqsRcvTrEn = 0
- */
- dword = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008);
- dword &= ~(0x1 << 13);
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000008, dword);
-
- /* 2.10.5.8.2 (6)
- * Read PhRecGrossDly, PhRecFineDly
- */
- read_dram_phase_recovery_control_registers(phase_recovery_delays, dev, Channel, dimm, index_reg);
-
- /* 2.10.5.8.2 (7)
- * Calculate and program the DQS Receiver Enable delay values
- */
- for (lane = 0; lane < lane_count; lane++) {
- current_total_delay[lane] = (phase_recovery_delays[lane] & 0x1f);
- current_total_delay[lane] |= ((seed_gross[lane] + ((phase_recovery_delays[lane] >> 5) & 0x1f) - seed_pre_gross[lane] + 1) << 5);
- if (nibble == 1) {
- /* 2.10.5.8.2 (1)
- * Average the trained values of both nibbles on x4 DIMMs
- */
- current_total_delay[lane] = (nibble0_current_total_delay[lane] + current_total_delay[lane]) / 2;
- }
- }
-
-#if DQS_TRAIN_DEBUG > 1
- for (lane = 0; lane < 8; lane++)
- printk(BIOS_DEBUG, "\t\tTrainRcvEn55: Channel: %d dimm: %d nibble: %d lane %d current_total_delay: %04x CH_D_B_RCVRDLY: %04x\n",
- Channel, dimm, nibble, lane, current_total_delay[lane], pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane]);
-#endif
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
-
- if (nibble == 0) {
- /* Back up the Nibble 0 delays for later use */
- memcpy(nibble0_current_total_delay, current_total_delay, sizeof(current_total_delay));
- }
-
- /* Exit nibble training if current DIMM is not x4 */
- if ((pDCTstat->Dimmx4Present & (1 << (dimm + Channel))) == 0)
- break;
- }
-
- if (_2Ranks) {
- if (rank == 0) {
- /* Back up the Rank 0 delays for later use */
- memcpy(rank0_current_total_delay, current_total_delay, sizeof(current_total_delay));
- }
- if (rank == 1) {
- /* 2.10.5.8.2 (8)
- * Compute the average delay across both ranks and program the result into
- * the DQS Receiver Enable delay registers
- */
- for (lane = 0; lane < lane_count; lane++) {
- current_total_delay[lane] = (rank0_current_total_delay[lane] + current_total_delay[lane]) / 2;
- if (lane == 8)
- pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
- else
- pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
- }
- write_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
- }
- } else {
- /* Save the current delay for later use by other routines */
- for (lane = 0; lane < lane_count; lane++) {
- if (lane == 8)
- pDCTstat->CH_D_BC_RCVRDLY[Channel][dimm] = current_total_delay[lane];
- else
- pDCTstat->CH_D_B_RCVRDLY[Channel][dimm][lane] = current_total_delay[lane];
- }
- }
- }
-
-#if DQS_TRAIN_DEBUG > 0
- for (lane = 0; lane < 8; lane++)
- print_debug_dqs_pair("\t\tTrainRcvEn56: Lane ", lane, " current_total_delay ", current_total_delay[lane], 2);
-#endif
- }
- }
-
- /* Calculate and program MaxRdLatency for both channels */
- Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, 0, 0);
- Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, 1, 0);
-
- if (_DisableDramECC) {
- mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
- }
-
- if (Pass == FirstPass) {
- /*Disable DQSRcvrEn training mode */
- mct_DisableDQSRcvEn_D(pDCTstat);
- }
-
- if (!_Wrap32Dis) {
- msr = HWCR_MSR;
- _RDMSR(msr, &lo, &hi);
- lo &= ~(1<<17); /* restore HWCR.wrap32dis */
- _WRMSR(msr, lo, hi);
- }
- if (!_SSE2) {
- cr4 = read_cr4();
- cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
- write_cr4(cr4);
- }
-
-#if DQS_TRAIN_DEBUG > 0
- {
- u8 ChannelDTD;
- printk(BIOS_DEBUG, "TrainRcvrEn: CH_MaxRdLat:\n");
- for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
- printk(BIOS_DEBUG, "Channel:%x: %x\n",
- ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD][0]);
- }
- }
-#endif
-
-#if DQS_TRAIN_DEBUG > 0
- {
- u16 valDTD;
- u8 ChannelDTD, ReceiverDTD;
- u8 i;
- u16 *p;
-
- printk(BIOS_DEBUG, "TrainRcvrEn: CH_D_B_RCVRDLY:\n");
- 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++) {
- valDTD = p[i];
- printk(BIOS_DEBUG, " %03x", valDTD);
- }
- printk(BIOS_DEBUG, "\n");
- }
- }
- }
-#endif
-
- printk(BIOS_DEBUG, "TrainRcvrEn: Status %x\n", pDCTstat->Status);
- printk(BIOS_DEBUG, "TrainRcvrEn: ErrStatus %x\n", pDCTstat->ErrStatus);
- printk(BIOS_DEBUG, "TrainRcvrEn: ErrCode %x\n", pDCTstat->ErrCode);
- printk(BIOS_DEBUG, "TrainRcvrEn: Done\n\n");
-}
-
-static void write_max_read_latency_to_registers(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, uint8_t dct, uint16_t *latency)
-{
- uint32_t dword;
- uint8_t nb_pstate;
-
- for (nb_pstate = 0; nb_pstate < 2; nb_pstate++) {
- dword = Get_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, nb_pstate, 0x210);
- dword &= ~(0x3ff << 22);
- dword |= ((latency[nb_pstate] & 0x3ff) << 22);
- Set_NB32_DCT_NBPstate(pDCTstat->dev_dct, dct, nb_pstate, 0x210, dword);
- }
-}
-
-/* DQS MaxRdLatency Training (Family 15h)
- * Algorithm detailed in:
- * The Fam15h BKDG Rev. 3.14 section 2.10.5.8.5.1
- * This algorithm runs at the highest supported MEMCLK.
- */
-void dqsTrainMaxRdLatency_SW_Fam15(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat)
-{
- u8 Channel;
- u8 Receiver;
- u8 _DisableDramECC = 0, _Wrap32Dis = 0, _SSE2 = 0;
- u32 Errors;
-
- u32 dev;
- u32 index_reg;
- u32 ch_start, ch_end;
- u32 msr;
- CRx_TYPE cr4;
- u32 lo, hi;
-
- uint32_t dword;
- uint8_t dimm;
- uint8_t lane;
- uint8_t mem_clk;
- uint32_t nb_clk;
- uint8_t nb_pstate;
- uint16_t current_total_delay[MAX_BYTE_LANES];
- uint16_t current_rdqs_total_delay[MAX_BYTE_LANES];
- uint8_t current_worst_case_total_delay_dimm;
- uint16_t current_worst_case_total_delay_value;
-
- uint8_t lane_count;
- lane_count = get_available_lane_count(pMCTstat, pDCTstat);
-
- 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};
-
- print_debug_dqs("\nTrainMaxRdLatency: Node", pDCTstat->Node_ID, 0);
-
- dev = pDCTstat->dev_dct;
- index_reg = 0x98;
- ch_start = 0;
- ch_end = 2;
-
- cr4 = read_cr4();
- if (cr4 & (1 << 9)) { /* save the old value */
- _SSE2 = 1;
- }
- cr4 |= (1 << 9); /* OSFXSR enable SSE2 */
- write_cr4(cr4);
-
- msr = HWCR_MSR;
- _RDMSR(msr, &lo, &hi);
- /* FIXME: Why use SSEDIS */
- if (lo & (1 << 17)) { /* save the old value */
- _Wrap32Dis = 1;
- }
- lo |= (1 << 17); /* HWCR.wrap32dis */
- lo &= ~(1 << 15); /* SSEDIS */
- _WRMSR(msr, lo, hi); /* Setting wrap32dis allows 64-bit memory references in real mode */
-
- _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
-
- Errors = 0;
- dev = pDCTstat->dev_dct;
-
- for (Channel = 0; Channel < 2; Channel++) {
- print_debug_dqs("\tTrainMaxRdLatency51: Node ", pDCTstat->Node_ID, 1);
- print_debug_dqs("\tTrainMaxRdLatency51: Channel ", Channel, 1);
- pDCTstat->Channel = Channel;
-
- if (pDCTstat->DIMMValidDCT[Channel] == 0)
- continue;
-
- mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
-
- Receiver = mct_InitReceiver_D(pDCTstat, Channel);
-
- /* Find DIMM with worst case receiver enable delays */
- current_worst_case_total_delay_dimm = 0;
- current_worst_case_total_delay_value = 0;
-
- /* There are four receiver pairs, loosely associated with chipselects.
- * This is essentially looping over each DIMM.
- */
- for (; Receiver < 8; Receiver += 2) {
- dimm = (Receiver >> 1);
-
- print_debug_dqs("\t\tTrainMaxRdLatency52: Receiver ", Receiver, 2);
-
- if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, Receiver)) {
- continue;
- }
-
- /* Retrieve the total delay values from pass 1 of DQS receiver enable training */
- read_dqs_receiver_enable_control_registers(current_total_delay, dev, Channel, dimm, index_reg);
- read_dqs_read_data_timing_registers(current_rdqs_total_delay, dev, Channel, dimm, index_reg);
-
- for (lane = 0; lane < lane_count; lane++) {
- current_total_delay[lane] += current_rdqs_total_delay[lane];
- if (current_total_delay[lane] > current_worst_case_total_delay_value) {
- current_worst_case_total_delay_dimm = dimm;
- current_worst_case_total_delay_value = current_total_delay[lane];
- }
- }
-
-#if DQS_TRAIN_DEBUG > 0
- for (lane = 0; lane < lane_count; lane++)
- print_debug_dqs_pair("\t\tTrainMaxRdLatency56: Lane ", lane, " current_total_delay ", current_total_delay[lane], 2);
-#endif
- }
-
- /* 2.10.5.8.5.1.1 */
- Calc_SetMaxRdLatency_D_Fam15(pMCTstat, pDCTstat, Channel, 1);
-
- /* 2.10.5.8.5.1.[2,3]
- * Write the DRAM training pattern to the test address
- */
- write_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff, 0);
-
- /* 2.10.5.8.5.1.4
- * Incrementally test each MaxRdLatency candidate
- */
- for (; pDCTstat->CH_MaxRdLat[Channel][0] < 0x3ff; pDCTstat->CH_MaxRdLat[Channel][0]++) {
- write_max_read_latency_to_registers(pMCTstat, pDCTstat, Channel, pDCTstat->CH_MaxRdLat[Channel]);
- read_dram_dqs_training_pattern_fam15(pMCTstat, pDCTstat, Channel, current_worst_case_total_delay_dimm << 1, 0xff, 0);
- dword = Get_NB32_DCT(dev, Channel, 0x268) & 0x3ffff;
- if (!dword)
- break;
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, 0x00000050, 0x13131313);
- }
- dword = Get_NB32_DCT(dev, Channel, 0x268) & 0x3ffff;
- if (dword)
- printk(BIOS_ERR, "WARNING: MaxRdLatency training FAILED! Attempting to continue but your system may be unstable...\n");
-
- /* 2.10.5.8.5.1.5 */
- nb_pstate = 0;
- mem_clk = Get_NB32_DCT(dev, Channel, 0x94) & 0x1f;
- if (fam15h_freq_tab[mem_clk] == 0) {
- return;
- }
- dword = Get_NB32(pDCTstat->dev_nbctl, (0x160 + (nb_pstate * 4))); /* Retrieve NbDid, NbFid */
- nb_clk = (200 * (((dword >> 1) & 0x1f) + 0x4)) / (((dword >> 7) & 0x1)?2:1);
-
- pDCTstat->CH_MaxRdLat[Channel][0]++;
- pDCTstat->CH_MaxRdLat[Channel][0] += ((((uint64_t)15 * 100000000000ULL) / ((uint64_t)fam15h_freq_tab[mem_clk] * 1000000ULL))
- * ((uint64_t)nb_clk * 1000)) / 1000000000ULL;
-
- write_max_read_latency_to_registers(pMCTstat, pDCTstat, Channel, pDCTstat->CH_MaxRdLat[Channel]);
- }
-
- if (_DisableDramECC) {
- mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC);
- }
-
- if (!_Wrap32Dis) {
- msr = HWCR_MSR;
- _RDMSR(msr, &lo, &hi);
- lo &= ~(1<<17); /* restore HWCR.wrap32dis */
- _WRMSR(msr, lo, hi);
- }
- if (!_SSE2) {
- cr4 = read_cr4();
- cr4 &= ~(1<<9); /* restore cr4.OSFXSR */
- write_cr4(cr4);
- }
-
-#if DQS_TRAIN_DEBUG > 0
- {
- u8 ChannelDTD;
- printk(BIOS_DEBUG, "TrainMaxRdLatency: CH_MaxRdLat:\n");
- for (ChannelDTD = 0; ChannelDTD < 2; ChannelDTD++) {
- printk(BIOS_DEBUG, "Channel:%x: %x\n",
- ChannelDTD, pDCTstat->CH_MaxRdLat[ChannelDTD][0]);
- }
- }
-#endif
-
- printk(BIOS_DEBUG, "TrainMaxRdLatency: Status %x\n", pDCTstat->Status);
- printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrStatus %x\n", pDCTstat->ErrStatus);
- printk(BIOS_DEBUG, "TrainMaxRdLatency: ErrCode %x\n", pDCTstat->ErrCode);
- printk(BIOS_DEBUG, "TrainMaxRdLatency: Done\n\n");
-}
-
-u8 mct_InitReceiver_D(struct DCTStatStruc *pDCTstat, u8 dct)
-{
- if (pDCTstat->DIMMValidDCT[dct] == 0) {
- return 8;
- } else {
- return 0;
- }
-}
-
-static void mct_DisableDQSRcvEn_D(struct DCTStatStruc *pDCTstat)
-{
- u8 ch_end, ch;
- u32 reg;
- u32 dev;
- u32 val;
-
- dev = pDCTstat->dev_dct;
- if (pDCTstat->GangedMode) {
- ch_end = 1;
- } else {
- ch_end = 2;
- }
-
- for (ch = 0; ch < ch_end; ch++) {
- reg = 0x78;
- val = Get_NB32_DCT(dev, ch, reg);
- val &= ~(1 << DqsRcvEnTrain);
- Set_NB32_DCT(dev, ch, reg, val);
- }
-}
-
-/* mct_ModifyIndex_D
- * Function only used once so it was inlined.
- */
-
-/* mct_GetInitFlag_D
- * Function only used once so it was inlined.
- */
-
-/* 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;
- u16 *p;
- u32 val;
-
- if (RcvrEnDly == 0x1fe) {
- /*set the boundary flag */
- pDCTstat->Status |= 1 << SB_DQSRcvLimit;
- }
-
- /* DimmOffset not needed for CH_D_B_RCVRDLY array */
- for (i = 0; i < 8; i++) {
- if (FinalValue) {
- /*calculate dimm offset */
- p = pDCTstat->CH_D_B_RCVRDLY[Channel][Receiver >> 1];
- RcvrEnDly = p[i];
- }
-
- /* if flag = 0, set DqsRcvEn value to reg. */
- /* get the register index from table */
- index = Table_DQSRcvEn_Offset[i >> 1];
- index += Addl_Index; /* DIMMx DqsRcvEn byte0 */
- val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, index);
- if (i & 1) {
- /* odd byte lane */
- val &= ~(0x1ff << 16);
- val |= ((RcvrEnDly & 0x1ff) << 16);
- } else {
- /* even byte lane */
- val &= ~0x1ff;
- val |= (RcvrEnDly & 0x1ff);
- }
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
- }
-
-}
-
-/* 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;
- u32 SubTotal;
- u32 index_reg;
- u32 val;
-
- 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;
-
- dev = pDCTstat->dev_dct;
- index_reg = 0x98;
-
- /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/
- val = Get_NB32_DCT(dev, Channel, 0x88);
- SubTotal = ((val & 0x0f) + 4) << 1; /* SubTotal is 1/2 Memclk unit */
-
- /* If registered DIMMs are being used then
- * add 1 MEMCLK to the sub-total.
- */
- val = Get_NB32_DCT(dev, Channel, 0x90);
- if (!(val & (1 << UnBuffDimm)))
- SubTotal += 2;
-
- /* If the address prelaunch is setup for 1/2 MEMCLKs then
- * add 1, else add 2 to the sub-total.
- * if (AddrCmdSetup || CsOdtSetup || CkeSetup) then K := K + 2;
- */
- val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04);
- if (!(val & 0x00202020))
- SubTotal += 1;
- else
- SubTotal += 2;
-
- /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs,
- * then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */
- val = Get_NB32_DCT(dev, Channel, 0x78);
- SubTotal += 8 - (val & 0x0f);
-
- /* 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; /* Retrieve gross delay portion of value */
-
- /* 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 += 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)
- */
- SubTotal *= 200 * ((Get_NB32(pDCTstat->dev_nbmisc, 0xd4) & 0x1f) + 4);
- SubTotal /= freq_tab[((Get_NB32_DCT(pDCTstat->dev_dct, Channel, 0x94) & 0x7) - 3)];
- SubTotal = (SubTotal + (2 - 1)) / 2; /* Round up */
-
- /* Add "N" NCLKs to the sub-total. "N" represents part of the
- * processor specific constant value in the northbridge
- * clock domain.
- */
- SubTotal += (cpu_val_n) / 2;
-
- pDCTstat->CH_MaxRdLat[Channel][0] = SubTotal;
- if (pDCTstat->GangedMode) {
- pDCTstat->CH_MaxRdLat[1][0] = SubTotal;
- }
-
- /* Program the F2x[1, 0]78[MaxRdLatency] register with
- * the total delay value (in NCLKs).
- */
- reg = 0x78;
- val = Get_NB32_DCT(dev, Channel, reg);
- val &= ~(0x3ff << 22);
- val |= (SubTotal & 0x3ff) << 22;
-
- /* program MaxRdLatency to correspond with current delay */
- Set_NB32_DCT(dev, Channel, reg, val);
-}
-
-static void mct_InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat)
-{
- /* Initialize the DQS Positions in preparation for
- * Receiver Enable Training.
- * Write Position is 1/2 Memclock Delay
- * Read Position is 1/2 Memclock Delay
- */
- u8 i;
- for (i = 0; i < 2; i++) {
- InitDQSPos4RcvrEn_D(pMCTstat, pDCTstat, i);
- }
-}
-
-static void InitDQSPos4RcvrEn_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u8 Channel)
-{
- /* Initialize the DQS Positions in preparation for
- * Receiver Enable Training.
- * Write Position is no Delay
- * Read Position is 1/2 Memclock Delay
- */
-
- u8 i, j;
- u32 dword;
- u8 dn = 4; /* TODO: Rev C could be 4 */
- u32 dev = pDCTstat->dev_dct;
- u32 index_reg = 0x98;
-
- /* FIXME: add Cx support */
- dword = 0x00000000;
- for (i = 1; i <= 3; i++) {
- for (j = 0; j < dn; j++)
- /* DIMM0 Write Data Timing Low */
- /* DIMM0 Write ECC Timing */
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 0x100 * j, dword);
- }
-
- /* errata #180 */
- dword = 0x2f2f2f2f;
- for (i = 5; i <= 6; i++) {
- for (j = 0; j < dn; j++)
- /* DIMM0 Read DQS Timing Control Low */
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, i + 0x100 * j, dword);
- }
-
- dword = 0x0000002f;
- for (j = 0; j < dn; j++)
- /* DIMM0 Read DQS ECC Timing Control */
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, 7 + 0x100 * j, dword);
-}
-
-void SetEccDQSRcvrEn_D(struct DCTStatStruc *pDCTstat, u8 Channel)
-{
- u32 dev;
- u32 index_reg;
- u32 index;
- u8 ChipSel;
- u16 *p;
- u32 val;
-
- dev = pDCTstat->dev_dct;
- index_reg = 0x98;
- index = 0x12;
- p = pDCTstat->CH_D_BC_RCVRDLY[Channel];
- print_debug_dqs("\t\tSetEccDQSRcvrPos: Channel ", Channel, 2);
- for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
- val = p[ChipSel>>1];
- Set_NB32_index_wait_DCT(dev, Channel, index_reg, index, val);
- print_debug_dqs_pair("\t\tSetEccDQSRcvrPos: ChipSel ",
- ChipSel, " rcvr_delay ", val, 2);
- index += 3;
- }
-}
-
-static void CalcEccDQSRcvrEn_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, u8 Channel)
-{
- u8 ChipSel;
- u16 EccDQSLike;
- u8 EccDQSScale;
- u32 val, val0, val1;
- int16_t delay_differential;
-
- EccDQSLike = pDCTstat->CH_EccDQSLike[Channel];
- EccDQSScale = pDCTstat->CH_EccDQSScale[Channel];
-
- for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel += 2) {
- if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, Channel, ChipSel)) {
- u16 *p;
- p = pDCTstat->CH_D_B_RCVRDLY[Channel][ChipSel>>1];
-
- if (pDCTstat->Status & (1 << SB_Registered)) {
- val0 = p[0x2];
- val1 = p[0x3];
-
- delay_differential = (int16_t)val1 - (int16_t)val0;
- delay_differential += (int16_t)val1;
-
- val = delay_differential;
- } else {
- /* DQS Delay Value of Data Bytelane
- * most like ECC byte lane */
- val0 = p[EccDQSLike & 0x07];
- /* DQS Delay Value of Data Bytelane
- * 2nd most like ECC byte lane */
- val1 = p[(EccDQSLike>>8) & 0x07];
-
- if (val0 > val1) {
- val = val0 - val1;
- } else {
- val = val1 - val0;
- }
-
- val *= ~EccDQSScale;
- val >>= 8; /* /256 */
-
- if (val0 > val1) {
- val -= val1;
- } else {
- val += val0;
- }
- }
-
- pDCTstat->CH_D_BC_RCVRDLY[Channel][ChipSel>>1] = val;
- }
- }
- 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)
-{
- u8 Node;
- u8 i;
-
- for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
- struct DCTStatStruc *pDCTstat;
- pDCTstat = pDCTstatA + Node;
- if (!pDCTstat->NodePresent)
- break;
- if (pDCTstat->DCTSysLimit) {
- for (i = 0; i < 2; i++)
- CalcEccDQSRcvrEn_D(pMCTstat, pDCTstat, i);
- }
- }
-}
-
-void phyAssistedMemFnceTraining(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstatA, int16_t single_node_number)
-{
- u8 Node = 0;
- struct DCTStatStruc *pDCTstat;
-
- printk(BIOS_DEBUG, "%s: Start\n", __func__);
-
- uint8_t start_node = 0;
- uint8_t end_node = MAX_NODES_SUPPORTED;
-
- if (single_node_number >= 0) {
- start_node = single_node_number;
- end_node = single_node_number + 1;
- }
-
- /* FIXME: skip for Ax */
- for (Node = start_node; Node < end_node; Node++) {
- pDCTstat = pDCTstatA + Node;
- if (!pDCTstat->NodePresent)
- continue;
-
- if (pDCTstat->DCTSysLimit) {
- if (is_fam15h()) {
- /* Fam15h BKDG v3.14 section 2.10.5.3.3
- * This picks up where InitDDRPhy left off
- */
- uint8_t dct;
- uint8_t index;
- uint32_t dword;
- uint32_t datc_backup;
- uint32_t training_dword;
- uint32_t fence2_config_dword;
- uint32_t fence_tx_pad_config_dword;
- uint32_t index_reg = 0x98;
- uint32_t dev = pDCTstat->dev_dct;
-
- for (dct = 0; dct < 2; dct++) {
- if (!pDCTstat->DIMMValidDCT[dct])
- continue;
-
- printk(BIOS_SPEW, "%s: training node %d DCT %d\n", __func__, Node, dct);
-
- /* Back up D18F2x9C_x0000_0004_dct[1:0] */
- datc_backup = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004);
-
- /* FenceTrSel = 0x2 */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008);
- dword &= ~(0x3 << 6);
- dword |= (0x2 << 6);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008, dword);
-
- /* Set phase recovery seed values */
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000050, 0x13131313);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000051, 0x13131313);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000052, 0x00000013);
-
- training_dword = fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-
- /* Save calculated fence value to the TX DLL */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
- dword &= ~(0x1f << 26);
- dword |= ((training_dword & 0x1f) << 26);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, dword);
-
- /* D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x1 */
- for (index = 0; index < 0x9; index++) {
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
- dword &= ~(0x7 << 12);
- dword |= (0x1 << 12);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8), dword);
- }
-
- /* FenceTrSel = 0x1 */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008);
- dword &= ~(0x3 << 6);
- dword |= (0x1 << 6);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008, dword);
-
- /* Set phase recovery seed values */
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000050, 0x13131313);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000051, 0x13131313);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000052, 0x00000013);
-
- training_dword = fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-
- /* Save calculated fence value to the RX DLL */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
- dword &= ~(0x1f << 21);
- dword |= ((training_dword & 0x1f) << 21);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, dword);
-
- /* D18F2x9C_x0D0F_0[F,8:0]0F_dct[1:0][AlwaysEnDllClks]=0x0 */
- for (index = 0; index < 0x9; index++) {
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8));
- dword &= ~(0x7 << 12);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000f | (index << 8), dword);
- }
-
- /* FenceTrSel = 0x3 */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008);
- dword &= ~(0x3 << 6);
- dword |= (0x3 << 6);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000008, dword);
-
- /* Set phase recovery seed values */
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000050, 0x13131313);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000051, 0x13131313);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000052, 0x00000013);
-
- fence_tx_pad_config_dword = fenceDynTraining_D(pMCTstat, pDCTstat, dct);
-
- /* Save calculated fence value to the TX Pad */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
- dword &= ~(0x1f << 16);
- dword |= ((fence_tx_pad_config_dword & 0x1f) << 16);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, dword);
-
- /* Program D18F2x9C_x0D0F_[C,8,2][2:0]31_dct[1:0] */
- training_dword = fence_tx_pad_config_dword;
- if (fence_tx_pad_config_dword < 16)
- training_dword |= (0x1 << 4);
- else
- training_dword = 0;
- for (index = 0; index < 0x3; index++) {
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2031 | (index << 8));
- dword &= ~(0x1f);
- dword |= (training_dword & 0x1f);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2031 | (index << 8), dword);
- }
- for (index = 0; index < 0x3; index++) {
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8031 | (index << 8));
- dword &= ~(0x1f);
- dword |= (training_dword & 0x1f);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8031 | (index << 8), dword);
- }
- for (index = 0; index < 0x3; index++) {
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc031 | (index << 8));
- dword &= ~(0x1f);
- dword |= (training_dword & 0x1f);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc031 | (index << 8), dword);
- }
-
- /* Assemble Fence2 configuration word (Fam15h BKDG v3.14 page 331) */
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
- fence2_config_dword = 0;
-
- /* TxPad */
- training_dword = (dword >> 16) & 0x1f;
- if (training_dword < 16)
- training_dword |= 0x10;
- else
- training_dword = 0;
- fence2_config_dword |= training_dword;
-
- /* RxDll */
- training_dword = (dword >> 21) & 0x1f;
- if (training_dword < 16)
- training_dword |= 0x10;
- else
- training_dword = 0;
- fence2_config_dword |= (training_dword << 10);
-
- /* TxDll */
- training_dword = (dword >> 26) & 0x1f;
- if (training_dword < 16)
- training_dword |= 0x10;
- else
- training_dword = 0;
- fence2_config_dword |= (training_dword << 5);
-
- /* Program D18F2x9C_x0D0F_0[F,8:0]31_dct[1:0] */
- for (index = 0; index < 0x9; index++) {
- dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0031 | (index << 8));
- dword &= ~(0x7fff);
- dword |= fence2_config_dword;
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0031 | (index << 8), dword);
- }
-
- /* Restore D18F2x9C_x0000_0004_dct[1:0] */
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000004, datc_backup);
-
- printk(BIOS_SPEW, "%s: done training node %d DCT %d\n", __func__, Node, dct);
- }
- } else {
- fenceDynTraining_D(pMCTstat, pDCTstat, 0);
- fenceDynTraining_D(pMCTstat, pDCTstat, 1);
- }
- }
- }
-
- printk(BIOS_DEBUG, "%s: Done\n", __func__);
-}
-
-uint32_t fenceDynTraining_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstat, uint8_t dct)
-{
- u16 avRecValue;
- u32 val;
- u32 dev;
- u32 index_reg = 0x98;
- u32 index;
-
- dev = pDCTstat->dev_dct;
-
- if (is_fam15h()) {
- /* Set F2x[1,0]9C_x08[PhyFenceTrEn] */
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
- val |= 1 << PhyFenceTrEn;
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-
- /* Wait 2000 MEMCLKs */
- precise_memclk_delay_fam15(pMCTstat, pDCTstat, dct, 2000);
-
- /* Clear F2x[1,0]9C_x08[PhyFenceTrEn] */
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
- val &= ~(1 << PhyFenceTrEn);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-
- /* BIOS reads the phase recovery engine registers
- * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52.
- * Average the fine delay components only.
- */
- avRecValue = 0;
- for (index = 0x50; index <= 0x52; index++) {
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
- avRecValue += val & 0x1f;
- if (index != 0x52) {
- avRecValue += (val >> 8) & 0x1f;
- avRecValue += (val >> 16) & 0x1f;
- avRecValue += (val >> 24) & 0x1f;
- }
- }
-
- val = avRecValue / 9;
- if (avRecValue % 9)
- val++;
- avRecValue = val;
-
- if (avRecValue < 6)
- avRecValue = 0;
- else
- avRecValue -= 6;
-
- return avRecValue;
- } else {
- /* BIOS first programs a seed value to the phase recovery engine
- * (recommended 19) registers.
- * Dram Phase Recovery Control Register (F2x[1,0]9C_x[51:50] and
- * F2x[1,0]9C_x52.) .
- */
- for (index = 0x50; index <= 0x52; index ++) {
- val = (FenceTrnFinDlySeed & 0x1F);
- if (index != 0x52) {
- val |= val << 8 | val << 16 | val << 24;
- }
- Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
- }
-
- /* Set F2x[1,0]9C_x08[PhyFenceTrEn]=1. */
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
- val |= 1 << PhyFenceTrEn;
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-
- /* Wait 200 MEMCLKs. */
- mct_Wait(50000); /* wait 200us */
-
- /* Clear F2x[1,0]9C_x08[PhyFenceTrEn]=0. */
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x08);
- val &= ~(1 << PhyFenceTrEn);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x08, val);
-
- /* BIOS reads the phase recovery engine registers
- * F2x[1,0]9C_x[51:50] and F2x[1,0]9C_x52. */
- avRecValue = 0;
- for (index = 0x50; index <= 0x52; index ++) {
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
- avRecValue += val & 0x7F;
- if (index != 0x52) {
- avRecValue += (val >> 8) & 0x7F;
- avRecValue += (val >> 16) & 0x7F;
- avRecValue += (val >> 24) & 0x7F;
- }
- }
-
- val = avRecValue / 9;
- if (avRecValue % 9)
- val++;
- avRecValue = val;
-
- /* Write the (averaged value -8) to F2x[1,0]9C_x0C[PhyFence]. */
- /* inlined mct_AdjustFenceValue() */
- /* TODO: The RBC0 is not supported. */
- /* if (pDCTstat->LogicalCPUID & AMD_RB_C0)
- avRecValue -= 3;
- else
- */
- 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;
-
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C);
- val &= ~(0x1F << 16);
- val |= (avRecValue & 0x1F) << 16;
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0C, val);
-
- /* Rewrite F2x[1,0]9C_x04-DRAM Address/Command Timing Control Register
- * delays (both channels).
- */
- val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x04);
- Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x04, val);
-
- return avRecValue;
- }
-}
-
-void mct_Wait(u32 cycles)
-{
- u32 saved;
- u32 hi, lo, msr;
-
- /* Wait # of 50ns cycles
- This seems like a hack to me... */
-
- cycles <<= 3; /* x8 (number of 1.25ns ticks) */
-
- msr = TSC_MSR; /* TSC */
- _RDMSR(msr, &lo, &hi);
- saved = lo;
- do {
- _RDMSR(msr, &lo, &hi);
- } while (lo - saved < cycles);
-}