DDR3 support for AMD Fam10.
[coreboot.git] / src / northbridge / amd / amdmct / mct_ddr3 / mctrci.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 u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
21                         struct DCTStatStruc *pDCTstat, u32 MrsChipSel, u32 CtrlWordNum)
22 {
23         u8 Dimms, DimmNum, MaxDimm, Speed;
24         u32 val;
25
26         DimmNum = MrsChipSel >> 20;
27
28         /* assume dct=0; */
29         /* if (dct == 1) */
30         /* DimmNum ++; */
31         /* cl +=8; */
32
33         MaxDimm = mctGet_NVbits(NV_MAX_DIMMS);
34         Speed = pDCTstat->DIMMAutoSpeed;
35         /* if (dct == 0) */
36         Dimms = pDCTstat->MAdimms[0];
37
38         val = 0;
39         if (CtrlWordNum == 0)
40                 val |= 1 << 1;
41         else if (CtrlWordNum == 1) {
42                 if (!((pDCTstat->DimmDRPresent | pDCTstat->DimmQRPresent) & (1 << DimmNum)))
43                         val |= 0xC; /* if single rank, set DBA1 and DBA0 */
44         }
45         else if (CtrlWordNum == 2) {
46                 if (MaxDimm == 4) {
47                         if (Speed == 4) {
48                                 if (((pDCTstat->DimmQRPresent & (1 << DimmNum)) && (Dimms == 1)) || Dimms == 2)
49                                         if (!(pDCTstat->MirrPresU_NumRegR & (1 << DimmNum)))
50                                                 val |= 1 << 2;
51                         } else {
52                                 if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
53                                         val |= 2;
54                         }
55                 } else {
56                         if (Dimms > 1)
57                                 val |= 2;
58                 }
59         } else if (CtrlWordNum == 3) {
60                 val = pDCTstat->CtrlWrd3 >> (DimmNum << 2);
61         } else if (CtrlWordNum == 4) {
62                 val = pDCTstat->CtrlWrd4 >> (DimmNum << 2);
63         } else if (CtrlWordNum == 5) {
64                 val = pDCTstat->CtrlWrd5 >> (DimmNum << 2);
65         } else if (CtrlWordNum == 8) {
66                 if (MaxDimm == 4)
67                         if (Speed == 4)
68                                 if (pDCTstat->MirrPresU_NumRegR & (1 << DimmNum))
69                                         val |= 1 << 2;
70         } else if (CtrlWordNum == 9) {
71                 val |= 0xD;     /* DBA1, DBA0, DA3 = 0 */
72         }
73         val &= 0xf;
74
75         val = MrsChipSel | ((val >> 2) & 3) << 16 | MrsChipSel | ((val >> 2) & 3);
76
77         /* transfer Control word number to address [BA2,A2,A1,A0] */
78         if (CtrlWordNum > 7) {
79                 val |= 1 << 18;
80                 CtrlWordNum &= 7;
81         }
82         val |= CtrlWordNum;
83
84         return val;
85 }
86
87 static void mct_SendCtrlWrd(struct MCTStatStruc *pMCTstat,
88                         struct DCTStatStruc *pDCTstat, u32 val)
89 {
90         u32 dev = pDCTstat->dev_dct;
91
92         val |= Get_NB32(dev, 0x7C) & ~0xFFFFFF;
93         val |= 1 << SendControlWord;
94         Set_NB32(dev, 0x7C, val);
95
96         do {
97                 val = Get_NB32(dev, 0x7C);
98         } while (val & (1 << SendControlWord));
99 }
100
101 void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
102                                 struct DCTStatStruc *pDCTstat, u8 dct)
103 {
104         u8 MrsChipSel;
105         u32 dev = pDCTstat->dev_dct;
106         u32 val, cw;
107
108         mct_Wait(1600);
109
110         mct_Wait(1200);
111
112         for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
113                 if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
114                         val = Get_NB32(dev, 0xA8);
115                         val &= ~(0xF << 8);
116
117                         switch (MrsChipSel) {
118                         case 0:
119                         case 1:
120                                 val |= 3 << 8;
121                         case 2:
122                         case 3:
123                                 val |= (3 << 2) << 8;
124                         case 4:
125                         case 5:
126                                 val |= (3 << 4) << 8;
127                         case 6:
128                         case 7:
129                                 val |= (3 << 6) << 8;
130                         }
131                         Set_NB32(dev, 0xA8, val);
132
133                         for (cw=0; cw <=15; cw ++) {
134                                 mct_Wait(1600);
135                                 if (!(cw==6 || cw==7)) {
136                                         val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, cw);
137                                         mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
138                                 }
139                         }
140                 }
141         }
142
143         mct_Wait(1200);
144 }
145
146 void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
147                         struct DCTStatStruc *pDCTstat)
148 {
149         u32 SaveSpeed = pDCTstat->DIMMAutoSpeed;
150         u32 MrsChipSel;
151         u32 dev = pDCTstat->dev_dct;
152         u32 val;
153
154         pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
155         for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
156                 if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
157                         val = Get_NB32(dev, 0xA8);
158                         val &= ~(0xFF << 8);
159                         val |= (0x3 << MrsChipSel) << 8;
160                         Set_NB32(dev, 0xA8, val);
161
162                         mct_Wait(1600);
163                         switch (pDCTstat->TargetFreq) {
164                         case 6:
165                                 mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4000A);
166                                 break;
167                         case 5:
168                                 mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x40012);
169                                 break;
170                         case 7:
171                                 mct_SendCtrlWrd(pMCTstat, pDCTstat, MrsChipSel << 20 | 0x4001A);
172                                 break;
173                         }
174
175                         mct_Wait(1600);
176
177                         val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 2);
178                         mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
179
180                         mct_Wait(1600);
181
182                         /* Resend control word 8 */
183                         val = mct_ControlRC(pMCTstat, pDCTstat, MrsChipSel << 20, 8);
184                         mct_SendCtrlWrd(pMCTstat, pDCTstat, val);
185
186                         mct_Wait(1600);
187                 }
188         }
189         pDCTstat->DIMMAutoSpeed = SaveSpeed;
190 }