18ef4770e2574a8efd6fc9911be68c5a6b822329
[coreboot.git] / src / northbridge / amd / amdmct / mct_ddr3 / mctsdi.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2010 Advanced Micro Devices, Inc.
5  *
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.
9  *
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.
14  *
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
18  */
19
20 static void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
21                                 struct DCTStatStruc *pDCTstat, u8 dct);
22
23 static void mct_DCTAccessDone(struct DCTStatStruc *pDCTstat, u8 dct)
24 {
25         u32 reg_off = 0x100 * dct;
26         u32 dev = pDCTstat->dev_dct;
27         u32 val;
28
29         do {
30                 val = Get_NB32(dev, reg_off + 0x98);
31         } while (!(val & (1 << DctAccessDone)));
32 }
33
34 static u32 swapAddrBits(struct DCTStatStruc *pDCTstat, u32 MR_register_setting, u8 MrsChipSel, u8 dct)
35 {
36         u16 word;
37         u32 ret;
38
39         if (!(pDCTstat->Status & (1 << SB_Registered))) {
40                 word = pDCTstat->MirrPresU_NumRegR;
41                 if (dct == 0) {
42                         word &= 0x55;
43                         word <<= 1;
44                 } else
45                         word &= 0xAA;
46
47                 if (word & (1 << MrsChipSel)) {
48                         /* A3<->A4,A5<->A6,A7<->A8,BA0<->BA1 */
49                         ret = 0;
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;
60                 }
61         }
62         return MR_register_setting;
63 }
64
65 static void mct_SendMrsCmd(struct DCTStatStruc *pDCTstat, u8 dct, u32 EMRS)
66 {
67         u32 reg_off = 0x100 * dct;
68         u32 dev = pDCTstat->dev_dct;
69         u32 val;
70
71         val = Get_NB32(dev, reg_off + 0x7C);
72         val &= ~0xFFFFFF;
73         val |= EMRS;
74         val |= 1 << SendMrsCmd;
75         Set_NB32(dev, reg_off + 0x7C, val);
76
77         do {
78                 val = Get_NB32(dev, reg_off + 0x7C);
79         } while (val & (1 << SendMrsCmd));
80 }
81
82 static u32 mct_MR2(struct MCTStatStruc *pMCTstat,
83                                 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
84 {
85         u32 reg_off = 0x100 * dct;
86         u32 dev = pDCTstat->dev_dct;
87         u32 dword, ret;
88
89         ret = 0x20000;
90         ret |= MrsChipSel;
91
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);
96
97         ret |= ((dword >> 20) & 7) << 3;
98
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;
104
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;
108
109         return ret;
110 }
111
112 static u32 mct_MR3(struct MCTStatStruc *pMCTstat,
113                                 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
114 {
115         u32 reg_off = 0x100 * dct;
116         u32 dev = pDCTstat->dev_dct;
117         u32 dword, ret;
118
119         ret = 0x30000;
120         ret |= MrsChipSel;
121
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]
126         */
127         dword = Get_NB32(dev, reg_off + 0x84);
128         ret |= (dword >> 24) & 7;
129
130         return ret;
131 }
132
133 static u32 mct_MR1(struct MCTStatStruc *pMCTstat,
134                                 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
135 {
136         u32 reg_off = 0x100 * dct;
137         u32 dev = pDCTstat->dev_dct;
138         u32 dword, ret;
139
140         ret = 0x10000;
141         ret |= MrsChipSel;
142
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))
147                 ret |= 1 << 5;
148         if (dword & (1 << 2))
149                 ret |= 1 << 1;
150
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))
155                         ret |= 1 << 9;
156                 if (dword & (1 << 8))
157                         ret |= 1 << 6;
158                 if (dword & (1 << 7))
159                         ret |= 1 << 2;
160         } else {
161                 /* TODO: mct_MR1Odt_RDimm */
162         }
163
164         /* program MrsAddress[11]=TDQS: based on F2x[1,0]94[RDqsEn] */
165         if (Get_NB32(dev, reg_off + 0x94) & (1 << RDqsEn)) {
166                 u8 bit;
167                 /* Set TDQS=1b for x8 DIMM, TDQS=0b for x4 DIMM, when mixed x8 & x4 */
168                 bit = (ret >> 21) << 1;
169                 if ((dct & 1) != 0)
170                         bit ++;
171                 if (pDCTstat->Dimmx8Present & (1 << bit))
172                         ret |= 1 << 11;
173         }
174
175         if (dword & (1 << 13))
176                 ret |= 1 << 12;
177
178         return ret;
179 }
180
181 static u32 mct_MR0(struct MCTStatStruc *pMCTstat,
182                                 struct DCTStatStruc *pDCTstat, u8 dct, u32 MrsChipSel)
183 {
184         u32 reg_off = 0x100 * dct;
185         u32 dev = pDCTstat->dev_dct;
186         u32 dword, ret, dword2;
187
188         ret = 0x00000;
189         ret |= MrsChipSel;
190
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);
194         ret |= dword & 3;
195
196         /* program MrsAddress[3]=1 (BT):interleaved */
197         ret |= 1 << 3;
198
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 */
203
204         /* program MrsAddress[12]=0 (PPD):slow exit */
205         if (dword & (1 << 23))
206                 ret |= 1 << 12;
207
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;
211
212         /* program MrsAddress[8]=1 (DLL):DLL reset
213            just issue DLL reset at first time */
214         ret |= 1 << 8;
215
216         return ret;
217 }
218
219 static void mct_SendZQCmd(struct DCTStatStruc *pDCTstat, u8 dct)
220 {
221         u32 reg_off = 0x100 * dct;
222         u32 dev = pDCTstat->dev_dct;
223         u32 dword;
224
225         /*1.Program MrsAddress[10]=1
226           2.Set SendZQCmd=1
227          */
228         dword = Get_NB32(dev, reg_off + 0x7C);
229         dword &= ~0xFFFFFF;
230         dword |= 1 << 10;
231         dword |= 1 << SendZQCmd;
232         Set_NB32(dev, reg_off + 0x7C, dword);
233
234         /* Wait for SendZQCmd=0 */
235         do {
236                 dword = Get_NB32(dev, reg_off + 0x7C);
237         } while (dword & (1 << SendZQCmd));
238
239         /* 4.Wait 512 MEMCLKs */
240         mct_Wait(300);
241 }
242
243 void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
244                                 struct DCTStatStruc *pDCTstat, u8 dct)
245 {
246         u8 MrsChipSel;
247         u32 dword;
248         u32 reg_off = 0x100 * dct;
249         u32 dev = pDCTstat->dev_dct;
250
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);
257
258                 /* 4.wait 200us */
259                 mct_Wait(40000);
260
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);
265
266                 /* 6.wait 500us */
267                 mct_Wait(200000);
268
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);
273
274                 /* 8.wait 360ns */
275                 mct_Wait(80);
276
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);
281         }
282
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)) {
287                         u32 EMRS;
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);
304
305                         if (pDCTstat->DIMMAutoSpeed == 4)
306                                 if (!(pDCTstat->Status & (1 << SB_Registered)))
307                                         break; /* For UDIMM, only send MR commands once per channel */
308                 }
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)))
311                                 MrsChipSel ++;
312         }
313
314         mct_Wait(100000);
315
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);
325         }
326 }