summaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c326
1 files changed, 326 insertions, 0 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
new file mode 100644
index 0000000000..18ef4770e2
--- /dev/null
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
@@ -0,0 +1,326 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct);
+
+static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 val;
+
+ do {
+ val = Get_NB32(dev, reg_off + 0x98);
+ } while (!(val & (1 << DctAccessDone)));
+}
+
+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 (MR_register_setting & (1 << 16)) ret |= 1 << 17;
+ if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
+ MR_register_setting &= ~0x301f8;
+ MR_register_setting |= ret;
+ }
+ }
+ return MR_register_setting;
+}
+
+static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 val;
+
+ val = Get_NB32(dev, reg_off + 0x7C);
+ val &= ~0xFFFFFF;
+ val |= EMRS;
+ val |= 1 << SendMrsCmd;
+ Set_NB32(dev, reg_off + 0x7C, val);
+
+ do {
+ val = Get_NB32(dev, reg_off + 0x7C);
+ } while (val & (1 << SendMrsCmd));
+}
+
+static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 dword, ret;
+
+ ret = 0x20000;
+ ret |= MrsChipSel;
+
+ /* program MrsAddress[5:3]=CAS write latency (CWL):
+ * based on F2x[1,0]84[Tcwl] */
+ dword = Get_NB32(dev, reg_off + 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;
+
+ return ret;
+}
+
+static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 dword, ret;
+
+ ret = 0x30000;
+ ret |= MrsChipSel;
+
+ /* 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(dev, reg_off + 0x84);
+ ret |= (dword >> 24) & 7;
+
+ return ret;
+}
+
+static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 dword, ret;
+
+ ret = 0x10000;
+ ret |= MrsChipSel;
+
+ /* program MrsAddress[5,1]=output driver impedance control (DIC):
+ * based on F2x[1,0]84[DrvImpCtrl] */
+ dword = Get_NB32(dev, reg_off + 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 {
+ /* TODO: mct_MR1Odt_RDimm */
+ }
+
+ /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
+ if (Get_NB32(dev, reg_off + 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;
+ }
+
+ if (dword & (1 << 13))
+ ret |= 1 << 12;
+
+ return ret;
+}
+
+static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 dword, ret, dword2;
+
+ ret = 0x00000;
+ ret |= MrsChipSel;
+
+ /* program MrsAddress[1:0]=burst length and control method
+ (BL):based on F2x[1,0]84[BurstCtrl] */
+ dword = Get_NB32(dev, reg_off + 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(dev, reg_off + 0x88);
+ ret |= (dword2 & 0xF) << 4; /* F2x88[3:0] to MrsAddress[6:4,2]=xxx0b */
+
+ /* 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;
+
+ return ret;
+}
+
+static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+ u32 dword;
+
+ /*1.Program MrsAddress[10]=1
+ 2.Set SendZQCmd=1
+ */
+ dword = Get_NB32(dev, reg_off + 0x7C);
+ dword &= ~0xFFFFFF;
+ dword |= 1 << 10;
+ dword |= 1 << SendZQCmd;
+ Set_NB32(dev, reg_off + 0x7C, dword);
+
+ /* Wait for SendZQCmd=0 */
+ do {
+ dword = Get_NB32(dev, reg_off + 0x7C);
+ } while (dword & (1 << SendZQCmd));
+
+ /* 4.Wait 512 MEMCLKs */
+ mct_Wait(300);
+}
+
+void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat, u8 dct)
+{
+ u8 MrsChipSel;
+ u32 dword;
+ u32 reg_off = 0x100 * dct;
+ u32 dev = pDCTstat->dev_dct;
+
+ if (pDCTstat->DIMMAutoSpeed == 4) {
+ /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
+ dword = Get_NB32(dev, reg_off + 0x7C);
+ dword |= 1 << EnDramInit;
+ Set_NB32(dev, reg_off + 0x7C, dword);
+ mct_DCTAccessDone(pDCTstat, dct);
+
+ /* 4.wait 200us */
+ mct_Wait(40000);
+
+ /* 5.On revision C processors, program F2x[1, 0]7C[DeassertMemRstX] = 1. */
+ dword = Get_NB32(dev, reg_off + 0x7C);
+ dword |= 1 << DeassertMemRstX;
+ Set_NB32(dev, reg_off + 0x7C, dword);
+
+ /* 6.wait 500us */
+ mct_Wait(200000);
+
+ /* 7.Program F2x[1,0]7C[AssertCke]=1 */
+ dword = Get_NB32(dev, reg_off + 0x7C);
+ dword |= 1 << AssertCke;
+ Set_NB32(dev, reg_off + 0x7C, dword);
+
+ /* 8.wait 360ns */
+ mct_Wait(80);
+
+ /* 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 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 << 20);
+ 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 << 20);
+ EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+ mct_SendMrsCmd(pDCTstat, dct, EMRS);
+ /* 15.Send EMRS(1) */
+ EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
+ 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 << 20);
+ EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
+ mct_SendMrsCmd(pDCTstat, dct, EMRS);
+
+ if (pDCTstat->DIMMAutoSpeed == 4)
+ if (!(pDCTstat->Status & (1 << SB_Registered)))
+ break; /* For UDIMM, only send MR commands once per channel */
+ }
+ if (pDCTstat->LogicalCPUID & (AMD_DR_Cx/* | AMD_RB_C0 */)) /* We dont support RB_C0 now. need to be added and tested. */
+ if (!(pDCTstat->Status & (1 << SB_Registered)))
+ MrsChipSel ++;
+ }
+
+ mct_Wait(100000);
+
+ if (pDCTstat->DIMMAutoSpeed == 4) {
+ /* 17.Send two ZQCL commands */
+ mct_SendZQCmd(pDCTstat, dct);
+ mct_SendZQCmd(pDCTstat, dct);
+ /* 18.Program F2x[1,0]7C[EnDramInit]=0 */
+ dword = Get_NB32(dev, reg_off + 0x7C);
+ dword &= ~(1 << EnDramInit);
+ Set_NB32(dev, reg_off + 0x7C, dword);
+ mct_DCTAccessDone(pDCTstat, dct);
+ }
+}