2 * This file is part of the coreboot project.
4 * Copyright (C) 2010 Advanced Micro Devices, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
21 struct DCTStatStruc *pDCTstat, u8 dct);
23 static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
25 u32 reg_off = 0x100 * dct;
26 u32 dev = pDCTstat->dev_dct;
30 val = Get_NB32(dev, reg_off + 0x98);
31 } while (!(val & (1 << DctAccessDone)));
34 static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting, u8 MrsChipSel, u8 dct)
39 if (!(pDCTstat->Status & (1 << SB_Registered))) {
40 word = pDCTstat->MirrPresU_NumRegR;
47 if (word & (1 << MrsChipSel)) {
48 /* A3<->A4,A5<->A6,A7<->A8,BA0<->BA1 */
50 if (MR_register_setting & (1 << 3)) ret |= 1 << 4;
51 if (MR_register_setting & (1 << 4)) ret |= 1 << 3;
52 if (MR_register_setting & (1 << 5)) ret |= 1 << 6;
53 if (MR_register_setting & (1 << 6)) ret |= 1 << 5;
54 if (MR_register_setting & (1 << 7)) ret |= 1 << 8;
55 if (MR_register_setting & (1 << 8)) ret |= 1 << 7;
56 if (MR_register_setting & (1 << 16)) ret |= 1 << 17;
57 if (MR_register_setting & (1 << 17)) ret |= 1 << 16;
58 MR_register_setting &= ~0x301f8;
59 MR_register_setting |= ret;
62 return MR_register_setting;
65 static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
67 u32 reg_off = 0x100 * dct;
68 u32 dev = pDCTstat->dev_dct;
71 val = Get_NB32(dev, reg_off + 0x7C);
74 val |= 1 << SendMrsCmd;
75 Set_NB32(dev, reg_off + 0x7C, val);
78 val = Get_NB32(dev, reg_off + 0x7C);
79 } while (val & (1 << SendMrsCmd));
82 static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
83 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
85 u32 reg_off = 0x100 * dct;
86 u32 dev = pDCTstat->dev_dct;
92 /* program MrsAddress[5:3]=CAS write latency (CWL):
93 * based on F2x[1,0]84[Tcwl] */
94 dword = Get_NB32(dev, reg_off + 0x84);
95 dword = mct_AdjustSPDTimings(pMCTstat, pDCTstat, dword);
97 ret |= ((dword >> 20) & 7) << 3;
99 /* program MrsAddress[6]=auto self refresh method (ASR):
100 based on F2x[1,0]84[ASR]
101 program MrsAddress[7]=self refresh temperature range (SRT):
102 based on F2x[1,0]84[ASR and SRT] */
103 ret |= ((dword >> 18) & 3) << 6;
105 /* program MrsAddress[10:9]=dynamic termination during writes (RTT_WR)
106 based on F2x[1,0]84[DramTermDyn] */
107 ret |= ((dword >> 10) & 3) << 9;
112 static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
113 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
115 u32 reg_off = 0x100 * dct;
116 u32 dev = pDCTstat->dev_dct;
122 /* program MrsAddress[1:0]=multi purpose register address location
123 (MPR Location):based on F2x[1,0]84[MprLoc]
124 program MrsAddress[2]=multi purpose register
125 (MPR):based on F2x[1,0]84[MprEn]
127 dword = Get_NB32(dev, reg_off + 0x84);
128 ret |= (dword >> 24) & 7;
133 static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
134 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
136 u32 reg_off = 0x100 * dct;
137 u32 dev = pDCTstat->dev_dct;
143 /* program MrsAddress[5,1]=output driver impedance control (DIC):
144 * based on F2x[1,0]84[DrvImpCtrl] */
145 dword = Get_NB32(dev, reg_off + 0x84);
146 if (dword & (1 << 3))
148 if (dword & (1 << 2))
151 /* program MrsAddress[9,6,2]=nominal termination resistance of ODT (RTT):
152 based on F2x[1,0]84[DramTerm] */
153 if (!(pDCTstat->Status & (1 << SB_Registered))) {
154 if (dword & (1 << 9))
156 if (dword & (1 << 8))
158 if (dword & (1 << 7))
161 /* TODO: mct_MR1Odt_RDimm */
164 /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
165 if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
167 /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
168 bit = (ret >> 21) << 1;
171 if (pDCTstat->Dimmx8Present & (1 << bit))
175 if (dword & (1 << 13))
181 static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
182 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
184 u32 reg_off = 0x100 * dct;
185 u32 dev = pDCTstat->dev_dct;
186 u32 dword, ret, dword2;
191 /* program MrsAddress[1:0]=burst length and control method
192 (BL):based on F2x[1,0]84[BurstCtrl] */
193 dword = Get_NB32(dev, reg_off + 0x84);
196 /* program MrsAddress[3]=1 (BT):interleaved */
199 /* program MrsAddress[6:4,2]=read CAS latency
200 (CL):based on F2x[1,0]88[Tcl] */
201 dword2 = Get_NB32(dev, reg_off + 0x88);
202 ret |= (dword2 & 0xF) << 4; /* F2x88[3:0] to MrsAddress[6:4,2]=xxx0b */
204 /* program MrsAddress[12]=0 (PPD):slow exit */
205 if (dword & (1 << 23))
208 /* program MrsAddress[11:9]=write recovery for auto-precharge
209 (WR):based on F2x[1,0]84[Twr] */
210 ret |= ((dword >> 4) & 7) << 9;
212 /* program MrsAddress[8]=1 (DLL):DLL reset
213 just issue DLL reset at first time */
219 static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
221 u32 reg_off = 0x100 * dct;
222 u32 dev = pDCTstat->dev_dct;
225 /*1.Program MrsAddress[10]=1
228 dword = Get_NB32(dev, reg_off + 0x7C);
231 dword |= 1 << SendZQCmd;
232 Set_NB32(dev, reg_off + 0x7C, dword);
234 /* Wait for SendZQCmd=0 */
236 dword = Get_NB32(dev, reg_off + 0x7C);
237 } while (dword & (1 << SendZQCmd));
239 /* 4.Wait 512 MEMCLKs */
243 void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
244 struct DCTStatStruc *pDCTstat, u8 dct)
248 u32 reg_off = 0x100 * dct;
249 u32 dev = pDCTstat->dev_dct;
251 if (pDCTstat->DIMMAutoSpeed == 4) {
252 /* 3.Program F2x[1,0]7C[EnDramInit]=1 */
253 dword = Get_NB32(dev, reg_off + 0x7C);
254 dword |= 1 << EnDramInit;
255 Set_NB32(dev, reg_off + 0x7C, dword);
256 mct_DCTAccessDone(pDCTstat, dct);
261 /* 5.On revision C processors, program F2x[1, 0]7C[DeassertMemRstX] = 1. */
262 dword = Get_NB32(dev, reg_off + 0x7C);
263 dword |= 1 << DeassertMemRstX;
264 Set_NB32(dev, reg_off + 0x7C, dword);
269 /* 7.Program F2x[1,0]7C[AssertCke]=1 */
270 dword = Get_NB32(dev, reg_off + 0x7C);
271 dword |= 1 << AssertCke;
272 Set_NB32(dev, reg_off + 0x7C, dword);
277 /* The following steps are performed with registered DIMMs only and
278 * must be done for each chip select pair */
279 if (pDCTstat->Status & (1 << SB_Registered))
280 mct_DramControlReg_Init_D(pMCTstat, pDCTstat, dct);
283 /* The following steps are performed once for unbuffered DIMMs and once for each
284 * chip select on registered DIMMs: */
285 for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
286 if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
288 /* 13.Send EMRS(2) */
289 EMRS = mct_MR2(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
290 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
291 mct_SendMrsCmd(pDCTstat, dct, EMRS);
292 /* 14.Send EMRS(3). Ordinarily at this time, MrsAddress[2:0]=000b */
293 EMRS= mct_MR3(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
294 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
295 mct_SendMrsCmd(pDCTstat, dct, EMRS);
296 /* 15.Send EMRS(1) */
297 EMRS= mct_MR1(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
298 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
299 mct_SendMrsCmd(pDCTstat, dct, EMRS);
300 /* 16.Send MRS with MrsAddress[8]=1(reset the DLL) */
301 EMRS= mct_MR0(pMCTstat, pDCTstat, dct, MrsChipSel << 20);
302 EMRS = swapAddrBits(pDCTstat, EMRS, MrsChipSel, dct);
303 mct_SendMrsCmd(pDCTstat, dct, EMRS);
305 if (pDCTstat->DIMMAutoSpeed == 4)
306 if (!(pDCTstat->Status & (1 << SB_Registered)))
307 break; /* For UDIMM, only send MR commands once per channel */
309 if (pDCTstat->LogicalCPUID & (AMD_DR_Cx/* | AMD_RB_C0 */)) /* We dont support RB_C0 now. need to be added and tested. */
310 if (!(pDCTstat->Status & (1 << SB_Registered)))
316 if (pDCTstat->DIMMAutoSpeed == 4) {
317 /* 17.Send two ZQCL commands */
318 mct_SendZQCmd(pDCTstat, dct);
319 mct_SendZQCmd(pDCTstat, dct);
320 /* 18.Program F2x[1,0]7C[EnDramInit]=0 */
321 dword = Get_NB32(dev, reg_off + 0x7C);
322 dword &= ~(1 << EnDramInit);
323 Set_NB32(dev, reg_off + 0x7C, dword);
324 mct_DCTAccessDone(pDCTstat, dct);