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; }
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__); }
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 void mct_setMaxRdLatTrnVal_D(struct DCTStatStruc *pDCTstat, u8 Channel, u16 MaxRdLatVal) { u8 i; u32 reg; u32 dev; u32 val; if (pDCTstat->GangedMode) { Channel = 0; /* for safe */ for (i = 0; i < 2; i++) pDCTstat->CH_MaxRdLat[i][0] = MaxRdLatVal; } else { pDCTstat->CH_MaxRdLat[Channel][0] = MaxRdLatVal; } dev = pDCTstat->dev_dct; reg = 0x78; val = Get_NB32_DCT(dev, Channel, reg); val &= ~(0x3ff<<22); val |= MaxRdLatVal<<22; /* program MaxRdLatency to correspond with current delay */ Set_NB32_DCT(dev, Channel, reg, val); }
static 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; 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 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 { /* 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 { /* TODO * Other sockets unimplemented */ } } } return term; }
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;
u8 mct_GetStartMaxRdLat_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 Channel, u8 DQSRcvEnDly, u32 *Margin) { u32 SubTotal; u32 val; u32 valx; u32 valxx; u32 index_reg; u32 dev; if (pDCTstat->GangedMode) Channel = 0; index_reg = 0x98; dev = pDCTstat->dev_dct; /* Multiply the CAS Latency by two to get a number of 1/2 MEMCLKs units.*/ val = Get_NB32_DCT(dev, Channel, 0x88); SubTotal = ((val & 0x0f) + 1) << 1; /* SubTotal is 1/2 Memclk unit */ /* If registered DIMMs are being used then add 1 MEMCLK to the sub-total*/ val = Get_NB32_DCT(dev, Channel, 0x90); if (!(val & (1 << UnBuffDimm))) SubTotal += 2; /*If the address prelaunch is setup for 1/2 MEMCLKs then add 1, * else add 2 to the sub-total. if (AddrCmdSetup || CsOdtSetup * || CkeSetup) then K := K + 2; */ val = Get_NB32_index_wait_DCT(dev, Channel, index_reg, 0x04); if (!(val & 0x00202020)) SubTotal += 1; else SubTotal += 2; /* If the F2x[1, 0]78[RdPtrInit] field is 4, 5, 6 or 7 MEMCLKs, * then add 4, 3, 2, or 1 MEMCLKs, respectively to the sub-total. */ val = Get_NB32_DCT(dev, Channel, 0x78); SubTotal += 8 - (val & 0x0f); /* Convert bits 7-5 (also referred to as the course delay) of the current * (or worst case) DQS receiver enable delay to 1/2 MEMCLKs units, * rounding up, and add this to the sub-total. */ SubTotal += DQSRcvEnDly >> 5; /*BOZO-no rounding up */ SubTotal <<= 1; /*scale 1/2 MemClk to 1/4 MemClk */ /* Convert the sub-total (in 1/2 MEMCLKs) to northbridge clocks (NCLKs) * as follows (assuming DDR400 and assuming that no P-state or link speed * changes have occurred). */ /*New formula: SubTotal *= 3*(Fn2xD4[NBFid]+4)/(3+Fn2x94[MemClkFreq])/2 */ val = Get_NB32_DCT(dev, Channel, 0x94); /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */ val &= 7; if (val >= 3) { val <<= 1; } else val += 3; valx = (val) << 2; /* SubTotal div 4 to scale 1/4 MemClk back to MemClk */ val = Get_NB32(pDCTstat->dev_nbmisc, 0xD4); val = ((val & 0x1f) + 4) * 3; /* Calculate 1 MemClk + 1 NCLK delay in NCLKs for margin */ valxx = val << 2; valxx /= valx; if (valxx % valx) valxx++; /* round up */ valxx++; /* add 1NCLK */ *Margin = valxx; /* one MemClk delay in NCLKs and one additional NCLK */ val *= SubTotal; val /= valx; if (val % valx) val++; /* round up */ return val; }
static uint8_t fam15h_rdimm_rc2_ibt_code(struct DCTStatStruc *pDCTstat, uint8_t dct) { uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH); uint8_t package_type; uint8_t control_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]; /* FIXME * Assume there is only one register on the RDIMM for now */ uint8_t num_registers = 1; if (package_type == PT_GR) { /* Socket G34 */ /* Fam15h BKDG Rev. 3.14 section 2.10.5.7.1.2.1 Table 85 */ if (MaxDimmsInstallable == 1) { if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { /* DDR3-667 - DDR3-800 */ control_code = 0x1; } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { /* DDR3-1066 - DDR3-1333 */ if (num_registers == 1) { control_code = 0x0; } else { control_code = 0x1; } } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { /* DDR3-1600 - DDR3-1866 */ control_code = 0x0; } } else if (MaxDimmsInstallable == 2) { if (dimm_count == 1) { /* 1 DIMM detected */ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { /* DDR3-667 - DDR3-800 */ control_code = 0x1; } else if ((MemClkFreq >= 0xa) && (MemClkFreq <= 0x12)) { /* DDR3-1066 - DDR3-1600 */ if (num_registers == 1) { control_code = 0x0; } else { control_code = 0x1; } } } else if (dimm_count == 2) { /* 2 DIMMs detected */ if (num_registers == 1) { control_code = 0x1; } else { control_code = 0x8; } } } else if (MaxDimmsInstallable == 3) { /* TODO * 3 DIMM/channel support unimplemented */ } } else if (package_type == PT_C3) { /* Socket C32 */ /* Fam15h BKDG Rev. 3.14 section 2.10.5.7.1.2.1 Table 86 */ if (MaxDimmsInstallable == 1) { if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { /* DDR3-667 - DDR3-800 */ control_code = 0x1; } else if ((MemClkFreq == 0xa) || (MemClkFreq == 0xe)) { /* DDR3-1066 - DDR3-1333 */ if (num_registers == 1) { control_code = 0x0; } else { control_code = 0x1; } } else if ((MemClkFreq == 0x12) || (MemClkFreq == 0x16)) { /* DDR3-1600 - DDR3-1866 */ control_code = 0x0; } } else if (MaxDimmsInstallable == 2) { if (dimm_count == 1) { /* 1 DIMM detected */ if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6)) { /* DDR3-667 - DDR3-800 */ control_code = 0x1; } else if ((MemClkFreq >= 0xa) && (MemClkFreq <= 0x12)) { /* DDR3-1066 - DDR3-1600 */ if (num_registers == 1) { control_code = 0x0; } else { control_code = 0x1; } } } else if (dimm_count == 2) { /* 2 DIMMs detected */ if (num_registers == 1) { control_code = 0x1; } else { control_code = 0x8; } } } else if (MaxDimmsInstallable == 3) { /* TODO * 3 DIMM/channel support unimplemented */ } } else { /* TODO * Other socket support unimplemented */ } return control_code; }