/* * This file is part of the coreboot project. * * Copyright (C) 2010 Advanced Micro Devices, Inc. * Copyright (C) 2015 Timothy Pearson , Raptor Engineering * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include "mct_d.h" #include "mct_d_gcc.h" static uint8_t is_fam15h(void) { uint8_t fam15h = 0; uint32_t family; family = cpuid_eax(0x80000001); family = ((family & 0xf00000) >> 16) | ((family & 0xf00) >> 8); if (family >= 0x6f) /* Family 15h or later */ fam15h = 1; return fam15h; } uint8_t fam15_dimm_dic(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type) { uint8_t dic; /* Calculate DIC based on recommendations in MR1_dct[1:0] */ if (pDCTstat->Status & (1 << SB_LoadReduced)) { /* TODO * LRDIMM unimplemented */ dic = 0x0; } else { dic = 0x1; } return dic; } uint8_t fam15_rttwr(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type) { uint8_t term = 0; uint8_t number_of_dimms = pDCTstat->MAdimms[dct]; uint8_t frequency_index; uint8_t rank_count = pDCTstat->DimmRanks[(dimm * 2) + dct]; uint8_t rank_count_dimm0; uint8_t rank_count_dimm1; uint8_t rank_count_dimm2; if (is_fam15h()) frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; else frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7; uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); if (is_fam15h()) { if (pDCTstat->Status & (1 << SB_LoadReduced)) { /* TODO * LRDIMM unimplemented */ } else if (pDCTstat->Status & (1 << SB_Registered)) { /* RDIMM */ if (package_type == PT_GR) { /* Socket G34: Fam15h BKDG v3.14 Table 57 */ if (MaxDimmsInstallable == 1) { if ((frequency_index == 0x4) || (frequency_index == 0x6) || (frequency_index == 0xa) || (frequency_index == 0xe)) { /* DDR3-667 - DDR3-1333 */ if (rank_count < 3) term = 0x0; else term = 0x2; } else { /* DDR3-1600 */ term = 0x0; } } else if (MaxDimmsInstallable == 2) { rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; if ((frequency_index == 0x4) || (frequency_index == 0x6)) { /* DDR3-667 - DDR3-800 */ if ((number_of_dimms == 1) && ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4))) term = 0x0; else term = 0x2; } else if (frequency_index == 0xa) { /* DDR3-1066 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x0; else term = 0x2; } else { term = 0x1; } } else if (frequency_index == 0xe) { /* DDR3-1333 */ term = 0x2; } else { /* DDR3-1600 */ if (number_of_dimms == 1) term = 0x0; else term = 0x1; } } else if (MaxDimmsInstallable == 3) { rank_count_dimm2 = pDCTstat->DimmRanks[(2 * 2) + dct]; if ((frequency_index == 0xa) || (frequency_index == 0xe)) { /* DDR3-1066 - DDR3-1333 */ if (rank_count_dimm2 < 4) term = 0x1; else term = 0x2; } else if (frequency_index == 0x12) { /* DDR3-1600 */ term = 0x1; } else { term = 0x2; } } } else if (package_type == PT_C3) { /* Socket C32: Fam15h BKDG v3.14 Table 60 */ if (MaxDimmsInstallable == 1) { if ((frequency_index == 0x4) || (frequency_index == 0x6) || (frequency_index == 0xa) || (frequency_index == 0xe)) { /* DDR3-667 - DDR3-1333 */ if (rank_count < 3) term = 0x0; else term = 0x2; } else { /* DDR3-1600 */ term = 0x0; } } else if (MaxDimmsInstallable == 2) { rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; if ((frequency_index == 0x4) || (frequency_index == 0x6)) { /* DDR3-667 - DDR3-800 */ if ((number_of_dimms == 1) && ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4))) term = 0x0; else term = 0x2; } else if (frequency_index == 0xa) { /* DDR3-1066 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x0; else term = 0x2; } else { term = 0x1; } } else if (frequency_index == 0xe) { /* DDR3-1333 */ term = 0x2; } else { /* DDR3-1600 */ if (number_of_dimms == 1) term = 0x0; else term = 0x1; } } else if (MaxDimmsInstallable == 3) { rank_count_dimm2 = pDCTstat->DimmRanks[(2 * 2) + dct]; if ((frequency_index == 0xa) || (frequency_index == 0xe)) { /* DDR3-1066 - DDR3-1333 */ if (rank_count_dimm2 < 4) term = 0x1; else term = 0x2; } else if (frequency_index == 0x12) { /* DDR3-1600 */ term = 0x1; } else { term = 0x2; } } } else { /* TODO * Other sockets unimplemented */ } } else { /* UDIMM */ if (package_type == PT_GR) { /* Socket G34: Fam15h BKDG v3.14 Table 56 */ if (MaxDimmsInstallable == 1) { term = 0x0; } else if (MaxDimmsInstallable == 2) { if ((number_of_dimms == 2) && (frequency_index == 0x12)) { term = 0x1; } else if (number_of_dimms == 1) { term = 0x0; } else { term = 0x2; } } else if (MaxDimmsInstallable == 3) { if (number_of_dimms == 1) { if (frequency_index <= 0xa) { term = 0x2; } else { if (rank_count < 3) { term = 0x1; } else { term = 0x2; } } } else if (number_of_dimms == 2) { term = 0x2; } } } else if (package_type == PT_C3) { /* Socket C32: Fam15h BKDG v3.14 Table 59 */ if (MaxDimmsInstallable == 1) { term = 0x0; } else if (MaxDimmsInstallable == 2) { if ((number_of_dimms == 2) && (frequency_index == 0x12)) { term = 0x1; } else if (number_of_dimms == 1) { term = 0x0; } else { term = 0x2; } } else if (MaxDimmsInstallable == 3) { if (number_of_dimms == 1) { if (frequency_index <= 0xa) { term = 0x2; } else { if (rank_count < 3) { term = 0x1; } else { term = 0x2; } } } else if (number_of_dimms == 2) { term = 0x2; } } } else if (package_type == PT_FM2) { /* Socket FM2: Fam15h Model10 BKDG 3.12 Table 32 */ if (MaxDimmsInstallable == 1) { term = 0x0; } else if (MaxDimmsInstallable == 2) { if ((number_of_dimms == 2) && (frequency_index >= 0x12)) { term = 0x1; } else if (number_of_dimms == 1) { term = 0x0; } else { term = 0x2; } } } else { /* TODO * Other sockets unimplemented */ } } } printk(BIOS_INFO, "DIMM %d RttWr: %01x\n", dimm, term); return term; } uint8_t fam15_rttnom(struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t rank, uint8_t package_type) { uint8_t term = 0; uint8_t number_of_dimms = pDCTstat->MAdimms[dct]; uint8_t frequency_index; uint8_t rank_count_dimm0; uint8_t rank_count_dimm1; if (is_fam15h()) frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x1f; else frequency_index = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x94) & 0x7; uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); if (is_fam15h()) { if (pDCTstat->Status & (1 << SB_LoadReduced)) { /* TODO * LRDIMM unimplemented */ } else if (pDCTstat->Status & (1 << SB_Registered)) { /* RDIMM */ if (package_type == PT_GR) { /* Socket G34: Fam15h BKDG v3.14 Table 57 */ if (MaxDimmsInstallable == 1) { rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; if ((frequency_index == 0x4) || (frequency_index == 0x6)) { /* DDR3-667 - DDR3-800 */ if (rank_count_dimm0 < 4) { term = 0x2; } else { if (!rank) term = 0x2; else term = 0x0; } } else if (frequency_index == 0xa) { /* DDR3-1066 */ term = 0x1; } else if (frequency_index == 0xe) { /* DDR3-1333 */ if (rank_count_dimm0 < 4) { term = 0x1; } else { if (!rank) term = 0x3; else term = 0x0; } } else { term = 0x3; } } else if (MaxDimmsInstallable == 2) { rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; if ((frequency_index == 0x4) || (frequency_index == 0x6)) { /* DDR3-667 - DDR3-800 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x2; else if (rank) term = 0x0; else term = 0x2; } else { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) { term = 0x3; } else { if (rank_count_dimm0 == 4) { if (rank_count_dimm1 == 1) term = 0x5; else term = 0x1; } else if (rank_count_dimm1 == 4) { if (rank_count_dimm0 == 1) term = 0x5; else term = 0x1; } if (rank) term = 0x0; } } } else if (frequency_index == 0xa) { /* DDR3-1066 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x1; else if (rank) term = 0x0; else term = 0x1; } else { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) { term = 0x3; } else { if (rank_count_dimm0 == 4) { if (rank_count_dimm1 == 1) term = 0x5; else term = 0x1; } else if (rank_count_dimm1 == 4) { if (rank_count_dimm0 == 1) term = 0x5; else term = 0x1; } if (rank) term = 0x0; } } } else if (frequency_index == 0xe) { /* DDR3-1333 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x1; else if (rank) term = 0x0; else term = 0x3; } else { term = 0x5; } } else { /* DDR3-1600 */ if (number_of_dimms == 1) term = 0x3; else term = 0x4; } } else if (MaxDimmsInstallable == 3) { /* TODO * 3 DIMM/channel support unimplemented */ } } else if (package_type == PT_C3) { /* Socket C32: Fam15h BKDG v3.14 Table 60 */ if (MaxDimmsInstallable == 1) { rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; if ((frequency_index == 0x4) || (frequency_index == 0x6)) { /* DDR3-667 - DDR3-800 */ if (rank_count_dimm0 < 4) { term = 0x2; } else { if (!rank) term = 0x2; else term = 0x0; } } else if (frequency_index == 0xa) { /* DDR3-1066 */ term = 0x1; } else if (frequency_index == 0xe) { /* DDR3-1333 */ if (rank_count_dimm0 < 4) { term = 0x1; } else { if (!rank) term = 0x3; else term = 0x0; } } else { term = 0x3; } } else if (MaxDimmsInstallable == 2) { rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct]; rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct]; if ((frequency_index == 0x4) || (frequency_index == 0x6)) { /* DDR3-667 - DDR3-800 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x2; else if (rank) term = 0x0; else term = 0x2; } else { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) { term = 0x3; } else { if (rank_count_dimm0 == 4) { if (rank_count_dimm1 == 1) term = 0x5; else term = 0x1; } else if (rank_count_dimm1 == 4) { if (rank_count_dimm0 == 1) term = 0x5; else term = 0x1; } if (rank) term = 0x0; } } } else if (frequency_index == 0xa) { /* DDR3-1066 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x1; else if (rank) term = 0x0; else term = 0x1; } else { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) { term = 0x3; } else { if (rank_count_dimm0 == 4) { if (rank_count_dimm1 == 1) term = 0x5; else term = 0x1; } else if (rank_count_dimm1 == 4) { if (rank_count_dimm0 == 1) term = 0x5; else term = 0x1; } if (rank) term = 0x0; } } } else if (frequency_index == 0xe) { /* DDR3-1333 */ if (number_of_dimms == 1) { if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4)) term = 0x1; else if (rank) term = 0x0; else term = 0x3; } else { term = 0x5; } } else { /* DDR3-1600 */ if (number_of_dimms == 1) term = 0x3; else term = 0x4; } } else if (MaxDimmsInstallable == 3) { /* TODO * 3 DIMM/channel support unimplemented */ } } else { /* TODO * Other sockets unimplemented */ } } else { /* UDIMM */ if (package_type == PT_GR) { /* Socket G34: Fam15h BKDG v3.14 Table 56 */ if (MaxDimmsInstallable == 1) { if ((frequency_index == 0x4) || (frequency_index == 0x6)) term = 0x2; else if ((frequency_index == 0xa) || (frequency_index == 0xe)) term = 0x1; else term = 0x3; } if (MaxDimmsInstallable == 2) { if (number_of_dimms == 1) { if (frequency_index <= 0x6) { term = 0x2; } else if (frequency_index <= 0xe) { term = 0x1; } else { term = 0x3; } } else { if (frequency_index <= 0xa) { term = 0x3; } else if (frequency_index <= 0xe) { term = 0x5; } else { term = 0x4; } } } else if (MaxDimmsInstallable == 3) { if (number_of_dimms == 1) { term = 0x0; } else if (number_of_dimms == 2) { if (frequency_index <= 0xa) { if (rank == 1) { term = 0x0; } else { term = 0x3; } } else if (frequency_index <= 0xe) { if (rank == 1) { term = 0x0; } else { term = 0x5; } } } } } else if (package_type == PT_C3) { /* Socket C32: Fam15h BKDG v3.14 Table 62 */ if (MaxDimmsInstallable == 1) { if ((frequency_index == 0x4) || (frequency_index == 0x6)) term = 0x2; else if ((frequency_index == 0xa) || (frequency_index == 0xe)) term = 0x1; else term = 0x3; } if (MaxDimmsInstallable == 2) { if (number_of_dimms == 1) { if (frequency_index <= 0x6) { term = 0x2; } else if (frequency_index <= 0xe) { term = 0x1; } else { term = 0x3; } } else { if (frequency_index <= 0xa) { term = 0x3; } else if (frequency_index <= 0xe) { term = 0x5; } else { term = 0x4; } } } else if (MaxDimmsInstallable == 3) { if (number_of_dimms == 1) { term = 0x0; } else if (number_of_dimms == 2) { if (frequency_index <= 0xa) { if (rank == 1) { term = 0x0; } else { term = 0x3; } } else if (frequency_index <= 0xe) { if (rank == 1) { term = 0x0; } else { term = 0x5; } } } } } else if (package_type == PT_FM2) { /* Socket FM2: Fam15h Model10 BKDG 3.12 Table 32 */ if (MaxDimmsInstallable == 1) { if ((frequency_index == 0x4) || (frequency_index == 0x6) || (frequency_index == 0xa)) term = 0x4; else if (frequency_index == 0xe) term = 0x3; else if (frequency_index >= 0x12) term = 0x2; } if (MaxDimmsInstallable == 2) { if (number_of_dimms == 1) { if (frequency_index <= 0xa) { term = 0x4; } else if (frequency_index <= 0xe) { term = 0x3; } else { term = 0x2; } } else { if (frequency_index <= 0xa) { term = 0x2; } else if (frequency_index <= 0xe) { term = 0x1; } else { term = 0x0; } } } } else { /* TODO * Other sockets unimplemented */ } } } printk(BIOS_INFO, "DIMM %d RttNom: %01x\n", dimm, term); return term; } static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct) { u32 dev = pDCTstat->dev_dct; u32 val; printk(BIOS_DEBUG, "%s: Start\n", __func__); do { val = Get_NB32_DCT(dev, dct, 0x98); } while (!(val & (1 << DctAccessDone))); printk(BIOS_DEBUG, "%s: Done\n", __func__); } static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting, u8 MrsChipSel, u8 dct) { u16 word; u32 ret; if (!(pDCTstat->Status & (1 << SB_Registered))) { word = pDCTstat->MirrPresU_NumRegR; if (dct == 0) { word &= 0x55; word <<= 1; } else word &= 0xAA; if (word & (1 << MrsChipSel)) { /* A3<->A4,A5<->A6,A7<->A8,BA0<->BA1 */ ret = 0; if (MR_register_setting & (1 << 3)) ret |= 1 << 4; if (MR_register_setting & (1 << 4)) ret |= 1 << 3; if (MR_register_setting & (1 << 5)) ret |= 1 << 6; if (MR_register_setting & (1 << 6)) ret |= 1 << 5; if (MR_register_setting & (1 << 7)) ret |= 1 << 8; if (MR_register_setting & (1 << 8)) ret |= 1 << 7; if (is_fam15h()) { if (MR_register_setting & (1 << 18)) ret |= 1 << 19; if (MR_register_setting & (1 << 19)) ret |= 1 << 18; MR_register_setting &= ~0x000c01f8; } else { if (MR_register_setting & (1 << 16)) ret |= 1 << 17; if (MR_register_setting & (1 << 17)) ret |= 1 << 16; MR_register_setting &= ~0x000301f8; } MR_register_setting |= ret; } } return MR_register_setting; } static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS) { u32 dev = pDCTstat->dev_dct; u32 val; printk(BIOS_DEBUG, "%s: Start\n", __func__); val = Get_NB32_DCT(dev, dct, 0x7c); val &= ~0x00ffffff; val |= EMRS; val |= 1 << SendMrsCmd; Set_NB32_DCT(dev, dct, 0x7c, val); do { val = Get_NB32_DCT(dev, dct, 0x7c); } while (val & (1 << SendMrsCmd)); printk(BIOS_DEBUG, "%s: Done\n", __func__); } u32 mct_MR2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel) { u32 dev = pDCTstat->dev_dct; u32 dword, ret; /* The formula for chip select number is: CS = dimm*2+rank */ uint8_t dimm = MrsChipSel / 2; uint8_t rank = MrsChipSel % 2; if (is_fam15h()) { uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE); /* FIXME: These parameters should be configurable * For now, err on the side of caution and enable automatic 2x refresh * when the DDR temperature rises above the internal limits */ uint8_t force_2x_self_refresh = 0; /* ASR */ uint8_t auto_2x_self_refresh = 1; /* SRT */ ret = 0x80000; ret |= (MrsChipSel << 21); /* Set self refresh parameters */ ret |= (force_2x_self_refresh << 6); ret |= (auto_2x_self_refresh << 7); /* Obtain Tcwl, adjust, and set CWL with the adjusted value */ dword = Get_NB32_DCT(dev, dct, 0x20c) & 0x1f; dword -= pDCTstat->tcwl_delay[dct]; ret |= ((dword - 5) << 3); /* Obtain and set RttWr */ ret |= (fam15_rttwr(pDCTstat, dct, dimm, rank, package_type) << 9); } else { ret = 0x20000; ret |= (MrsChipSel << 20); /* program MrsAddress[5:3]=CAS write latency (CWL): * based on F2x[1,0]84[Tcwl] */ dword = Get_NB32_DCT(dev, dct, 0x84); dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword); ret |= ((dword >> 20) & 7) << 3; /* program MrsAddress[6]=auto self refresh method (ASR): * based on F2x[1,0]84[ASR] * program MrsAddress[7]=self refresh temperature range (SRT): * based on F2x[1,0]84[ASR and SRT] */ ret |= ((dword >> 18) & 3) << 6; /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR) * based on F2x[1,0]84[DramTermDyn] */ ret |= ((dword >> 10) & 3) << 9; } printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR2 control word %08x\n", dct, dimm, rank, ret); return ret; } static u32 mct_MR3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel) { u32 dev = pDCTstat->dev_dct; u32 dword, ret; /* The formula for chip select number is: CS = dimm*2+rank */ uint8_t dimm = MrsChipSel / 2; uint8_t rank = MrsChipSel % 2; if (is_fam15h()) { ret = 0xc0000; ret |= (MrsChipSel << 21); /* Program MPR and MPRLoc to 0 */ // ret |= 0x0; /* MPR */ // ret |= (0x0 << 2); /* MPRLoc */ } else { ret = 0x30000; ret |= (MrsChipSel << 20); /* program MrsAddress[1:0]=multi purpose register address location * (MPR Location):based on F2x[1,0]84[MprLoc] * program MrsAddress[2]=multi purpose register * (MPR):based on F2x[1,0]84[MprEn] */ dword = Get_NB32_DCT(dev, dct, 0x84); ret |= (dword >> 24) & 7; } printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR3 control word %08x\n", dct, dimm, rank, ret); return ret; } u32 mct_MR1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel) { u32 dev = pDCTstat->dev_dct; u32 dword, ret; /* The formula for chip select number is: CS = dimm*2+rank */ uint8_t dimm = MrsChipSel / 2; uint8_t rank = MrsChipSel % 2; if (is_fam15h()) { uint8_t package_type = mctGet_NVbits(NV_PACK_TYPE); /* Set defaults */ uint8_t qoff = 0; /* Enable output buffers */ uint8_t wrlvl = 0; /* Disable write levelling */ uint8_t tqds = 0; uint8_t rttnom = 0; uint8_t dic = 0; uint8_t additive_latency = 0; uint8_t dll_enable = 0; ret = 0x40000; ret |= (MrsChipSel << 21); /* Determine if TQDS should be set */ if ((pDCTstat->Dimmx8Present & (1 << dimm)) && (((dimm & 0x1)?(pDCTstat->Dimmx4Present&0x55):(pDCTstat->Dimmx4Present&0xaa)) != 0x0) && (pDCTstat->Status & (1 << SB_LoadReduced))) tqds = 1; /* Obtain RttNom */ rttnom = fam15_rttnom(pDCTstat, dct, dimm, rank, package_type); /* Obtain DIC */ dic = fam15_dimm_dic(pDCTstat, dct, dimm, rank, package_type); /* Load data into MRS word */ ret |= (qoff & 0x1) << 12; ret |= (tqds & 0x1) << 11; ret |= ((rttnom & 0x4) >> 2) << 9; ret |= ((rttnom & 0x2) >> 1) << 6; ret |= ((rttnom & 0x1) >> 0) << 2; ret |= (wrlvl & 0x1) << 7; ret |= ((dic & 0x2) >> 1) << 5; ret |= ((dic & 0x1) >> 0) << 1; ret |= (additive_latency & 0x3) << 3; ret |= (dll_enable & 0x1); } else { ret = 0x10000; ret |= (MrsChipSel << 20); /* program MrsAddress[5,1]=output driver impedance control (DIC): * based on F2x[1,0]84[DrvImpCtrl] */ dword = Get_NB32_DCT(dev, dct, 0x84); if (dword & (1 << 3)) ret |= 1 << 5; if (dword & (1 << 2)) ret |= 1 << 1; /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT): * based on F2x[1,0]84[DramTerm] */ if (!(pDCTstat->Status & (1 << SB_Registered))) { if (dword & (1 << 9)) ret |= 1 << 9; if (dword & (1 << 8)) ret |= 1 << 6; if (dword & (1 << 7)) ret |= 1 << 2; } else { ret |= mct_MR1Odt_RDimm(pMCTstat, pDCTstat, dct, MrsChipSel); } /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */ if (Get_NB32_DCT(dev, dct, 0x94) & (1 << RDqsEn)) { u8 bit; /* Set TDQS = 1b for x8 DIMM, TDQS = 0b for x4 DIMM, when mixed x8 & x4 */ bit = (ret >> 21) << 1; if ((dct & 1) != 0) bit ++; if (pDCTstat->Dimmx8Present & (1 << bit)) ret |= 1 << 11; } /* program MrsAddress[12]=QOFF: based on F2x[1,0]84[Qoff] */ if (dword & (1 << 13)) ret |= 1 << 12; } printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR1 control word %08x\n", dct, dimm, rank, ret); return ret; } static u32 mct_MR0(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel) { u32 dev = pDCTstat->dev_dct; u32 dword, ret, dword2; /* The formula for chip select number is: CS = dimm*2+rank */ uint8_t dimm = MrsChipSel / 2; uint8_t rank = MrsChipSel % 2; if (is_fam15h()) { ret = 0x00000; ret |= (MrsChipSel << 21); /* Set defaults */ uint8_t ppd = 0; uint8_t wr_ap = 0; uint8_t dll_reset = 1; uint8_t test_mode = 0; uint8_t cas_latency = 0; uint8_t read_burst_type = 1; uint8_t burst_length = 0; /* Obtain PchgPDModeSel */ dword = Get_NB32_DCT(dev, dct, 0x84); ppd = (dword >> 23) & 0x1; /* Obtain Twr */ dword = Get_NB32_DCT(dev, dct, 0x22c) & 0x1f; /* Calculate wr_ap (Fam15h BKDG v3.14 Table 82) */ if (dword == 0x10) wr_ap = 0x0; else if (dword == 0x5) wr_ap = 0x1; else if (dword == 0x6) wr_ap = 0x2; else if (dword == 0x7) wr_ap = 0x3; else if (dword == 0x8) wr_ap = 0x4; else if (dword == 0xa) wr_ap = 0x5; else if (dword == 0xc) wr_ap = 0x6; else if (dword == 0xe) wr_ap = 0x7; /* Obtain Tcl */ dword = Get_NB32_DCT(dev, dct, 0x200) & 0x1f; /* Calculate cas_latency (Fam15h BKDG v3.14 Table 83) */ if (dword == 0x5) cas_latency = 0x2; else if (dword == 0x6) cas_latency = 0x4; else if (dword == 0x7) cas_latency = 0x6; else if (dword == 0x8) cas_latency = 0x8; else if (dword == 0x9) cas_latency = 0xa; else if (dword == 0xa) cas_latency = 0xc; else if (dword == 0xb) cas_latency = 0xe; else if (dword == 0xc) cas_latency = 0x1; else if (dword == 0xd) cas_latency = 0x3; else if (dword == 0xe) cas_latency = 0x5; else if (dword == 0xf) cas_latency = 0x7; else if (dword == 0x10) cas_latency = 0x9; /* Obtain BurstCtrl */ burst_length = Get_NB32_DCT(dev, dct, 0x84) & 0x3; /* Load data into MRS word */ ret |= (ppd & 0x1) << 12; ret |= (wr_ap & 0x7) << 9; ret |= (dll_reset & 0x1) << 8; ret |= (test_mode & 0x1) << 7; ret |= ((cas_latency & 0xe) >> 1) << 4; ret |= ((cas_latency & 0x1) >> 0) << 2; ret |= (read_burst_type & 0x1) << 3; ret |= (burst_length & 0x3); } else { ret = 0x00000; ret |= (MrsChipSel << 20); /* program MrsAddress[1:0]=burst length and control method (BL):based on F2x[1,0]84[BurstCtrl] */ dword = Get_NB32_DCT(dev, dct, 0x84); ret |= dword & 3; /* program MrsAddress[3]=1 (BT):interleaved */ ret |= 1 << 3; /* program MrsAddress[6:4,2]=read CAS latency (CL):based on F2x[1,0]88[Tcl] */ dword2 = Get_NB32_DCT(dev, dct, 0x88); ret |= (dword2 & 0x7) << 4; /* F2x88[2:0] to MrsAddress[6:4] */ ret |= ((dword2 & 0x8) >> 3) << 2; /* F2x88[3] to MrsAddress[2] */ /* program MrsAddress[12]=0 (PPD):slow exit */ if (dword & (1 << 23)) ret |= 1 << 12; /* program MrsAddress[11:9]=write recovery for auto-precharge (WR):based on F2x[1,0]84[Twr] */ ret |= ((dword >> 4) & 7) << 9; /* program MrsAddress[8]=1 (DLL):DLL reset just issue DLL reset at first time */ ret |= 1 << 8; } printk(BIOS_SPEW, "Going to send DCT %d DIMM %d rank %d MR0 control word %08x\n", dct, dimm, rank, ret); return ret; } static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct) { u32 dev = pDCTstat->dev_dct; u32 dword; printk(BIOS_DEBUG, "%s: Start\n", __func__); /*1.Program MrsAddress[10]=1 2.Set SendZQCmd = 1 */ dword = Get_NB32_DCT(dev, dct, 0x7C); dword &= ~0xFFFFFF; dword |= 1 << 10; dword |= 1 << SendZQCmd; Set_NB32_DCT(dev, dct, 0x7C, dword); /* Wait for SendZQCmd = 0 */ do { dword = Get_NB32_DCT(dev, dct, 0x7C); } while (dword & (1 << SendZQCmd)); /* 4.Wait 512 MEMCLKs */ mct_Wait(300); printk(BIOS_DEBUG, "%s: Done\n", __func__); } void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct) { u8 MrsChipSel; u32 dword; u32 dev = pDCTstat->dev_dct; printk(BIOS_DEBUG, "%s: Start\n", __func__); if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) { /* 3.Program F2x[1,0]7C[EnDramInit]=1 */ dword = Get_NB32_DCT(dev, dct, 0x7c); dword |= 1 << EnDramInit; Set_NB32_DCT(dev, dct, 0x7c, dword); mct_DCTAccessDone(pDCTstat, dct); /* 4.wait 200us */ mct_Wait(40000); /* 5.Program F2x[1, 0]7C[DeassertMemRstX] = 1. */ dword = Get_NB32_DCT(dev, dct, 0x7c); dword |= 1 << DeassertMemRstX; Set_NB32_DCT(dev, dct, 0x7c, dword); /* 6.wait 500us */ mct_Wait(200000); /* 7.Program F2x[1,0]7C[AssertCke]=1 */ dword = Get_NB32_DCT(dev, dct, 0x7c); dword |= 1 << AssertCke; Set_NB32_DCT(dev, dct, 0x7c, dword); /* 8.wait 360ns */ mct_Wait(80); /* Set up address parity */ if ((pDCTstat->Status & (1 << SB_Registered)) || (pDCTstat->Status & (1 << SB_LoadReduced))) { if (is_fam15h()) { dword = Get_NB32_DCT(dev, dct, 0x90); dword |= 1 << ParEn; Set_NB32_DCT(dev, dct, 0x90, dword); } } /* The following steps are performed with registered DIMMs only and * must be done for each chip select pair */ if (pDCTstat->Status & (1 << SB_Registered)) mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct); /* The following steps are performed with load reduced DIMMs only and * must be done for each DIMM */ // if (pDCTstat->Status & (1 << SB_LoadReduced)) /* TODO * Implement LRDIMM configuration */ } pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct]; if (pDCTstat->GangedMode & 1) pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0]; /* The following steps are performed once for unbuffered DIMMs and once for each * chip select on registered DIMMs: */ for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) { if (pDCTstat->CSPresent & (1 << MrsChipSel)) { u32 EMRS; /* 13.Send EMRS(2) */ EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel); EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct); mct_SendMrsCmd(pDCTstat, dct, EMRS); /* 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b */ EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel); EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct); mct_SendMrsCmd(pDCTstat, dct, EMRS); /* 15.Send EMRS(1) */ EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel); EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct); mct_SendMrsCmd(pDCTstat, dct, EMRS); /* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */ EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel); EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct); mct_SendMrsCmd(pDCTstat, dct, EMRS); if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) if (!(pDCTstat->Status & (1 << SB_Registered))) break; /* For UDIMM, only send MR commands once per channel */ } if (pDCTstat->LogicalCPUID & (AMD_DR_Bx/* | AMD_RB_C0 */)) /* TODO: We dont support RB_C0 now. need to be added and tested. */ if (!(pDCTstat->Status & (1 << SB_Registered))) MrsChipSel ++; } if (pDCTstat->DIMMAutoSpeed == mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK))) { /* 17.Send two ZQCL commands */ mct_SendZQCmd(pDCTstat, dct); mct_SendZQCmd(pDCTstat, dct); /* 18.Program F2x[1,0]7C[EnDramInit]=0 */ dword = Get_NB32_DCT(dev, dct, 0x7C); dword &= ~(1 << EnDramInit); Set_NB32_DCT(dev, dct, 0x7C, dword); mct_DCTAccessDone(pDCTstat, dct); } printk(BIOS_DEBUG, "%s: Done\n", __func__); }