diff options
author | Zheng Bao <zheng.bao@amd.com> | 2010-04-23 17:32:48 +0000 |
---|---|---|
committer | Stefan Reinauer <stepan@openbios.org> | 2010-04-23 17:32:48 +0000 |
commit | eb75f652d392d2f4f257194e112f3f0db7479145 (patch) | |
tree | aa972907734abcba4ca52f2a3a71f8d81d4bdce0 /src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c | |
parent | fe6c2cda6e6977894d9b668af9509b983c850f68 (diff) | |
download | coreboot-eb75f652d392d2f4f257194e112f3f0db7479145.tar.xz |
DDR3 support for AMD Fam10.
Signed-off-by: Zheng Bao <zheng.bao@amd.com>
Acked-by: Stefan Reinauer <stepan@coresystems.de>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@5481 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c')
-rw-r--r-- | src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c | 326 |
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); + } +} |