| /* |
| * This file is part of the coreboot project. |
| * |
| * Copyright (C) 2015-2016 Raptor Engineering, LLC |
| * Copyright (C) 2010 Advanced Micro Devices, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * 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. |
| */ |
| |
| /* Description: Main memory controller system configuration for DDR 3 */ |
| |
| /* KNOWN ISSUES - ERRATA |
| * |
| * Trtp is not calculated correctly when the controller is in 64-bit mode, it |
| * is 1 busclock off. No fix planned. The controller is not ordinarily in |
| * 64-bit mode. |
| * |
| * 32 Byte burst not supported. No fix planned. The controller is not |
| * ordinarily in 64-bit mode. |
| * |
| * Trc precision does not use extra Jedec defined fractional component. |
| * InsteadTrc (course) is rounded up to nearest 1 ns. |
| * |
| * Mini and Micro DIMM not supported. Only RDIMM, UDIMM, SO-DIMM defined types |
| * supported. |
| */ |
| |
| #include <reset.h> |
| |
| // #define DEBUG_DIMM_SPD 1 |
| |
| static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void DQSTiming_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA, |
| uint8_t allow_config_restore); |
| static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void MCTMemClr_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static u8 NodePresent_D(u8 Node); |
| static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void StartupDCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void ClearDCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void GetPresetmaxF_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void StitchMemory_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u16 Get_Fk_D(u8 k); |
| static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i); |
| static void mct_preInitDCT(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void mct_initDCT(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void mct_DramInit(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u8 mct_BeforePlatformSpec(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void mct_SyncDCTsReady(struct DCTStatStruc *pDCTstat); |
| static void Get_Trdrd(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void mct_AfterGetCLT(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat,\ |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u8 mct_DIMMPresence(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void Set_OtherTiming(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void Get_Twrwr(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void Get_Twrrd(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void Get_TrwtTO(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void Get_TrwtWB(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat, |
| u32 dev, uint8_t dct, u32 index_reg); |
| static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat, u8 dct, |
| u32 dev, u32 index_reg); |
| static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat, |
| u32 dev, uint8_t dct, u32 index_reg, u32 index); |
| static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat, u8 dct, |
| u32 dev, u32 index_reg, u32 index); |
| static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void mct_init(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void clear_legacy_Mode(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void SetCSTriState(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void SetCKETriState(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void SetODTTriState(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void InitDDRPhy(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void InitPhyCompensation(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u32 mct_NodePresent_D(void); |
| static void mct_OtherTiming(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| void mct_ClrWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA); |
| static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct); |
| static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct); |
| static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void ChangeMemClk(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat); |
| void SetTargetFreq(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA, uint8_t Node); |
| |
| static u32 mct_MR1Odt_RDimm(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel); |
| static u32 mct_DramTermDyn_RDimm(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dimm); |
| static u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, |
| uint8_t dct, uint32_t misc2, uint32_t DramControl); |
| static void mct_BeforeDQSTrainSamp(struct DCTStatStruc *pDCTstat); |
| static void mct_WriteLevelization_HW(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA, uint8_t Pass); |
| static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct); |
| static void SyncSetting(struct DCTStatStruc *pDCTstat); |
| static uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm); |
| static void mct_ExtMCTConfig_Bx(struct DCTStatStruc *pDCTstat); |
| static void mct_ExtMCTConfig_Cx(struct DCTStatStruc *pDCTstat); |
| static void mct_ExtMCTConfig_Dx(struct DCTStatStruc *pDCTstat); |
| |
| uint8_t is_ecc_enabled(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat); |
| uint8_t get_available_lane_count(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat); |
| |
| static 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); |
| |
| static 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); |
| |
| /*See mctAutoInitMCT header for index relationships to CL and T*/ |
| static const u16 Table_F_k[] = {00,200,266,333,400,533 }; |
| static const u8 Tab_BankAddr[] = {0x3F,0x01,0x09,0x3F,0x3F,0x11,0x0A,0x19,0x12,0x1A,0x21,0x22,0x23}; |
| static const u8 Table_DQSRcvEn_Offset[] = {0x00,0x01,0x10,0x11,0x2}; |
| |
| /**************************************************************************** |
| Describe how platform maps MemClk pins to logical DIMMs. The MemClk pins |
| are identified based on BKDG definition of Fn2x88[MemClkDis] bitmap. |
| AGESA will base on this value to disable unused MemClk to save power. |
| |
| If MEMCLK_MAPPING or MEMCLK_MAPPING contains all zeroes, AGESA will use |
| default MemClkDis setting based on package type. |
| |
| Example: |
| BKDG definition of Fn2x88[MemClkDis] bitmap for AM3 package is like below: |
| Bit AM3/S1g3 pin name |
| 0 M[B,A]_CLK_H/L[0] |
| 1 M[B,A]_CLK_H/L[1] |
| 2 M[B,A]_CLK_H/L[2] |
| 3 M[B,A]_CLK_H/L[3] |
| 4 M[B,A]_CLK_H/L[4] |
| 5 M[B,A]_CLK_H/L[5] |
| 6 M[B,A]_CLK_H/L[6] |
| 7 M[B,A]_CLK_H/L[7] |
| |
| And platform has the following routing: |
| CS0 M[B,A]_CLK_H/L[4] |
| CS1 M[B,A]_CLK_H/L[2] |
| CS2 M[B,A]_CLK_H/L[3] |
| CS3 M[B,A]_CLK_H/L[5] |
| |
| Then: |
| ; CS0 CS1 CS2 CS3 CS4 CS5 CS6 CS7 |
| MEMCLK_MAPPING EQU 00010000b, 00000100b, 00001000b, 00100000b, 00000000b, 00000000b, 00000000b, 00000000b |
| */ |
| |
| /* ========================================================================================== |
| * Set up clock pin to DIMM mappings, |
| * NOTE: If you are not sure about the pin mappings, you can keep all MemClk signals active, |
| * just set all entries in the relevant table(s) to 0xff. |
| * ========================================================================================== |
| */ |
| static const u8 Tab_L1CLKDis[] = {0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04}; |
| static const u8 Tab_AM3CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; |
| static const u8 Tab_S1CLKDis[] = {0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| |
| /* C32: Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */ |
| static const u8 Tab_C32CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; |
| |
| /* G34: Enable CS0 - CS3 clocks (DIMM0 - DIMM1) */ |
| static const u8 Tab_G34CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; |
| |
| /* FM2: Enable all the clocks for the dimms */ |
| static const u8 Tab_FM2CLKDis[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; |
| |
| static const u8 Tab_ManualCLKDis[]= {0x10, 0x04, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00}; |
| /* ========================================================================================== */ |
| |
| static const u8 Table_Comp_Rise_Slew_20x[] = {7, 3, 2, 2, 0xFF}; |
| static const u8 Table_Comp_Rise_Slew_15x[] = {7, 7, 3, 2, 0xFF}; |
| static const u8 Table_Comp_Fall_Slew_20x[] = {7, 5, 3, 2, 0xFF}; |
| static const u8 Table_Comp_Fall_Slew_15x[] = {7, 7, 5, 3, 0xFF}; |
| |
| static uint8_t dct_ddr_voltage_index(struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| uint8_t dimm; |
| uint8_t ddr_voltage_index = 0; |
| |
| /* If no DIMMs are present on this DCT, report 1.5V operation and skip checking the hardware */ |
| if (pDCTstat->DIMMValidDCT[dct] == 0) |
| return 0x1; |
| |
| /* Find current DDR supply voltage for this DCT */ |
| for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) { |
| if (pDCTstat->DIMMValidDCT[dct] & (1 << dimm)) |
| ddr_voltage_index |= pDCTstat->DimmConfiguredVoltage[dimm]; |
| } |
| if (ddr_voltage_index > 0x7) { |
| printk(BIOS_DEBUG, "%s: Insufficient DDR supply voltage indicated! Configuring processor for 1.25V operation, but this attempt may fail...\n", __func__); |
| ddr_voltage_index = 0x4; |
| } |
| if (ddr_voltage_index == 0x0) { |
| printk(BIOS_DEBUG, "%s: No DDR supply voltage indicated! Configuring processor for 1.5V operation, but this attempt may fail...\n", __func__); |
| ddr_voltage_index = 0x1; |
| } |
| |
| return ddr_voltage_index; |
| } |
| |
| static uint16_t fam15h_mhz_to_memclk_config(uint16_t freq) |
| { |
| 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}; |
| uint16_t iter; |
| |
| /* Compute the index value for the given frequency */ |
| for (iter = 0; iter <= 0x16; iter++) { |
| if (fam15h_freq_tab[iter] == freq) |
| break; |
| } |
| if (fam15h_freq_tab[iter] == freq) |
| freq = iter; |
| if (freq == 0) |
| freq = 0x4; |
| |
| return freq; |
| } |
| |
| static uint16_t fam10h_mhz_to_memclk_config(uint16_t freq) |
| { |
| uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800}; |
| uint16_t iter; |
| |
| /* Compute the index value for the given frequency */ |
| for (iter = 0; iter <= 0x6; iter++) { |
| if (fam10h_freq_tab[iter] == freq) |
| break; |
| } |
| if (fam10h_freq_tab[iter] == freq) |
| freq = iter; |
| if (freq == 0) |
| freq = 0x3; |
| |
| return freq; |
| } |
| |
| static inline uint8_t is_model10_1f(void) |
| { |
| uint8_t model101f = 0; |
| uint32_t family; |
| |
| family = cpuid_eax(0x80000001); |
| family = ((family & 0x0ff000) >> 12); |
| |
| if (family >= 0x10 && family <= 0x1f) |
| /* Model 0x10 to 0x1f */ |
| model101f = 1; |
| |
| return model101f; |
| } |
| |
| uint8_t is_ecc_enabled(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) |
| { |
| uint8_t ecc_enabled = 1; |
| |
| if (!pMCTstat->try_ecc) |
| ecc_enabled = 0; |
| |
| if (pDCTstat->NodePresent && (pDCTstat->DIMMValidDCT[0] || pDCTstat->DIMMValidDCT[1])) |
| if (!(pDCTstat->Status & (1 << SB_ECCDIMMs))) |
| ecc_enabled = 0; |
| |
| return !!ecc_enabled; |
| } |
| |
| uint8_t get_available_lane_count(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) |
| { |
| if (is_ecc_enabled(pMCTstat, pDCTstat)) |
| return 9; |
| else |
| return 8; |
| } |
| |
| static uint16_t mhz_to_memclk_config(uint16_t freq) |
| { |
| if (is_fam15h()) |
| return fam15h_mhz_to_memclk_config(freq); |
| else |
| return fam10h_mhz_to_memclk_config(freq) + 1; |
| } |
| |
| static uint32_t fam10h_address_timing_compensation_code(struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| uint8_t package_type; |
| uint32_t calibration_code = 0; |
| |
| package_type = mctGet_NVbits(NV_PACK_TYPE); |
| uint16_t MemClkFreq = (Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7) + 1; |
| |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[dct]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| |
| if (package_type == PT_GR) { |
| /* Socket G34 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Tables 60 - 61 */ |
| if (MaxDimmsInstallable == 1) { |
| if (MemClkFreq == 0x4) { |
| /* DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0x5) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003c3c3c; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-1333 */ |
| calibration_code = 0x003a3a3a; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if (MemClkFreq == 0x4) { |
| /* DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0x5) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003c3c3c; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-1333 */ |
| calibration_code = 0x003a3a3a; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| if (MemClkFreq == 0x4) { |
| /* DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0x5) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003a3c3a; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00383a38; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else { |
| /* UDIMM */ |
| /* Fam10h BKDG Rev. 3.62 section 2.8.9.5.8 Table 56 */ |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-800 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0x5) { |
| /* DDR3-1066 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x00380000; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-1333 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x00360000; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-800 */ |
| calibration_code = 0x00390039; |
| } else if (MemClkFreq == 0x5) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00350037; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00000035; |
| } |
| } |
| } |
| } else { |
| /* TODO |
| * Other socket support unimplemented |
| */ |
| } |
| |
| return calibration_code; |
| } |
| |
| static uint32_t fam15h_phy_predriver_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength) |
| { |
| uint8_t lrdimm = 0; |
| uint8_t package_type; |
| uint8_t ddr_voltage_index; |
| uint32_t calibration_code = 0; |
| uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; |
| |
| ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); |
| package_type = mctGet_NVbits(NV_PACK_TYPE); |
| |
| if (!lrdimm) { |
| /* Not an LRDIMM */ |
| if ((package_type == PT_M2) || (package_type == PT_GR)) { |
| /* Socket AM3 or G34 */ |
| if (ddr_voltage_index & 0x4) { |
| /* 1.25V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 43 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xdb6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x924; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xfff; |
| } |
| } else if (ddr_voltage_index & 0x2) { |
| /* 1.35V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 42 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xdb6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xbd6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xdb6; |
| } |
| } else if (ddr_voltage_index & 0x1) { |
| /* 1.5V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 41 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xb6d; |
| } |
| } |
| } else if (package_type == PT_C3) { |
| /* Socket C32 */ |
| if (ddr_voltage_index & 0x4) { |
| /* 1.25V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 46 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xdb6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x924; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xfff; |
| } |
| } else if (ddr_voltage_index & 0x2) { |
| /* 1.35V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 45 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xdb6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xdb6; |
| } |
| } else if (ddr_voltage_index & 0x1) { |
| /* 1.5V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 44 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xfff; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xb6d; |
| } |
| } |
| } else if (package_type == PT_FM2) { |
| /* Socket FM2 */ |
| if (ddr_voltage_index & 0x1) { |
| /* 1.5V */ |
| /* Fam15h BKDG Rev. 3.12 section 2.9.5.4.4 Table 22 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| calibration_code = 0xb24; |
| } else if (MemClkFreq >= 0xa) { |
| /* DDR3-1066 or higher */ |
| calibration_code = 0xff6; |
| } |
| } |
| } |
| } else { |
| /* LRDIMM */ |
| |
| /* TODO |
| * Implement LRDIMM support |
| * See Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Tables 47 - 49 |
| */ |
| } |
| |
| return calibration_code; |
| } |
| |
| static uint32_t fam15h_phy_predriver_cmd_addr_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength) |
| { |
| uint8_t ddr_voltage_index; |
| uint32_t calibration_code = 0; |
| uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; |
| |
| ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); |
| |
| if (ddr_voltage_index & 0x4) { |
| /* 1.25V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 52 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xdad; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xdad; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xb64; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xb64; |
| } |
| } else if (ddr_voltage_index & 0x2) { |
| /* 1.35V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 51 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x924; |
| } |
| } else if (ddr_voltage_index & 0x1) { |
| /* 1.5V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 50 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x492; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x492; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x6db; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x6db; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xb6d; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xb6d; |
| } |
| } |
| |
| return calibration_code; |
| } |
| |
| static uint32_t fam15h_phy_predriver_clk_calibration_code(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t drive_strength) |
| { |
| uint8_t ddr_voltage_index; |
| uint32_t calibration_code = 0; |
| uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; |
| |
| ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); |
| |
| if (ddr_voltage_index & 0x4) { |
| /* 1.25V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 55 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xdad; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xdad; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x924; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xff6; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xff6; |
| } |
| } else if (ddr_voltage_index & 0x2) { |
| /* 1.35V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 54 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xdad; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xdad; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x924; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xdad; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xdad; |
| } |
| } else if (ddr_voltage_index & 0x1) { |
| /* 1.5V */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 53 */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x1) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x2) |
| calibration_code = 0x924; |
| else if (drive_strength == 0x3) |
| calibration_code = 0x924; |
| } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { |
| /* DDR3-1066 - DDR3-1333 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xb6d; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (drive_strength == 0x0) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x1) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x2) |
| calibration_code = 0xff6; |
| else if (drive_strength == 0x3) |
| calibration_code = 0xff6; |
| } |
| } |
| |
| return calibration_code; |
| } |
| |
| static uint32_t fam15h_output_driver_compensation_code(struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| uint8_t package_type; |
| uint32_t calibration_code = 0; |
| |
| package_type = mctGet_NVbits(NV_PACK_TYPE); |
| uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; |
| |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[dct]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| |
| if (package_type == PT_GR) { |
| /* Socket G34 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } else if (MemClkFreq == 0x16) { |
| /* DDR3-1866 */ |
| calibration_code = 0x30332222; |
| } |
| |
| if (rank_count_dimm0 == 4) { |
| calibration_code &= ~(0xff << 16); |
| calibration_code |= 0x22 << 16; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } |
| |
| if ((rank_count_dimm0 == 4) || (rank_count_dimm1 == 4)) { |
| calibration_code &= ~(0xff << 16); |
| calibration_code |= 0x22 << 16; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x10222222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x20222222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| calibration_code = 0x30222222; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| /* TODO |
| * LRDIMM support unimplemented |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */ |
| if (MaxDimmsInstallable == 1) { |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } else if (MemClkFreq == 0x16) { |
| /* DDR3-1866 */ |
| calibration_code = 0x30332222; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x10222222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x20222222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| calibration_code = 0x30222222; |
| else |
| calibration_code = 0x30112222; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_C3) { |
| /* Socket C32 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 77 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } |
| |
| if (rank_count_dimm0 == 4) { |
| calibration_code &= ~(0xff << 16); |
| calibration_code |= 0x22 << 16; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } |
| |
| if ((rank_count_dimm0 == 4) || (rank_count_dimm1 == 4)) { |
| calibration_code &= ~(0xff << 16); |
| calibration_code |= 0x22 << 16; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x10222222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x20222222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| calibration_code = 0x30222222; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| /* TODO |
| * LRDIMM support unimplemented |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */ |
| if (MaxDimmsInstallable == 1) { |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| calibration_code = 0x30112222; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x10222222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x20222222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x30222222; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| calibration_code = 0x30222222; |
| else |
| calibration_code = 0x30112222; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_FM2) { |
| /* Socket FM2 */ |
| /* Assume UDIMM */ |
| /* Fam15h Model10h BKDG Rev. 3.12 section 2.9.5.6.6 Table 32 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x20112222; |
| } else if (MemClkFreq >= 0xe) { |
| /* DDR3-1333 or higher */ |
| calibration_code = 0x30112222; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 or DDR3-800 */ |
| calibration_code = 0x00112222; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x10112222; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x20112222; |
| } else if (MemClkFreq >= 0x12) { |
| /* DDR3-1600 or higher */ |
| calibration_code = 0x30112222; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x10222322; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x20222322; |
| } else if (MemClkFreq >= 0xa) { |
| /* DDR3-1066 or higher */ |
| calibration_code = 0x30222322; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else { |
| /* TODO |
| * Other socket support unimplemented |
| */ |
| } |
| |
| return calibration_code; |
| } |
| |
| static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| uint8_t package_type; |
| uint32_t calibration_code = 0; |
| |
| package_type = mctGet_NVbits(NV_PACK_TYPE); |
| uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; |
| |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[dct]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| |
| if (package_type == PT_GR) { |
| /* Socket G34 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */ |
| if (MaxDimmsInstallable == 1) { |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003c3c3c; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x003a3a3a; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| calibration_code = 0x00393939; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00393c39; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00373a37; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| calibration_code = 0x00363936; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003a3c3a; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00383a38; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| calibration_code = 0x00353935; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| /* TODO |
| * LRDIMM support unimplemented |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 76 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00383837; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00363635; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00353533; |
| else |
| calibration_code = 0x00003533; |
| } else if (MemClkFreq == 0x16) { |
| /* DDR3-1866 */ |
| calibration_code = 0x00333330; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00383837; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00363635; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00353533; |
| else |
| calibration_code = 0x00003533; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00390039; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x00390039; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003a3a3a; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00003939; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| calibration_code = 0x00003738; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_C3) { |
| /* Socket C32 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 77 */ |
| if (MaxDimmsInstallable == 1) { |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003c3c3c; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x003a3a3a; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| calibration_code = 0x00393939; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00393c39; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00373a37; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| calibration_code = 0x00363936; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 - DDR3-800 */ |
| calibration_code = 0x00000000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003a3c3a; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00383a38; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| calibration_code = 0x00353935; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| /* TODO |
| * LRDIMM support unimplemented |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 76 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00383837; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00363635; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00353533; |
| else |
| calibration_code = 0x00003533; |
| } else if (MemClkFreq == 0x16) { |
| /* DDR3-1866 */ |
| calibration_code = 0x00333330; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00383837; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00363635; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00353533; |
| else |
| calibration_code = 0x00003533; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (MemClkFreq == 0x4) { |
| /* DDR3-667 */ |
| calibration_code = 0x00390039; |
| } else if (MemClkFreq == 0x6) { |
| /* DDR3-800 */ |
| calibration_code = 0x00390039; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x003a3a3a; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00003939; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| calibration_code = 0x00003738; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_FM2) { |
| /* Socket FM2 */ |
| /* Assume UDIMM */ |
| /* Fam15h Model10h BKDG Rev. 3.12 section 2.9.5.6.6 Table 32 */ |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 or DDR3-800 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x003b0000; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x00380000; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| if (rank_count_dimm0 == 1) |
| calibration_code = 0x00000000; |
| else |
| calibration_code = 0x00360000; |
| } else if (MemClkFreq >= 0x12) { |
| /* DDR3-1600 or higher */ |
| calibration_code = 0x00000000; |
| } |
| |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { |
| /* DDR3-667 or DDR3-800 */ |
| calibration_code = 0x00390039; |
| } else if (MemClkFreq == 0xa) { |
| /* DDR3-1066 */ |
| calibration_code = 0x00350037; |
| } else if (MemClkFreq == 0xe) { |
| /* DDR3-1333 */ |
| calibration_code = 0x00000035; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| calibration_code = 0x0000002b; |
| } else if (MemClkFreq > 0x12) { |
| /* DDR3-1866 or greater */ |
| calibration_code = 0x00000031; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else { |
| /* TODO |
| * Other socket support unimplemented |
| */ |
| } |
| |
| return calibration_code; |
| } |
| |
| static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| uint8_t package_type; |
| uint32_t slow_access = 0; |
| |
| package_type = mctGet_NVbits(NV_PACK_TYPE); |
| uint16_t MemClkFreq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; |
| |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[dct]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| |
| if (package_type == PT_GR) { |
| /* Socket G34 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 74 */ |
| slow_access = 0; |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 75 */ |
| slow_access = 0; |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 73 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) { |
| /* DDR3-667 - DDR3-1333 */ |
| slow_access = 0; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (rank_count_dimm0 == 1) |
| slow_access = 0; |
| else |
| slow_access = 1; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) { |
| /* DDR3-667 - DDR3-1333 */ |
| slow_access = 0; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if (rank_count_dimm0 == 1) |
| slow_access = 0; |
| else |
| slow_access = 1; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa)) { |
| /* DDR3-667 - DDR3-1066 */ |
| slow_access = 0; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| slow_access = 1; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_C3) { |
| /* Socket C32 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 77 */ |
| slow_access = 0; |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 78 */ |
| slow_access = 0; |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 Table 76 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) { |
| /* DDR3-667 - DDR3-1333 */ |
| slow_access = 0; |
| } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { |
| /* DDR3-1600 - DDR3-1866 */ |
| if (rank_count_dimm0 == 1) |
| slow_access = 0; |
| else |
| slow_access = 1; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) { |
| /* DDR3-667 - DDR3-1333 */ |
| slow_access = 0; |
| } else if (MemClkFreq == 0x12) { |
| /* DDR3-1600 */ |
| if (rank_count_dimm0 == 1) |
| slow_access = 0; |
| else |
| slow_access = 1; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa)) { |
| /* DDR3-667 - DDR3-1066 */ |
| slow_access = 0; |
| } else if ((MemClkFreq == 0xe) || (MemClkFreq == 0x12)) { |
| /* DDR3-1333 - DDR3-1600 */ |
| slow_access = 1; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_FM2) { |
| /* Socket FM2 */ |
| /* UDIMM */ |
| /* Fam15h Model10 BKDG Rev. 3.12 section 2.9.5.6.6 Table 32 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) { |
| /* DDR3-667 - DDR3-1333 */ |
| slow_access = 0; |
| } else if (MemClkFreq >= 0x12) { |
| /* DDR3-1600 or higher */ |
| if (rank_count_dimm0 == 1) |
| slow_access = 0; |
| else |
| slow_access = 1; |
| } |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa) | (MemClkFreq == 0xe)) { |
| /* DDR3-667 - DDR3-1333 */ |
| slow_access = 0; |
| } else if (MemClkFreq >= 0x12) { |
| /* DDR3-1600 or higher */ |
| if (rank_count_dimm0 == 1) |
| slow_access = 0; |
| else |
| slow_access = 1; |
| } |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) |
| || (MemClkFreq == 0xa)) { |
| /* DDR3-667 - DDR3-1066 */ |
| slow_access = 0; |
| } else if (MemClkFreq >= 0xe) { |
| /* DDR3-1333 or higher */ |
| slow_access = 1; |
| } |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else { |
| /* TODO |
| * Other socket support unimplemented |
| */ |
| } |
| |
| return slow_access; |
| } |
| |
| static uint8_t fam15h_odt_tristate_enable_code(struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| uint8_t package_type; |
| uint8_t odt_tristate_code = 0; |
| |
| package_type = mctGet_NVbits(NV_PACK_TYPE); |
| |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[dct]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| |
| if (package_type == PT_GR) { |
| /* Socket G34 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| odt_tristate_code = 0xe; |
| else |
| odt_tristate_code = 0xa; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm1 == 1) |
| odt_tristate_code = 0xd; |
| else |
| odt_tristate_code = 0x5; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0xc; |
| else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 >= 2)) |
| odt_tristate_code = 0x4; |
| else if ((rank_count_dimm0 >= 2) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0x8; |
| else |
| odt_tristate_code = 0x0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| |
| /* TODO |
| * Implement LRDIMM support |
| * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 105 |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| odt_tristate_code = 0xe; |
| else |
| odt_tristate_code = 0xa; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| odt_tristate_code = 0xd; |
| else |
| odt_tristate_code = 0x5; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0xc; |
| else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2)) |
| odt_tristate_code = 0x4; |
| else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0x8; |
| else |
| odt_tristate_code = 0x0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_C3) { |
| /* Socket C32 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 107 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| odt_tristate_code = 0xe; |
| else |
| odt_tristate_code = 0xa; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm1 == 1) |
| odt_tristate_code = 0xd; |
| else |
| odt_tristate_code = 0x5; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0xc; |
| else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 >= 2)) |
| odt_tristate_code = 0x4; |
| else if ((rank_count_dimm0 >= 2) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0x8; |
| else |
| odt_tristate_code = 0x0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| |
| /* TODO |
| * Implement LRDIMM support |
| * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 108 |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 106 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| odt_tristate_code = 0xe; |
| else |
| odt_tristate_code = 0xa; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| odt_tristate_code = 0xd; |
| else |
| odt_tristate_code = 0x5; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0xc; |
| else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2)) |
| odt_tristate_code = 0x4; |
| else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1)) |
| odt_tristate_code = 0x8; |
| else |
| odt_tristate_code = 0x0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_FM2) { |
| /* Socket FM2 */ |
| /* UDIMM */ |
| odt_tristate_code = 0x0; |
| } else { |
| /* TODO |
| * Other socket support unimplemented |
| */ |
| } |
| |
| return odt_tristate_code; |
| } |
| |
| static uint8_t fam15h_cs_tristate_enable_code(struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| uint8_t package_type; |
| uint8_t cs_tristate_code = 0; |
| |
| package_type = mctGet_NVbits(NV_PACK_TYPE); |
| |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[dct]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| |
| if (package_type == PT_GR) { |
| /* Socket G34 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 < 4) |
| cs_tristate_code = 0xfc; |
| else |
| cs_tristate_code = 0xcc; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm1 < 4) |
| cs_tristate_code = 0xf3; |
| else |
| cs_tristate_code = 0x33; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) |
| cs_tristate_code = 0xf0; |
| else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4)) |
| cs_tristate_code = 0x30; |
| else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4)) |
| cs_tristate_code = 0xc0; |
| else |
| cs_tristate_code = 0x0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| |
| /* TODO |
| * Implement LRDIMM support |
| * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 105 |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| cs_tristate_code = 0xfe; |
| else |
| cs_tristate_code = 0xfc; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| cs_tristate_code = 0xfb; |
| else |
| cs_tristate_code = 0xf3; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| cs_tristate_code = 0xfa; |
| else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2)) |
| cs_tristate_code = 0xf2; |
| else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1)) |
| cs_tristate_code = 0xf8; |
| else |
| cs_tristate_code = 0xf0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_C3) { |
| /* Socket C32 */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| /* RDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 107 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 < 4) |
| cs_tristate_code = 0xfc; |
| else |
| cs_tristate_code = 0xcc; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm1 < 4) |
| cs_tristate_code = 0xf3; |
| else |
| cs_tristate_code = 0x33; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) |
| cs_tristate_code = 0xf0; |
| else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4)) |
| cs_tristate_code = 0x30; |
| else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4)) |
| cs_tristate_code = 0xc0; |
| else |
| cs_tristate_code = 0x0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| |
| /* TODO |
| * Implement LRDIMM support |
| * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 108 |
| */ |
| } else { |
| /* UDIMM */ |
| /* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 106 */ |
| if (MaxDimmsInstallable == 1) { |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| cs_tristate_code = 0xfe; |
| else |
| cs_tristate_code = 0xfc; |
| } else if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if (rank_count_dimm0 == 1) |
| cs_tristate_code = 0xfb; |
| else |
| cs_tristate_code = 0xf3; |
| } else if (dimm_count == 2) { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| |
| if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1)) |
| cs_tristate_code = 0xfa; |
| else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2)) |
| cs_tristate_code = 0xf2; |
| else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1)) |
| cs_tristate_code = 0xf8; |
| else |
| cs_tristate_code = 0xf0; |
| } |
| } else if (MaxDimmsInstallable == 3) { |
| /* TODO |
| * 3 DIMM/channel support unimplemented |
| */ |
| } |
| } |
| } else if (package_type == PT_FM2) { |
| /* Socket FM2 */ |
| /* UDIMM */ |
| cs_tristate_code = 0x0; |
| } else { |
| /* TODO |
| * Other socket support unimplemented |
| */ |
| } |
| |
| return cs_tristate_code; |
| } |
| |
| static void set_2t_configuration(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| uint32_t dev; |
| uint32_t reg; |
| uint32_t dword; |
| |
| uint8_t enable_slow_access_mode = 0; |
| dev = pDCTstat->dev_dct; |
| |
| if (is_fam15h()) { |
| if (pDCTstat->_2Tmode) |
| enable_slow_access_mode = 1; |
| } else { |
| if (pDCTstat->_2Tmode == 2) |
| enable_slow_access_mode = 1; |
| } |
| |
| reg = 0x94; /* DRAM Configuration High */ |
| dword = Get_NB32_DCT(dev, dct, reg); |
| if (enable_slow_access_mode) |
| dword |= (0x1 << 20); /* Set 2T CMD mode */ |
| else |
| dword &= ~(0x1 << 20); /* Clear 2T CMD mode */ |
| Set_NB32_DCT(dev, dct, reg, dword); |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static void precise_ndelay_fam15(struct MCTStatStruc *pMCTstat, uint32_t nanoseconds) { |
| msr_t tsc_msr; |
| uint64_t cycle_count = (((uint64_t)pMCTstat->TSCFreq) * nanoseconds) / 1000; |
| uint64_t start_timestamp; |
| uint64_t current_timestamp; |
| |
| tsc_msr = rdmsr(0x00000010); |
| start_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo; |
| do { |
| tsc_msr = rdmsr(0x00000010); |
| current_timestamp = (((uint64_t)tsc_msr.hi) << 32) | tsc_msr.lo; |
| } while ((current_timestamp - start_timestamp) < cycle_count); |
| } |
| |
| static void precise_memclk_delay_fam15(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint32_t clocks) { |
| uint16_t memclk_freq; |
| uint32_t delay_ns; |
| 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}; |
| |
| memclk_freq = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; |
| |
| if (fam15h_freq_tab[memclk_freq] == 0) { |
| printk(BIOS_DEBUG, "ERROR: precise_memclk_delay_fam15 for DCT %d (delay %d clocks) failed to obtain valid memory frequency!" |
| " (pDCTstat: %p pDCTstat->dev_dct: %08x memclk_freq: %02x)\n", dct, clocks, pDCTstat, pDCTstat->dev_dct, memclk_freq); |
| } |
| delay_ns = (((uint64_t)clocks * 1000) / fam15h_freq_tab[memclk_freq]); |
| precise_ndelay_fam15(pMCTstat, delay_ns); |
| } |
| |
| static void read_spd_bytes(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, uint8_t dimm) |
| { |
| uint8_t addr; |
| uint16_t byte; |
| |
| addr = Get_DIMMAddress_D(pDCTstat, dimm); |
| pDCTstat->spd_data.spd_address[dimm] = addr; |
| |
| for (byte = 0; byte < 256; byte++) { |
| pDCTstat->spd_data.spd_bytes[dimm][byte] = mctRead_SPD(addr, byte); |
| } |
| } |
| |
| #ifdef DEBUG_DIMM_SPD |
| static void dump_spd_bytes(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, uint8_t dimm) |
| { |
| uint16_t byte; |
| |
| printk(BIOS_DEBUG, "SPD dump for DIMM %d\n ", dimm); |
| for (byte = 0; byte < 16; byte++) { |
| printk(BIOS_DEBUG, "%02x ", byte); |
| } |
| for (byte = 0; byte < 256; byte++) { |
| if ((byte & 0xf) == 0x0) { |
| printk(BIOS_DEBUG, "\n%02x ", byte >> 4); |
| } |
| printk(BIOS_DEBUG, "%02x ", pDCTstat->spd_data.spd_bytes[dimm][byte]); |
| } |
| printk(BIOS_DEBUG, "\n"); |
| } |
| #endif |
| |
| #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) |
| static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| uint8_t dimm; |
| |
| for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) { |
| calculate_spd_hash(pDCTstat->spd_data.spd_bytes[dimm], &pDCTstat->spd_data.spd_hash[dimm]); |
| } |
| } |
| |
| static void compare_nvram_spd_hashes(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| uint8_t dimm; |
| |
| pDCTstat->spd_data.nvram_spd_match = 1; |
| for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) { |
| if (pDCTstat->spd_data.spd_hash[dimm] != pDCTstat->spd_data.nvram_spd_hash[dimm]) |
| pDCTstat->spd_data.nvram_spd_match = 0; |
| } |
| } |
| #endif |
| |
| static void set_up_cc6_storage_fam15(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, uint8_t num_nodes) |
| { |
| uint8_t interleaved; |
| uint8_t destination_node; |
| int8_t range; |
| int8_t max_range; |
| uint8_t max_node; |
| uint64_t max_range_limit; |
| uint8_t byte; |
| uint32_t dword; |
| uint32_t dword2; |
| uint64_t qword; |
| |
| interleaved = 0; |
| if (pMCTstat->GStatus & (1 << GSB_NodeIntlv)) |
| interleaved = 1; |
| |
| printk(BIOS_INFO, |
| "%s: Initializing CC6 DRAM storage area for node %d" |
| " (interleaved: %d)\n", |
| __func__, pDCTstat->Node_ID, interleaved); |
| |
| /* Find highest DRAM range (DramLimitAddr) */ |
| max_node = 0; |
| max_range = -1; |
| max_range_limit = 0; |
| for (range = 0; range < 8; range++) { |
| dword = Get_NB32(pDCTstat->dev_map, 0x40 + (range * 0x8)); |
| if (!(dword & 0x3)) |
| continue; |
| |
| dword = Get_NB32(pDCTstat->dev_map, 0x44 + (range * 0x8)); |
| dword2 = Get_NB32(pDCTstat->dev_map, 0x144 + (range * 0x8)); |
| qword = 0xffffff; |
| qword |= ((((uint64_t)dword) >> 16) & 0xffff) << 24; |
| qword |= (((uint64_t)dword2) & 0xff) << 40; |
| |
| if (qword > max_range_limit) { |
| max_range = range; |
| max_range_limit = qword; |
| max_node = dword & 0x7; |
| } |
| } |
| |
| if (max_range >= 0) { |
| printk(BIOS_INFO, |
| "%s:\toriginal (node %d) max_range_limit: %16llx DRAM" |
| " limit: %16llx\n", |
| __func__, max_node, max_range_limit, |
| (((uint64_t)(Get_NB32(pDCTstat->dev_map, 0x124) |
| & 0x1fffff)) << 27) | 0x7ffffff); |
| |
| if (interleaved) |
| /* Move upper limit down by 16M * the number of nodes */ |
| max_range_limit -= (0x1000000 * num_nodes); |
| else |
| /* Move upper limit down by 16M */ |
| max_range_limit -= 0x1000000; |
| |
| printk(BIOS_INFO, "%s:\tnew max_range_limit: %16llx\n", |
| __func__, max_range_limit); |
| |
| /* Disable the range */ |
| dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8)); |
| byte = dword & 0x3; |
| dword &= ~(0x3); |
| Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword); |
| |
| /* Store modified range */ |
| dword = Get_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8)); |
| dword &= ~(0xffff << 16); /* DramLimit[39:24] = max_range_limit[39:24] */ |
| dword |= ((max_range_limit >> 24) & 0xffff) << 16; |
| Set_NB32(pDCTstat->dev_map, 0x44 + (max_range * 0x8), dword); |
| |
| dword = Get_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8)); |
| dword &= ~0xff; /* DramLimit[47:40] = max_range_limit[47:40] */ |
| dword |= (max_range_limit >> 40) & 0xff; |
| Set_NB32(pDCTstat->dev_map, 0x144 + (max_range * 0x8), dword); |
| |
| /* Reenable the range */ |
| dword = Get_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8)); |
| dword |= byte; |
| Set_NB32(pDCTstat->dev_map, 0x40 + (max_range * 0x8), dword); |
| } |
| |
| /* Determine save state destination node */ |
| if (interleaved) |
| destination_node = Get_NB32(pDCTstat->dev_host, 0x60) & 0x7; |
| else |
| destination_node = max_node; |
| |
| /* Set save state destination node */ |
| dword = Get_NB32(pDCTstat->dev_link, 0x128); |
| dword &= ~(0x3f << 12); /* CoreSaveStateDestNode = destination_node */ |
| dword |= (destination_node & 0x3f) << 12; |
| Set_NB32(pDCTstat->dev_link, 0x128, dword); |
| |
| printk(BIOS_INFO, "%s:\tTarget node: %d\n", __func__, destination_node); |
| |
| printk(BIOS_INFO, "%s:\tDone\n", __func__); |
| } |
| |
| static void lock_dram_config(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| uint32_t dword; |
| |
| dword = Get_NB32(pDCTstat->dev_dct, 0x118); |
| dword |= 0x1 << 19; /* LockDramCfg = 1 */ |
| Set_NB32(pDCTstat->dev_dct, 0x118, dword); |
| } |
| |
| static void set_cc6_save_enable(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, uint8_t enable) |
| { |
| uint32_t dword; |
| |
| dword = Get_NB32(pDCTstat->dev_dct, 0x118); |
| dword &= ~(0x1 << 18); /* CC6SaveEn = enable */ |
| dword |= (enable & 0x1) << 18; |
| Set_NB32(pDCTstat->dev_dct, 0x118, dword); |
| } |
| |
| static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| /* |
| * Memory may be mapped contiguously all the way up to 4GB (depending on setup |
| * options). It is the responsibility of PCI subsystem to create an uncacheable |
| * IO region below 4GB and to adjust TOP_MEM downward prior to any IO mapping or |
| * accesses. It is the same responsibility of the CPU sub-system prior to |
| * accessing LAPIC. |
| * |
| * Slot Number is an external convention, and is determined by OEM with accompanying |
| * silk screening. OEM may choose to use Slot number convention which is consistent |
| * with DIMM number conventions. All AMD engineering platforms do. |
| * |
| * Build Requirements: |
| * 1. MCT_SEG0_START and MCT_SEG0_END macros to begin and end the code segment, |
| * defined in mcti.inc. |
| * |
| * Run-Time Requirements: |
| * 1. Complete Hypertransport Bus Configuration |
| * 2. SMBus Controller Initialized |
| * 1. BSP in Big Real Mode |
| * 2. Stack at SS:SP, located somewhere between A000:0000 and F000:FFFF |
| * 3. Checksummed or Valid NVRAM bits |
| * 4. MCG_CTL = -1, MC4_CTL_EN = 0 for all CPUs |
| * 5. MCi_STS from shutdown/warm reset recorded (if desired) prior to entry |
| * 6. All var MTRRs reset to zero |
| * 7. State of NB_CFG.DisDatMsk set properly on all CPUs |
| * 8. All CPUs at 2GHz Speed (unless DQS training is not installed). |
| * 9. All cHT links at max Speed/Width (unless DQS training is not installed). |
| * |
| * |
| * Global relationship between index values and item values: |
| * |
| * pDCTstat.CASL pDCTstat.Speed |
| * j CL(j) k F(k) |
| * -------------------------- |
| * 0 2.0 - - |
| * 1 3.0 1 200 MHz |
| * 2 4.0 2 266 MHz |
| * 3 5.0 3 333 MHz |
| * 4 6.0 4 400 MHz |
| * 5 7.0 5 533 MHz |
| * 6 8.0 6 667 MHz |
| * 7 9.0 7 800 MHz |
| */ |
| u8 Node, NodesWmem; |
| u32 node_sys_base; |
| uint8_t dimm; |
| uint8_t nvram; |
| uint8_t enable_cc6; |
| uint8_t ecc_enabled; |
| uint8_t allow_config_restore; |
| |
| uint8_t s3resume = acpi_is_wakeup_s3(); |
| |
| restartinit: |
| |
| if (!mctGet_NVbits(NV_ECC_CAP) || !mctGet_NVbits(NV_ECC)) |
| pMCTstat->try_ecc = 0; |
| else |
| pMCTstat->try_ecc = 1; |
| |
| mctInitMemGPIOs_A_D(); /* Set any required GPIOs*/ |
| if (s3resume) { |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_En_Fam15\n"); |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat); |
| } |
| |
| #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT configuration from NVRAM\n"); |
| if (restore_mct_information_from_nvram(0) != 0) |
| printk(BIOS_CRIT, "%s: ERROR: Unable to restore DCT configuration from NVRAM\n", __func__); |
| pMCTstat->GStatus |= 1 << GSB_ConfigRestored; |
| #endif |
| |
| if (is_fam15h()) { |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n"); |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat); |
| } |
| } |
| } else { |
| NodesWmem = 0; |
| node_sys_base = 0; |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| /* Zero out data structures to avoid false detection of DIMMs */ |
| memset(pDCTstat, 0, sizeof(struct DCTStatStruc)); |
| |
| /* Initialize data structures */ |
| pDCTstat->Node_ID = Node; |
| pDCTstat->dev_host = PA_HOST(Node); |
| pDCTstat->dev_map = PA_MAP(Node); |
| pDCTstat->dev_dct = PA_DCT(Node); |
| pDCTstat->dev_nbmisc = PA_NBMISC(Node); |
| pDCTstat->dev_link = PA_LINK(Node); |
| pDCTstat->dev_nbctl = PA_NBCTL(Node); |
| pDCTstat->NodeSysBase = node_sys_base; |
| |
| if (mctGet_NVbits(NV_PACK_TYPE) == PT_GR) { |
| uint32_t dword; |
| pDCTstat->Dual_Node_Package = 1; |
| |
| /* Get the internal node number */ |
| dword = Get_NB32(pDCTstat->dev_nbmisc, 0xe8); |
| dword = (dword >> 30) & 0x3; |
| pDCTstat->Internal_Node_ID = dword; |
| } else { |
| pDCTstat->Dual_Node_Package = 0; |
| } |
| |
| printk(BIOS_DEBUG, "%s: mct_init Node %d\n", __func__, Node); |
| mct_init(pMCTstat, pDCTstat); |
| mctNodeIDDebugPort_D(); |
| pDCTstat->NodePresent = NodePresent_D(Node); |
| if (pDCTstat->NodePresent) { |
| pDCTstat->LogicalCPUID = mctGetLogicalCPUID_D(Node); |
| |
| printk(BIOS_DEBUG, "%s: mct_InitialMCT_D\n", __func__); |
| mct_InitialMCT_D(pMCTstat, pDCTstat); |
| |
| printk(BIOS_DEBUG, "%s: mctSMBhub_Init\n", __func__); |
| mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node */ |
| |
| printk(BIOS_DEBUG, "%s: mct_preInitDCT\n", __func__); |
| mct_preInitDCT(pMCTstat, pDCTstat); |
| } |
| node_sys_base = pDCTstat->NodeSysBase; |
| node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F; |
| } |
| |
| /* If the boot fails make sure training is attempted after reset */ |
| nvram = 0; |
| set_option("allow_spd_nvram_cache_restore", &nvram); |
| |
| #if IS_ENABLED(CONFIG_DIMM_VOLTAGE_SET_SUPPORT) |
| printk(BIOS_DEBUG, "%s: DIMMSetVoltage\n", __func__); |
| DIMMSetVoltages(pMCTstat, pDCTstatA); /* Set the DIMM voltages (mainboard specific) */ |
| #endif |
| if (!IS_ENABLED(CONFIG_DIMM_VOLTAGE_SET_SUPPORT)) { |
| /* Assume 1.5V operation */ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (!pDCTstat->NodePresent) |
| continue; |
| |
| for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) { |
| if (pDCTstat->DIMMValid & (1 << dimm)) |
| pDCTstat->DimmConfiguredVoltage[dimm] = 0x1; |
| } |
| } |
| } |
| |
| /* If DIMM configuration has not changed since last boot restore training values */ |
| allow_config_restore = 1; |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) |
| if (!pDCTstat->spd_data.nvram_spd_match) |
| allow_config_restore = 0; |
| } |
| |
| /* FIXME |
| * Stability issues have arisen on multiple Family 15h systems |
| * when configuration restoration is enabled. In all cases these |
| * stability issues resolved by allowing the RAM to go through a |
| * full training cycle. |
| * |
| * Debug and reenable this! |
| */ |
| allow_config_restore = 0; |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| printk(BIOS_DEBUG, "%s: mctSMBhub_Init\n", __func__); |
| mctSMBhub_Init(Node); /* Switch SMBUS crossbar to proper node*/ |
| |
| printk(BIOS_DEBUG, "%s: mct_initDCT\n", __func__); |
| mct_initDCT(pMCTstat, pDCTstat); |
| if (pDCTstat->ErrCode == SC_FatalErr) { |
| goto fatalexit; /* any fatal errors?*/ |
| } else if (pDCTstat->ErrCode < SC_StopError) { |
| NodesWmem++; |
| } |
| } |
| } |
| if (NodesWmem == 0) { |
| printk(BIOS_ALERT, "Unable to detect valid memory on any nodes. Halting!\n"); |
| goto fatalexit; |
| } |
| |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: SyncDCTsReady_D\n"); |
| SyncDCTsReady_D(pMCTstat, pDCTstatA); /* Make sure DCTs are ready for accesses.*/ |
| |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: HTMemMapInit_D\n"); |
| HTMemMapInit_D(pMCTstat, pDCTstatA); /* Map local memory into system address space.*/ |
| mctHookAfterHTMap(); |
| |
| if (!is_fam15h()) { |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n"); |
| CPUMemTyping_D(pMCTstat, pDCTstatA); /* Map dram into WB/UC CPU cacheability */ |
| } |
| |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: mctHookAfterCPU\n"); |
| mctHookAfterCPU(); /* Setup external northbridge(s) */ |
| |
| /* FIXME |
| * Previous training values should only be used if the current desired |
| * speed is the same as the speed used in the previous boot. |
| * How to get the desired speed at this point in the code? |
| */ |
| #if 0 |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| if (pDCTstat->spd_data.nvram_memclk[0] != pDCTstat->DIMMAutoSpeed) |
| allow_config_restore = 0; |
| } |
| } |
| #endif |
| |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n"); |
| DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get Receiver Enable and DQS signal timing*/ |
| |
| if (!is_fam15h()) { |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n"); |
| UMAMemTyping_D(pMCTstat, pDCTstatA); /* Fix up for UMA sizing */ |
| } |
| |
| if (!allow_config_restore) { |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n"); |
| mct_OtherTiming(pMCTstat, pDCTstatA); |
| } |
| |
| if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st pass of DIMM spare enabled*/ |
| goto restartinit; |
| } |
| |
| InterleaveNodes_D(pMCTstat, pDCTstatA); |
| InterleaveChannels_D(pMCTstat, pDCTstatA); |
| |
| ecc_enabled = 1; |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) |
| if (!is_ecc_enabled(pMCTstat, pDCTstat)) |
| ecc_enabled = 0; |
| } |
| |
| if (ecc_enabled) { |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n"); |
| if (!ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/ |
| /* Memory was not cleared during ECC setup */ |
| /* mctDoWarmResetMemClr_D(); */ |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n"); |
| MCTMemClr_D(pMCTstat,pDCTstatA); |
| } |
| } |
| |
| if (is_fam15h()) { |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: CPUMemTyping_D\n"); |
| CPUMemTyping_D(pMCTstat, pDCTstatA); /* Map dram into WB/UC CPU cacheability */ |
| |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n"); |
| UMAMemTyping_D(pMCTstat, pDCTstatA); /* Fix up for UMA sizing */ |
| |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n"); |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| mct_ForceNBPState0_Dis_Fam15(pMCTstat, pDCTstat); |
| } |
| } |
| |
| if (is_fam15h()) { |
| enable_cc6 = 0; |
| if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS) |
| enable_cc6 = !!nvram; |
| |
| if (enable_cc6) { |
| uint8_t num_nodes; |
| |
| num_nodes = 0; |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) |
| num_nodes++; |
| } |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) |
| set_up_cc6_storage_fam15(pMCTstat, pDCTstat, num_nodes); |
| } |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| set_cc6_save_enable(pMCTstat, pDCTstat, 1); |
| lock_dram_config(pMCTstat, pDCTstat); |
| } |
| } |
| } |
| } |
| |
| mct_FinalMCT_D(pMCTstat, pDCTstatA); |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D Done: Global Status: %x\n", pMCTstat->GStatus); |
| } |
| |
| return; |
| |
| fatalexit: |
| die("mct_d: fatalexit"); |
| } |
| |
| void initialize_mca(uint8_t bsp, uint8_t suppress_errors) { |
| uint8_t node; |
| uint32_t mc4_status_high; |
| uint32_t mc4_status_low; |
| |
| for (node = 0; node < MAX_NODES_SUPPORTED; node++) { |
| if (bsp && (node > 0)) |
| break; |
| |
| mc4_status_high = pci_read_config32(PCI_DEV(0, 0x18 + node, 3), 0x4c); |
| mc4_status_low = pci_read_config32(PCI_DEV(0, 0x18 + node, 3), 0x48); |
| if ((mc4_status_high & (0x1 << 31)) && (mc4_status_high != 0xffffffff)) { |
| if (!suppress_errors) |
| printk(BIOS_WARNING, "WARNING: MC4 Machine Check Exception detected on node %d!\n" |
| "Signature: %08x%08x\n", node, mc4_status_high, mc4_status_low); |
| |
| /* Clear MC4 error status */ |
| pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x48, 0x0); |
| pci_write_config32(PCI_DEV(0, 0x18 + node, 3), 0x4c, 0x0); |
| } |
| } |
| } |
| |
| static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| u8 ret; |
| |
| if (mctGet_NVbits(NV_CS_SpareCTL)) { |
| if (MCT_DIMM_SPARE_NO_WARM) { |
| /* Do no warm-reset DIMM spare */ |
| if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) { |
| LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA); |
| ret = 0; |
| } else { |
| mct_ResetDataStruct_D(pMCTstat, pDCTstatA); |
| pMCTstat->GStatus |= 1 << GSB_EnDIMMSpareNW; |
| ret = 1; |
| } |
| } else { |
| /* Do warm-reset DIMM spare */ |
| if (mctGet_NVbits(NV_DQSTrainCTL)) |
| mctWarmReset_D(); |
| ret = 0; |
| } |
| } else { |
| ret = 0; |
| } |
| |
| return ret; |
| } |
| |
| /* Enable or disable phy-assisted training mode |
| * Phy-assisted training mode applies to the follow DRAM training procedures: |
| * Write Levelization Training (2.10.5.8.1) |
| * DQS Receiver Enable Training (2.10.5.8.2) |
| */ |
| static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t enable) |
| { |
| uint8_t index; |
| uint32_t dword; |
| uint32_t index_reg = 0x98; |
| uint32_t dev = pDCTstat->dev_dct; |
| |
| if (enable) { |
| /* Enable training mode */ |
| dword = Get_NB32_DCT(dev, dct, 0x78); /* DRAM Control */ |
| dword &= ~(0x1 << 17); /* AddrCmdTriEn = 0 */ |
| Set_NB32_DCT(dev, dct, 0x78, dword); /* DRAM Control */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x8c); /* DRAM Timing High */ |
| dword |= (0x1 << 18); /* DisAutoRefresh = 1 */ |
| Set_NB32_DCT(dev, dct, 0x8c, dword); /* DRAM Timing High */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x94); /* DRAM Configuration High */ |
| dword &= ~(0xf << 24); /* DcqBypassMax = 0 */ |
| dword &= ~(0x1 << 22); /* BankSwizzleMode = 0 */ |
| dword &= ~(0x1 << 15); /* PowerDownEn = 0 */ |
| dword &= ~(0x3 << 10); /* ZqcsInterval = 0 */ |
| Set_NB32_DCT(dev, dct, 0x94, dword); /* DRAM Configuration High */ |
| |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d); |
| dword &= ~(0xf << 16); /* RxMaxDurDllNoLock = 0 */ |
| dword &= ~(0xf); /* TxMaxDurDllNoLock = 0 */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword); |
| |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8)); |
| dword &= ~(0x1 << 12); /* EnRxPadStandby = 0 */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8), dword); |
| } |
| |
| dword = Get_NB32_DCT(dev, dct, 0xa4); /* DRAM Controller Temperature Throttle */ |
| dword &= ~(0x1 << 11); /* BwCapEn = 0 */ |
| dword &= ~(0x1 << 8); /* ODTSEn = 0 */ |
| Set_NB32_DCT(dev, dct, 0xa4, dword); /* DRAM Controller Temperature Throttle */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x110); /* DRAM Controller Select Low */ |
| dword &= ~(0x1 << 2); /* DctSelIntLvEn = 0 */ |
| Set_NB32_DCT(dev, dct, 0x110, dword); /* DRAM Controller Select Low */ |
| |
| dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58); /* Scrub Rate Control */ |
| dword &= ~(0x1f << 24); /* L3Scrub = 0 */ |
| dword &= ~(0x1f); /* DramScrub = 0 */ |
| Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword); /* Scrub Rate Control */ |
| |
| dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c); /* DRAM Scrub Address Low */ |
| dword &= ~(0x1); /* ScrubReDirEn = 0 */ |
| Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword); /* DRAM Scrub Address Low */ |
| |
| dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */ |
| dword |= (0x1 << 4); /* L3ScrbRedirDis = 1 */ |
| Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword); /* L3 Control 1 */ |
| |
| /* Fam15h BKDG section 2.10.5.5.1 */ |
| dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */ |
| dword &= ~(0xf << 24); /* TrdrdSdSc = 0xb */ |
| dword |= (0xb << 24); |
| dword &= ~(0xf << 16); /* TrdrdSdDc = 0xb */ |
| dword |= (0xb << 16); |
| dword &= ~(0xf); /* TrdrdDd = 0xb */ |
| dword |= 0xb; |
| Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */ |
| |
| /* Fam15h BKDG section 2.10.5.5.2 */ |
| dword = Get_NB32_DCT(dev, dct, 0x214); /* DRAM Timing 4 */ |
| dword &= ~(0xf << 16); /* TwrwrSdSc = 0xb */ |
| dword |= (0xb << 16); |
| dword &= ~(0xf << 8); /* TwrwrSdDc = 0xb */ |
| dword |= (0xb << 8); |
| dword &= ~(0xf); /* TwrwrDd = 0xb */ |
| dword |= 0xb; |
| Set_NB32_DCT(dev, dct, 0x214, dword); /* DRAM Timing 4 */ |
| |
| /* Fam15h BKDG section 2.10.5.5.3 */ |
| dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */ |
| dword &= ~(0xf << 8); /* Twrrd = 0xb */ |
| dword |= (0xb << 8); |
| Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */ |
| |
| /* Fam15h BKDG section 2.10.5.5.4 */ |
| dword = Get_NB32_DCT(dev, dct, 0x21c); /* DRAM Timing 6 */ |
| dword &= ~(0x1f << 8); /* TrwtTO = 0x16 */ |
| dword |= (0x16 << 8); |
| dword &= ~(0x1f << 16); /* TrwtWB = TrwtTO + 1 */ |
| dword |= ((((dword >> 8) & 0x1f) + 1) << 16); |
| Set_NB32_DCT(dev, dct, 0x21c, dword); /* DRAM Timing 6 */ |
| } else { |
| /* Disable training mode */ |
| uint8_t lane; |
| uint8_t dimm; |
| uint16_t max_cdd_we_delta; |
| uint16_t cdd_trwtto_we_delta; |
| uint8_t receiver; |
| uint8_t lane_count; |
| uint8_t x4_present = 0; |
| uint8_t x8_present = 0; |
| uint8_t memclk_index; |
| uint8_t interleave_channels = 0; |
| uint16_t trdrdsddc; |
| uint16_t trdrddd; |
| uint16_t cdd_trdrddd; |
| uint16_t twrwrsddc; |
| uint16_t twrwrdd; |
| uint16_t cdd_twrwrdd; |
| uint16_t twrrd; |
| uint16_t cdd_twrrd; |
| uint16_t cdd_trwtto; |
| uint16_t trwtto; |
| uint8_t first_dimm; |
| uint16_t delay; |
| uint16_t delay2; |
| uint8_t min_value; |
| uint8_t write_early; |
| uint8_t read_odt_delay; |
| uint8_t write_odt_delay; |
| uint8_t buffer_data_delay; |
| int16_t latency_difference; |
| uint16_t difference; |
| uint16_t current_total_delay_1[MAX_BYTE_LANES]; |
| uint16_t current_total_delay_2[MAX_BYTE_LANES]; |
| uint8_t ddr_voltage_index; |
| uint8_t max_dimms_installable; |
| |
| /* FIXME |
| * This should be platform configurable |
| */ |
| uint8_t dimm_event_l_pin_support = 0; |
| |
| if (pDCTstat->DIMMValidDCT[dct] == 0) |
| ddr_voltage_index = 1; |
| else |
| ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); |
| |
| ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); |
| max_dimms_installable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| lane_count = get_available_lane_count(pMCTstat, pDCTstat); |
| |
| if (pDCTstat->Dimmx4Present & ((dct)?0xaa:0x55)) |
| x4_present = 1; |
| if (pDCTstat->Dimmx8Present & ((dct)?0xaa:0x55)) |
| x8_present = 1; |
| memclk_index = Get_NB32_DCT(dev, dct, 0x94) & 0x1f; |
| |
| if (pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1] && mctGet_NVbits(NV_Unganged)) |
| interleave_channels = 1; |
| |
| dword = (Get_NB32_DCT(dev, dct, 0x240) >> 4) & 0xf; |
| if (dword > 6) |
| read_odt_delay = dword - 6; |
| else |
| read_odt_delay = 0; |
| |
| dword = Get_NB32_DCT(dev, dct, 0x240); |
| delay = (dword >> 4) & 0xf; |
| if (delay > 6) |
| read_odt_delay = delay - 6; |
| else |
| read_odt_delay = 0; |
| delay = (dword >> 12) & 0x7; |
| if (delay > 6) |
| write_odt_delay = delay - 6; |
| else |
| write_odt_delay = 0; |
| |
| dword = (Get_NB32_DCT(dev, dct, 0xa8) >> 24) & 0x3; |
| write_early = dword / 2; |
| |
| latency_difference = Get_NB32_DCT(dev, dct, 0x200) & 0x1f; |
| dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f; |
| latency_difference -= dword; |
| |
| if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| |
| /* TODO |
| * Implement LRDIMM support |
| * See Fam15h BKDG Rev. 3.14 section 2.10.5.5 |
| */ |
| } else { |
| buffer_data_delay = 0; |
| } |
| |
| /* TODO: |
| * Adjust trdrdsddc if four-rank DIMMs are installed per |
| * section 2.10.5.5.1 of the Family 15h BKDG. |
| * cdd_trdrdsddc will also need to be calculated in that process. |
| */ |
| trdrdsddc = 3; |
| |
| /* Calculate the Critical Delay Difference for TrdrdDd */ |
| cdd_trdrddd = 0; |
| first_dimm = 1; |
| for (receiver = 0; receiver < 8; receiver += 2) { |
| dimm = (receiver >> 1); |
| |
| if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) |
| continue; |
| |
| read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); |
| |
| if (first_dimm) { |
| memcpy(current_total_delay_1, current_total_delay_2, sizeof(current_total_delay_1)); |
| first_dimm = 0; |
| } |
| |
| for (lane = 0; lane < lane_count; lane++) { |
| if (current_total_delay_1[lane] > current_total_delay_2[lane]) |
| difference = current_total_delay_1[lane] - current_total_delay_2[lane]; |
| else |
| difference = current_total_delay_2[lane] - current_total_delay_1[lane]; |
| |
| if (difference > cdd_trdrddd) |
| cdd_trdrddd = difference; |
| } |
| } |
| |
| /* Convert the difference to MEMCLKs */ |
| cdd_trdrddd = (((cdd_trdrddd + (1 << 6) - 1) >> 6) & 0xf); |
| |
| /* Calculate Trdrddd */ |
| delay = (read_odt_delay + 3) * 2; |
| delay2 = cdd_trdrddd + 7; |
| if (delay2 > delay) |
| delay = delay2; |
| trdrddd = (delay + 1) / 2; /* + 1 is equivalent to ceiling function here */ |
| if (trdrdsddc > trdrddd) |
| trdrddd = trdrdsddc; |
| |
| /* TODO: |
| * Adjust twrwrsddc if four-rank DIMMs are installed per |
| * section 2.10.5.5.1 of the Family 15h BKDG. |
| * cdd_twrwrsddc will also need to be calculated in that process. |
| */ |
| twrwrsddc = 4; |
| |
| /* Calculate the Critical Delay Difference for TwrwrDd */ |
| cdd_twrwrdd = 0; |
| first_dimm = 1; |
| for (receiver = 0; receiver < 8; receiver += 2) { |
| dimm = (receiver >> 1); |
| |
| if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) |
| continue; |
| |
| read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); |
| |
| if (first_dimm) { |
| memcpy(current_total_delay_1, current_total_delay_2, sizeof(current_total_delay_1)); |
| first_dimm = 0; |
| } |
| |
| for (lane = 0; lane < lane_count; lane++) { |
| if (current_total_delay_1[lane] > current_total_delay_2[lane]) |
| difference = current_total_delay_1[lane] - current_total_delay_2[lane]; |
| else |
| difference = current_total_delay_2[lane] - current_total_delay_1[lane]; |
| |
| if (difference > cdd_twrwrdd) |
| cdd_twrwrdd = difference; |
| } |
| } |
| |
| /* Convert the difference to MEMCLKs */ |
| cdd_twrwrdd = (((cdd_twrwrdd + (1 << 6) - 1) >> 6) & 0xf); |
| |
| /* Calculate Twrwrdd */ |
| delay = (write_odt_delay + 3) * 2; |
| delay2 = cdd_twrwrdd + 7; |
| if (delay2 > delay) |
| delay = delay2; |
| twrwrdd = (delay + 1) / 2; /* + 1 is equivalent to ceiling function here */ |
| if (twrwrsddc > twrwrdd) |
| twrwrdd = twrwrsddc; |
| |
| dword = Get_NB32_DCT(dev, dct, 0x78); /* DRAM Control */ |
| dword |= (0x1 << 17); /* AddrCmdTriEn = 1 */ |
| Set_NB32_DCT(dev, dct, 0x78, dword); /* DRAM Control */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x8c); /* DRAM Timing High */ |
| dword &= ~(0x1 << 18); /* DisAutoRefresh = 0 */ |
| Set_NB32_DCT(dev, dct, 0x8c, dword); /* DRAM Timing High */ |
| |
| /* Configure power saving options */ |
| dword = Get_NB32_DCT(dev, dct, 0xa8); /* Dram Miscellaneous 2 */ |
| dword |= (0x1 << 22); /* PrtlChPDEnhEn = 0x1 */ |
| dword |= (0x1 << 21); /* AggrPDEn = 0x1 */ |
| Set_NB32_DCT(dev, dct, 0xa8, dword); /* Dram Miscellaneous 2 */ |
| |
| /* Configure partial power down delay */ |
| dword = Get_NB32(dev, 0x244); /* DRAM Controller Miscellaneous 3 */ |
| dword &= ~0xf; /* PrtlChPDDynDly = 0x2 */ |
| dword |= 0x2; |
| Set_NB32(dev, 0x244, dword); /* DRAM Controller Miscellaneous 3 */ |
| |
| /* Configure power save delays */ |
| delay = 0xa; |
| delay2 = 0x3; |
| |
| /* Family 15h BKDG Table 214 */ |
| if ((pDCTstat->Status & (1 << SB_Registered)) |
| || (pDCTstat->Status & (1 << SB_LoadReduced))) { |
| if (memclk_index <= 0x6) { |
| if (ddr_voltage_index < 0x4) |
| /* 1.5 or 1.35V */ |
| delay2 = 0x3; |
| else |
| /* 1.25V */ |
| delay2 = 0x4; |
| } |
| else if ((memclk_index == 0xa) |
| || (memclk_index == 0xe)) |
| delay2 = 0x4; |
| else if (memclk_index == 0x12) |
| delay2 = 0x5; |
| else if (memclk_index == 0x16) |
| delay2 = 0x6; |
| } else { |
| if (memclk_index <= 0x6) |
| delay2 = 0x3; |
| else if ((memclk_index == 0xa) |
| || (memclk_index == 0xe)) |
| delay2 = 0x4; |
| else if (memclk_index == 0x12) |
| delay2 = 0x5; |
| else if (memclk_index == 0x16) |
| delay2 = 0x6; |
| } |
| |
| /* Family 15h BKDG Table 215 */ |
| if (memclk_index <= 0x6) |
| delay = 0xa; |
| else if (memclk_index == 0xa) |
| delay = 0xd; |
| else if (memclk_index == 0xe) |
| delay = 0x10; |
| else if (memclk_index == 0x12) |
| delay = 0x14; |
| else if (memclk_index == 0x16) |
| delay = 0x17; |
| |
| dword = Get_NB32_DCT(dev, dct, 0x248); /* Dram Power Management 0 */ |
| dword &= ~(0x3f << 24); /* AggrPDDelay = 0x0 */ |
| dword &= ~(0x3f << 16); /* PchgPDEnDelay = 0x1 */ |
| dword |= (0x1 << 16); |
| dword &= ~(0x1f << 8); /* Txpdll = delay */ |
| dword |= ((delay & 0x1f) << 8); |
| dword &= ~0xf; /* Txp = delay2 */ |
| dword |= delay2 & 0xf; |
| Set_NB32_DCT(dev, dct, 0x248, dword); /* Dram Power Management 0 */ |
| |
| /* Family 15h BKDG Table 216 */ |
| if (memclk_index <= 0x6) { |
| delay = 0x5; |
| delay2 = 0x3; |
| } else if (memclk_index == 0xa) { |
| delay = 0x6; |
| delay2 = 0x3; |
| } else if (memclk_index == 0xe) { |
| delay = 0x7; |
| delay2 = 0x4; |
| } else if (memclk_index == 0x12) { |
| delay = 0x8; |
| delay2 = 0x4; |
| } else if (memclk_index == 0x16) { |
| delay = 0xa; |
| delay2 = 0x5; |
| } |
| |
| dword = Get_NB32_DCT(dev, dct, 0x24c); /* Dram Power Management 1 */ |
| dword &= ~(0x3f << 24); /* Tcksrx = delay */ |
| dword |= ((delay & 0x3f) << 24); |
| dword &= ~(0x3f << 16); /* Tcksre = delay */ |
| dword |= ((delay & 0x3f) << 16); |
| dword &= ~(0x3f << 8); /* Tckesr = delay2 + 1 */ |
| dword |= (((delay2 + 1) & 0x3f) << 8); |
| dword &= ~0xf; /* Tpd = delay2 */ |
| dword |= delay2 & 0xf; |
| Set_NB32_DCT(dev, dct, 0x24c, dword); /* Dram Power Management 1 */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x94); /* DRAM Configuration High */ |
| dword |= (0xf << 24); /* DcqBypassMax = 0xf */ |
| dword |= (0x1 << 22); /* BankSwizzleMode = 1 */ |
| dword |= (0x1 << 15); /* PowerDownEn = 1 */ |
| dword &= ~(0x3 << 10); /* ZqcsInterval = 0x2 */ |
| dword |= (0x2 << 10); |
| Set_NB32_DCT(dev, dct, 0x94, dword); /* DRAM Configuration High */ |
| |
| if (x4_present && x8_present) { |
| /* Mixed channel of 4x and 8x DIMMs */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d); |
| dword &= ~(0x3 << 24); /* RxDLLWakeupTime = 0 */ |
| dword &= ~(0x7 << 20); /* RxCPUpdPeriod = 0 */ |
| dword &= ~(0xf << 16); /* RxMaxDurDllNoLock = 0 */ |
| dword &= ~(0x3 << 8); /* TxDLLWakeupTime = 0 */ |
| dword &= ~(0x7 << 4); /* TxCPUpdPeriod = 0 */ |
| dword &= ~(0xf); /* TxMaxDurDllNoLock = 0 */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword); |
| } else { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d); |
| dword &= ~(0x3 << 24); /* RxDLLWakeupTime = 3 */ |
| dword |= (0x3 << 24); |
| dword &= ~(0x7 << 20); /* RxCPUpdPeriod = 3 */ |
| dword |= (0x3 << 20); |
| dword &= ~(0xf << 16); /* RxMaxDurDllNoLock = 7 */ |
| dword |= (0x7 << 16); |
| dword &= ~(0x3 << 8); /* TxDLLWakeupTime = 3 */ |
| dword |= (0x3 << 8); |
| dword &= ~(0x7 << 4); /* TxCPUpdPeriod = 3 */ |
| dword |= (0x3 << 4); |
| dword &= ~(0xf); /* TxMaxDurDllNoLock = 7 */ |
| dword |= 0x7; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000d, dword); |
| } |
| |
| if ((memclk_index <= 0x12) && (x4_present != x8_present)) { |
| /* MemClkFreq <= 800MHz |
| * Not a mixed channel of x4 and x8 DIMMs |
| */ |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8)); |
| dword |= (0x1 << 12); /* EnRxPadStandby = 1 */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8), dword); |
| } |
| } else { |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8)); |
| dword &= ~(0x1 << 12); /* EnRxPadStandby = 0 */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0010 | (index << 8), dword); |
| } |
| } |
| |
| /* Calculate the Critical Delay Difference for Twrrd */ |
| cdd_twrrd = 0; |
| for (receiver = 0; receiver < 8; receiver += 2) { |
| dimm = (receiver >> 1); |
| |
| if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) |
| continue; |
| |
| read_dqs_write_timing_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); |
| read_dqs_receiver_enable_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); |
| |
| for (lane = 0; lane < lane_count; lane++) { |
| if (current_total_delay_1[lane] > current_total_delay_2[lane]) |
| difference = current_total_delay_1[lane] - current_total_delay_2[lane]; |
| else |
| difference = current_total_delay_2[lane] - current_total_delay_1[lane]; |
| |
| if (difference > cdd_twrrd) |
| cdd_twrrd = difference; |
| } |
| } |
| |
| /* Convert the difference to MEMCLKs */ |
| cdd_twrrd = (((cdd_twrrd + (1 << 6) - 1) >> 6) & 0xf); |
| |
| /* Fam15h BKDG section 2.10.5.5.3 */ |
| if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* LRDIMM */ |
| |
| /* TODO |
| * Implement LRDIMM support |
| * See Fam15h BKDG Rev. 3.14 section 2.10.5.5 |
| */ |
| twrrd = 0xb; |
| } else { |
| max_cdd_we_delta = (((int16_t)cdd_twrrd + 1 - ((int16_t)write_early * 2)) + 1) / 2; |
| if (max_cdd_we_delta < 0) |
| max_cdd_we_delta = 0; |
| if (((uint16_t)max_cdd_we_delta) > write_odt_delay) |
| dword = max_cdd_we_delta; |
| else |
| dword = write_odt_delay; |
| dword += 3; |
| if (latency_difference < dword) { |
| dword -= latency_difference; |
| if (dword < 1) |
| twrrd = 1; |
| else |
| twrrd = dword; |
| } else { |
| twrrd = 1; |
| } |
| } |
| |
| /* Calculate the Critical Delay Difference for TrwtTO */ |
| cdd_trwtto = 0; |
| for (receiver = 0; receiver < 8; receiver += 2) { |
| dimm = (receiver >> 1); |
| |
| if (!mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, receiver)) |
| continue; |
| |
| read_dqs_receiver_enable_control_registers(current_total_delay_1, dev, dct, dimm, index_reg); |
| read_dqs_write_timing_control_registers(current_total_delay_2, dev, dct, dimm, index_reg); |
| |
| for (lane = 0; lane < lane_count; lane++) { |
| if (current_total_delay_1[lane] > current_total_delay_2[lane]) |
| difference = current_total_delay_1[lane] - current_total_delay_2[lane]; |
| else |
| difference = current_total_delay_2[lane] - current_total_delay_1[lane]; |
| |
| if (difference > cdd_trwtto) |
| cdd_trwtto = difference; |
| } |
| } |
| |
| /* Convert the difference to MEMCLKs */ |
| cdd_trwtto = (((cdd_trwtto + (1 << 6) - 1) >> 6) & 0xf); |
| |
| /* Fam15h BKDG section 2.10.5.5.4 */ |
| if (max_dimms_installable == 1) |
| min_value = 0; |
| else |
| min_value = read_odt_delay + buffer_data_delay; |
| cdd_trwtto_we_delta = (((int16_t)cdd_trwtto - 1 + ((int16_t)write_early * 2)) + 1) / 2; |
| cdd_trwtto_we_delta += latency_difference + 3; |
| if (cdd_trwtto_we_delta < 0) |
| cdd_trwtto_we_delta = 0; |
| if ((cdd_trwtto_we_delta) > min_value) |
| trwtto = cdd_trwtto_we_delta; |
| else |
| trwtto = min_value; |
| |
| dword = Get_NB32_DCT(dev, dct, 0xa4); /* DRAM Controller Temperature Throttle */ |
| dword &= ~(0x1 << 11); /* BwCapEn = 0 */ |
| dword &= ~(0x1 << 8); /* ODTSEn = dimm_event_l_pin_support */ |
| dword |= (dimm_event_l_pin_support & 0x1) << 8; |
| Set_NB32_DCT(dev, dct, 0xa4, dword); /* DRAM Controller Temperature Throttle */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x110); /* DRAM Controller Select Low */ |
| dword &= ~(0x1 << 2); /* DctSelIntLvEn = interleave_channels */ |
| dword |= (interleave_channels & 0x1) << 2; |
| dword |= (0x3 << 6); /* DctSelIntLvAddr = 0x3 */ |
| Set_NB32_DCT(dev, dct, 0x110, dword); /* DRAM Controller Select Low */ |
| |
| /* NOTE |
| * ECC-related setup is performed as part of ECCInit_D and must not be located here, |
| * otherwise semi-random lockups will occur due to misconfigured scrubbing hardware! |
| */ |
| |
| /* Fam15h BKDG section 2.10.5.5.2 */ |
| dword = Get_NB32_DCT(dev, dct, 0x214); /* DRAM Timing 4 */ |
| dword &= ~(0xf << 16); /* TwrwrSdSc = 0x1 */ |
| dword |= (0x1 << 16); |
| dword &= ~(0xf << 8); /* TwrwrSdDc = twrwrsddc */ |
| dword |= ((twrwrsddc & 0xf) << 8); |
| dword &= ~(0xf); /* TwrwrDd = twrwrdd */ |
| dword |= (twrwrdd & 0xf); |
| Set_NB32_DCT(dev, dct, 0x214, dword); /* DRAM Timing 4 */ |
| |
| /* Fam15h BKDG section 2.10.5.5.3 */ |
| dword = Get_NB32_DCT(dev, dct, 0x218); /* DRAM Timing 5 */ |
| dword &= ~(0xf << 24); /* TrdrdSdSc = 0x1 */ |
| dword |= (0x1 << 24); |
| dword &= ~(0xf << 16); /* TrdrdSdDc = trdrdsddc */ |
| dword |= ((trdrdsddc & 0xf) << 16); |
| dword &= ~(0xf << 8); /* Twrrd = twrrd */ |
| dword |= ((twrrd & 0xf) << 8); |
| dword &= ~(0xf); /* TrdrdDd = trdrddd */ |
| dword |= (trdrddd & 0xf); |
| Set_NB32_DCT(dev, dct, 0x218, dword); /* DRAM Timing 5 */ |
| |
| /* Fam15h BKDG section 2.10.5.5.4 */ |
| dword = Get_NB32_DCT(dev, dct, 0x21c); /* DRAM Timing 6 */ |
| dword &= ~(0x1f << 8); /* TrwtTO = trwtto */ |
| dword |= ((trwtto & 0x1f) << 8); |
| dword &= ~(0x1f << 16); /* TrwtWB = TrwtTO + 1 */ |
| dword |= ((((dword >> 8) & 0x1f) + 1) << 16); |
| Set_NB32_DCT(dev, dct, 0x21c, dword); /* DRAM Timing 6 */ |
| |
| /* Enable prefetchers */ |
| dword = Get_NB32(dev, 0x11c); /* Memory Controller Configuration High */ |
| dword &= ~(0x1 << 13); /* PrefIoDis = 0 */ |
| dword &= ~(0x1 << 12); /* PrefCpuDis = 0 */ |
| Set_NB32(dev, 0x11c, dword); /* Memory Controller Configuration High */ |
| } |
| } |
| |
| static void exit_training_mode_fam15(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| uint8_t node; |
| uint8_t dct; |
| |
| for (node = 0; node < MAX_NODES_SUPPORTED; node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + node; |
| |
| if (pDCTstat->NodePresent) |
| for (dct = 0; dct < 2; dct++) |
| fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 0); |
| } |
| } |
| |
| static void DQSTiming_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA, uint8_t allow_config_restore) |
| { |
| uint8_t Node; |
| u8 nv_DQSTrainCTL; |
| uint8_t retry_requested; |
| |
| if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) { |
| return; |
| } |
| |
| /* Set initial TCWL offset to zero */ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| uint8_t dct; |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| for (dct = 0; dct < 2; dct++) |
| pDCTstat->tcwl_delay[dct] = 0; |
| } |
| |
| retry_dqs_training_and_levelization: |
| // nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL); |
| nv_DQSTrainCTL = !allow_config_restore; |
| |
| mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA); |
| phyAssistedMemFnceTraining(pMCTstat, pDCTstatA, -1); |
| |
| if (is_fam15h()) { |
| struct DCTStatStruc *pDCTstat; |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| if (pDCTstat->NodePresent) { |
| if (pDCTstat->DIMMValidDCT[0]) |
| InitPhyCompensation(pMCTstat, pDCTstat, 0); |
| if (pDCTstat->DIMMValidDCT[1]) |
| InitPhyCompensation(pMCTstat, pDCTstat, 1); |
| } |
| } |
| } |
| |
| mctHookBeforeAnyTraining(pMCTstat, pDCTstatA); |
| if (!is_fam15h()) { |
| /* TODO: should be in mctHookBeforeAnyTraining */ |
| _WRMSR(0x26C, 0x04040404, 0x04040404); |
| _WRMSR(0x26D, 0x04040404, 0x04040404); |
| _WRMSR(0x26E, 0x04040404, 0x04040404); |
| _WRMSR(0x26F, 0x04040404, 0x04040404); |
| } |
| |
| if (nv_DQSTrainCTL) { |
| mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass); |
| |
| if (is_fam15h()) { |
| /* Receiver Enable Training Pass 1 */ |
| TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass); |
| } |
| |
| mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass); |
| |
| if (is_fam15h()) { |
| /* Receiver Enable Training Pass 2 */ |
| // TrainReceiverEn_D(pMCTstat, pDCTstatA, SecondPass); |
| |
| /* TODO: |
| * Determine why running TrainReceiverEn_D in SecondPass |
| * mode yields less stable training values than when run |
| * in FirstPass mode as in the HACK below. |
| */ |
| TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass); |
| } else { |
| TrainReceiverEn_D(pMCTstat, pDCTstatA, FirstPass); |
| } |
| |
| mct_TrainDQSPos_D(pMCTstat, pDCTstatA); |
| |
| /* Determine if DQS training requested a retrain attempt */ |
| retry_requested = 0; |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| if (pDCTstat->TrainErrors & (1 << SB_FatalError)) { |
| printk(BIOS_ERR, "DIMM training FAILED! Restarting system..."); |
| soft_reset(); |
| } |
| if (pDCTstat->TrainErrors & (1 << SB_RetryConfigTrain)) { |
| retry_requested = 1; |
| |
| /* Clear previous errors */ |
| pDCTstat->TrainErrors &= ~(1 << SB_RetryConfigTrain); |
| pDCTstat->TrainErrors &= ~(1 << SB_NODQSPOS); |
| pDCTstat->ErrStatus &= ~(1 << SB_RetryConfigTrain); |
| pDCTstat->ErrStatus &= ~(1 << SB_NODQSPOS); |
| } |
| } |
| } |
| |
| /* Retry training and levelization if requested */ |
| if (retry_requested) { |
| printk(BIOS_DEBUG, "%s: Restarting training on algorithm request\n", __func__); |
| /* Reset frequency to minimum */ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| if (pDCTstat->NodePresent) { |
| uint8_t original_target_freq = pDCTstat->TargetFreq; |
| uint8_t original_auto_speed = pDCTstat->DIMMAutoSpeed; |
| pDCTstat->TargetFreq = mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK)); |
| pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq; |
| SetTargetFreq(pMCTstat, pDCTstatA, Node); |
| pDCTstat->TargetFreq = original_target_freq; |
| pDCTstat->DIMMAutoSpeed = original_auto_speed; |
| } |
| } |
| /* Apply any DIMM timing changes */ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| if (pDCTstat->NodePresent) { |
| AutoCycTiming_D(pMCTstat, pDCTstat, 0); |
| if (!pDCTstat->GangedMode) |
| if (pDCTstat->DIMMValidDCT[1] > 0) |
| AutoCycTiming_D(pMCTstat, pDCTstat, 1); |
| } |
| } |
| goto retry_dqs_training_and_levelization; |
| } |
| |
| TrainMaxRdLatency_En_D(pMCTstat, pDCTstatA); |
| |
| if (is_fam15h()) |
| exit_training_mode_fam15(pMCTstat, pDCTstatA); |
| else |
| mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA); |
| } else { |
| mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass); |
| |
| mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass); |
| |
| #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) |
| printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DIMM training configuration from NVRAM\n"); |
| if (restore_mct_information_from_nvram(1) != 0) |
| printk(BIOS_CRIT, "%s: ERROR: Unable to restore DCT configuration from NVRAM\n", __func__); |
| #endif |
| |
| if (is_fam15h()) |
| exit_training_mode_fam15(pMCTstat, pDCTstatA); |
| |
| pMCTstat->GStatus |= 1 << GSB_ConfigRestored; |
| } |
| |
| if (is_fam15h()) { |
| struct DCTStatStruc *pDCTstat; |
| |
| /* Switch DCT control register to DCT 0 per Erratum 505 */ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| if (pDCTstat->NodePresent) { |
| fam15h_switch_dct(pDCTstat->dev_map, 0); |
| } |
| } |
| } |
| |
| /* FIXME - currently uses calculated value TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */ |
| mctHookAfterAnyTraining(); |
| } |
| |
| static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| u8 Node, Receiver, Channel, Dir, DIMM; |
| u32 dev; |
| u32 index_reg; |
| u32 reg; |
| u32 index; |
| u32 val; |
| u8 ByteLane; |
| u8 txdqs; |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->DCTSysLimit) { |
| dev = pDCTstat->dev_dct; |
| for (Channel = 0;Channel < 2; Channel++) { |
| /* there are four receiver pairs, |
| loosely associated with chipselects.*/ |
| index_reg = 0x98; |
| for (Receiver = 0; Receiver < 8; Receiver += 2) { |
| /* Set Receiver Enable Values */ |
| mct_SetRcvrEnDly_D(pDCTstat, |
| 0, /* RcvrEnDly */ |
| 1, /* FinalValue, From stack */ |
| Channel, |
| Receiver, |
| dev, index_reg, |
| (Receiver >> 1) * 3 + 0x10, /* Addl_Index */ |
| 2); /* Pass Second Pass ? */ |
| /* Restore Write levelization training data */ |
| for (ByteLane = 0; ByteLane < 9; ByteLane ++) { |
| txdqs = pDCTstat->CH_D_B_TxDqs[Channel][Receiver >> 1][ByteLane]; |
| index = Table_DQSRcvEn_Offset[ByteLane >> 1]; |
| index += (Receiver >> 1) * 3 + 0x10 + 0x20; /* Addl_Index */ |
| val = Get_NB32_index_wait_DCT(dev, Channel, 0x98, index); |
| if (ByteLane & 1) { /* odd byte lane */ |
| val &= ~(0xFF << 16); |
| val |= txdqs << 16; |
| } else { |
| val &= ~0xFF; |
| val |= txdqs; |
| } |
| Set_NB32_index_wait_DCT(dev, Channel, 0x98, index, val); |
| } |
| } |
| } |
| for (Channel = 0; Channel < 2; Channel++) { |
| SetEccDQSRcvrEn_D(pDCTstat, Channel); |
| } |
| |
| for (Channel = 0; Channel < 2; Channel++) { |
| u8 *p; |
| index_reg = 0x98; |
| |
| /* NOTE: |
| * when 400, 533, 667, it will support dimm0/1/2/3, |
| * and set conf for dimm0, hw will copy to dimm1/2/3 |
| * set for dimm1, hw will copy to dimm3 |
| * Rev A/B only support DIMM0/1 when 800MHz and above |
| * + 0x100 to next dimm |
| * Rev C support DIMM0/1/2/3 when 800MHz and above |
| * + 0x100 to next dimm |
| */ |
| for (DIMM = 0; DIMM < 4; DIMM++) { |
| if (DIMM == 0) { |
| index = 0; /* CHA Write Data Timing Low */ |
| } else { |
| if (pDCTstat->Speed >= mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) { |
| index = 0x100 * DIMM; |
| } else { |
| break; |
| } |
| } |
| for (Dir = 0; Dir < 2; Dir++) {/* RD/WR */ |
| p = pDCTstat->CH_D_DIR_B_DQS[Channel][DIMM][Dir]; |
| val = stream_to_int(p); /* CHA Read Data Timing High */ |
| Set_NB32_index_wait_DCT(dev, Channel, index_reg, index+1, val); |
| val = stream_to_int(p+4); /* CHA Write Data Timing High */ |
| Set_NB32_index_wait_DCT(dev, Channel, index_reg, index+2, val); |
| val = *(p+8); /* CHA Write ECC Timing */ |
| Set_NB32_index_wait_DCT(dev, Channel, index_reg, index+3, val); |
| index += 4; |
| } |
| } |
| } |
| |
| for (Channel = 0; Channel < 2; Channel++) { |
| reg = 0x78; |
| val = Get_NB32_DCT(dev, Channel, reg); |
| val &= ~(0x3ff<<22); |
| val |= ((u32) pDCTstat->CH_MaxRdLat[Channel][0] << 22); |
| val &= ~(1<<DqsRcvEnTrain); |
| Set_NB32_DCT(dev, Channel, reg, val); /* program MaxRdLatency to correspond with current delay*/ |
| } |
| } |
| } |
| } |
| |
| static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| u8 Node; |
| u32 NextBase, BottomIO; |
| u8 _MemHoleRemap, DramHoleBase, DramHoleOffset; |
| u32 HoleSize, DramSelBaseAddr; |
| |
| u32 val; |
| u32 base; |
| u32 limit; |
| u32 dev, devx; |
| struct DCTStatStruc *pDCTstat; |
| |
| _MemHoleRemap = mctGet_NVbits(NV_MemHole); |
| |
| if (pMCTstat->HoleBase == 0) { |
| DramHoleBase = mctGet_NVbits(NV_BottomIO); |
| } else { |
| DramHoleBase = pMCTstat->HoleBase >> (24-8); |
| } |
| |
| BottomIO = DramHoleBase << (24-8); |
| |
| NextBase = 0; |
| pDCTstat = pDCTstatA + 0; |
| dev = pDCTstat->dev_map; |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| devx = pDCTstat->dev_map; |
| DramSelBaseAddr = 0; |
| if (!pDCTstat->GangedMode) { |
| DramSelBaseAddr = pDCTstat->NodeSysLimit - pDCTstat->DCTSysLimit; |
| /*In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */ |
| val = pDCTstat->NodeSysLimit; |
| if ((val & 0xFF) == 0xFE) { |
| DramSelBaseAddr++; |
| val++; |
| } |
| pDCTstat->DCTSysLimit = val; |
| } |
| |
| base = pDCTstat->DCTSysBase; |
| limit = pDCTstat->DCTSysLimit; |
| if (limit > base) { |
| base += NextBase; |
| limit += NextBase; |
| DramSelBaseAddr += NextBase; |
| printk(BIOS_DEBUG, " Node: %02x base: %02x limit: %02x BottomIO: %02x\n", Node, base, limit, BottomIO); |
| |
| if (_MemHoleRemap) { |
| if ((base < BottomIO) && (limit >= BottomIO)) { |
| /* HW Dram Remap */ |
| pDCTstat->Status |= 1 << SB_HWHole; |
| pMCTstat->GStatus |= 1 << GSB_HWHole; |
| pDCTstat->DCTSysBase = base; |
| pDCTstat->DCTSysLimit = limit; |
| pDCTstat->DCTHoleBase = BottomIO; |
| pMCTstat->HoleBase = BottomIO; |
| HoleSize = _4GB_RJ8 - BottomIO; /* HoleSize[39:8] */ |
| if ((DramSelBaseAddr > 0) && (DramSelBaseAddr < BottomIO)) |
| base = DramSelBaseAddr; |
| val = ((base + HoleSize) >> (24-8)) & 0xFF; |
| DramHoleOffset = val; |
| val <<= 8; /* shl 16, rol 24 */ |
| val |= DramHoleBase << 24; |
| val |= 1 << DramHoleValid; |
| Set_NB32(devx, 0xF0, val); /* Dram Hole Address Reg */ |
| pDCTstat->DCTSysLimit += HoleSize; |
| base = pDCTstat->DCTSysBase; |
| limit = pDCTstat->DCTSysLimit; |
| } else if (base == BottomIO) { |
| /* SW Node Hoist */ |
| pMCTstat->GStatus |= 1<<GSB_SpIntRemapHole; |
| pDCTstat->Status |= 1<<SB_SWNodeHole; |
| pMCTstat->GStatus |= 1<<GSB_SoftHole; |
| pMCTstat->HoleBase = base; |
| limit -= base; |
| base = _4GB_RJ8; |
| limit += base; |
| pDCTstat->DCTSysBase = base; |
| pDCTstat->DCTSysLimit = limit; |
| } else { |
| /* No Remapping. Normal Contiguous mapping */ |
| pDCTstat->DCTSysBase = base; |
| pDCTstat->DCTSysLimit = limit; |
| } |
| } else { |
| /*No Remapping. Normal Contiguous mapping*/ |
| pDCTstat->DCTSysBase = base; |
| pDCTstat->DCTSysLimit = limit; |
| } |
| base |= 3; /* set WE,RE fields*/ |
| pMCTstat->SysLimit = limit; |
| } |
| Set_NB32(dev, 0x40 + (Node << 3), base); /* [Node] + Dram Base 0 */ |
| |
| val = limit & 0xFFFF0000; |
| val |= Node; |
| Set_NB32(dev, 0x44 + (Node << 3), val); /* set DstNode */ |
| |
| printk(BIOS_DEBUG, " Node: %02x base: %02x limit: %02x\n", Node, base, limit); |
| limit = pDCTstat->DCTSysLimit; |
| if (limit) { |
| NextBase = (limit & 0xFFFF0000) + 0x10000; |
| } |
| } |
| |
| /* Copy dram map from Node 0 to Node 1-7 */ |
| for (Node = 1; Node < MAX_NODES_SUPPORTED; Node++) { |
| u32 reg; |
| pDCTstat = pDCTstatA + Node; |
| devx = pDCTstat->dev_map; |
| |
| if (pDCTstat->NodePresent) { |
| printk(BIOS_DEBUG, " Copy dram map from Node 0 to Node %02x\n", Node); |
| reg = 0x40; /*Dram Base 0*/ |
| do { |
| val = Get_NB32(dev, reg); |
| Set_NB32(devx, reg, val); |
| reg += 4; |
| } while (reg < 0x80); |
| } else { |
| break; /* stop at first absent Node */ |
| } |
| } |
| |
| /*Copy dram map to F1x120/124*/ |
| mct_HTMemMapExt(pMCTstat, pDCTstatA); |
| } |
| |
| static void MCTMemClr_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| |
| /* Initiates a memory clear operation for all node. The mem clr |
| * is done in parallel. After the memclr is complete, all processors |
| * status are checked to ensure that memclr has completed. |
| */ |
| u8 Node; |
| uint32_t dword; |
| struct DCTStatStruc *pDCTstat; |
| |
| if (!mctGet_NVbits(NV_DQSTrainCTL)) { |
| /* FIXME: callback to wrapper: mctDoWarmResetMemClr_D */ |
| } else { /* NV_DQSTrainCTL == 1 */ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| DCTMemClr_Init_D(pMCTstat, pDCTstat); |
| } |
| } |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| DCTMemClr_Sync_D(pMCTstat, pDCTstat); |
| } |
| } |
| } |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| |
| /* Enable prefetchers */ |
| dword = Get_NB32(pDCTstat->dev_dct, 0x11c); /* Memory Controller Configuration High */ |
| dword &= ~(0x1 << 13); /* PrefIoDis = 0 */ |
| dword &= ~(0x1 << 12); /* PrefCpuDis = 0 */ |
| Set_NB32(pDCTstat->dev_dct, 0x11c, dword); /* Memory Controller Configuration High */ |
| } |
| } |
| |
| static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 val; |
| u32 dev; |
| uint32_t dword; |
| |
| /* Initiates a memory clear operation on one node */ |
| if (pDCTstat->DCTSysLimit) { |
| dev = pDCTstat->dev_dct; |
| |
| /* Disable prefetchers */ |
| dword = Get_NB32(dev, 0x11c); /* Memory Controller Configuration High */ |
| dword |= 0x1 << 13; /* PrefIoDis = 1 */ |
| dword |= 0x1 << 12; /* PrefCpuDis = 1 */ |
| Set_NB32(dev, 0x11c, dword); /* Memory Controller Configuration High */ |
| |
| do { |
| val = Get_NB32(dev, 0x110); |
| } while (val & (1 << MemClrBusy)); |
| |
| val |= (1 << MemClrInit); |
| Set_NB32(dev, 0x110, val); |
| } |
| } |
| |
| static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| uint32_t dword; |
| uint32_t dev = pDCTstat->dev_dct; |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| /* Ensure that a memory clear operation has completed on one node */ |
| if (pDCTstat->DCTSysLimit) { |
| printk(BIOS_DEBUG, "%s: Waiting for memory clear to complete", __func__); |
| do { |
| dword = Get_NB32(dev, 0x110); |
| |
| printk(BIOS_DEBUG, "."); |
| } while (dword & (1 << MemClrBusy)); |
| |
| printk(BIOS_DEBUG, "\n"); |
| do { |
| printk(BIOS_DEBUG, "."); |
| dword = Get_NB32(dev, 0x110); |
| } while (!(dword & (1 << Dr_MemClrStatus))); |
| printk(BIOS_DEBUG, "\n"); |
| } |
| |
| /* Enable prefetchers */ |
| dword = Get_NB32(dev, 0x11c); /* Memory Controller Configuration High */ |
| dword &= ~(0x1 << 13); /* PrefIoDis = 0 */ |
| dword &= ~(0x1 << 12); /* PrefCpuDis = 0 */ |
| Set_NB32(dev, 0x11c, dword); /* Memory Controller Configuration High */ |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static u8 NodePresent_D(u8 Node) |
| { |
| /* |
| * Determine if a single Hammer Node exists within the network. |
| */ |
| u32 dev; |
| u32 val; |
| u32 dword; |
| u8 ret = 0; |
| |
| dev = PA_HOST(Node); /*test device/vendor id at host bridge */ |
| val = Get_NB32(dev, 0); |
| dword = mct_NodePresent_D(); /* FIXME: BOZO -11001022h rev for F */ |
| if (val == dword) { /* AMD Hammer Family CPU HT Configuration */ |
| if (oemNodePresent_D(Node, &ret)) |
| goto finish; |
| /* Node ID register */ |
| val = Get_NB32(dev, 0x60); |
| val &= 0x07; |
| dword = Node; |
| if (val == dword) /* current nodeID = requested nodeID ? */ |
| ret = 1; |
| } |
| finish: |
| return ret; |
| } |
| |
| static void DCTPreInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| /* |
| * Run DCT pre-initialization tasks |
| */ |
| uint32_t dword; |
| |
| /* Reset DCT registers */ |
| ClearDCT_D(pMCTstat, pDCTstat, dct); |
| pDCTstat->stopDCT[dct] = 1; /* preload flag with 'disable' */ |
| |
| if (!is_fam15h()) { |
| /* Enable DDR3 support */ |
| dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94); |
| dword |= 1 << Ddr3Mode; |
| Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword); |
| } |
| |
| /* Read the SPD information into the data structures */ |
| if (mct_DIMMPresence(pMCTstat, pDCTstat, dct) < SC_StopError) { |
| printk(BIOS_DEBUG, "\t\tDCTPreInit_D: mct_DIMMPresence Done\n"); |
| } |
| } |
| |
| static void DCTInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| /* |
| * Initialize DRAM on single Athlon 64/Opteron Node. |
| */ |
| uint32_t dword; |
| |
| if (!is_fam15h()) { |
| /* (Re)-enable DDR3 support */ |
| dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94); |
| dword |= 1 << Ddr3Mode; |
| Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword); |
| } |
| |
| if (mct_SPDCalcWidth(pMCTstat, pDCTstat, dct) < SC_StopError) { |
| printk(BIOS_DEBUG, "\t\tDCTInit_D: mct_SPDCalcWidth Done\n"); |
| if (AutoCycTiming_D(pMCTstat, pDCTstat, dct) < SC_StopError) { |
| printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoCycTiming_D Done\n"); |
| |
| /* SkewMemClk must be set before MemClkFreqVal is set |
| * This relies on DCTInit_D being called for DCT 1 after |
| * it has already been called for DCT 0... |
| */ |
| if (is_fam15h()) { |
| /* Set memory clock skew if needed */ |
| if (dct == 1) { |
| if (!pDCTstat->stopDCT[0]) { |
| printk(BIOS_DEBUG, "\t\tDCTInit_D: enabling intra-channel clock skew\n"); |
| dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe00a); |
| dword |= (0x1 << 4); /* SkewMemClk = 1 */ |
| Set_NB32_index_wait_DCT(pDCTstat->dev_dct, 0, 0x98, 0x0d0fe00a, dword); |
| } |
| } |
| } |
| |
| if (AutoConfig_D(pMCTstat, pDCTstat, dct) < SC_StopError) { |
| printk(BIOS_DEBUG, "\t\tDCTInit_D: AutoConfig_D Done\n"); |
| if (PlatformSpec_D(pMCTstat, pDCTstat, dct) < SC_StopError) { |
| printk(BIOS_DEBUG, "\t\tDCTInit_D: PlatformSpec_D Done\n"); |
| pDCTstat->stopDCT[dct] = 0; |
| } |
| } |
| } |
| } |
| } |
| |
| static void DCTFinalInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| uint32_t dword; |
| |
| /* Finalize DRAM init on a single node */ |
| if (!pDCTstat->stopDCT[dct]) { |
| if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) { |
| printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D Start\n"); |
| StartupDCT_D(pMCTstat, pDCTstat, dct); |
| printk(BIOS_DEBUG, "\t\tDCTFinalInit_D: StartupDCT_D Done\n"); |
| } |
| } |
| |
| if (pDCTstat->stopDCT[dct]) { |
| dword = 1 << DisDramInterface; |
| Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x94, dword); |
| |
| dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x90); |
| dword &= ~(1 << ParEn); |
| Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x90, dword); |
| |
| /* To maximize power savings when DisDramInterface = 1b, |
| * all of the MemClkDis bits should also be set. |
| */ |
| Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x88, 0xff000000); |
| } else { |
| mct_EnDllShutdownSR(pMCTstat, pDCTstat, dct); |
| } |
| } |
| |
| static void SyncDCTsReady_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| /* Wait (and block further access to dram) for all DCTs to be ready, |
| * by polling all InitDram bits and waiting for possible memory clear |
| * operations to be complete. Read MemClkFreqVal bit to see if |
| * the DIMMs are present in this node. |
| */ |
| u8 Node; |
| u32 val; |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| mct_SyncDCTsReady(pDCTstat); |
| } |
| |
| if (!is_fam15h()) { |
| /* v6.1.3 */ |
| /* re-enable phy compensation engine when dram init is completed on all nodes. */ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| if (pDCTstat->NodePresent) { |
| if (pDCTstat->DIMMValidDCT[0] > 0 || pDCTstat->DIMMValidDCT[1] > 0) { |
| /* re-enable phy compensation engine when dram init on both DCTs is completed. */ |
| val = Get_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8); |
| val &= ~(1 << DisAutoComp); |
| Set_NB32_index_wait(pDCTstat->dev_dct, 0x98, 0x8, val); |
| } |
| } |
| } |
| } |
| |
| /* wait 750us before any memory access can be made. */ |
| mct_Wait(15000); |
| } |
| |
| static void StartupDCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| /* Read MemClkFreqVal bit to see if the DIMMs are present in this node. |
| * If the DIMMs are present then set the DRAM Enable bit for this node. |
| * |
| * Setting dram init starts up the DCT state machine, initializes the |
| * dram devices with MRS commands, and kicks off any |
| * HW memory clear process that the chip is capable of. The sooner |
| * that dram init is set for all nodes, the faster the memory system |
| * initialization can complete. Thus, the init loop is unrolled into |
| * two loops so as to start the processes for non BSP nodes sooner. |
| * This procedure will not wait for the process to finish. |
| * Synchronization is handled elsewhere. |
| */ |
| u32 val; |
| u32 dev; |
| |
| dev = pDCTstat->dev_dct; |
| val = Get_NB32_DCT(dev, dct, 0x94); |
| if (val & (1<<MemClkFreqVal)) { |
| mctHookBeforeDramInit(); /* generalized Hook */ |
| if (!(pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW))) |
| mct_DramInit(pMCTstat, pDCTstat, dct); |
| AfterDramInit_D(pDCTstat, dct); |
| mctHookAfterDramInit(); /* generalized Hook*/ |
| } |
| } |
| |
| static void ClearDCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 reg_end; |
| u32 dev = pDCTstat->dev_dct; |
| u32 reg = 0x40; |
| u32 val = 0; |
| |
| if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) { |
| reg_end = 0x78; |
| } else { |
| reg_end = 0xA4; |
| } |
| |
| while (reg < reg_end) { |
| if ((reg & 0xFF) == 0x84) { |
| if (is_fam15h()) { |
| val = Get_NB32_DCT(dev, dct, reg); |
| val &= ~(0x1 << 23); /* Clear PchgPDModeSel */ |
| val &= ~0x3; /* Clear BurstCtrl */ |
| } |
| } |
| if ((reg & 0xFF) == 0x90) { |
| if (pDCTstat->LogicalCPUID & AMD_DR_Dx) { |
| val = Get_NB32_DCT(dev, dct, reg); /* get DRAMConfigLow */ |
| val |= 0x08000000; /* preserve value of DisDllShutdownSR for only Rev.D */ |
| } |
| } |
| Set_NB32_DCT(dev, dct, reg, val); |
| val = 0; |
| reg += 4; |
| } |
| |
| val = 0; |
| dev = pDCTstat->dev_map; |
| reg = 0xF0; |
| Set_NB32(dev, reg, val); |
| } |
| |
| static void SPD2ndTiming(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 i; |
| u16 Twr, Trtp; |
| u16 Trp, Trrd, Trcd, Tras, Trc; |
| u8 Trfc[4]; |
| u16 Tfaw; |
| u16 Tcwl; /* Fam15h only */ |
| u32 DramTimingLo, DramTimingHi; |
| u8 tCK16x; |
| u16 Twtr; |
| uint8_t Etr[2]; |
| u8 LDIMM; |
| u8 MTB16x; |
| u8 byte; |
| u32 dword; |
| u32 dev; |
| u32 val; |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| /* Gather all DIMM mini-max values for cycle timing data */ |
| Trp = 0; |
| Trrd = 0; |
| Trcd = 0; |
| Trtp = 0; |
| Tras = 0; |
| Trc = 0; |
| Twr = 0; |
| Twtr = 0; |
| for (i = 0; i < 2; i++) |
| Etr[i] = 0; |
| for (i = 0; i < 4; i++) |
| Trfc[i] = 0; |
| Tfaw = 0; |
| |
| for (i = 0; i< MAX_DIMMS_SUPPORTED; i++) { |
| LDIMM = i >> 1; |
| if (pDCTstat->DIMMValid & (1 << i)) { |
| val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDivisor]; /* MTB = Dividend/Divisor */ |
| MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDividend] & 0xff) << 4); |
| MTB16x /= val; /* transfer to MTB*16 */ |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRPmin]; |
| val = byte * MTB16x; |
| if (Trp < val) |
| Trp = val; |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRRDmin]; |
| val = byte * MTB16x; |
| if (Trrd < val) |
| Trrd = val; |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRCDmin]; |
| val = byte * MTB16x; |
| if (Trcd < val) |
| Trcd = val; |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRTPmin]; |
| val = byte * MTB16x; |
| if (Trtp < val) |
| Trtp = val; |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tWRmin]; |
| val = byte * MTB16x; |
| if (Twr < val) |
| Twr = val; |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tWTRmin]; |
| val = byte * MTB16x; |
| if (Twtr < val) |
| Twtr = val; |
| |
| val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Upper_tRAS_tRC] & 0xff; |
| val >>= 4; |
| val <<= 8; |
| val |= pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRCmin] & 0xff; |
| val *= MTB16x; |
| if (Trc < val) |
| Trc = val; |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Density] & 0xf; |
| if (Trfc[LDIMM] < byte) |
| Trfc[LDIMM] = byte; |
| |
| val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Upper_tRAS_tRC] & 0xf; |
| val <<= 8; |
| val |= (pDCTstat->spd_data.spd_bytes[dct + i][SPD_tRASmin] & 0xff); |
| val *= MTB16x; |
| if (Tras < val) |
| Tras = val; |
| |
| val = pDCTstat->spd_data.spd_bytes[dct + i][SPD_Upper_tFAW] & 0xf; |
| val <<= 8; |
| val |= pDCTstat->spd_data.spd_bytes[dct + i][SPD_tFAWmin] & 0xff; |
| val *= MTB16x; |
| if (Tfaw < val) |
| Tfaw = val; |
| |
| /* Determine if the DIMMs on this channel support 95°C ETR */ |
| if (pDCTstat->spd_data.spd_bytes[dct + i][SPD_Thermal] & 0x1) |
| Etr[dct] = 1; |
| } /* Dimm Present */ |
| } |
| |
| /* Convert DRAM CycleTiming values and store into DCT structure */ |
| byte = pDCTstat->DIMMAutoSpeed; |
| if (is_fam15h()) { |
| if (byte == 0x16) |
| tCK16x = 17; |
| else if (byte == 0x12) |
| tCK16x = 20; |
| else if (byte == 0xe) |
| tCK16x = 24; |
| else if (byte == 0xa) |
| tCK16x = 30; |
| else if (byte == 0x6) |
| tCK16x = 40; |
| else |
| tCK16x = 48; |
| } else { |
| if (byte == 7) |
| tCK16x = 20; |
| else if (byte == 6) |
| tCK16x = 24; |
| else if (byte == 5) |
| tCK16x = 30; |
| else |
| tCK16x = 40; |
| } |
| |
| /* Notes: |
| 1. All secondary time values given in SPDs are in binary with units of ns. |
| 2. Some time values are scaled by 16, in order to have least count of 0.25 ns |
| (more accuracy). JEDEC SPD spec. shows which ones are x1 and x4. |
| 3. Internally to this SW, cycle time, tCK16x, is scaled by 16 to match time values |
| */ |
| |
| /* Tras */ |
| pDCTstat->DIMMTras = (u16)Tras; |
| val = Tras / tCK16x; |
| if (Tras % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TrasT) |
| val = Min_TrasT; |
| else if (val > Max_TrasT) |
| val = Max_TrasT; |
| pDCTstat->Tras = val; |
| |
| /* Trp */ |
| pDCTstat->DIMMTrp = Trp; |
| val = Trp / tCK16x; |
| if (Trp % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TrpT) |
| val = Min_TrpT; |
| else if (val > Max_TrpT) |
| val = Max_TrpT; |
| pDCTstat->Trp = val; |
| |
| /* Trrd */ |
| pDCTstat->DIMMTrrd = Trrd; |
| val = Trrd / tCK16x; |
| if (Trrd % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TrrdT) |
| val = Min_TrrdT; |
| else if (val > Max_TrrdT) |
| val = Max_TrrdT; |
| pDCTstat->Trrd = val; |
| |
| /* Trcd */ |
| pDCTstat->DIMMTrcd = Trcd; |
| val = Trcd / tCK16x; |
| if (Trcd % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TrcdT) |
| val = Min_TrcdT; |
| else if (val > Max_TrcdT) |
| val = Max_TrcdT; |
| pDCTstat->Trcd = val; |
| |
| /* Trc */ |
| pDCTstat->DIMMTrc = Trc; |
| val = Trc / tCK16x; |
| if (Trc % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TrcT) |
| val = Min_TrcT; |
| else if (val > Max_TrcT) |
| val = Max_TrcT; |
| pDCTstat->Trc = val; |
| |
| /* Trtp */ |
| pDCTstat->DIMMTrtp = Trtp; |
| val = Trtp / tCK16x; |
| if (Trtp % tCK16x) { |
| val ++; |
| } |
| if (val < Min_TrtpT) |
| val = Min_TrtpT; |
| else if (val > Max_TrtpT) |
| val = Max_TrtpT; |
| pDCTstat->Trtp = val; |
| |
| /* Twr */ |
| pDCTstat->DIMMTwr = Twr; |
| val = Twr / tCK16x; |
| if (Twr % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TwrT) |
| val = Min_TwrT; |
| else if (val > Max_TwrT) |
| val = Max_TwrT; |
| pDCTstat->Twr = val; |
| |
| /* Twtr */ |
| pDCTstat->DIMMTwtr = Twtr; |
| val = Twtr / tCK16x; |
| if (Twtr % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TwtrT) |
| val = Min_TwtrT; |
| else if (val > Max_TwtrT) |
| val = Max_TwtrT; |
| pDCTstat->Twtr = val; |
| |
| /* Trfc0-Trfc3 */ |
| for (i = 0; i < 4; i++) |
| pDCTstat->Trfc[i] = Trfc[i]; |
| |
| /* Tfaw */ |
| pDCTstat->DIMMTfaw = Tfaw; |
| val = Tfaw / tCK16x; |
| if (Tfaw % tCK16x) { /* round up number of busclocks */ |
| val++; |
| } |
| if (val < Min_TfawT) |
| val = Min_TfawT; |
| else if (val > Max_TfawT) |
| val = Max_TfawT; |
| pDCTstat->Tfaw = val; |
| |
| mctAdjustAutoCycTmg_D(); |
| |
| if (is_fam15h()) { |
| /* Compute Tcwl (Fam15h BKDG v3.14 Table 203) */ |
| if (pDCTstat->Speed <= 0x6) |
| Tcwl = 0x5; |
| else if (pDCTstat->Speed == 0xa) |
| Tcwl = 0x6; |
| else if (pDCTstat->Speed == 0xe) |
| Tcwl = 0x7; |
| else if (pDCTstat->Speed == 0x12) |
| Tcwl = 0x8; |
| else if (pDCTstat->Speed == 0x16) |
| Tcwl = 0x9; |
| else |
| Tcwl = 0x5; /* Power-on default */ |
| |
| /* Apply offset */ |
| Tcwl += pDCTstat->tcwl_delay[dct]; |
| } |
| |
| /* Program DRAM Timing values */ |
| if (is_fam15h()) { |
| dev = pDCTstat->dev_dct; |
| |
| dword = Get_NB32_DCT(dev, dct, 0x8c); /* DRAM Timing High */ |
| if (Etr[dct]) |
| val = 3; /* Tref = 3.9us */ |
| else |
| val = 2; /* Tref = 7.8us */ |
| dword &= ~(0x3 << 16); |
| dword |= (val & 0x3) << 16; |
| Set_NB32_DCT(dev, dct, 0x8c, dword); /* DRAM Timing High */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x200); /* DRAM Timing 0 */ |
| dword &= ~(0x3f1f1f1f); |
| dword |= (pDCTstat->Tras & 0x3f) << 24; /* Tras */ |
| val = pDCTstat->Trp; |
| val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val); |
| dword |= (val & 0x1f) << 16; /* Trp */ |
| dword |= (pDCTstat->Trcd & 0x1f) << 8; /* Trcd */ |
| dword |= (pDCTstat->CASL & 0x1f); /* Tcl */ |
| Set_NB32_DCT(dev, dct, 0x200, dword); /* DRAM Timing 0 */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x204); /* DRAM Timing 1 */ |
| dword &= ~(0x0f3f0f3f); |
| dword |= (pDCTstat->Trtp & 0xf) << 24; /* Trtp */ |
| if (pDCTstat->Tfaw != 0) { |
| val = pDCTstat->Tfaw; |
| val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val); |
| if ((val > 0x5) && (val < 0x2b)) |
| dword |= (val & 0x3f) << 16; /* FourActWindow */ |
| } |
| dword |= (pDCTstat->Trrd & 0xf) << 8; /* Trrd */ |
| dword |= (pDCTstat->Trc & 0x3f); /* Trc */ |
| Set_NB32_DCT(dev, dct, 0x204, dword); /* DRAM Timing 1 */ |
| |
| /* Trfc0-Trfc3 */ |
| for (i = 0; i < 4; i++) |
| if (pDCTstat->Trfc[i] == 0x0) |
| pDCTstat->Trfc[i] = 0x1; |
| dword = Get_NB32_DCT(dev, dct, 0x208); /* DRAM Timing 2 */ |
| dword &= ~(0x07070707); |
| dword |= (pDCTstat->Trfc[3] & 0x7) << 24; /* Trfc3 */ |
| dword |= (pDCTstat->Trfc[2] & 0x7) << 16; /* Trfc2 */ |
| dword |= (pDCTstat->Trfc[1] & 0x7) << 8; /* Trfc1 */ |
| dword |= (pDCTstat->Trfc[0] & 0x7); /* Trfc0 */ |
| Set_NB32_DCT(dev, dct, 0x208, dword); /* DRAM Timing 2 */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x20c); /* DRAM Timing 3 */ |
| dword &= ~(0x00000f00); |
| dword |= (pDCTstat->Twtr & 0xf) << 8; /* Twtr */ |
| dword &= ~(0x0000001f); |
| dword |= (Tcwl & 0x1f); /* Tcwl */ |
| Set_NB32_DCT(dev, dct, 0x20c, dword); /* DRAM Timing 3 */ |
| |
| dword = Get_NB32_DCT(dev, dct, 0x22c); /* DRAM Timing 10 */ |
| dword &= ~(0x0000001f); |
| dword |= (pDCTstat->Twr & 0x1f); /* Twr */ |
| Set_NB32_DCT(dev, dct, 0x22c, dword); /* DRAM Timing 10 */ |
| |
| if (pDCTstat->Speed > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) { |
| /* Enable phy-assisted training mode */ |
| fam15EnableTrainingMode(pMCTstat, pDCTstat, dct, 1); |
| } |
| |
| /* Other setup (not training specific) */ |
| dword = Get_NB32_DCT(dev, dct, 0x90); /* DRAM Configuration Low */ |
| dword &= ~(0x1 << 23); /* ForceAutoPchg = 0 */ |
| dword &= ~(0x1 << 20); /* DynPageCloseEn = 0 */ |
| Set_NB32_DCT(dev, dct, 0x90, dword); /* DRAM Configuration Low */ |
| |
| Set_NB32_DCT(dev, dct, 0x228, 0x14141414); /* DRAM Timing 9 */ |
| } else { |
| DramTimingLo = 0; /* Dram Timing Low init */ |
| val = pDCTstat->CASL - 4; /* pDCTstat.CASL to reg. definition */ |
| DramTimingLo |= val; |
| |
| val = pDCTstat->Trcd - Bias_TrcdT; |
| DramTimingLo |= val<<4; |
| |
| val = pDCTstat->Trp - Bias_TrpT; |
| val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val); |
| DramTimingLo |= val<<7; |
| |
| val = pDCTstat->Trtp - Bias_TrtpT; |
| DramTimingLo |= val<<10; |
| |
| val = pDCTstat->Tras - Bias_TrasT; |
| DramTimingLo |= val<<12; |
| |
| val = pDCTstat->Trc - Bias_TrcT; |
| DramTimingLo |= val<<16; |
| |
| val = pDCTstat->Trrd - Bias_TrrdT; |
| DramTimingLo |= val<<22; |
| |
| DramTimingHi = 0; /* Dram Timing High init */ |
| val = pDCTstat->Twtr - Bias_TwtrT; |
| DramTimingHi |= val<<8; |
| |
| val = 2; /* Tref = 7.8us */ |
| DramTimingHi |= val<<16; |
| |
| val = 0; |
| for (i = 4; i > 0; i--) { |
| val <<= 3; |
| val |= Trfc[i-1]; |
| } |
| DramTimingHi |= val << 20; |
| |
| dev = pDCTstat->dev_dct; |
| /* Twr */ |
| val = pDCTstat->Twr; |
| if (val == 10) |
| val = 9; |
| else if (val == 12) |
| val = 10; |
| val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val); |
| val -= Bias_TwrT; |
| val <<= 4; |
| dword = Get_NB32_DCT(dev, dct, 0x84); |
| dword &= ~0x70; |
| dword |= val; |
| Set_NB32_DCT(dev, dct, 0x84, dword); |
| |
| /* Tfaw */ |
| val = pDCTstat->Tfaw; |
| val = mct_AdjustSPDTimings(pMCTstat, pDCTstat, val); |
| val -= Bias_TfawT; |
| val >>= 1; |
| val <<= 28; |
| dword = Get_NB32_DCT(dev, dct, 0x94); |
| dword &= ~0xf0000000; |
| dword |= val; |
| Set_NB32_DCT(dev, dct, 0x94, dword); |
| |
| /* dev = pDCTstat->dev_dct; */ |
| |
| if (pDCTstat->Speed > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) { |
| val = Get_NB32_DCT(dev, dct, 0x88); |
| val &= 0xFF000000; |
| DramTimingLo |= val; |
| } |
| Set_NB32_DCT(dev, dct, 0x88, DramTimingLo); /*DCT Timing Low*/ |
| |
| if (pDCTstat->Speed > mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) { |
| DramTimingHi |= 1 << DisAutoRefresh; |
| } |
| DramTimingHi |= 0x000018FF; |
| Set_NB32_DCT(dev, dct, 0x8c, DramTimingHi); /*DCT Timing Hi*/ |
| } |
| |
| /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */ |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static u8 AutoCycTiming_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| /* Initialize DCT Timing registers as per DIMM SPD. |
| * For primary timing (T, CL) use best case T value. |
| * For secondary timing params., use most aggressive settings |
| * of slowest DIMM. |
| * |
| * There are three components to determining "maximum frequency": |
| * SPD component, Bus load component, and "Preset" max frequency |
| * component. |
| * |
| * The SPD component is a function of the min cycle time specified |
| * by each DIMM, and the interaction of cycle times from all DIMMs |
| * in conjunction with CAS latency. The SPD component only applies |
| * when user timing mode is 'Auto'. |
| * |
| * The Bus load component is a limiting factor determined by electrical |
| * characteristics on the bus as a result of varying number of device |
| * loads. The Bus load component is specific to each platform but may |
| * also be a function of other factors. The bus load component only |
| * applies when user timing mode is 'Auto'. |
| * |
| * The Preset component is subdivided into three items and is |
| * the minimum of the set: Silicon revision, user limit |
| * setting when user timing mode is 'Auto' and memclock mode |
| * is 'Limit', OEM build specification of the maximum |
| * frequency. The Preset component is only applies when user |
| * timing mode is 'Auto'. |
| */ |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| /* Get primary timing (CAS Latency and Cycle Time) */ |
| if (pDCTstat->Speed == 0) { |
| mctGet_MaxLoadFreq(pDCTstat); |
| |
| /* and Factor in presets (setup options, Si cap, etc.) */ |
| GetPresetmaxF_D(pMCTstat, pDCTstat); |
| |
| /* Go get best T and CL as specified by DIMM mfgs. and OEM */ |
| SPDGetTCL_D(pMCTstat, pDCTstat, dct); |
| |
| /* skip callback mctForce800to1067_D */ |
| pDCTstat->Speed = pDCTstat->DIMMAutoSpeed; |
| pDCTstat->CASL = pDCTstat->DIMMCASL; |
| |
| } |
| mct_AfterGetCLT(pMCTstat, pDCTstat, dct); |
| |
| SPD2ndTiming(pMCTstat, pDCTstat, dct); |
| |
| printk(BIOS_DEBUG, "AutoCycTiming: Status %x\n", pDCTstat->Status); |
| printk(BIOS_DEBUG, "AutoCycTiming: ErrStatus %x\n", pDCTstat->ErrStatus); |
| printk(BIOS_DEBUG, "AutoCycTiming: ErrCode %x\n", pDCTstat->ErrCode); |
| printk(BIOS_DEBUG, "AutoCycTiming: Done\n\n"); |
| |
| mctHookAfterAutoCycTmg(); |
| |
| return pDCTstat->ErrCode; |
| } |
| |
| static void GetPresetmaxF_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| /* Get max frequency from OEM platform definition, from any user |
| * override (limiting) of max frequency, and from any Si Revision |
| * Specific information. Return the least of these three in |
| * DCTStatStruc.PresetmaxFreq. |
| */ |
| /* TODO: Set the proper max frequency in wrappers/mcti_d.c. */ |
| u16 proposedFreq; |
| u16 word; |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| /* Get CPU Si Revision defined limit (NPT) */ |
| if (is_fam15h()) |
| proposedFreq = 933; |
| else |
| proposedFreq = 800; /* Rev F0 programmable max memclock is */ |
| |
| /*Get User defined limit if "limit" mode */ |
| if (mctGet_NVbits(NV_MCTUSRTMGMODE) == 1) { |
| word = Get_Fk_D(mctGet_NVbits(NV_MemCkVal) + 1); |
| if (word < proposedFreq) |
| proposedFreq = word; |
| |
| /* Get Platform defined limit */ |
| word = mctGet_NVbits(NV_MAX_MEMCLK); |
| if (word < proposedFreq) |
| proposedFreq = word; |
| |
| word = pDCTstat->PresetmaxFreq; |
| if (word > proposedFreq) |
| word = proposedFreq; |
| |
| pDCTstat->PresetmaxFreq = word; |
| } |
| /* Check F3xE8[DdrMaxRate] for maximum DRAM data rate support */ |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static void SPDGetTCL_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, uint8_t dct) |
| { |
| /* Find the best T and CL primary timing parameter pair, per Mfg., |
| * for the given set of DIMMs, and store into DCTStatStruc |
| * (.DIMMAutoSpeed and .DIMMCASL). See "Global relationship between |
| * index values and item values" for definition of CAS latency |
| * index (j) and Frequency index (k). |
| */ |
| u8 i, CASLatLow, CASLatHigh; |
| u16 tAAmin16x; |
| u8 MTB16x; |
| u16 tCKmin16x; |
| u16 tCKproposed16x; |
| u8 CLactual, CLdesired, CLT_Fail; |
| uint16_t min_frequency_tck16x; |
| |
| u8 byte = 0, bytex = 0; |
| |
| CASLatLow = 0xFF; |
| CASLatHigh = 0xFF; |
| tAAmin16x = 0; |
| tCKmin16x = 0; |
| CLT_Fail = 0; |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| if (is_fam15h()) { |
| uint16_t minimum_frequency_mhz = mctGet_NVbits(NV_MIN_MEMCLK); |
| if (minimum_frequency_mhz == 0) |
| minimum_frequency_mhz = 333; |
| min_frequency_tck16x = 16000 / minimum_frequency_mhz; |
| } else { |
| min_frequency_tck16x = 40; |
| } |
| |
| for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) { |
| if (pDCTstat->DIMMValid & (1 << i)) { |
| /* Step 1: Determine the common set of supported CAS Latency |
| * values for all modules on the memory channel using the CAS |
| * Latencies Supported in SPD bytes 14 and 15. |
| */ |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_CASLow]; |
| CASLatLow &= byte; |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_CASHigh]; |
| CASLatHigh &= byte; |
| /* Step 2: Determine tAAmin(all) which is the largest tAAmin |
| value for all modules on the memory channel (SPD byte 16). */ |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDivisor]; |
| |
| MTB16x = ((pDCTstat->spd_data.spd_bytes[dct + i][SPD_MTBDividend] & 0xFF)<<4); |
| MTB16x /= byte; /* transfer to MTB*16 */ |
| |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tAAmin]; |
| if (tAAmin16x < byte * MTB16x) |
| tAAmin16x = byte * MTB16x; |
| /* Step 3: Determine tCKmin(all) which is the largest tCKmin |
| value for all modules on the memory channel (SPD byte 12). */ |
| byte = pDCTstat->spd_data.spd_bytes[dct + i][SPD_tCKmin]; |
| |
| if (tCKmin16x < byte * MTB16x) |
| tCKmin16x = byte * MTB16x; |
| } |
| } |
| /* calculate tCKproposed16x (proposed clock period in ns * 16) */ |
| tCKproposed16x = 16000 / pDCTstat->PresetmaxFreq; |
| if (tCKmin16x > tCKproposed16x) |
| tCKproposed16x = tCKmin16x; |
| |
| /* TODO: get user manual tCK16x(Freq.) and overwrite current tCKproposed16x if manual. */ |
| if (is_fam15h()) { |
| if (tCKproposed16x == 17) |
| pDCTstat->TargetFreq = 0x16; |
| else if (tCKproposed16x <= 20) { |
| pDCTstat->TargetFreq = 0x12; |
| tCKproposed16x = 20; |
| } else if (tCKproposed16x <= 24) { |
| pDCTstat->TargetFreq = 0xe; |
| tCKproposed16x = 24; |
| } else if (tCKproposed16x <= 30) { |
| pDCTstat->TargetFreq = 0xa; |
| tCKproposed16x = 30; |
| } else if (tCKproposed16x <= 40) { |
| pDCTstat->TargetFreq = 0x6; |
| tCKproposed16x = 40; |
| } else { |
| pDCTstat->TargetFreq = 0x4; |
| tCKproposed16x = 48; |
| } |
| } else { |
| if (tCKproposed16x == 20) |
| pDCTstat->TargetFreq = 7; |
| else if (tCKproposed16x <= 24) { |
| pDCTstat->TargetFreq = 6; |
| tCKproposed16x = 24; |
| } else if (tCKproposed16x <= 30) { |
| pDCTstat->TargetFreq = 5; |
| tCKproposed16x = 30; |
| } else { |
| pDCTstat->TargetFreq = 4; |
| tCKproposed16x = 40; |
| } |
| } |
| /* Running through this loop twice: |
| - First time find tCL at target frequency |
| - Second time find tCL at 400MHz */ |
| |
| for (;;) { |
| CLT_Fail = 0; |
| /* Step 4: For a proposed tCK value (tCKproposed) between tCKmin(all) and tCKmax, |
| determine the desired CAS Latency. If tCKproposed is not a standard JEDEC |
| value (2.5, 1.875, 1.5, or 1.25 ns) then tCKproposed must be adjusted to the |
| next lower standard tCK value for calculating CLdesired. |
| CLdesired = ceiling (tAAmin(all) / tCKproposed) |
| where tAAmin is defined in Byte 16. The ceiling function requires that the |
| quotient be rounded up always. */ |
| CLdesired = tAAmin16x / tCKproposed16x; |
| if (tAAmin16x % tCKproposed16x) |
| CLdesired ++; |
| /* Step 5: Chose an actual CAS Latency (CLactual) that is greather than or equal |
| to CLdesired and is supported by all modules on the memory channel as |
| determined in step 1. If no such value exists, choose a higher tCKproposed |
| value and repeat steps 4 and 5 until a solution is found. */ |
| for (i = 0, CLactual = 4; i < 15; i++, CLactual++) { |
| if ((CASLatHigh << 8 | CASLatLow) & (1 << i)) { |
| if (CLdesired <= CLactual) |
| break; |
| } |
| } |
| if (i == 15) |
| CLT_Fail = 1; |
| /* Step 6: Once the calculation of CLactual is completed, the BIOS must also |
| verify that this CAS Latency value does not exceed tAAmax, which is 20 ns |
| for all DDR3 speed grades, by multiplying CLactual times tCKproposed. If |
| not, choose a lower CL value and repeat steps 5 and 6 until a solution is found. */ |
| if (CLactual * tCKproposed16x > 320) |
| CLT_Fail = 1; |
| /* get CL and T */ |
| if (!CLT_Fail) { |
| bytex = CLactual; |
| if (is_fam15h()) { |
| if (tCKproposed16x == 17) |
| byte = 0x16; |
| else if (tCKproposed16x == 20) |
| byte = 0x12; |
| else if (tCKproposed16x == 24) |
| byte = 0xe; |
| else if (tCKproposed16x == 30) |
| byte = 0xa; |
| else if (tCKproposed16x == 40) |
| byte = 0x6; |
| else |
| byte = 0x4; |
| } else { |
| if (tCKproposed16x == 20) |
| byte = 7; |
| else if (tCKproposed16x == 24) |
| byte = 6; |
| else if (tCKproposed16x == 30) |
| byte = 5; |
| else |
| byte = 4; |
| } |
| } else { |
| /* mctHookManualCLOverride */ |
| /* TODO: */ |
| } |
| |
| if (tCKproposed16x != min_frequency_tck16x) { |
| if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) { |
| pDCTstat->DIMMAutoSpeed = byte; |
| pDCTstat->DIMMCASL = bytex; |
| break; |
| } else { |
| pDCTstat->TargetCASL = bytex; |
| tCKproposed16x = min_frequency_tck16x; |
| } |
| } else { |
| pDCTstat->DIMMAutoSpeed = byte; |
| pDCTstat->DIMMCASL = bytex; |
| break; |
| } |
| } |
| |
| printk(BIOS_DEBUG, "SPDGetTCL_D: DIMMCASL %x\n", pDCTstat->DIMMCASL); |
| printk(BIOS_DEBUG, "SPDGetTCL_D: DIMMAutoSpeed %x\n", pDCTstat->DIMMAutoSpeed); |
| |
| printk(BIOS_DEBUG, "SPDGetTCL_D: Status %x\n", pDCTstat->Status); |
| printk(BIOS_DEBUG, "SPDGetTCL_D: ErrStatus %x\n", pDCTstat->ErrStatus); |
| printk(BIOS_DEBUG, "SPDGetTCL_D: ErrCode %x\n", pDCTstat->ErrCode); |
| printk(BIOS_DEBUG, "SPDGetTCL_D: Done\n\n"); |
| } |
| |
| static u8 PlatformSpec_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| if (!is_fam15h()) { |
| mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct); |
| |
| if (pDCTstat->GangedMode == 1) { |
| mctGet_PS_Cfg_D(pMCTstat, pDCTstat, 1); |
| mct_BeforePlatformSpec(pMCTstat, pDCTstat, 1); |
| } |
| |
| set_2t_configuration(pMCTstat, pDCTstat, dct); |
| |
| mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct); |
| mct_PlatformSpec(pMCTstat, pDCTstat, dct); |
| if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) |
| InitPhyCompensation(pMCTstat, pDCTstat, dct); |
| } |
| mctHookAfterPSCfg(); |
| |
| return pDCTstat->ErrCode; |
| } |
| |
| static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 DramControl, DramTimingLo, Status; |
| u32 DramConfigLo, DramConfigHi, DramConfigMisc, DramConfigMisc2; |
| u32 val; |
| u32 dev; |
| u16 word; |
| u32 dword; |
| u8 byte; |
| uint32_t offset; |
| |
| DramConfigLo = 0; |
| DramConfigHi = 0; |
| DramConfigMisc = 0; |
| DramConfigMisc2 = 0; |
| |
| /* set bank addressing and Masks, plus CS pops */ |
| SPDSetBanks_D(pMCTstat, pDCTstat, dct); |
| if (pDCTstat->ErrCode == SC_StopError) |
| goto AutoConfig_exit; |
| |
| /* map chip-selects into local address space */ |
| StitchMemory_D(pMCTstat, pDCTstat, dct); |
| InterleaveBanks_D(pMCTstat, pDCTstat, dct); |
| |
| /* temp image of status (for convenience). RO usage! */ |
| Status = pDCTstat->Status; |
| |
| dev = pDCTstat->dev_dct; |
| |
| /* Build Dram Control Register Value */ |
| DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xa8); /* Dram Miscellaneous 2 */ |
| DramControl = Get_NB32_DCT(dev, dct, 0x78); /* Dram Control */ |
| |
| /* FIXME: Skip mct_checkForDxSupport */ |
| /* REV_CALL mct_DoRdPtrInit if not Dx */ |
| if (pDCTstat->LogicalCPUID & AMD_DR_Bx) |
| val = 5; |
| else |
| val = 6; |
| DramControl &= ~0xFF; |
| DramControl |= val; /* RdPtrInit = 6 for Cx CPU */ |
| |
| if (mctGet_NVbits(NV_CLKHZAltVidC3)) |
| DramControl |= 1<<16; /* check */ |
| |
| DramControl |= 0x00002A00; |
| |
| /* FIXME: Skip for Ax versions */ |
| /* callback not required - if (!mctParityControl_D()) */ |
| if (Status & (1 << SB_128bitmode)) |
| DramConfigLo |= 1 << Width128; /* 128-bit mode (normal) */ |
| |
| word = dct; |
| dword = X4Dimm; |
| while (word < 8) { |
| if (pDCTstat->Dimmx4Present & (1 << word)) |
| DramConfigLo |= 1 << dword; /* X4Dimm[3:0] */ |
| word++; |
| word++; |
| dword++; |
| } |
| |
| if (Status & (1 << SB_Registered)) { |
| /* Registered DIMMs */ |
| if (!is_fam15h()) { |
| DramConfigLo |= 1 << ParEn; |
| } |
| } else { |
| /* Unbuffered DIMMs */ |
| DramConfigLo |= 1 << UnBuffDimm; |
| } |
| |
| if (mctGet_NVbits(NV_ECC_CAP)) |
| if (Status & (1 << SB_ECCDIMMs)) |
| if (mctGet_NVbits(NV_ECC)) |
| DramConfigLo |= 1 << DimmEcEn; |
| |
| DramConfigLo = mct_DisDllShutdownSR(pMCTstat, pDCTstat, DramConfigLo, dct); |
| |
| /* Build Dram Config Hi Register Value */ |
| if (is_fam15h()) |
| offset = 0x0; |
| else |
| offset = 0x1; |
| dword = pDCTstat->Speed; |
| DramConfigHi |= dword - offset; /* get MemClk encoding */ |
| DramConfigHi |= 1 << MemClkFreqVal; |
| |
| if (!is_fam15h()) |
| if (Status & (1 << SB_Registered)) |
| if ((pDCTstat->Dimmx4Present != 0) && (pDCTstat->Dimmx8Present != 0)) |
| /* set only if x8 Registered DIMMs in System*/ |
| DramConfigHi |= 1 << RDqsEn; |
| |
| if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) { |
| DramConfigLo |= 1 << 25; /* PendRefPaybackS3En = 1 */ |
| DramConfigLo |= 1 << 24; /* StagRefEn = 1 */ |
| DramConfigHi |= 1 << 16; /* PowerDownMode = 1 */ |
| } else { |
| if (mctGet_NVbits(NV_CKE_CTL)) |
| /*Chip Select control of CKE*/ |
| DramConfigHi |= 1 << 16; |
| } |
| |
| if (!is_fam15h()) { |
| /* Control Bank Swizzle */ |
| if (0) /* call back not needed mctBankSwizzleControl_D()) */ |
| DramConfigHi &= ~(1 << BankSwizzleMode); |
| else |
| DramConfigHi |= 1 << BankSwizzleMode; /* recommended setting (default) */ |
| } |
| |
| /* Check for Quadrank DIMM presence */ |
| if (pDCTstat->DimmQRPresent != 0) { |
| byte = mctGet_NVbits(NV_4RANKType); |
| if (byte == 2) |
| DramConfigHi |= 1 << 17; /* S4 (4-Rank SO-DIMMs) */ |
| else if (byte == 1) |
| DramConfigHi |= 1 << 18; /* R4 (4-Rank Registered DIMMs) */ |
| } |
| |
| if (0) /* call back not needed mctOverrideDcqBypMax_D) */ |
| val = mctGet_NVbits(NV_BYPMAX); |
| else |
| val = 0x0f; /* recommended setting (default) */ |
| DramConfigHi |= val << 24; |
| |
| if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx | AMD_DR_Bx | AMD_FAM15_ALL)) |
| DramConfigHi |= 1 << DcqArbBypassEn; |
| |
| /* Build MemClkDis Value from Dram Timing Lo and |
| Dram Config Misc Registers |
| 1. We will assume that MemClkDis field has been preset prior to this |
| point. |
| 2. We will only set MemClkDis bits if a DIMM is NOT present AND if: |
| NV_AllMemClks <>0 AND SB_DiagClks == 0 */ |
| |
| /* Dram Timing Low (owns Clock Enable bits) */ |
| DramTimingLo = Get_NB32_DCT(dev, dct, 0x88); |
| if (mctGet_NVbits(NV_AllMemClks) == 0) { |
| /* Special Jedec SPD diagnostic bit - "enable all clocks" */ |
| if (!(pDCTstat->Status & (1<<SB_DiagClks))) { |
| const u8 *p; |
| const u32 *q; |
| p = Tab_ManualCLKDis; |
| q = (u32 *)p; |
| |
| byte = mctGet_NVbits(NV_PACK_TYPE); |
| if (byte == PT_L1) |
| p = Tab_L1CLKDis; |
| else if (byte == PT_M2 || byte == PT_AS) |
| p = Tab_AM3CLKDis; |
| else if (byte == PT_C3) |
| p = Tab_C32CLKDis; |
| else if (byte == PT_GR) |
| p = Tab_G34CLKDis; |
| else if (byte == PT_FM2) |
| p = Tab_FM2CLKDis; |
| else |
| p = Tab_S1CLKDis; |
| |
| dword = 0; |
| byte = 0xFF; |
| while (dword < MAX_CS_SUPPORTED) { |
| if (pDCTstat->CSPresent & (1<<dword)) { |
| /* re-enable clocks for the enabled CS */ |
| val = p[dword]; |
| byte &= ~val; |
| } |
| dword++ ; |
| } |
| DramTimingLo &= ~(0xff << 24); |
| DramTimingLo |= byte << 24; |
| } |
| } |
| |
| DramConfigMisc2 = mct_SetDramConfigMisc2(pDCTstat, dct, DramConfigMisc2, DramControl); |
| |
| printk(BIOS_DEBUG, "AutoConfig_D: DramControl: %08x\n", DramControl); |
| printk(BIOS_DEBUG, "AutoConfig_D: DramTimingLo: %08x\n", DramTimingLo); |
| printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc: %08x\n", DramConfigMisc); |
| printk(BIOS_DEBUG, "AutoConfig_D: DramConfigMisc2: %08x\n", DramConfigMisc2); |
| printk(BIOS_DEBUG, "AutoConfig_D: DramConfigLo: %08x\n", DramConfigLo); |
| printk(BIOS_DEBUG, "AutoConfig_D: DramConfigHi: %08x\n", DramConfigHi); |
| |
| /* Write Values to the registers */ |
| Set_NB32_DCT(dev, dct, 0x78, DramControl); |
| Set_NB32_DCT(dev, dct, 0x88, DramTimingLo); |
| Set_NB32_DCT(dev, dct, 0xa0, DramConfigMisc); |
| Set_NB32_DCT(dev, dct, 0xa8, DramConfigMisc2); |
| Set_NB32_DCT(dev, dct, 0x90, DramConfigLo); |
| ProgDramMRSReg_D(pMCTstat, pDCTstat, dct); |
| |
| if (is_fam15h()) |
| InitDDRPhy(pMCTstat, pDCTstat, dct); |
| |
| /* Write the DRAM Configuration High register, including memory frequency change */ |
| dword = Get_NB32_DCT(dev, dct, 0x94); |
| DramConfigHi |= dword; |
| mct_SetDramConfigHi_D(pMCTstat, pDCTstat, dct, DramConfigHi); |
| mct_EarlyArbEn_D(pMCTstat, pDCTstat, dct); |
| mctHookAfterAutoCfg(); |
| |
| /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */ |
| |
| printk(BIOS_DEBUG, "AutoConfig: Status %x\n", pDCTstat->Status); |
| printk(BIOS_DEBUG, "AutoConfig: ErrStatus %x\n", pDCTstat->ErrStatus); |
| printk(BIOS_DEBUG, "AutoConfig: ErrCode %x\n", pDCTstat->ErrCode); |
| printk(BIOS_DEBUG, "AutoConfig: Done\n\n"); |
| |
| AutoConfig_exit: |
| return pDCTstat->ErrCode; |
| } |
| |
| static void SPDSetBanks_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| /* Set bank addressing, program Mask values and build a chip-select |
| * population map. This routine programs PCI 0:24N:2x80 config register |
| * and PCI 0:24N:2x60,64,68,6C config registers (CS Mask 0-3). |
| */ |
| u8 ChipSel, Rows, Cols, Ranks, Banks; |
| u32 BankAddrReg, csMask; |
| |
| u32 val; |
| u32 reg; |
| u32 dev; |
| u8 byte; |
| u16 word; |
| u32 dword; |
| |
| dev = pDCTstat->dev_dct; |
| |
| BankAddrReg = 0; |
| for (ChipSel = 0; ChipSel < MAX_CS_SUPPORTED; ChipSel+=2) { |
| byte = ChipSel; |
| if ((pDCTstat->Status & (1 << SB_64MuxedMode)) && ChipSel >=4) |
| byte -= 3; |
| |
| if (pDCTstat->DIMMValid & (1<<byte)) { |
| byte = pDCTstat->spd_data.spd_bytes[ChipSel + dct][SPD_Addressing]; |
| Rows = (byte >> 3) & 0x7; /* Rows:0b = 12-bit,... */ |
| Cols = byte & 0x7; /* Cols:0b = 9-bit,... */ |
| |
| byte = pDCTstat->spd_data.spd_bytes[ChipSel + dct][SPD_Density]; |
| Banks = (byte >> 4) & 7; /* Banks:0b = 3-bit,... */ |
| |
| byte = pDCTstat->spd_data.spd_bytes[ChipSel + dct][SPD_Organization]; |
| Ranks = ((byte >> 3) & 7) + 1; |
| |
| /* Configure Bank encoding |
| * Use a 6-bit key into a lookup table. |
| * Key (index) = RRRBCC, where CC is the number of Columns minus 9, |
| * RRR is the number of Rows minus 12, and B is the number of banks |
| * minus 3. |
| */ |
| byte = Cols; |
| if (Banks == 1) |
| byte |= 4; |
| |
| byte |= Rows << 3; /* RRRBCC internal encode */ |
| |
| for (dword = 0; dword < 13; dword++) { |
| if (byte == Tab_BankAddr[dword]) |
| break; |
| } |
| |
| if (dword > 12) |
| continue; |
| |
| /* bit no. of CS field in address mapping reg.*/ |
| dword <<= (ChipSel<<1); |
| BankAddrReg |= dword; |
| |
| /* Mask value=(2pow(rows+cols+banks+3)-1)>>8, |
| or 2pow(rows+cols+banks-5)-1*/ |
| csMask = 0; |
| |
| byte = Rows + Cols; /* cl = rows+cols*/ |
| byte += 21; /* row:12+col:9 */ |
| byte -= 2; /* 3 banks - 5 */ |
| |
| if (pDCTstat->Status & (1 << SB_128bitmode)) |
| byte++; /* double mask size if in 128-bit mode*/ |
| |
| csMask |= 1 << byte; |
| csMask--; |
| |
| /*set ChipSelect population indicator even bits*/ |
| pDCTstat->CSPresent |= (1<<ChipSel); |
| if (Ranks >= 2) |
| /*set ChipSelect population indicator odd bits*/ |
| pDCTstat->CSPresent |= 1 << (ChipSel + 1); |
| |
| reg = 0x60+(ChipSel<<1); /*Dram CS Mask Register */ |
| val = csMask; |
| val &= 0x1FF83FE0; /* Mask out reserved bits.*/ |
| Set_NB32_DCT(dev, dct, reg, val); |
| } else { |
| if (pDCTstat->DIMMSPDCSE & (1<<ChipSel)) |
| pDCTstat->CSTestFail |= (1<<ChipSel); |
| } /* if DIMMValid*/ |
| } /* while ChipSel*/ |
| |
| SetCSTriState(pMCTstat, pDCTstat, dct); |
| SetCKETriState(pMCTstat, pDCTstat, dct); |
| SetODTTriState(pMCTstat, pDCTstat, dct); |
| |
| if (pDCTstat->Status & (1 << SB_128bitmode)) { |
| SetCSTriState(pMCTstat, pDCTstat, 1); /* force dct1) */ |
| SetCKETriState(pMCTstat, pDCTstat, 1); /* force dct1) */ |
| SetODTTriState(pMCTstat, pDCTstat, 1); /* force dct1) */ |
| } |
| |
| word = pDCTstat->CSPresent; |
| mctGetCS_ExcludeMap(); /* mask out specified chip-selects */ |
| word ^= pDCTstat->CSPresent; |
| pDCTstat->CSTestFail |= word; /* enable ODT to disabled DIMMs */ |
| if (!pDCTstat->CSPresent) |
| pDCTstat->ErrCode = SC_StopError; |
| |
| reg = 0x80; /* Bank Addressing Register */ |
| Set_NB32_DCT(dev, dct, reg, BankAddrReg); |
| |
| pDCTstat->CSPresent_DCT[dct] = pDCTstat->CSPresent; |
| /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */ |
| |
| printk(BIOS_DEBUG, "SPDSetBanks: CSPresent %x\n", pDCTstat->CSPresent_DCT[dct]); |
| printk(BIOS_DEBUG, "SPDSetBanks: Status %x\n", pDCTstat->Status); |
| printk(BIOS_DEBUG, "SPDSetBanks: ErrStatus %x\n", pDCTstat->ErrStatus); |
| printk(BIOS_DEBUG, "SPDSetBanks: ErrCode %x\n", pDCTstat->ErrCode); |
| printk(BIOS_DEBUG, "SPDSetBanks: Done\n\n"); |
| } |
| |
| static void SPDCalcWidth_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| /* Per SPDs, check the symmetry of DIMM pairs (DIMM on Channel A |
| * matching with DIMM on Channel B), the overall DIMM population, |
| * and determine the width mode: 64-bit, 64-bit muxed, 128-bit. |
| */ |
| u8 i; |
| u8 byte, byte1; |
| |
| /* Check Symmetry of Channel A and Channel B DIMMs |
| (must be matched for 128-bit mode).*/ |
| for (i = 0; i < MAX_DIMMS_SUPPORTED; i += 2) { |
| if ((pDCTstat->DIMMValid & (1 << i)) && (pDCTstat->DIMMValid & (1<<(i+1)))) { |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x7; |
| byte1 = pDCTstat->spd_data.spd_bytes[i + 1][SPD_Addressing] & 0x7; |
| if (byte != byte1) { |
| pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO); |
| break; |
| } |
| |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 0x0f; |
| byte1 = pDCTstat->spd_data.spd_bytes[i + 1][SPD_Density] & 0x0f; |
| if (byte != byte1) { |
| pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO); |
| break; |
| } |
| |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7; |
| byte1 = pDCTstat->spd_data.spd_bytes[i + 1][SPD_Organization] & 0x7; |
| if (byte != byte1) { |
| pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO); |
| break; |
| } |
| |
| byte = (pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3) & 0x7; |
| byte1 = (pDCTstat->spd_data.spd_bytes[i + 1][SPD_Organization] >> 3) & 0x7; |
| if (byte != byte1) { |
| pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO); |
| break; |
| } |
| |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_DMBANKS] & 7; /* #ranks-1 */ |
| byte1 = pDCTstat->spd_data.spd_bytes[i + 1][SPD_DMBANKS] & 7; /* #ranks-1 */ |
| if (byte != byte1) { |
| pDCTstat->ErrStatus |= (1<<SB_DimmMismatchO); |
| break; |
| } |
| |
| } |
| } |
| |
| } |
| |
| static void StitchMemory_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| /* Requires that Mask values for each bank be programmed first and that |
| * the chip-select population indicator is correctly set. |
| */ |
| u8 b = 0; |
| u32 nxtcsBase, curcsBase; |
| u8 p, q; |
| u32 Sizeq, BiggestBank; |
| u8 _DSpareEn; |
| |
| u16 word; |
| u32 dev; |
| u32 reg; |
| u32 val; |
| |
| dev = pDCTstat->dev_dct; |
| |
| _DSpareEn = 0; |
| |
| /* CS Sparing 1 = enabled, 0 = disabled */ |
| if (mctGet_NVbits(NV_CS_SpareCTL) & 1) { |
| if (MCT_DIMM_SPARE_NO_WARM) { |
| /* Do no warm-reset DIMM spare */ |
| if (pMCTstat->GStatus & 1 << GSB_EnDIMMSpareNW) { |
| word = pDCTstat->CSPresent; |
| val = bsf(word); |
| word &= ~(1<<val); |
| if (word) |
| /* Make sure at least two chip-selects are available */ |
| _DSpareEn = 1; |
| else |
| pDCTstat->ErrStatus |= 1 << SB_SpareDis; |
| } |
| } else { |
| if (!mctGet_NVbits(NV_DQSTrainCTL)) { /*DQS Training 1 = enabled, 0 = disabled */ |
| word = pDCTstat->CSPresent; |
| val = bsf(word); |
| word &= ~(1 << val); |
| if (word) |
| /* Make sure at least two chip-selects are available */ |
| _DSpareEn = 1; |
| else |
| pDCTstat->ErrStatus |= 1 << SB_SpareDis; |
| } |
| } |
| } |
| |
| nxtcsBase = 0; /* Next available cs base ADDR[39:8] */ |
| for (p = 0; p < MAX_DIMMS_SUPPORTED; p++) { |
| BiggestBank = 0; |
| for (q = 0; q < MAX_CS_SUPPORTED; q++) { /* from DIMMS to CS */ |
| if (pDCTstat->CSPresent & (1 << q)) { /* bank present? */ |
| reg = 0x40 + (q << 2); /* Base[q] reg.*/ |
| val = Get_NB32_DCT(dev, dct, reg); |
| if (!(val & 3)) { /* (CSEnable|Spare == 1)bank is enabled already? */ |
| reg = 0x60 + (q << 1); /*Mask[q] reg.*/ |
| val = Get_NB32_DCT(dev, dct, reg); |
| val >>= 19; |
| val++; |
| val <<= 19; |
| Sizeq = val; /* never used */ |
| if (val > BiggestBank) { |
| /*Bingo! possibly Map this chip-select next! */ |
| BiggestBank = val; |
| b = q; |
| } |
| } |
| } /*if bank present */ |
| } /* while q */ |
| if (BiggestBank !=0) { |
| curcsBase = nxtcsBase; /* curcsBase = nxtcsBase*/ |
| /* DRAM CS Base b Address Register offset */ |
| reg = 0x40 + (b << 2); |
| if (_DSpareEn) { |
| BiggestBank = 0; |
| val = 1 << Spare; /* Spare Enable*/ |
| } else { |
| val = curcsBase; |
| val |= 1 << CSEnable; /* Bank Enable */ |
| } |
| if (((reg - 0x40) >> 2) & 1) { |
| if (!(pDCTstat->Status & (1 << SB_Registered))) { |
| u16 dimValid; |
| dimValid = pDCTstat->DIMMValid; |
| if (dct & 1) |
| dimValid <<= 1; |
| if ((dimValid & pDCTstat->MirrPresU_NumRegR) != 0) { |
| val |= 1 << onDimmMirror; |
| } |
| } |
| } |
| Set_NB32_DCT(dev, dct, reg, val); |
| if (_DSpareEn) |
| _DSpareEn = 0; |
| else |
| /* let nxtcsBase+=Size[b] */ |
| nxtcsBase += BiggestBank; |
| } |
| |
| /* bank present but disabled?*/ |
| if (pDCTstat->CSTestFail & (1 << p)) { |
| /* DRAM CS Base b Address Register offset */ |
| reg = (p << 2) + 0x40; |
| val = 1 << TestFail; |
| Set_NB32_DCT(dev, dct, reg, val); |
| } |
| } |
| |
| if (nxtcsBase) { |
| pDCTstat->DCTSysLimit = nxtcsBase - 1; |
| mct_AfterStitchMemory(pMCTstat, pDCTstat, dct); |
| } |
| |
| /* dump_pci_device(PCI_DEV(0, 0x18+pDCTstat->Node_ID, 2)); */ |
| |
| printk(BIOS_DEBUG, "StitchMemory: Status %x\n", pDCTstat->Status); |
| printk(BIOS_DEBUG, "StitchMemory: ErrStatus %x\n", pDCTstat->ErrStatus); |
| printk(BIOS_DEBUG, "StitchMemory: ErrCode %x\n", pDCTstat->ErrCode); |
| printk(BIOS_DEBUG, "StitchMemory: Done\n\n"); |
| } |
| |
| static u16 Get_Fk_D(u8 k) |
| { |
| return Table_F_k[k]; /* FIXME: k or k<<1 ? */ |
| } |
| |
| static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| /* Check DIMMs present, verify checksum, flag SDRAM type, |
| * build population indicator bitmaps, and preload bus loading |
| * of DIMMs into DCTStatStruc. |
| * MAAload = number of devices on the "A" bus. |
| * MABload = number of devices on the "B" bus. |
| * MAAdimms = number of DIMMs on the "A" bus slots. |
| * MABdimms = number of DIMMs on the "B" bus slots. |
| * DATAAload = number of ranks on the "A" bus slots. |
| * DATABload = number of ranks on the "B" bus slots. |
| */ |
| u16 i, j, k; |
| u8 smbaddr; |
| u8 SPDCtrl; |
| u16 RegDIMMPresent, LRDIMMPresent, MaxDimms; |
| u8 devwidth; |
| u16 DimmSlots; |
| u8 byte = 0, bytex; |
| uint8_t crc_status; |
| |
| /* preload data structure with addrs */ |
| mctGet_DIMMAddr(pDCTstat, pDCTstat->Node_ID); |
| |
| DimmSlots = MaxDimms = mctGet_NVbits(NV_MAX_DIMMS); |
| |
| SPDCtrl = mctGet_NVbits(NV_SPDCHK_RESTRT); |
| |
| RegDIMMPresent = 0; |
| LRDIMMPresent = 0; |
| pDCTstat->DimmQRPresent = 0; |
| |
| for (i = 0; i < MAX_DIMMS_SUPPORTED; i++) { |
| if (i >= MaxDimms) |
| break; |
| |
| if ((pDCTstat->DimmQRPresent & (1 << i)) || (i < DimmSlots)) { |
| int status; |
| smbaddr = Get_DIMMAddress_D(pDCTstat, i); |
| status = mctRead_SPD(smbaddr, SPD_ByteUse); |
| if (status >= 0) { |
| /* Verify result */ |
| status = mctRead_SPD(smbaddr, SPD_ByteUse); |
| } |
| if (status >= 0) { /* SPD access is ok */ |
| pDCTstat->DIMMPresent |= 1 << i; |
| read_spd_bytes(pMCTstat, pDCTstat, i); |
| #ifdef DEBUG_DIMM_SPD |
| dump_spd_bytes(pMCTstat, pDCTstat, i); |
| #endif |
| crc_status = crcCheck(pDCTstat, i); |
| if (!crc_status) { |
| /* Try again in case there was a transient glitch */ |
| read_spd_bytes(pMCTstat, pDCTstat, i); |
| crc_status = crcCheck(pDCTstat, i); |
| } |
| if ((crc_status) || (SPDCtrl == 2)) { /* CRC is OK */ |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_TYPE]; |
| if (byte == JED_DDR3SDRAM) { |
| /*Dimm is 'Present'*/ |
| pDCTstat->DIMMValid |= 1 << i; |
| } |
| } else { |
| printk(BIOS_WARNING, "Node %d DIMM %d: SPD checksum invalid\n", pDCTstat->Node_ID, i); |
| pDCTstat->DIMMSPDCSE = 1 << i; |
| if (SPDCtrl == 0) { |
| pDCTstat->ErrStatus |= 1 << SB_DIMMChkSum; |
| pDCTstat->ErrCode = SC_StopError; |
| } else { |
| /*if NV_SPDCHK_RESTRT is set to 1, ignore faulty SPD checksum*/ |
| pDCTstat->ErrStatus |= 1<<SB_DIMMChkSum; |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_TYPE]; |
| if (byte == JED_DDR3SDRAM) |
| pDCTstat->DIMMValid |= 1 << i; |
| } |
| } |
| |
| /* Zero DIMM SPD data cache if DIMM not present / valid */ |
| if (!(pDCTstat->DIMMValid & (1 << i))) |
| memset(pDCTstat->spd_data.spd_bytes[i], 0, sizeof(pDCTstat->spd_data.spd_bytes[i])); |
| |
| /* Get module information for SMBIOS */ |
| if (pDCTstat->DIMMValid & (1 << i)) { |
| pDCTstat->DimmManufacturerID[i] = 0; |
| for (k = 0; k < 8; k++) |
| pDCTstat->DimmManufacturerID[i] |= ((uint64_t)pDCTstat->spd_data.spd_bytes[i][SPD_MANID_START + k]) << (k * 8); |
| for (k = 0; k < SPD_PARTN_LENGTH; k++) |
| pDCTstat->DimmPartNumber[i][k] = pDCTstat->spd_data.spd_bytes[i][SPD_PARTN_START + k]; |
| pDCTstat->DimmPartNumber[i][SPD_PARTN_LENGTH] = 0; |
| pDCTstat->DimmRevisionNumber[i] = 0; |
| for (k = 0; k < 2; k++) |
| pDCTstat->DimmRevisionNumber[i] |= ((uint16_t)pDCTstat->spd_data.spd_bytes[i][SPD_REVNO_START + k]) << (k * 8); |
| pDCTstat->DimmSerialNumber[i] = 0; |
| for (k = 0; k < 4; k++) |
| pDCTstat->DimmSerialNumber[i] |= ((uint32_t)pDCTstat->spd_data.spd_bytes[i][SPD_SERIAL_START + k]) << (k * 8); |
| pDCTstat->DimmRows[i] = (pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x38) >> 3; |
| pDCTstat->DimmCols[i] = pDCTstat->spd_data.spd_bytes[i][SPD_Addressing] & 0x7; |
| pDCTstat->DimmRanks[i] = ((pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x38) >> 3) + 1; |
| pDCTstat->DimmBanks[i] = 1ULL << (((pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 0x70) >> 4) + 3); |
| pDCTstat->DimmWidth[i] = 1ULL << ((pDCTstat->spd_data.spd_bytes[i][SPD_BusWidth] & 0x7) + 3); |
| pDCTstat->DimmChipSize[i] = 1ULL << ((pDCTstat->spd_data.spd_bytes[i][SPD_Density] & 0xf) + 28); |
| pDCTstat->DimmChipWidth[i] = 1ULL << ((pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7) + 2); |
| } |
| /* Check supported voltage(s) */ |
| pDCTstat->DimmSupportedVoltages[i] = pDCTstat->spd_data.spd_bytes[i][SPD_Voltage] & 0x7; |
| pDCTstat->DimmSupportedVoltages[i] ^= 0x1; /* Invert LSB to convert from SPD format to internal bitmap format */ |
| /* Check module type */ |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_DIMMTYPE] & 0x7; |
| if (byte == JED_RDIMM || byte == JED_MiniRDIMM) { |
| RegDIMMPresent |= 1 << i; |
| pDCTstat->DimmRegistered[i] = 1; |
| } else { |
| pDCTstat->DimmRegistered[i] = 0; |
| } |
| if (byte == JED_LRDIMM) { |
| LRDIMMPresent |= 1 << i; |
| pDCTstat->DimmLoadReduced[i] = 1; |
| } else { |
| pDCTstat->DimmLoadReduced[i] = 0; |
| } |
| /* Check ECC capable */ |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_BusWidth]; |
| if (byte & JED_ECC) { |
| /* DIMM is ECC capable */ |
| pDCTstat->DimmECCPresent |= 1 << i; |
| } |
| /* Check if x4 device */ |
| devwidth = pDCTstat->spd_data.spd_bytes[i][SPD_Organization] & 0x7; /* 0:x4,1:x8,2:x16 */ |
| if (devwidth == 0) { |
| /* DIMM is made with x4 or x16 drams */ |
| pDCTstat->Dimmx4Present |= 1 << i; |
| } else if (devwidth == 1) { |
| pDCTstat->Dimmx8Present |= 1 << i; |
| } else if (devwidth == 2) { |
| pDCTstat->Dimmx16Present |= 1 << i; |
| } |
| |
| byte = (pDCTstat->spd_data.spd_bytes[i][SPD_Organization] >> 3); |
| byte &= 7; |
| if (byte == 3) { /* 4ranks */ |
| /* if any DIMMs are QR, we have to make two passes through DIMMs*/ |
| if (pDCTstat->DimmQRPresent == 0) { |
| MaxDimms <<= 1; |
| } |
| if (i < DimmSlots) { |
| pDCTstat->DimmQRPresent |= (1 << i) | (1 << (i+4)); |
| } else { |
| pDCTstat->MAdimms[i & 1] --; |
| } |
| byte = 1; /* upper two ranks of QR DIMM will be counted on another DIMM number iteration*/ |
| } else if (byte == 1) { /* 2ranks */ |
| pDCTstat->DimmDRPresent |= 1 << i; |
| } |
| bytex = devwidth; |
| if (devwidth == 0) |
| bytex = 16; |
| else if (devwidth == 1) |
| bytex = 8; |
| else if (devwidth == 2) |
| bytex = 4; |
| |
| byte++; /* al+1 = rank# */ |
| if (byte == 2) |
| bytex <<= 1; /*double Addr bus load value for dual rank DIMMs*/ |
| |
| j = i & (1<<0); |
| pDCTstat->DATAload[j] += byte; /*number of ranks on DATA bus*/ |
| pDCTstat->MAload[j] += bytex; /*number of devices on CMD/ADDR bus*/ |
| pDCTstat->MAdimms[j]++; /*number of DIMMs on A bus */ |
| |
| /* check address mirror support for unbuffered dimm */ |
| /* check number of registers on a dimm for registered dimm */ |
| byte = pDCTstat->spd_data.spd_bytes[i][SPD_AddressMirror]; |
| if (RegDIMMPresent & (1 << i)) { |
| if ((byte & 3) > 1) |
| pDCTstat->MirrPresU_NumRegR |= 1 << i; |
| } else { |
| if ((byte & 1) == 1) |
| pDCTstat->MirrPresU_NumRegR |= 1 << i; |
| } |
| /* Get byte62: Reference Raw Card information. We dont need it now. */ |
| /* byte = pDCTstat->spd_data.spd_bytes[i][SPD_RefRawCard]; */ |
| /* Get Byte65/66 for register manufacture ID code */ |
| if ((0x97 == pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_H]) && |
| (0x80 == pDCTstat->spd_data.spd_bytes[i][SPD_RegManufactureID_L])) { |
| if (0x16 == pDCTstat->spd_data.spd_bytes[i][SPD_RegManRevID]) |
| pDCTstat->RegMan2Present |= 1 << i; |
| else |
| pDCTstat->RegMan1Present |= 1 << i; |
| } |
| /* Get control word value for RC3 */ |
| byte = pDCTstat->spd_data.spd_bytes[i][70]; |
| pDCTstat->CtrlWrd3 |= ((byte >> 4) & 0xf) << (i << 2); /* RC3 = SPD byte 70 [7:4] */ |
| /* Get control word values for RC4 and RC5 */ |
| byte = pDCTstat->spd_data.spd_bytes[i][71]; |
| pDCTstat->CtrlWrd4 |= (byte & 0xf) << (i << 2); /* RC4 = SPD byte 71 [3:0] */ |
| pDCTstat->CtrlWrd5 |= ((byte >> 4) & 0xf) << (i << 2); /* RC5 = SPD byte 71 [7:4] */ |
| } |
| } |
| } |
| printk(BIOS_DEBUG, "\t DIMMPresence: DIMMValid=%x\n", pDCTstat->DIMMValid); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DIMMPresent=%x\n", pDCTstat->DIMMPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: RegDIMMPresent=%x\n", RegDIMMPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: LRDIMMPresent=%x\n", LRDIMMPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DimmECCPresent=%x\n", pDCTstat->DimmECCPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DimmPARPresent=%x\n", pDCTstat->DimmPARPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx4Present=%x\n", pDCTstat->Dimmx4Present); |
| printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx8Present=%x\n", pDCTstat->Dimmx8Present); |
| printk(BIOS_DEBUG, "\t DIMMPresence: Dimmx16Present=%x\n", pDCTstat->Dimmx16Present); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DimmPlPresent=%x\n", pDCTstat->DimmPlPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DimmDRPresent=%x\n", pDCTstat->DimmDRPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DimmQRPresent=%x\n", pDCTstat->DimmQRPresent); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DATAload[0]=%x\n", pDCTstat->DATAload[0]); |
| printk(BIOS_DEBUG, "\t DIMMPresence: MAload[0]=%x\n", pDCTstat->MAload[0]); |
| printk(BIOS_DEBUG, "\t DIMMPresence: MAdimms[0]=%x\n", pDCTstat->MAdimms[0]); |
| printk(BIOS_DEBUG, "\t DIMMPresence: DATAload[1]=%x\n", pDCTstat->DATAload[1]); |
| printk(BIOS_DEBUG, "\t DIMMPresence: MAload[1]=%x\n", pDCTstat->MAload[1]); |
| printk(BIOS_DEBUG, "\t DIMMPresence: MAdimms[1]=%x\n", pDCTstat->MAdimms[1]); |
| |
| if (pDCTstat->DIMMValid != 0) { /* If any DIMMs are present...*/ |
| if (RegDIMMPresent != 0) { |
| if ((RegDIMMPresent ^ pDCTstat->DIMMValid) !=0) { |
| /* module type DIMM mismatch (reg'ed, unbuffered) */ |
| pDCTstat->ErrStatus |= 1<<SB_DimmMismatchM; |
| pDCTstat->ErrCode = SC_StopError; |
| } else{ |
| /* all DIMMs are registered */ |
| pDCTstat->Status |= 1<<SB_Registered; |
| } |
| } |
| if (LRDIMMPresent != 0) { |
| if ((LRDIMMPresent ^ pDCTstat->DIMMValid) !=0) { |
| /* module type DIMM mismatch (reg'ed, unbuffered) */ |
| pDCTstat->ErrStatus |= 1<<SB_DimmMismatchM; |
| pDCTstat->ErrCode = SC_StopError; |
| } else{ |
| /* all DIMMs are registered */ |
| pDCTstat->Status |= 1<<SB_LoadReduced; |
| } |
| } |
| if (pDCTstat->DimmECCPresent != 0) { |
| if ((pDCTstat->DimmECCPresent ^ pDCTstat->DIMMValid) == 0) { |
| /* all DIMMs are ECC capable */ |
| pDCTstat->Status |= 1<<SB_ECCDIMMs; |
| } |
| } |
| if (pDCTstat->DimmPARPresent != 0) { |
| if ((pDCTstat->DimmPARPresent ^ pDCTstat->DIMMValid) == 0) { |
| /*all DIMMs are Parity capable */ |
| pDCTstat->Status |= 1<<SB_PARDIMMs; |
| } |
| } |
| } else { |
| /* no DIMMs present or no DIMMs that qualified. */ |
| pDCTstat->ErrStatus |= 1<<SB_NoDimms; |
| pDCTstat->ErrCode = SC_StopError; |
| } |
| |
| printk(BIOS_DEBUG, "\t DIMMPresence: Status %x\n", pDCTstat->Status); |
| printk(BIOS_DEBUG, "\t DIMMPresence: ErrStatus %x\n", pDCTstat->ErrStatus); |
| printk(BIOS_DEBUG, "\t DIMMPresence: ErrCode %x\n", pDCTstat->ErrCode); |
| printk(BIOS_DEBUG, "\t DIMMPresence: Done\n\n"); |
| |
| mctHookAfterDIMMpre(); |
| |
| return pDCTstat->ErrCode; |
| } |
| |
| static u8 Get_DIMMAddress_D(struct DCTStatStruc *pDCTstat, u8 i) |
| { |
| u8 *p; |
| |
| p = pDCTstat->DIMMAddr; |
| /* mct_BeforeGetDIMMAddress(); */ |
| return p[i]; |
| } |
| |
| static void mct_preInitDCT(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u8 err_code; |
| uint8_t nvram; |
| uint8_t allow_config_restore; |
| |
| /* Preconfigure DCT0 */ |
| DCTPreInit_D(pMCTstat, pDCTstat, 0); |
| |
| /* Configure DCT1 if unganged and enabled*/ |
| if (!pDCTstat->GangedMode) { |
| if (pDCTstat->DIMMValidDCT[1] > 0) { |
| err_code = pDCTstat->ErrCode; /* save DCT0 errors */ |
| pDCTstat->ErrCode = 0; |
| DCTPreInit_D(pMCTstat, pDCTstat, 1); |
| if (pDCTstat->ErrCode == 2) /* DCT1 is not Running */ |
| pDCTstat->ErrCode = err_code; /* Using DCT0 Error code to update pDCTstat.ErrCode */ |
| } |
| } |
| |
| #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) |
| calculate_and_store_spd_hashes(pMCTstat, pDCTstat); |
| |
| if (load_spd_hashes_from_nvram(pMCTstat, pDCTstat) < 0) { |
| pDCTstat->spd_data.nvram_spd_match = 0; |
| } else { |
| compare_nvram_spd_hashes(pMCTstat, pDCTstat); |
| } |
| #else |
| pDCTstat->spd_data.nvram_spd_match = 0; |
| #endif |
| |
| /* Check to see if restoration of SPD data from NVRAM is allowed */ |
| allow_config_restore = 0; |
| if (get_option(&nvram, "allow_spd_nvram_cache_restore") == CB_SUCCESS) |
| allow_config_restore = !!nvram; |
| |
| #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) |
| if (pMCTstat->nvram_checksum != calculate_nvram_mct_hash()) |
| allow_config_restore = 0; |
| #else |
| allow_config_restore = 0; |
| #endif |
| |
| if (!allow_config_restore) |
| pDCTstat->spd_data.nvram_spd_match = 0; |
| } |
| |
| static void mct_initDCT(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 val; |
| u8 err_code; |
| |
| /* Config. DCT0 for Ganged or unganged mode */ |
| DCTInit_D(pMCTstat, pDCTstat, 0); |
| DCTFinalInit_D(pMCTstat, pDCTstat, 0); |
| if (pDCTstat->ErrCode == SC_FatalErr) { |
| /* Do nothing goto exitDCTInit; any fatal errors? */ |
| } else { |
| /* Configure DCT1 if unganged and enabled */ |
| if (!pDCTstat->GangedMode) { |
| if (pDCTstat->DIMMValidDCT[1] > 0) { |
| err_code = pDCTstat->ErrCode; /* save DCT0 errors */ |
| pDCTstat->ErrCode = 0; |
| DCTInit_D(pMCTstat, pDCTstat, 1); |
| DCTFinalInit_D(pMCTstat, pDCTstat, 1); |
| if (pDCTstat->ErrCode == 2) /* DCT1 is not Running */ |
| pDCTstat->ErrCode = err_code; /* Using DCT0 Error code to update pDCTstat.ErrCode */ |
| } else { |
| val = 1 << DisDramInterface; |
| Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val); |
| |
| val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90); |
| val &= ~(1 << ParEn); |
| Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val); |
| |
| /* To maximize power savings when DisDramInterface = 1b, |
| * all of the MemClkDis bits should also be set. |
| */ |
| Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x88, 0xff000000); |
| } |
| } |
| } |
| } |
| |
| static void mct_DramInit(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| mct_BeforeDramInit_Prod_D(pMCTstat, pDCTstat, dct); |
| mct_DramInit_Sw_D(pMCTstat, pDCTstat, dct); |
| /* mct_DramInit_Hw_D(pMCTstat, pDCTstat, dct); */ |
| } |
| |
| static u8 mct_setMode(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u8 byte; |
| u8 bytex; |
| u32 val; |
| u32 reg; |
| |
| byte = bytex = pDCTstat->DIMMValid; |
| bytex &= 0x55; /* CHA DIMM pop */ |
| pDCTstat->DIMMValidDCT[0] = bytex; |
| |
| byte &= 0xAA; /* CHB DIMM popa */ |
| byte >>= 1; |
| pDCTstat->DIMMValidDCT[1] = byte; |
| |
| if (byte != bytex) { |
| pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); |
| } else { |
| byte = mctGet_NVbits(NV_Unganged); |
| if (byte) |
| pDCTstat->ErrStatus |= (1 << SB_DimmMismatchO); /* Set temp. to avoid setting of ganged mode */ |
| |
| if ((!(pDCTstat->ErrStatus & (1 << SB_DimmMismatchO))) && (pDCTstat->LogicalCPUID & AMD_FAM10_ALL)) { |
| /* Ganged channel mode not supported on Family 15h or higher */ |
| pDCTstat->GangedMode = 1; |
| /* valid 128-bit mode population. */ |
| pDCTstat->Status |= 1 << SB_128bitmode; |
| reg = 0x110; |
| val = Get_NB32(pDCTstat->dev_dct, reg); |
| val |= 1 << DctGangEn; |
| Set_NB32(pDCTstat->dev_dct, reg, val); |
| } |
| if (byte) /* NV_Unganged */ |
| pDCTstat->ErrStatus &= ~(1 << SB_DimmMismatchO); /* Clear so that there is no DIMM mismatch error */ |
| } |
| |
| return pDCTstat->ErrCode; |
| } |
| |
| u32 Get_NB32(u32 dev, u32 reg) |
| { |
| return pci_read_config32(dev, reg); |
| } |
| |
| void Set_NB32(u32 dev, u32 reg, u32 val) |
| { |
| pci_write_config32(dev, reg, val); |
| } |
| |
| |
| u32 Get_NB32_index(u32 dev, u32 index_reg, u32 index) |
| { |
| u32 dword; |
| |
| Set_NB32(dev, index_reg, index); |
| dword = Get_NB32(dev, index_reg+0x4); |
| |
| return dword; |
| } |
| |
| void Set_NB32_index(u32 dev, u32 index_reg, u32 index, u32 data) |
| { |
| Set_NB32(dev, index_reg, index); |
| Set_NB32(dev, index_reg + 0x4, data); |
| } |
| |
| u32 Get_NB32_index_wait(u32 dev, u32 index_reg, u32 index) |
| { |
| u32 dword; |
| |
| index &= ~(1 << DctAccessWrite); |
| Set_NB32(dev, index_reg, index); |
| do { |
| dword = Get_NB32(dev, index_reg); |
| } while (!(dword & (1 << DctAccessDone))); |
| dword = Get_NB32(dev, index_reg + 0x4); |
| |
| return dword; |
| } |
| |
| void Set_NB32_index_wait(u32 dev, u32 index_reg, u32 index, u32 data) |
| { |
| u32 dword; |
| |
| Set_NB32(dev, index_reg + 0x4, data); |
| index |= (1 << DctAccessWrite); |
| Set_NB32(dev, index_reg, index); |
| do { |
| dword = Get_NB32(dev, index_reg); |
| } while (!(dword & (1 << DctAccessDone))); |
| |
| } |
| |
| static u8 mct_BeforePlatformSpec(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| /* mct_checkForCxDxSupport_D */ |
| if (pDCTstat->LogicalCPUID & AMD_DR_GT_Bx) { |
| /* Family 10h Errata 322: Address and Command Fine Delay Values May Be Incorrect */ |
| /* 1. Write 00000000h to F2x[1,0]9C_xD08E000 */ |
| Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0D08E000, 0); |
| /* 2. If DRAM Configuration Register[MemClkFreq] (F2x[1,0]94[2:0]) is |
| greater than or equal to 011b (DDR-800 and higher), |
| then write 00000080h to F2x[1,0]9C_xD02E001, |
| else write 00000090h to F2x[1,0]9C_xD02E001. */ |
| if (pDCTstat->Speed >= mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) |
| Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0D02E001, 0x80); |
| else |
| Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, 0x98, 0x0D02E001, 0x90); |
| } |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| |
| return pDCTstat->ErrCode; |
| } |
| |
| static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| /* Get platform specific config/timing values from the interface layer |
| * and program them into DCT. |
| */ |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| u32 dev = pDCTstat->dev_dct; |
| u32 index_reg; |
| u8 i, i_start, i_end; |
| |
| if (pDCTstat->GangedMode) { |
| SyncSetting(pDCTstat); |
| /* mct_SetupSync_D */ |
| i_start = 0; |
| i_end = 2; |
| } else { |
| i_start = dct; |
| i_end = dct + 1; |
| } |
| for (i = i_start; i < i_end; i++) { |
| index_reg = 0x98; |
| Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */ |
| Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */ |
| printk(BIOS_SPEW, "Programmed DCT %d timing/termination pattern %08x %08x\n", dct, pDCTstat->CH_ADDR_TMG[i], pDCTstat->CH_ODC_CTL[i]); |
| } |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| |
| return pDCTstat->ErrCode; |
| } |
| |
| static void mct_SyncDCTsReady(struct DCTStatStruc *pDCTstat) |
| { |
| u32 dev; |
| u32 val; |
| |
| if (pDCTstat->NodePresent) { |
| dev = pDCTstat->dev_dct; |
| |
| if ((pDCTstat->DIMMValidDCT[0]) || (pDCTstat->DIMMValidDCT[1])) { |
| /* This Node has DRAM */ |
| do { |
| val = Get_NB32(dev, 0x110); |
| } while (!(val & (1 << DramEnabled))); |
| } |
| } /* Node is present */ |
| } |
| |
| static void mct_AfterGetCLT(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| if (!pDCTstat->GangedMode) { |
| if (dct == 0) { |
| pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct]; |
| if (pDCTstat->DIMMValidDCT[dct] == 0) |
| pDCTstat->ErrCode = SC_StopError; |
| } else { |
| pDCTstat->CSPresent = 0; |
| pDCTstat->CSTestFail = 0; |
| pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[dct]; |
| if (pDCTstat->DIMMValidDCT[dct] == 0) |
| pDCTstat->ErrCode = SC_StopError; |
| } |
| } |
| } |
| |
| static u8 mct_SPDCalcWidth(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 ret; |
| u32 val; |
| |
| if (dct == 0) { |
| SPDCalcWidth_D(pMCTstat, pDCTstat); |
| ret = mct_setMode(pMCTstat, pDCTstat); |
| } else { |
| ret = pDCTstat->ErrCode; |
| } |
| |
| if (pDCTstat->DIMMValidDCT[0] == 0) { |
| val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x94); |
| val |= 1 << DisDramInterface; |
| Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x94, val); |
| |
| val = Get_NB32_DCT(pDCTstat->dev_dct, 0, 0x90); |
| val &= ~(1 << ParEn); |
| Set_NB32_DCT(pDCTstat->dev_dct, 0, 0x90, val); |
| } |
| if (pDCTstat->DIMMValidDCT[1] == 0) { |
| val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x94); |
| val |= 1 << DisDramInterface; |
| Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x94, val); |
| |
| val = Get_NB32_DCT(pDCTstat->dev_dct, 1, 0x90); |
| val &= ~(1 << ParEn); |
| Set_NB32_DCT(pDCTstat->dev_dct, 1, 0x90, val); |
| } |
| |
| printk(BIOS_DEBUG, "SPDCalcWidth: Status %x\n", pDCTstat->Status); |
| printk(BIOS_DEBUG, "SPDCalcWidth: ErrStatus %x\n", pDCTstat->ErrStatus); |
| printk(BIOS_DEBUG, "SPDCalcWidth: ErrCode %x\n", pDCTstat->ErrCode); |
| printk(BIOS_DEBUG, "SPDCalcWidth: Done\n"); |
| /* Disable dram interface before DRAM init */ |
| |
| return ret; |
| } |
| |
| static void mct_AfterStitchMemory(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 val; |
| u32 dword; |
| u32 dev; |
| u32 reg; |
| u8 _MemHoleRemap; |
| u32 DramHoleBase; |
| |
| _MemHoleRemap = mctGet_NVbits(NV_MemHole); |
| DramHoleBase = mctGet_NVbits(NV_BottomIO); |
| DramHoleBase <<= 8; |
| /* Increase hole size so;[31:24]to[31:16] |
| * it has granularity of 128MB shl eax,8 |
| * Set 'effective' bottom IOmov DramHoleBase,eax |
| */ |
| pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8; |
| |
| /* In unganged mode, we must add DCT0 and DCT1 to DCTSysLimit */ |
| if (!pDCTstat->GangedMode) { |
| dev = pDCTstat->dev_dct; |
| pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit; |
| /* if DCT0 and DCT1 both exist, set DctSelBaseAddr[47:27] to the top of DCT0 */ |
| if (dct == 0) { |
| if (pDCTstat->DIMMValidDCT[1] > 0) { |
| dword = pDCTstat->DCTSysLimit + 1; |
| dword += pDCTstat->NodeSysBase; |
| dword >>= 8; /* scale [39:8] to [47:27],and to F2x110[31:11] */ |
| if ((dword >= DramHoleBase) && _MemHoleRemap) { |
| pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8; |
| val = pMCTstat->HoleBase; |
| val >>= 16; |
| val = (((~val) & 0xFF) + 1); |
| val <<= 8; |
| dword += val; |
| } |
| reg = 0x110; |
| val = Get_NB32(dev, reg); |
| val &= 0x7F; |
| val |= dword; |
| val |= 3; /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */ |
| Set_NB32(dev, reg, val); |
| |
| reg = 0x114; |
| val = dword; |
| Set_NB32(dev, reg, val); |
| } |
| } else { |
| /* Program the DctSelBaseAddr value to 0 |
| if DCT 0 is disabled */ |
| if (pDCTstat->DIMMValidDCT[0] == 0) { |
| dword = pDCTstat->NodeSysBase; |
| dword >>= 8; |
| if ((dword >= DramHoleBase) && _MemHoleRemap) { |
| pMCTstat->HoleBase = (DramHoleBase & 0xFFFFF800) << 8; |
| val = pMCTstat->HoleBase; |
| val >>= 8; |
| val &= ~(0xFFFF); |
| val |= (((~val) & 0xFFFF) + 1); |
| dword += val; |
| } |
| reg = 0x114; |
| val = dword; |
| Set_NB32(dev, reg, val); |
| |
| reg = 0x110; |
| val |= 3; /* Set F2x110[DctSelHiRngEn], F2x110[DctSelHi] */ |
| Set_NB32(dev, reg, val); |
| } |
| } |
| } else { |
| pDCTstat->NodeSysLimit += pDCTstat->DCTSysLimit; |
| } |
| printk(BIOS_DEBUG, "AfterStitch pDCTstat->NodeSysBase = %x\n", pDCTstat->NodeSysBase); |
| printk(BIOS_DEBUG, "mct_AfterStitchMemory: pDCTstat->NodeSysLimit = %x\n", pDCTstat->NodeSysLimit); |
| } |
| |
| static u8 mct_DIMMPresence(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 ret; |
| |
| if (dct == 0) |
| ret = DIMMPresence_D(pMCTstat, pDCTstat); |
| else |
| ret = pDCTstat->ErrCode; |
| |
| return ret; |
| } |
| |
| /* mct_BeforeGetDIMMAddress inline in C */ |
| |
| static void mct_OtherTiming(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| u8 Node; |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| struct DCTStatStruc *pDCTstat; |
| pDCTstat = pDCTstatA + Node; |
| if (pDCTstat->NodePresent) { |
| if (pDCTstat->DIMMValidDCT[0]) { |
| pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[0]; |
| Set_OtherTiming(pMCTstat, pDCTstat, 0); |
| } |
| if (pDCTstat->DIMMValidDCT[1] && !pDCTstat->GangedMode) { |
| pDCTstat->DIMMValid = pDCTstat->DIMMValidDCT[1]; |
| Set_OtherTiming(pMCTstat, pDCTstat, 1); |
| } |
| } /* Node is present*/ |
| } /* while Node */ |
| } |
| |
| static void Set_OtherTiming(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 reg; |
| u32 val; |
| u32 dword; |
| u32 dev = pDCTstat->dev_dct; |
| |
| Get_DqsRcvEnGross_Diff(pDCTstat, dev, dct, 0x98); |
| Get_WrDatGross_Diff(pDCTstat, dct, dev, 0x98); |
| Get_Trdrd(pMCTstat, pDCTstat, dct); |
| Get_Twrwr(pMCTstat, pDCTstat, dct); |
| Get_Twrrd(pMCTstat, pDCTstat, dct); |
| Get_TrwtTO(pMCTstat, pDCTstat, dct); |
| Get_TrwtWB(pMCTstat, pDCTstat); |
| |
| if (!is_fam15h()) { |
| reg = 0x8c; /* Dram Timing Hi */ |
| val = Get_NB32_DCT(dev, dct, reg); |
| val &= 0xffff0300; |
| dword = pDCTstat->TrwtTO; |
| val |= dword << 4; |
| dword = pDCTstat->Twrrd & 3; |
| val |= dword << 10; |
| dword = pDCTstat->Twrwr & 3; |
| val |= dword << 12; |
| dword = (pDCTstat->Trdrd - 0x3) & 3; |
| val |= dword << 14; |
| dword = pDCTstat->TrwtWB; |
| val |= dword; |
| Set_NB32_DCT(dev, dct, reg, val); |
| |
| reg = 0x78; |
| val = Get_NB32_DCT(dev, dct, reg); |
| val &= 0xffffc0ff; |
| dword = pDCTstat->Twrrd >> 2; |
| val |= dword << 8; |
| dword = pDCTstat->Twrwr >> 2; |
| val |= dword << 10; |
| dword = (pDCTstat->Trdrd - 0x3) >> 2; |
| val |= dword << 12; |
| Set_NB32_DCT(dev, dct, reg, val); |
| } |
| } |
| |
| static void Get_Trdrd(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| int8_t Trdrd; |
| |
| Trdrd = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - pDCTstat->DqsRcvEnGrossMin) >> 1) + 1; |
| if (Trdrd > 8) |
| Trdrd = 8; |
| if (Trdrd < 3) |
| Trdrd = 3; |
| pDCTstat->Trdrd = Trdrd; |
| } |
| |
| static void Get_Twrwr(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| int8_t Twrwr = 0; |
| |
| Twrwr = ((int8_t)(pDCTstat->WrDatGrossMax - pDCTstat->WrDatGrossMin) >> 1) + 2; |
| |
| if (Twrwr < 2) |
| Twrwr = 2; |
| else if (Twrwr > 9) |
| Twrwr = 9; |
| |
| pDCTstat->Twrwr = Twrwr; |
| } |
| |
| static void Get_Twrrd(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 LDplus1; |
| int8_t Twrrd; |
| |
| LDplus1 = Get_Latency_Diff(pMCTstat, pDCTstat, dct); |
| |
| Twrrd = ((int8_t)(pDCTstat->WrDatGrossMax - pDCTstat->DqsRcvEnGrossMin) >> 1) + 4 - LDplus1; |
| |
| if (Twrrd < 2) |
| Twrrd = 2; |
| else if (Twrrd > 10) |
| Twrrd = 10; |
| pDCTstat->Twrrd = Twrrd; |
| } |
| |
| static void Get_TrwtTO(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 LDplus1; |
| int8_t TrwtTO; |
| |
| LDplus1 = Get_Latency_Diff(pMCTstat, pDCTstat, dct); |
| |
| TrwtTO = ((int8_t)(pDCTstat->DqsRcvEnGrossMax - pDCTstat->WrDatGrossMin) >> 1) + LDplus1; |
| |
| pDCTstat->TrwtTO = TrwtTO; |
| } |
| |
| static void Get_TrwtWB(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| /* TrwtWB ensures read-to-write data-bus turnaround. |
| This value should be one more than the programmed TrwtTO.*/ |
| pDCTstat->TrwtWB = pDCTstat->TrwtTO; |
| } |
| |
| static u8 Get_Latency_Diff(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 dev = pDCTstat->dev_dct; |
| u32 val1, val2; |
| |
| val1 = Get_NB32_DCT(dev, dct, 0x88) & 0xF; |
| val2 = (Get_NB32_DCT(dev, dct, 0x84) >> 20) & 7; |
| |
| return val1 - val2; |
| } |
| |
| static void Get_DqsRcvEnGross_Diff(struct DCTStatStruc *pDCTstat, |
| u32 dev, uint8_t dct, u32 index_reg) |
| { |
| u8 Smallest, Largest; |
| u32 val; |
| u8 byte, bytex; |
| |
| /* The largest DqsRcvEnGrossDelay of any DIMM minus the |
| DqsRcvEnGrossDelay of any other DIMM is equal to the Critical |
| Gross Delay Difference (CGDD) */ |
| /* DqsRcvEn byte 1,0 */ |
| val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x10); |
| Largest = val & 0xFF; |
| Smallest = (val >> 8) & 0xFF; |
| |
| /* DqsRcvEn byte 3,2 */ |
| val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x11); |
| byte = val & 0xFF; |
| bytex = (val >> 8) & 0xFF; |
| if (bytex < Smallest) |
| Smallest = bytex; |
| if (byte > Largest) |
| Largest = byte; |
| |
| /* DqsRcvEn byte 5,4 */ |
| val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x20); |
| byte = val & 0xFF; |
| bytex = (val >> 8) & 0xFF; |
| if (bytex < Smallest) |
| Smallest = bytex; |
| if (byte > Largest) |
| Largest = byte; |
| |
| /* DqsRcvEn byte 7,6 */ |
| val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x21); |
| byte = val & 0xFF; |
| bytex = (val >> 8) & 0xFF; |
| if (bytex < Smallest) |
| Smallest = bytex; |
| if (byte > Largest) |
| Largest = byte; |
| |
| if (pDCTstat->DimmECCPresent> 0) { |
| /*DqsRcvEn Ecc */ |
| val = Get_DqsRcvEnGross_MaxMin(pDCTstat, dev, dct, index_reg, 0x12); |
| byte = val & 0xFF; |
| bytex = (val >> 8) & 0xFF; |
| if (bytex < Smallest) |
| Smallest = bytex; |
| if (byte > Largest) |
| Largest = byte; |
| } |
| |
| pDCTstat->DqsRcvEnGrossMax = Largest; |
| pDCTstat->DqsRcvEnGrossMin = Smallest; |
| } |
| |
| static void Get_WrDatGross_Diff(struct DCTStatStruc *pDCTstat, |
| u8 dct, u32 dev, u32 index_reg) |
| { |
| u8 Smallest = 0, Largest = 0; |
| u32 val; |
| u8 byte, bytex; |
| |
| /* The largest WrDatGrossDlyByte of any DIMM minus the |
| WrDatGrossDlyByte of any other DIMM is equal to CGDD */ |
| if (pDCTstat->DIMMValid & (1 << 0)) { |
| val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x01); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM0 */ |
| Largest = val & 0xFF; |
| Smallest = (val >> 8) & 0xFF; |
| } |
| if (pDCTstat->DIMMValid & (1 << 2)) { |
| val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x101); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM1 */ |
| byte = val & 0xFF; |
| bytex = (val >> 8) & 0xFF; |
| if (bytex < Smallest) |
| Smallest = bytex; |
| if (byte > Largest) |
| Largest = byte; |
| } |
| |
| /* If Cx, 2 more dimm need to be checked to find out the largest and smallest */ |
| if (pDCTstat->LogicalCPUID & AMD_DR_Cx) { |
| if (pDCTstat->DIMMValid & (1 << 4)) { |
| val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x201); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM2 */ |
| byte = val & 0xFF; |
| bytex = (val >> 8) & 0xFF; |
| if (bytex < Smallest) |
| Smallest = bytex; |
| if (byte > Largest) |
| Largest = byte; |
| } |
| if (pDCTstat->DIMMValid & (1 << 6)) { |
| val = Get_WrDatGross_MaxMin(pDCTstat, dct, dev, index_reg, 0x301); /* WrDatGrossDlyByte byte 0,1,2,3 for DIMM2 */ |
| byte = val & 0xFF; |
| bytex = (val >> 8) & 0xFF; |
| if (bytex < Smallest) |
| Smallest = bytex; |
| if (byte > Largest) |
| Largest = byte; |
| } |
| } |
| |
| pDCTstat->WrDatGrossMax = Largest; |
| pDCTstat->WrDatGrossMin = Smallest; |
| } |
| |
| static u16 Get_DqsRcvEnGross_MaxMin(struct DCTStatStruc *pDCTstat, |
| u32 dev, uint8_t dct, u32 index_reg, |
| u32 index) |
| { |
| u8 Smallest, Largest; |
| u8 i; |
| u8 byte; |
| u32 val; |
| u16 word; |
| u8 ecc_reg = 0; |
| |
| Smallest = 7; |
| Largest = 0; |
| |
| if (index == 0x12) |
| ecc_reg = 1; |
| |
| for (i = 0; i < 8; i+=2) { |
| if (pDCTstat->DIMMValid & (1 << i)) { |
| val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index); |
| val &= 0x00E000E0; |
| byte = (val >> 5) & 0xFF; |
| if (byte < Smallest) |
| Smallest = byte; |
| if (byte > Largest) |
| Largest = byte; |
| if (!(ecc_reg)) { |
| byte = (val >> (16 + 5)) & 0xFF; |
| if (byte < Smallest) |
| Smallest = byte; |
| if (byte > Largest) |
| Largest = byte; |
| } |
| } |
| index += 3; |
| } /* while ++i */ |
| |
| word = Smallest; |
| word <<= 8; |
| word |= Largest; |
| |
| return word; |
| } |
| |
| static u16 Get_WrDatGross_MaxMin(struct DCTStatStruc *pDCTstat, |
| u8 dct, u32 dev, u32 index_reg, |
| u32 index) |
| { |
| u8 Smallest, Largest; |
| u8 i, j; |
| u32 val; |
| u8 byte; |
| u16 word; |
| |
| Smallest = 3; |
| Largest = 0; |
| for (i = 0; i < 2; i++) { |
| val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index); |
| val &= 0x60606060; |
| val >>= 5; |
| for (j = 0; j < 4; j++) { |
| byte = val & 0xFF; |
| if (byte < Smallest) |
| Smallest = byte; |
| if (byte > Largest) |
| Largest = byte; |
| val >>= 8; |
| } /* while ++j */ |
| index++; |
| } /*while ++i*/ |
| |
| if (pDCTstat->DimmECCPresent > 0) { |
| index++; |
| val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index); |
| val &= 0x00000060; |
| val >>= 5; |
| byte = val & 0xFF; |
| if (byte < Smallest) |
| Smallest = byte; |
| if (byte > Largest) |
| Largest = byte; |
| } |
| |
| word = Smallest; |
| word <<= 8; |
| word |= Largest; |
| |
| return word; |
| } |
| |
| static void mct_PhyController_Config(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| uint8_t index; |
| uint32_t dword; |
| u32 index_reg = 0x98; |
| u32 dev = pDCTstat->dev_dct; |
| |
| if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_RB_C3 | AMD_FAM15_ALL)) { |
| if (is_fam15h()) { |
| /* Set F2x[1, 0]98_x0D0F0F13 DllDisEarlyU and DllDisEarlyL to save power */ |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8)); |
| dword |= (0x1 << 1); /* DllDisEarlyU = 1 */ |
| dword |= 0x1; /* DllDisEarlyL = 1 */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8), dword); |
| } |
| } |
| |
| if (pDCTstat->Dimmx4Present == 0) { |
| /* Set bit7 RxDqsUDllPowerDown to register F2x[1, 0]98_x0D0F0F13 for |
| * additional power saving when x4 DIMMs are not present. |
| */ |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8)); |
| dword |= (0x1 << 7); /* RxDqsUDllPowerDown = 1 */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0013 | (index << 8), dword); |
| } |
| } |
| } |
| |
| if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3 | AMD_FAM15_ALL)) { |
| if (pDCTstat->DimmECCPresent == 0) { |
| /* Set bit4 PwrDn to register F2x[1, 0]98_x0D0F0830 for power saving */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0830); |
| dword |= 1 << 4; /* BIOS should set this bit if ECC DIMMs are not present */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0830, dword); |
| } |
| } |
| |
| } |
| |
| static void mct_FinalMCT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| u8 Node; |
| struct DCTStatStruc *pDCTstat; |
| u32 val; |
| |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| mct_PhyController_Config(pMCTstat, pDCTstat, 0); |
| mct_PhyController_Config(pMCTstat, pDCTstat, 1); |
| |
| if (!is_fam15h()) { |
| /* Family 10h CPUs */ |
| mct_ExtMCTConfig_Cx(pDCTstat); |
| mct_ExtMCTConfig_Bx(pDCTstat); |
| mct_ExtMCTConfig_Dx(pDCTstat); |
| } else { |
| /* Family 15h CPUs */ |
| uint8_t nvram; |
| uint8_t enable_experimental_memory_speed_boost; |
| |
| /* Check to see if cache partitioning is allowed */ |
| enable_experimental_memory_speed_boost = 0; |
| if (get_option(&nvram, "experimental_memory_speed_boost") == CB_SUCCESS) |
| enable_experimental_memory_speed_boost = !!nvram; |
| |
| val = 0x0ce00f00; /* FlushWrOnStpGnt = 0x0 */ |
| val |= 0x10 << 2; /* MctWrLimit = 0x10 */ |
| val |= 0x1; /* DctWrLimit = 0x1 */ |
| Set_NB32(pDCTstat->dev_dct, 0x11c, val); |
| |
| val = Get_NB32(pDCTstat->dev_dct, 0x1b0); |
| val &= ~0x3; /* AdapPrefMissRatio = 0x1 */ |
| val |= 0x1; |
| val &= ~(0x3 << 2); /* AdapPrefPositiveStep = 0x0 */ |
| val &= ~(0x3 << 4); /* AdapPrefNegativeStep = 0x0 */ |
| val &= ~(0x7 << 8); /* CohPrefPrbLmt = 0x1 */ |
| val |= (0x1 << 8); |
| val |= (0x1 << 12); /* EnSplitDctLimits = 0x1 */ |
| if (enable_experimental_memory_speed_boost) |
| val |= (0x1 << 20); /* DblPrefEn = 0x1 */ |
| val |= (0x7 << 22); /* PrefFourConf = 0x7 */ |
| val |= (0x7 << 25); /* PrefFiveConf = 0x7 */ |
| val &= ~(0xf << 28); /* DcqBwThrotWm = 0x0 */ |
| Set_NB32(pDCTstat->dev_dct, 0x1b0, val); |
| |
| uint8_t wm1; |
| uint8_t wm2; |
| |
| switch (pDCTstat->Speed) { |
| case 0x4: |
| wm1 = 0x3; |
| wm2 = 0x4; |
| break; |
| case 0x6: |
| wm1 = 0x3; |
| wm2 = 0x5; |
| break; |
| case 0xa: |
| wm1 = 0x4; |
| wm2 = 0x6; |
| break; |
| case 0xe: |
| wm1 = 0x5; |
| wm2 = 0x8; |
| break; |
| case 0x12: |
| wm1 = 0x6; |
| wm2 = 0x9; |
| break; |
| default: |
| wm1 = 0x7; |
| wm2 = 0xa; |
| break; |
| } |
| |
| val = Get_NB32(pDCTstat->dev_dct, 0x1b4); |
| val &= ~(0x3ff); |
| val |= ((wm2 & 0x1f) << 5); |
| val |= (wm1 & 0x1f); |
| Set_NB32(pDCTstat->dev_dct, 0x1b4, val); |
| } |
| } |
| } |
| |
| /* ClrClToNB_D postponed until we're done executing from ROM */ |
| mct_ClrWbEnhWsbDis_D(pMCTstat, pDCTstat); |
| |
| /* set F3x8C[DisFastTprWr] on all DR, if L3Size = 0 */ |
| if (pDCTstat->LogicalCPUID & AMD_DR_ALL) { |
| if (!(cpuid_edx(0x80000006) & 0xFFFC0000)) { |
| val = Get_NB32(pDCTstat->dev_nbmisc, 0x8C); |
| val |= 1 << 24; |
| Set_NB32(pDCTstat->dev_nbmisc, 0x8C, val); |
| } |
| } |
| } |
| |
| void mct_ForceNBPState0_En_Fam15(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| /* Force the NB P-state to P0 */ |
| uint32_t dword; |
| uint32_t dword2; |
| |
| dword = Get_NB32(pDCTstat->dev_nbctl, 0x174); |
| if (!(dword & 0x1)) { |
| dword = Get_NB32(pDCTstat->dev_nbctl, 0x170); |
| pDCTstat->SwNbPstateLoDis = (dword >> 14) & 0x1; |
| pDCTstat->NbPstateDisOnP0 = (dword >> 13) & 0x1; |
| pDCTstat->NbPstateThreshold = (dword >> 9) & 0x7; |
| pDCTstat->NbPstateHi = (dword >> 6) & 0x3; |
| dword &= ~(0x1 << 14); /* SwNbPstateLoDis = 0 */ |
| dword &= ~(0x1 << 13); /* NbPstateDisOnP0 = 0 */ |
| dword &= ~(0x7 << 9); /* NbPstateThreshold = 0 */ |
| dword &= ~(0x3 << 3); /* NbPstateLo = NbPstateMaxVal */ |
| dword |= ((dword & 0x3) << 3); |
| Set_NB32(pDCTstat->dev_nbctl, 0x170, dword); |
| |
| if (!is_model10_1f()) { |
| /* Wait until CurNbPState == NbPstateLo */ |
| do { |
| dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174); |
| } while (((dword2 << 19) & 0x7) != (dword & 0x3)); |
| } |
| dword = Get_NB32(pDCTstat->dev_nbctl, 0x170); |
| dword &= ~(0x3 << 6); /* NbPstateHi = 0 */ |
| dword |= (0x3 << 14); /* SwNbPstateLoDis = 1 */ |
| Set_NB32(pDCTstat->dev_nbctl, 0x170, dword); |
| |
| if (!is_model10_1f()) { |
| /* Wait until CurNbPState == 0 */ |
| do { |
| dword2 = Get_NB32(pDCTstat->dev_nbctl, 0x174); |
| } while (((dword2 << 19) & 0x7) != 0); |
| } |
| } |
| } |
| |
| void mct_ForceNBPState0_Dis_Fam15(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| /* Restore normal NB P-state functionailty */ |
| uint32_t dword; |
| |
| dword = Get_NB32(pDCTstat->dev_nbctl, 0x174); |
| if (!(dword & 0x1)) { |
| dword = Get_NB32(pDCTstat->dev_nbctl, 0x170); |
| dword &= ~(0x1 << 14); /* SwNbPstateLoDis*/ |
| dword |= ((pDCTstat->SwNbPstateLoDis & 0x1) << 14); |
| dword &= ~(0x1 << 13); /* NbPstateDisOnP0 */ |
| dword |= ((pDCTstat->NbPstateDisOnP0 & 0x1) << 13); |
| dword &= ~(0x7 << 9); /* NbPstateThreshold */ |
| dword |= ((pDCTstat->NbPstateThreshold & 0x7) << 9); |
| dword &= ~(0x3 << 6); /* NbPstateHi */ |
| dword |= ((pDCTstat->NbPstateHi & 0x3) << 3); |
| Set_NB32(pDCTstat->dev_nbctl, 0x170, dword); |
| } |
| } |
| |
| static void mct_InitialMCT_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) |
| { |
| if (is_fam15h()) { |
| msr_t p0_state_msr; |
| uint8_t cpu_fid; |
| uint8_t cpu_did; |
| uint32_t cpu_divisor; |
| uint8_t boost_states; |
| |
| /* Retrieve the number of boost states */ |
| boost_states = (Get_NB32(pDCTstat->dev_link, 0x15c) >> 2) & 0x7; |
| |
| /* Retrieve and store the TSC frequency (P0 COF) */ |
| p0_state_msr = rdmsr(0xc0010064 + boost_states); |
| cpu_fid = p0_state_msr.lo & 0x3f; |
| cpu_did = (p0_state_msr.lo >> 6) & 0x7; |
| cpu_divisor = (0x1 << cpu_did); |
| pMCTstat->TSCFreq = (100 * (cpu_fid + 0x10)) / cpu_divisor; |
| |
| printk(BIOS_DEBUG, "mct_InitialMCT_D: mct_ForceNBPState0_En_Fam15\n"); |
| mct_ForceNBPState0_En_Fam15(pMCTstat, pDCTstat); |
| } else { |
| /* K10 BKDG v3.62 section 2.8.9.2 */ |
| printk(BIOS_DEBUG, "mct_InitialMCT_D: clear_legacy_Mode\n"); |
| clear_legacy_Mode(pMCTstat, pDCTstat); |
| |
| /* Northbridge configuration */ |
| mct_SetClToNB_D(pMCTstat, pDCTstat); |
| mct_SetWbEnhWsbDis_D(pMCTstat, pDCTstat); |
| } |
| } |
| |
| static u32 mct_NodePresent_D(void) |
| { |
| u32 val; |
| if (is_fam15h()) { |
| if (is_model10_1f()) { |
| val = 0x14001022; |
| } else { |
| val = 0x16001022; |
| } |
| } else { |
| val = 0x12001022; |
| } |
| return val; |
| } |
| |
| static void mct_init(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 lo, hi; |
| u32 addr; |
| |
| pDCTstat->GangedMode = 0; |
| pDCTstat->DRPresent = 1; |
| |
| /* enable extend PCI configuration access */ |
| addr = 0xC001001F; |
| _RDMSR(addr, &lo, &hi); |
| if (hi & (1 << (46-32))) { |
| pDCTstat->Status |= 1 << SB_ExtConfig; |
| } else { |
| hi |= 1 << (46-32); |
| _WRMSR(addr, lo, hi); |
| } |
| } |
| |
| static void clear_legacy_Mode(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 reg; |
| u32 val; |
| u32 dev = pDCTstat->dev_dct; |
| |
| /* Clear Legacy BIOS Mode bit */ |
| reg = 0x94; |
| val = Get_NB32_DCT(dev, 0, reg); |
| val &= ~(1<<LegacyBiosMode); |
| Set_NB32_DCT(dev, 0, reg, val); |
| |
| val = Get_NB32_DCT(dev, 1, reg); |
| val &= ~(1<<LegacyBiosMode); |
| Set_NB32_DCT(dev, 1, reg, val); |
| } |
| |
| static void mct_HTMemMapExt(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| u8 Node; |
| u32 Drambase, Dramlimit; |
| u32 val; |
| u32 reg; |
| u32 dev; |
| u32 devx; |
| u32 dword; |
| struct DCTStatStruc *pDCTstat; |
| |
| pDCTstat = pDCTstatA + 0; |
| dev = pDCTstat->dev_map; |
| |
| /* Copy dram map from F1x40/44,F1x48/4c, |
| to F1x120/124(Node0),F1x120/124(Node1),...*/ |
| for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| devx = pDCTstat->dev_map; |
| |
| /* get base/limit from Node0 */ |
| reg = 0x40 + (Node << 3); /* Node0/Dram Base 0 */ |
| val = Get_NB32(dev, reg); |
| Drambase = val >> (16 + 3); |
| |
| reg = 0x44 + (Node << 3); /* Node0/Dram Base 0 */ |
| val = Get_NB32(dev, reg); |
| Dramlimit = val >> (16 + 3); |
| |
| /* set base/limit to F1x120/124 per Node */ |
| if (pDCTstat->NodePresent) { |
| reg = 0x120; /* F1x120,DramBase[47:27] */ |
| val = Get_NB32(devx, reg); |
| val &= 0xFFE00000; |
| val |= Drambase; |
| Set_NB32(devx, reg, val); |
| |
| reg = 0x124; |
| val = Get_NB32(devx, reg); |
| val &= 0xFFE00000; |
| val |= Dramlimit; |
| Set_NB32(devx, reg, val); |
| |
| if (pMCTstat->GStatus & (1 << GSB_HWHole)) { |
| reg = 0xF0; |
| val = Get_NB32(devx, reg); |
| val |= (1 << DramMemHoistValid); |
| val &= ~(0xFF << 24); |
| dword = (pMCTstat->HoleBase >> (24 - 8)) & 0xFF; |
| dword <<= 24; |
| val |= dword; |
| Set_NB32(devx, reg, val); |
| } |
| |
| } |
| } |
| } |
| |
| static void SetCSTriState(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 val; |
| u32 dev = pDCTstat->dev_dct; |
| u32 index_reg = 0x98; |
| u16 word; |
| |
| if (is_fam15h()) { |
| word = fam15h_cs_tristate_enable_code(pDCTstat, dct); |
| } else { |
| /* Tri-state unused chipselects when motherboard |
| termination is available */ |
| |
| /* FIXME: skip for Ax */ |
| |
| word = pDCTstat->CSPresent; |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| word |= (word & 0x55) << 1; |
| } |
| word = (~word) & 0xff; |
| } |
| |
| val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c); |
| val &= ~0xff; |
| val |= word; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val); |
| } |
| |
| static void SetCKETriState(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 val; |
| u32 dev; |
| u32 index_reg = 0x98; |
| u16 word; |
| |
| /* Tri-state unused CKEs when motherboard termination is available */ |
| |
| /* FIXME: skip for Ax */ |
| |
| dev = pDCTstat->dev_dct; |
| word = pDCTstat->CSPresent; |
| |
| val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c); |
| val &= ~(0x3 << 12); |
| if ((word & 0x55) == 0) |
| val |= 1 << 12; |
| if ((word & 0xaa) == 0) |
| val |= 1 << 13; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val); |
| } |
| |
| static void SetODTTriState(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 val; |
| u32 dev; |
| u32 index_reg = 0x98; |
| u8 cs; |
| u8 odt; |
| u8 max_dimms; |
| |
| dev = pDCTstat->dev_dct; |
| |
| if (is_fam15h()) { |
| odt = fam15h_odt_tristate_enable_code(pDCTstat, dct); |
| } else { |
| /* FIXME: skip for Ax */ |
| |
| /* Tri-state unused ODTs when motherboard termination is available */ |
| max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS); |
| odt = 0x0f; /* ODT tri-state setting */ |
| |
| if (pDCTstat->Status & (1 <<SB_Registered)) { |
| for (cs = 0; cs < 8; cs += 2) { |
| if (pDCTstat->CSPresent & (1 << cs)) { |
| odt &= ~(1 << (cs / 2)); |
| if (mctGet_NVbits(NV_4RANKType) != 0) { /* quad-rank capable platform */ |
| if (pDCTstat->CSPresent & (1 << (cs + 1))) |
| odt &= ~(4 << (cs / 2)); |
| } |
| } |
| } |
| } else { /* AM3 package */ |
| val = ~(pDCTstat->CSPresent); |
| odt = val & 9; /* swap bits 1 and 2 */ |
| if (val & (1 << 1)) |
| odt |= 1 << 2; |
| if (val & (1 << 2)) |
| odt |= 1 << 1; |
| } |
| } |
| |
| val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c); |
| val &= ~(0xf << 8); /* ODTTri = odt */ |
| val |= (odt & 0xf) << 8; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val); |
| } |
| |
| /* Family 15h */ |
| static void InitDDRPhy(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| uint8_t index; |
| uint32_t dword; |
| uint8_t ddr_voltage_index; |
| uint8_t amd_voltage_level_index = 0; |
| uint32_t index_reg = 0x98; |
| uint32_t dev = pDCTstat->dev_dct; |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| /* Find current DDR supply voltage for this DCT */ |
| ddr_voltage_index = dct_ddr_voltage_index(pDCTstat, dct); |
| |
| /* Fam15h BKDG v3.14 section 2.10.5.3 |
| * The remainder of the Phy Initialization algorithm picks up in phyAssistedMemFnceTraining |
| */ |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000b, 0x80000000); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe013, 0x00000118); |
| |
| /* Program desired VDDIO level */ |
| if (ddr_voltage_index & 0x4) { |
| /* 1.25V */ |
| amd_voltage_level_index = 0x2; |
| } else if (ddr_voltage_index & 0x2) { |
| /* 1.35V */ |
| amd_voltage_level_index = 0x1; |
| } else if (ddr_voltage_index & 0x1) { |
| /* 1.50V */ |
| amd_voltage_level_index = 0x0; |
| } |
| |
| /* D18F2x9C_x0D0F_0[F,8:0]1F_dct[1:0][RxVioLvl] */ |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f | (index << 8)); |
| dword &= ~(0x3 << 3); |
| dword |= (amd_voltage_level_index << 3); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f001f | (index << 8), dword); |
| } |
| |
| /* D18F2x9C_x0D0F_[C,8,2][2:0]1F_dct[1:0][RxVioLvl] */ |
| for (index = 0; index < 0x3; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f | (index << 8)); |
| dword &= ~(0x3 << 3); |
| dword |= (amd_voltage_level_index << 3); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f201f | (index << 8), dword); |
| } |
| for (index = 0; index < 0x2; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f | (index << 8)); |
| dword &= ~(0x3 << 3); |
| dword |= (amd_voltage_level_index << 3); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f801f | (index << 8), dword); |
| } |
| for (index = 0; index < 0x1; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f | (index << 8)); |
| dword &= ~(0x3 << 3); |
| dword |= (amd_voltage_level_index << 3); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc01f | (index << 8), dword); |
| } |
| |
| /* D18F2x9C_x0D0F_4009_dct[1:0][CmpVioLvl, ComparatorAdjust] */ |
| /* NOTE: CmpVioLvl and ComparatorAdjust only take effect when set on DCT 0 */ |
| dword = Get_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0f4009); |
| dword &= ~(0x0000c00c); |
| dword |= (amd_voltage_level_index << 14); |
| dword |= (amd_voltage_level_index << 2); |
| Set_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0f4009, dword); |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static void InitPhyCompensation(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 i; |
| u32 index_reg = 0x98; |
| u32 dev = pDCTstat->dev_dct; |
| u32 valx = 0; |
| uint8_t index; |
| uint32_t dword; |
| const u8 *p; |
| |
| printk(BIOS_DEBUG, "%s: DCT %d: Start\n", __func__, dct); |
| |
| if (is_fam15h()) { |
| /* Algorithm detailed in the Fam15h BKDG Rev. 3.14 section 2.10.5.3.4 */ |
| uint32_t tx_pre; |
| uint32_t drive_strength; |
| |
| /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisAutoComp] */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003); |
| dword |= (0x1 << 14); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fe003, dword); |
| |
| /* Program D18F2x9C_x0D0F_E003_dct[1:0][DisablePredriverCal] */ |
| /* NOTE: DisablePredriverCal only takes effect when set on DCT 0 */ |
| dword = Get_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0fe003); |
| dword |= (0x1 << 13); |
| Set_NB32_index_wait_DCT(dev, 0, index_reg, 0x0d0fe003, dword); |
| |
| /* Determine TxPreP/TxPreN for data lanes (Stage 1) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000); |
| drive_strength = (dword >> 20) & 0x7; /* DqsDrvStren */ |
| tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, drive_strength); |
| |
| /* Program TxPreP/TxPreN for data lanes (Stage 1) */ |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0006 | (index << 8)); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0006 | (index << 8), dword); |
| } |
| |
| /* Determine TxPreP/TxPreN for data lanes (Stage 2) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000); |
| drive_strength = (dword >> 16) & 0x7; /* DataDrvStren */ |
| tx_pre = fam15h_phy_predriver_calibration_code(pDCTstat, dct, drive_strength); |
| |
| /* Program TxPreP/TxPreN for data lanes (Stage 2) */ |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000a | (index << 8)); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f000a | (index << 8), dword); |
| } |
| for (index = 0; index < 0x9; index++) { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0002 | (index << 8)); |
| dword &= ~(0xffff); |
| dword |= (0x8000 | tx_pre); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0002 | (index << 8), dword); |
| } |
| |
| /* Determine TxPreP/TxPreN for command/address lines (Stage 1) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000); |
| drive_strength = (dword >> 4) & 0x7; /* CsOdtDrvStren */ |
| tx_pre = fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength); |
| |
| /* Program TxPreP/TxPreN for command/address lines (Stage 1) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8006); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8006, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f800a); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f800a, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8002); |
| dword &= ~(0xffff); |
| dword |= (0x8000 | tx_pre); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8002, dword); |
| |
| /* Determine TxPreP/TxPreN for command/address lines (Stage 2) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000); |
| drive_strength = (dword >> 8) & 0x7; /* AddrCmdDrvStren */ |
| tx_pre = fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength); |
| |
| /* Program TxPreP/TxPreN for command/address lines (Stage 2) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8106); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8106, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f810a); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f810a, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc006); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc006, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00a); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00a, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00e); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc00e, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc012); |
| dword &= ~(0xffff); |
| dword |= tx_pre; |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc012, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8102); |
| dword &= ~(0xffff); |
| dword |= (0x8000 | tx_pre); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f8102, dword); |
| |
| /* Determine TxPreP/TxPreN for command/address lines (Stage 3) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000); |
| drive_strength = (dword >> 0) & 0x7; /* CkeDrvStren */ |
| tx_pre = fam15h_phy_predriver_cmd_addr_calibration_code(pDCTstat, dct, drive_strength); |
| |
| /* Program TxPreP/TxPreN for command/address lines (Stage 3) */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc002); |
| dword &= ~(0xffff); |
| dword |= (0x8000 | tx_pre); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0fc002, dword); |
| |
| /* Determine TxPreP/TxPreN for clock lines */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00000000); |
| drive_strength = (dword >> 12) & 0x7; /* ClkDrvStren */ |
| tx_pre = fam15h_phy_predriver_clk_calibration_code(pDCTstat, dct, drive_strength); |
| |
| /* Program TxPreP/TxPreN for clock lines */ |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2002); |
| dword &= ~(0xffff); |
| dword |= (0x8000 | tx_pre); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2002, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2102); |
| dword &= ~(0xffff); |
| dword |= (0x8000 | tx_pre); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2102, dword); |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2202); |
| dword &= ~(0xffff); |
| dword |= (0x8000 | tx_pre); |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f2202, dword); |
| |
| if (!is_model10_1f()) { |
| /* Be extra safe and wait for the predriver calibration |
| * to be applied to the hardware. The BKDG does not |
| * require this, but it does take some time for the |
| * data to propagate, so it's probably a good idea. |
| */ |
| uint8_t predriver_cal_pending = 1; |
| printk(BIOS_DEBUG, "Waiting for predriver calibration to be applied..."); |
| while (predriver_cal_pending) { |
| predriver_cal_pending = 0; |
| for (index = 0; index < 0x9; index++) { |
| if (Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0d0f0002 | (index << 8)) & 0x8000) |
| predriver_cal_pending = 1; |
| } |
| } |
| printk(BIOS_DEBUG, "done!\n"); |
| } |
| } else { |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x00); |
| dword = 0; |
| for (i = 0; i < 6; i++) { |
| switch (i) { |
| case 0: |
| case 4: |
| p = Table_Comp_Rise_Slew_15x; |
| valx = p[(dword >> 16) & 3]; |
| break; |
| case 1: |
| case 5: |
| p = Table_Comp_Fall_Slew_15x; |
| valx = p[(dword >> 16) & 3]; |
| break; |
| case 2: |
| p = Table_Comp_Rise_Slew_20x; |
| valx = p[(dword >> 8) & 3]; |
| break; |
| case 3: |
| p = Table_Comp_Fall_Slew_20x; |
| valx = p[(dword >> 8) & 3]; |
| break; |
| } |
| dword |= valx << (5 * i); |
| } |
| |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0a, dword); |
| } |
| |
| printk(BIOS_DEBUG, "%s: DCT %d: Done\n", __func__, dct); |
| } |
| |
| static void mct_EarlyArbEn_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| if (!is_fam15h()) { |
| u32 reg; |
| u32 val; |
| u32 dev = pDCTstat->dev_dct; |
| |
| /* GhEnhancement #18429 modified by askar: For low NB CLK : |
| * Memclk ratio, the DCT may need to arbitrate early to avoid |
| * unnecessary bubbles. |
| * bit 19 of F2x[1,0]78 Dram Control Register, set this bit only when |
| * NB CLK : Memclk ratio is between 3:1 (inclusive) to 4:5 (inclusive) |
| */ |
| reg = 0x78; |
| val = Get_NB32_DCT(dev, dct, reg); |
| |
| if (pDCTstat->LogicalCPUID & (AMD_DR_Cx | AMD_DR_Dx)) |
| val |= (1 << EarlyArbEn); |
| else if (CheckNBCOFEarlyArbEn(pMCTstat, pDCTstat)) |
| val |= (1 << EarlyArbEn); |
| |
| Set_NB32_DCT(dev, dct, reg, val); |
| } |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static u8 CheckNBCOFEarlyArbEn(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 reg; |
| u32 val; |
| u32 tmp; |
| u32 rem; |
| u32 dev = pDCTstat->dev_dct; |
| u32 hi, lo; |
| u8 NbDid = 0; |
| |
| /* Check if NB COF >= 4*Memclk, if it is not, return a fatal error |
| */ |
| |
| /* 3*(Fn2xD4[NBFid]+4)/(2^NbDid)/(3+Fn2x94[MemClkFreq]) */ |
| _RDMSR(0xC0010071, &lo, &hi); |
| if (lo & (1 << 22)) |
| NbDid |= 1; |
| |
| reg = 0x94; |
| val = Get_NB32_DCT(dev, 0, reg); |
| if (!(val & (1 << MemClkFreqVal))) |
| val = Get_NB32_DCT(dev, 1, reg); /* get the DCT1 value */ |
| |
| val &= 0x07; |
| val += 3; |
| if (NbDid) |
| val <<= 1; |
| tmp = val; |
| |
| dev = pDCTstat->dev_nbmisc; |
| reg = 0xD4; |
| val = Get_NB32(dev, reg); |
| val &= 0x1F; |
| val += 3; |
| val *= 3; |
| val = val / tmp; |
| rem = val % tmp; |
| tmp >>= 1; |
| |
| /* Yes this could be nicer but this was how the asm was.... */ |
| if (val < 3) { /* NClk:MemClk < 3:1 */ |
| return 0; |
| } else if (val > 4) { /* NClk:MemClk >= 5:1 */ |
| return 0; |
| } else if ((val == 4) && (rem > tmp)) { /* NClk:MemClk > 4.5:1 */ |
| return 0; |
| } else { |
| return 1; /* 3:1 <= NClk:MemClk <= 4.5:1*/ |
| } |
| } |
| |
| static void mct_ResetDataStruct_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| uint8_t Node; |
| struct DCTStatStruc *pDCTstat; |
| uint16_t host_serv1, host_serv2; |
| uint8_t CH_D_B_TxDqs_bkp[2][4][9]; |
| |
| /* Initialize Data structures by clearing all entries to 0 */ |
| memset(pMCTstat, 0, sizeof(struct MCTStatStruc)); |
| |
| for (Node = 0; Node < 8; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| host_serv1 = pDCTstat->HostBiosSrvc1; |
| host_serv2 = pDCTstat->HostBiosSrvc2; |
| memcpy(CH_D_B_TxDqs_bkp, pDCTstat->CH_D_B_TxDqs, sizeof(CH_D_B_TxDqs_bkp)); |
| |
| memset(pDCTstat, 0, sizeof(struct DCTStatStruc)); |
| |
| pDCTstat->HostBiosSrvc1 = host_serv1; |
| pDCTstat->HostBiosSrvc2 = host_serv2; |
| memcpy(pDCTstat->CH_D_B_TxDqs, CH_D_B_TxDqs_bkp, sizeof(pDCTstat->CH_D_B_TxDqs)); |
| } |
| } |
| |
| static void mct_BeforeDramInit_Prod_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| mct_ProgramODT_D(pMCTstat, pDCTstat, dct); |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 i; |
| u32 dword; |
| u32 dev = pDCTstat->dev_dct; |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); |
| |
| if (is_fam15h()) { |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[dct]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| uint32_t odt_pattern_0; |
| uint32_t odt_pattern_1; |
| uint32_t odt_pattern_2; |
| uint32_t odt_pattern_3; |
| uint8_t write_odt_duration; |
| uint8_t read_odt_duration; |
| uint8_t write_odt_delay; |
| uint8_t read_odt_delay; |
| |
| /* NOTE |
| * Rank count per DIMM and DCT is encoded by pDCTstat->DimmRanks[(<dimm number> * 2) + dct] |
| */ |
| |
| /* Select appropriate ODT pattern for installed DIMMs |
| * Refer to the Fam15h BKDG Rev. 3.14, page 149 onwards |
| */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| if (rank_count_dimm1 == 1) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00020000; |
| } else if (rank_count_dimm1 == 2) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x08020000; |
| } else if (rank_count_dimm1 == 4) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x020a0000; |
| odt_pattern_3 = 0x080a0000; |
| } else { |
| /* Fallback */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x08020000; |
| } |
| } else { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x01010202; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x09030603; |
| } else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4)) { |
| odt_pattern_0 = 0x01010000; |
| odt_pattern_1 = 0x01010a0a; |
| odt_pattern_2 = 0x01090000; |
| odt_pattern_3 = 0x01030e0b; |
| } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4)) { |
| odt_pattern_0 = 0x00000202; |
| odt_pattern_1 = 0x05050202; |
| odt_pattern_2 = 0x00000206; |
| odt_pattern_3 = 0x0d070203; |
| } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 == 4)) { |
| odt_pattern_0 = 0x05050a0a; |
| odt_pattern_1 = 0x05050a0a; |
| odt_pattern_2 = 0x050d0a0e; |
| odt_pattern_3 = 0x05070a0b; |
| } else { |
| /* Fallback */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } |
| } else { |
| /* FIXME |
| * 3 DIMMs per channel UNIMPLEMENTED |
| */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } else if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* TODO |
| * Load reduced dimms UNIMPLEMENTED |
| */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } else { |
| if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; |
| if (rank_count_dimm1 == 1) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00020000; |
| } else if (rank_count_dimm1 == 2) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x08020000; |
| } else { |
| /* Fallback */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x08020000; |
| } |
| } else { |
| /* 2 DIMMs detected */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x01010202; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x09030603; |
| } |
| } else { |
| /* FIXME |
| * 3 DIMMs per channel UNIMPLEMENTED |
| */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } |
| |
| if (pDCTstat->Status & (1 << SB_LoadReduced)) { |
| /* TODO |
| * Load reduced dimms UNIMPLEMENTED |
| */ |
| write_odt_duration = 0x0; |
| read_odt_duration = 0x0; |
| write_odt_delay = 0x0; |
| read_odt_delay = 0x0; |
| } else { |
| uint8_t tcl; |
| uint8_t tcwl; |
| tcl = Get_NB32_DCT(dev, dct, 0x200) & 0x1f; |
| tcwl = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f; |
| |
| write_odt_duration = 0x6; |
| read_odt_duration = 0x6; |
| write_odt_delay = 0x0; |
| if (tcl > tcwl) |
| read_odt_delay = tcl - tcwl; |
| else |
| read_odt_delay = 0x0; |
| } |
| |
| /* Program ODT pattern */ |
| Set_NB32_DCT(dev, dct, 0x230, odt_pattern_1); |
| Set_NB32_DCT(dev, dct, 0x234, odt_pattern_0); |
| Set_NB32_DCT(dev, dct, 0x238, odt_pattern_3); |
| Set_NB32_DCT(dev, dct, 0x23c, odt_pattern_2); |
| dword = Get_NB32_DCT(dev, dct, 0x240); |
| dword &= ~(0x7 << 12); /* WrOdtOnDuration = write_odt_duration */ |
| dword |= (write_odt_duration & 0x7) << 12; |
| dword &= ~(0x7 << 8); /* WrOdtTrnOnDly = write_odt_delay */ |
| dword |= (write_odt_delay & 0x7) << 8; |
| dword &= ~(0xf << 4); /* RdOdtOnDuration = read_odt_duration */ |
| dword |= (read_odt_duration & 0xf) << 4; |
| dword &= ~(0xf); /* RdOdtTrnOnDly = read_odt_delay */ |
| dword |= (read_odt_delay & 0xf); |
| Set_NB32_DCT(dev, dct, 0x240, dword); |
| |
| printk(BIOS_SPEW, "Programmed DCT %d ODT pattern %08x %08x %08x %08x\n", dct, odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3); |
| } else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) { |
| if (pDCTstat->Speed == 3) |
| dword = 0x00000800; |
| else |
| dword = 0x00000000; |
| for (i = 0; i < 2; i++) { |
| Set_NB32_DCT(dev, i, 0x98, 0x0D000030); |
| Set_NB32_DCT(dev, i, 0x9C, dword); |
| Set_NB32_DCT(dev, i, 0x98, 0x4D040F30); |
| |
| /* Obtain number of DIMMs on channel */ |
| uint8_t dimm_count = pDCTstat->MAdimms[i]; |
| uint8_t rank_count_dimm0; |
| uint8_t rank_count_dimm1; |
| uint32_t odt_pattern_0; |
| uint32_t odt_pattern_1; |
| uint32_t odt_pattern_2; |
| uint32_t odt_pattern_3; |
| |
| /* Select appropriate ODT pattern for installed DIMMs |
| * Refer to the Fam10h BKDG Rev. 3.62, page 120 onwards |
| */ |
| if (pDCTstat->Status & (1 << SB_Registered)) { |
| if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + i]; |
| if (rank_count_dimm1 == 1) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00020000; |
| } else if (rank_count_dimm1 == 2) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x02080000; |
| } else if (rank_count_dimm1 == 4) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x020a0000; |
| odt_pattern_3 = 0x080a0000; |
| } else { |
| /* Fallback */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } else { |
| /* 2 DIMMs detected */ |
| rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + i]; |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + i]; |
| if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x01010202; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x09030603; |
| } else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4)) { |
| odt_pattern_0 = 0x01010000; |
| odt_pattern_1 = 0x01010a0a; |
| odt_pattern_2 = 0x01090000; |
| odt_pattern_3 = 0x01030e0b; |
| } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4)) { |
| odt_pattern_0 = 0x00000202; |
| odt_pattern_1 = 0x05050202; |
| odt_pattern_2 = 0x00000206; |
| odt_pattern_3 = 0x0d070203; |
| } else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 == 4)) { |
| odt_pattern_0 = 0x05050a0a; |
| odt_pattern_1 = 0x05050a0a; |
| odt_pattern_2 = 0x050d0a0e; |
| odt_pattern_3 = 0x05070a0b; |
| } else { |
| /* Fallback */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } |
| } else { |
| /* FIXME |
| * 3 DIMMs per channel UNIMPLEMENTED |
| */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } else { |
| if (MaxDimmsInstallable == 2) { |
| if (dimm_count == 1) { |
| /* 1 DIMM detected */ |
| rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + i]; |
| if (rank_count_dimm1 == 1) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00020000; |
| } else if (rank_count_dimm1 == 2) { |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x02080000; |
| } else { |
| /* Fallback */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } else { |
| /* 2 DIMMs detected */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x01010202; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x09030603; |
| } |
| } else { |
| /* FIXME |
| * 3 DIMMs per channel UNIMPLEMENTED |
| */ |
| odt_pattern_0 = 0x00000000; |
| odt_pattern_1 = 0x00000000; |
| odt_pattern_2 = 0x00000000; |
| odt_pattern_3 = 0x00000000; |
| } |
| } |
| |
| /* Program ODT pattern */ |
| Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x180, odt_pattern_1); |
| Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x181, odt_pattern_0); |
| Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x182, odt_pattern_3); |
| Set_NB32_index_wait_DCT(dev, i, 0xf0, 0x183, odt_pattern_2); |
| |
| printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x %08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3); |
| } |
| } |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static void mct_EnDllShutdownSR(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 dev = pDCTstat->dev_dct, val; |
| |
| /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */ |
| if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) { |
| Set_NB32_DCT(dev, dct, 0x9C, 0x1C); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006); |
| Set_NB32_DCT(dev, dct, 0x9C, 0x13D); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007); |
| |
| val = Get_NB32_DCT(dev, dct, 0x90); |
| val &= ~(1 << 27/* DisDllShutdownSR */); |
| Set_NB32_DCT(dev, dct, 0x90, val); |
| } |
| } |
| |
| static u32 mct_DisDllShutdownSR(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u32 DramConfigLo, u8 dct) |
| { |
| u32 dev = pDCTstat->dev_dct; |
| |
| /* Write 0000_07D0h to register F2x[1, 0]98_x4D0FE006 */ |
| if (pDCTstat->LogicalCPUID & (AMD_DR_DAC2_OR_C3)) { |
| Set_NB32_DCT(dev, dct, 0x9C, 0x7D0); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE006); |
| Set_NB32_DCT(dev, dct, 0x9C, 0x190); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D0FE007); |
| |
| DramConfigLo |= /* DisDllShutdownSR */ 1 << 27; |
| } |
| |
| return DramConfigLo; |
| } |
| |
| void mct_SetClToNB_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 lo, hi; |
| u32 msr; |
| |
| /* FIXME: Maybe check the CPUID? - not for now. */ |
| /* pDCTstat->LogicalCPUID; */ |
| |
| msr = BU_CFG2; |
| _RDMSR(msr, &lo, &hi); |
| lo |= 1 << ClLinesToNbDis; |
| _WRMSR(msr, lo, hi); |
| } |
| |
| void mct_ClrClToNB_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| |
| u32 lo, hi; |
| u32 msr; |
| |
| /* FIXME: Maybe check the CPUID? - not for now. */ |
| /* pDCTstat->LogicalCPUID; */ |
| |
| msr = BU_CFG2; |
| _RDMSR(msr, &lo, &hi); |
| if (!pDCTstat->ClToNB_flag) |
| lo &= ~(1<<ClLinesToNbDis); |
| _WRMSR(msr, lo, hi); |
| |
| } |
| |
| void mct_SetWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 lo, hi; |
| u32 msr; |
| |
| /* FIXME: Maybe check the CPUID? - not for now. */ |
| /* pDCTstat->LogicalCPUID; */ |
| |
| msr = BU_CFG; |
| _RDMSR(msr, &lo, &hi); |
| hi |= (1 << WbEnhWsbDis_D); |
| _WRMSR(msr, lo, hi); |
| } |
| |
| void mct_ClrWbEnhWsbDis_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 lo, hi; |
| u32 msr; |
| |
| /* FIXME: Maybe check the CPUID? - not for now. */ |
| /* pDCTstat->LogicalCPUID; */ |
| |
| msr = BU_CFG; |
| _RDMSR(msr, &lo, &hi); |
| hi &= ~(1 << WbEnhWsbDis_D); |
| _WRMSR(msr, lo, hi); |
| } |
| |
| void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u32 DramMRS, dword; |
| u8 byte; |
| |
| DramMRS = 0; |
| |
| /* Set chip select CKE control mode */ |
| if (mctGet_NVbits(NV_CKE_CTL)) { |
| if (pDCTstat->CSPresent == 3) { |
| u16 word; |
| word = pDCTstat->DIMMSPDCSE; |
| if (dct == 0) |
| word &= 0b01010100; |
| else |
| word &= 0b10101000; |
| if (word == 0) |
| DramMRS |= 1 << 23; |
| } |
| } |
| |
| if (is_fam15h()) { |
| DramMRS |= (0x1 << 23); /* PchgPDModeSel = 1 */ |
| } else { |
| /* |
| DRAM MRS Register |
| DrvImpCtrl: drive impedance control.01b(34 ohm driver; Ron34 = Rzq/7) |
| */ |
| DramMRS |= 1 << 2; |
| /* Dram nominal termination: */ |
| byte = pDCTstat->MAdimms[dct]; |
| if (!(pDCTstat->Status & (1 << SB_Registered))) { |
| DramMRS |= 1 << 7; /* 60 ohms */ |
| if (byte & 2) { |
| if (pDCTstat->Speed < 6) |
| DramMRS |= 1 << 8; /* 40 ohms */ |
| else |
| DramMRS |= 1 << 9; /* 30 ohms */ |
| } |
| } |
| /* Dram dynamic termination: Disable(1DIMM), 120ohm(>=2DIMM) */ |
| if (!(pDCTstat->Status & (1 << SB_Registered))) { |
| if (byte >= 2) { |
| if (pDCTstat->Speed == 7) |
| DramMRS |= 1 << 10; |
| else |
| DramMRS |= 1 << 11; |
| } |
| } else { |
| DramMRS |= mct_DramTermDyn_RDimm(pMCTstat, pDCTstat, byte); |
| } |
| |
| /* Qoff = 0, output buffers enabled */ |
| /* Tcwl */ |
| DramMRS |= (pDCTstat->Speed - 4) << 20; |
| /* ASR = 1, auto self refresh */ |
| /* SRT = 0 */ |
| DramMRS |= 1 << 18; |
| } |
| |
| /* burst length control */ |
| if (pDCTstat->Status & (1 << SB_128bitmode)) |
| DramMRS |= 1 << 1; |
| |
| dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84); |
| if (is_fam15h()) { |
| dword &= ~0x00800003; |
| dword |= DramMRS; |
| } else { |
| dword &= ~0x00fc2f8f; |
| dword |= DramMRS; |
| } |
| Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword); |
| } |
| |
| void mct_SetDramConfigHi_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u32 dct, u32 DramConfigHi) |
| { |
| /* Bug#15114: Comp. update interrupted by Freq. change can cause |
| * subsequent update to be invalid during any MemClk frequency change: |
| * Solution: From the bug report: |
| * 1. A software-initiated frequency change should be wrapped into the |
| * following sequence : |
| * - a) Disable Compensation (F2[1, 0]9C_x08[30]) |
| * b) Reset the Begin Compensation bit (D3CMP->COMP_CONFIG[0]) in all the compensation engines |
| * c) Do frequency change |
| * d) Enable Compensation (F2[1, 0]9C_x08[30]) |
| * 2. A software-initiated Disable Compensation should always be |
| * followed by step b) of the above steps. |
| * Silicon Status: Fixed In Rev B0 |
| * |
| * Errata#177: DRAM Phy Automatic Compensation Updates May Be Invalid |
| * Solution: BIOS should disable the phy automatic compensation prior |
| * to initiating a memory clock frequency change as follows: |
| * 1. Disable PhyAutoComp by writing 1'b1 to F2x[1, 0]9C_x08[30] |
| * 2. Reset the Begin Compensation bits by writing 32'h0 to |
| * F2x[1, 0]9C_x4D004F00 |
| * 3. Perform frequency change |
| * 4. Enable PhyAutoComp by writing 1'b0 to F2x[1, 0]9C_08[30] |
| * In addition, any time software disables the automatic phy |
| * compensation it should reset the begin compensation bit per step 2. |
| * Silicon Status: Fixed in DR-B0 |
| */ |
| |
| u32 dev = pDCTstat->dev_dct; |
| u32 index_reg = 0x98; |
| u32 index; |
| |
| uint32_t dword; |
| |
| printk(BIOS_DEBUG, "%s: Start\n", __func__); |
| |
| if (is_fam15h()) { |
| /* Initial setup for frequency change |
| * 9C_x0000_0004 must be configured before MemClkFreqVal is set |
| */ |
| |
| /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0x190 */ |
| dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006); |
| dword &= ~(0x0000ffff); |
| dword |= 0x00000190; |
| Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006, dword); |
| |
| dword = Get_NB32_DCT(dev, dct, 0x94); |
| dword &= ~(1 << MemClkFreqVal); |
| Set_NB32_DCT(dev, dct, 0x94, dword); |
| |
| dword = DramConfigHi; |
| dword &= ~(1 << MemClkFreqVal); |
| Set_NB32_DCT(dev, dct, 0x94, dword); |
| |
| mctGet_PS_Cfg_D(pMCTstat, pDCTstat, dct); |
| set_2t_configuration(pMCTstat, pDCTstat, dct); |
| mct_BeforePlatformSpec(pMCTstat, pDCTstat, dct); |
| mct_PlatformSpec(pMCTstat, pDCTstat, dct); |
| } else { |
| index = 0x08; |
| dword = Get_NB32_index_wait_DCT(dev, dct, index_reg, index); |
| if (!(dword & (1 << DisAutoComp))) |
| Set_NB32_index_wait_DCT(dev, dct, index_reg, index, dword | (1 << DisAutoComp)); |
| |
| mct_Wait(100); |
| } |
| |
| printk(BIOS_DEBUG, "mct_SetDramConfigHi_D: DramConfigHi: %08x\n", DramConfigHi); |
| |
| /* Program the DRAM Configuration High register */ |
| Set_NB32_DCT(dev, dct, 0x94, DramConfigHi); |
| |
| if (is_fam15h()) { |
| /* Wait until F2x[1, 0]94[FreqChgInProg]=0. */ |
| do { |
| printk(BIOS_DEBUG, "*"); |
| dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94); |
| } while (dword & (1 << FreqChgInProg)); |
| printk(BIOS_DEBUG, "\n"); |
| |
| /* Program D18F2x9C_x0D0F_E006_dct[1:0][PllLockTime] = 0xf */ |
| dword = Get_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006); |
| dword &= ~(0x0000ffff); |
| dword |= 0x0000000f; |
| Set_NB32_index_wait_DCT(pDCTstat->dev_dct, dct, index_reg, 0x0d0fe006, dword); |
| } |
| |
| /* Clear MC4 error status */ |
| pci_write_config32(pDCTstat->dev_nbmisc, 0x48, 0x0); |
| pci_write_config32(pDCTstat->dev_nbmisc, 0x4c, 0x0); |
| |
| printk(BIOS_DEBUG, "%s: Done\n", __func__); |
| } |
| |
| static void mct_BeforeDQSTrain_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstatA) |
| { |
| if (!is_fam15h()) { |
| u8 Node; |
| struct DCTStatStruc *pDCTstat; |
| |
| /* Errata 178 |
| * |
| * Bug#15115: Uncertainty In The Sync Chain Leads To Setup Violations |
| * In TX FIFO |
| * Solution: BIOS should program DRAM Control Register[RdPtrInit] = |
| * 5h, (F2x[1, 0]78[3:0] = 5h). |
| * Silicon Status: Fixed In Rev B0 |
| * |
| * Bug#15880: Determine validity of reset settings for DDR PHY timing. |
| * Solution: At least, set WrDqs fine delay to be 0 for DDR3 training. |
| */ |
| for (Node = 0; Node < 8; Node++) { |
| pDCTstat = pDCTstatA + Node; |
| |
| if (pDCTstat->NodePresent) { |
| mct_BeforeDQSTrainSamp(pDCTstat); /* only Bx */ |
| mct_ResetDLL_D(pMCTstat, pDCTstat, 0); |
| mct_ResetDLL_D(pMCTstat, pDCTstat, 1); |
| } |
| } |
| } |
| } |
| |
| /* Erratum 350 */ |
| static void mct_ResetDLL_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| u8 Receiver; |
| u32 dev = pDCTstat->dev_dct; |
| u32 addr; |
| u32 lo, hi; |
| u8 wrap32dis = 0; |
| u8 valid = 0; |
| |
| /* Skip reset DLL for B3 */ |
| if (pDCTstat->LogicalCPUID & AMD_DR_B3) { |
| return; |
| } |
| |
| /* Skip reset DLL for Family 15h */ |
| if (is_fam15h()) { |
| return; |
| } |
| |
| addr = HWCR; |
| _RDMSR(addr, &lo, &hi); |
| if (lo & (1<<17)) { /* save the old value */ |
| wrap32dis = 1; |
| } |
| lo |= (1<<17); /* HWCR.wrap32dis */ |
| /* Setting wrap32dis allows 64-bit memory references in 32bit mode */ |
| _WRMSR(addr, lo, hi); |
| |
| pDCTstat->Channel = dct; |
| Receiver = mct_InitReceiver_D(pDCTstat, dct); |
| /* there are four receiver pairs, loosely associated with chipselects.*/ |
| for (; Receiver < 8; Receiver += 2) { |
| if (mct_RcvrRankEnabled_D(pMCTstat, pDCTstat, dct, Receiver)) { |
| addr = mct_GetRcvrSysAddr_D(pMCTstat, pDCTstat, dct, Receiver, &valid); |
| if (valid) { |
| mct_Read1LTestPattern_D(pMCTstat, pDCTstat, addr); /* cache fills */ |
| |
| /* Write 0000_8000h to register F2x[1,0]9C_xD080F0C */ |
| Set_NB32_index_wait_DCT(dev, dct, 0x98, 0xD080F0C, 0x00008000); |
| mct_Wait(80); /* wait >= 300ns */ |
| |
| /* Write 0000_0000h to register F2x[1,0]9C_xD080F0C */ |
| Set_NB32_index_wait_DCT(dev, dct, 0x98, 0xD080F0C, 0x00000000); |
| mct_Wait(800); /* wait >= 2us */ |
| break; |
| } |
| } |
| } |
| |
| if (!wrap32dis) { |
| addr = HWCR; |
| _RDMSR(addr, &lo, &hi); |
| lo &= ~(1<<17); /* restore HWCR.wrap32dis */ |
| _WRMSR(addr, lo, hi); |
| } |
| } |
| |
| static void mct_EnableDatIntlv_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat) |
| { |
| u32 dev = pDCTstat->dev_dct; |
| u32 val; |
| |
| /* Enable F2x110[DctDatIntlv] */ |
| /* Call back not required mctHookBeforeDatIntlv_D() */ |
| /* FIXME Skip for Ax */ |
| if (!pDCTstat->GangedMode) { |
| val = Get_NB32(dev, 0x110); |
| val |= 1 << 5; /* DctDatIntlv */ |
| Set_NB32(dev, 0x110, val); |
| |
| /* FIXME Skip for Cx */ |
| dev = pDCTstat->dev_nbmisc; |
| val = Get_NB32(dev, 0x8C); /* NB Configuration Hi */ |
| val |= 1 << (36-32); /* DisDatMask */ |
| Set_NB32(dev, 0x8C, val); |
| } |
| } |
| |
| static void SetDllSpeedUp_D(struct MCTStatStruc *pMCTstat, |
| struct DCTStatStruc *pDCTstat, u8 dct) |
| { |
| if (!is_fam15h()) { |
| u32 val; |
| u32 dev = pDCTstat->dev_dct; |
| |
| if (pDCTstat->Speed >= mhz_to_memclk_config(800)) { /* DDR1600 and above */ |
| /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F10 */ |
| Set_NB32_DCT(dev, dct, 0x98, 0x0D080F10); |
| val = Get_NB32_DCT(dev, dct, 0x9C); |
| val |= 1 < 13; |
| Set_NB32_DCT(dev, dct, 0x9C, val); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D080F10); |
| |
| /* Set bit13 PowerDown to register F2x[1, 0]98_x0D080F11 */ |
| Set_NB32_DCT(dev, dct, 0x98, 0x0D080F11); |
| val = Get_NB32_DCT(dev, dct, 0x9C); |
| val |= 1 < 13; |
| Set_NB32_DCT(dev, dct, 0x9C, val); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D080F11); |
| |
| /* Set bit13 PowerDown to register F2x[1, 0]98_x0D088F30 */ |
| Set_NB32_DCT(dev, dct, 0x98, 0x0D088F30); |
| val = Get_NB32_DCT(dev, dct, 0x9C); |
| val |= 1 < 13; |
| Set_NB32_DCT(dev, dct, 0x9C, val); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D088F30); |
| |
| /* Set bit13 PowerDown to register F2x[1, 0]98_x0D08CF30 */ |
| Set_NB32_DCT(dev, dct, 0x98, 0x0D08CF30); |
| val = Get_NB32_DCT(dev, dct, 0x9C); |
| val |= 1 < 13; |
| Set_NB32_DCT(dev, dct, 0x9C, val); |
| Set_NB32_DCT(dev, dct, 0x98, 0x4D08CF30); |
| } |
| } |
| } |
| |
| static void SyncSetting(struct DCTStatStruc *pDCTstat) |
| { |
| /* set F2x78[ChSetupSync] when F2x[1, 0]9C_x04[AddrCmdSetup, CsOdtSetup, |
| * CkeSetup] setups for one DCT are all 0s and at least one of the setups, |
| * F2x[1, 0]9C_x04[AddrCmdSetup, CsOdtSetup, CkeSetup], of the other |
| * controller is 1 |
| */ |
| u32 cha, chb; |
| u32 dev = pDCTstat->dev_dct; |
| u32 val; |
| |
| cha = pDCTstat->CH_ADDR_TMG[0] & 0x0202020; |
| chb = pDCTstat->CH_ADDR_TMG[1] & 0x0202020; |
| |
| if ((cha != chb) && ((cha == 0) || (chb == 0))) { |
| val = Get_NB32(dev, 0x78); |
| val |= 1 << ChSetupSync; |
| Set_NB32(dev, 0x78, val); |
| } |
| } |
| |
| static void AfterDramInit_D(struct DCTStatStruc *pDCTstat, u8 dct) { |
| |
| u32 val; |
| u32 dev = pDCTstat->dev_dct; |
| |
| if (pDCTstat->LogicalCPUID & (AMD_DR_B2 | AMD_DR_B3)) { |
| mct_Wait(10000); /* Wait 50 us*/ |
| val = Get_NB32(dev, 0x110); |
| if (!(val & (1 << DramEnabled))) { |
| /* If 50 us expires while DramEnable =0 then do the following */ |
| val = Get_NB32_DCT(dev, dct, 0x90); |
| val &= ~(1 << Width128); /* Program Width128 = 0 */ |
| Set_NB32_DCT(dev, dct, 0x90, val); |
| |
| val = Get_NB32_index_wait_DCT(dev, dct, 0x98, 0x05); /* Perform dummy CSR read to F2x09C_x05 */ |
| |
| if (pDCTstat->GangedMode) { |
| val = Get_NB32_DCT(dev, dct, 0x90); |
| val |= 1 << Width128; /* Program Width128 = 0 */ |
| Set_NB32_DCT(dev, dct, 0x90, val); |
| } |
| } |
| } |
| } |
| |
| /* ========================================================== |
| * 6-bit Bank Addressing Table |
| * RR = rows-13 binary |
| * B = Banks-2 binary |
| * CCC = Columns-9 binary |
| * ========================================================== |
| * DCT CCCBRR Rows Banks Columns 64-bit CS Size |
| * Encoding |
| * 0000 000000 13 2 9 128MB |
| * 0001 001000 13 2 10 256MB |
| * 0010 001001 14 2 10 512MB |
| * 0011 010000 13 2 11 512MB |
| * 0100 001100 13 3 10 512MB |
| * 0101 001101 14 3 10 1GB |
| * 0110 010001 14 2 11 1GB |
| * 0111 001110 15 3 10 2GB |
| * 1000 010101 14 3 11 2GB |
| * 1001 010110 15 3 11 4GB |
| * 1010 001111 16 3 10 4GB |
| * 1011 010111 16 3 11 8GB |
| */ |
| uint8_t crcCheck(struct DCTStatStruc *pDCTstat, uint8_t dimm) |
| { |
| u8 byte_use; |
| u8 Index; |
| u16 CRC; |
| u8 byte, i; |
| |
| byte_use = pDCTstat->spd_data.spd_bytes[dimm][SPD_ByteUse]; |
| if (byte_use & 0x80) |
| byte_use = 117; |
| else |
| byte_use = 126; |
| |
| CRC = 0; |
| for (Index = 0; Index < byte_use; Index ++) { |
| byte = pDCTstat->spd_data.spd_bytes[dimm][Index]; |
| CRC ^= byte << 8; |
| for (i = 0; i < 8; i++) { |
| if (CRC & 0x8000) { |
| CRC <<= 1; |
| CRC ^= 0x1021; |
| } else |
| CRC <<= 1; |
| } |
| } |
| return CRC == (pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_127] << 8 | pDCTstat->spd_data.spd_bytes[dimm][SPD_byte_126]); |
| } |