6c88c68953893f8d2d1ea8890e5231443c39f81f
[coreboot.git] / src / northbridge / via / vx800 / rank_map.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2009 One Laptop per Child, Association, 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 void DRAMClearEndingAddress(DRAM_SYS_ATTR * DramAttr);
21
22 void DRAMSizingEachRank(DRAM_SYS_ATTR * DramAttr);
23
24 BOOLEAN DoDynamicSizing1XM(DRAM_SYS_ATTR * DramAttr,
25                            u8 * nRA, u8 * nCA, u8 * nBS, u8 PhyRank);
26
27 void DRAMSetRankMAType(DRAM_SYS_ATTR * DramAttr);
28
29 void DRAMSetEndingAddress(DRAM_SYS_ATTR * DramAttr);
30
31 void DRAMPRToVRMapping(DRAM_SYS_ATTR * DramAttr);
32
33 /*===================================================================
34 Function   : DRAMBankInterleave()
35 Precondition : 
36 Input        : 
37                    DramAttr: pointer point to  DRAMSYSATTR  which consist the DDR and Dimm information in MotherBoard
38 Output     :  Void
39 Purpose   :  STEP 13 Set Bank Interleave  VIANB3DRAMREG69[7:6] 00:No Interleave 01:2 Bank 10:4 Bank     11:8 Bank
40                    Scan all DIMMs on board to find out the lowest Bank Interleave among these DIMMs and set register.
41 ===================================================================*/
42 void DRAMBankInterleave(DRAM_SYS_ATTR * DramAttr)
43 {
44         u8 Data, SpdBAData;
45         DIMM_INFO *CurrentDimminfo;
46         u8 Bank = 3, Shift, RankNO, Count;
47         Shift = 1;
48         for (RankNO = 0; RankNO < 4; RankNO += 2)       //all_even  0 RankNO 4 6
49         {
50                 if ((DramAttr->RankPresentMap & Shift) != 0) {
51                         CurrentDimminfo = &(DramAttr->DimmInfo[RankNO >> 1]);   //this Rank in a dimm
52                         SpdBAData =
53                             (u8) (CurrentDimminfo->SPDDataBuf
54                                   [SPD_SDRAM_NO_OF_BANKS]);
55                         if (SpdBAData == 4)
56                                 Count = 2;
57                         else if (SpdBAData == 8)
58                                 Count = 3;
59                         else
60                                 Count = 0;
61                         if (Count < Bank)
62                                 Bank = Count;
63                 }
64                 Shift <<= 2;
65         }
66
67         Data = pci_read_config8(MEMCTRL, 0x69);
68         Data &= ~0xc0;
69         Data |= (Bank << 6);
70         pci_write_config8(MEMCTRL, 0x69, Data);
71
72         if (DramAttr->DimmNumChB > 0) {
73                 CurrentDimminfo = &(DramAttr->DimmInfo[3]);     //this Rank in a dimm
74                 SpdBAData =
75                     (u8) (CurrentDimminfo->SPDDataBuf[SPD_SDRAM_NO_OF_BANKS]);
76                 if (SpdBAData == 4)
77                         Bank = 2;
78                 else if (SpdBAData == 2)
79                         Bank = 1;
80                 else
81                         Bank = 0;
82                 pci_write_config8(MEMCTRL, 0x87, Bank);
83         }
84 }
85
86 /*===================================================================
87 Function   : DRAMSizingMATypeM()
88 Precondition : 
89 Input        :
90                    DramAttr: pointer point to  DRAMSYSATTR  which consist the DDR and Dimm information in MotherBoard
91 Output     :  Void
92  Purpose  : STEP 14  1 DRAM Sizing 2  Fill MA type 3 Prank to vrankMapping 
93 ===================================================================*/
94 void DRAMSizingMATypeM(DRAM_SYS_ATTR * DramAttr)
95 {
96         DRAMClearEndingAddress(DramAttr);
97         DRAMSizingEachRank(DramAttr);
98         //DRAMReInitDIMMBL           (DramAttr);
99         DRAMSetRankMAType(DramAttr);
100         DRAMSetEndingAddress(DramAttr);
101         DRAMPRToVRMapping(DramAttr);
102 }
103
104 /*===================================================================
105 Function   : DRAMClearEndingAddress()
106 Precondition : 
107 Input        : 
108                    DramAttr: pointer point to  DRAMSYSATTR  which consist the DDR and Dimm information in MotherBoard
109 Output     : Void
110 Purpose   : clear Ending and Start adress from 0x40-4f to zero
111 ===================================================================*/
112 void DRAMClearEndingAddress(DRAM_SYS_ATTR * DramAttr)
113 {
114         u8 Data, Reg;
115         Data = 0;
116         for (Reg = 0x40; Reg <= 0x4f; Reg++) {
117                 pci_write_config8(MEMCTRL, Reg, Data);
118         }
119 }
120
121 /*===================================================================
122 Function   : DRAMSizingEachRank()
123 Precondition : 
124 Input        : 
125                    DramAttr: pointer point to  DRAMSYSATTR  which consist the DDR and Dimm information in MotherBoard
126 Output     : Void
127 Purpose   : Sizing each Rank invidually, by number of rows column banks pins, be care about 128bit
128 ===================================================================*/
129 void DRAMSizingEachRank(DRAM_SYS_ATTR * DramAttr)
130 {
131         u8 Slot, RankIndex, Rows, Columns, Banks;
132         u32 Size;
133         BOOLEAN HasThreeBitBA;
134         u8 Data;
135
136         HasThreeBitBA = FALSE;
137         for (Slot = 0; Slot < 2; Slot++) {
138                 if (!DramAttr->DimmInfo[Slot].bPresence)
139                         continue;
140                 Rows = DramAttr->DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_ROW_ADDR];
141                 Columns =
142                     DramAttr->DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_COL_ADDR];
143                 Banks = DramAttr->DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_NO_OF_BANKS];     //this is Bank number not Bank address bit
144                 if (Banks == 4)
145                         Banks = 2;
146                 else if (Banks == 8)
147                         Banks = 3;
148                 else
149                         Banks = 0;
150                 Size = (u32) (1 << (Rows + Columns + Banks + 3));
151                 RankIndex = 2 * Slot;
152                 DramAttr->RankSize[RankIndex] = Size;
153                 //if this module have two ranks
154                 if ((DramAttr->
155                      DimmInfo[Slot].SPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x07) ==
156                     0x01) {
157                         RankIndex++;
158                         DramAttr->RankSize[RankIndex] = Size;
159                 }
160
161                 PRINT_DEBUG_MEM("rows: ");
162                 PRINT_DEBUG_MEM_HEX8(Rows);
163                 PRINT_DEBUG_MEM(", columns:");
164                 PRINT_DEBUG_MEM_HEX8(Columns);
165                 PRINT_DEBUG_MEM(", banks:");
166                 PRINT_DEBUG_MEM_HEX8(Banks);
167                 PRINT_DEBUG_MEM("\r");
168
169                 if (Banks == 3)
170                         HasThreeBitBA = TRUE;
171         }
172
173         //must set BA2 enable if any 8-bank device exists
174         if (HasThreeBitBA) {
175                 Data = pci_read_config8(MEMCTRL, 0x53);
176                 Data |= 0x80;
177                 pci_write_config8(MEMCTRL, 0x53, Data);
178         }
179 #if 1
180         for (RankIndex = 0; DramAttr->RankSize[RankIndex] != 0; RankIndex++) {
181                 PRINT_DEBUG_MEM("Rank:");
182                 PRINT_DEBUG_MEM_HEX8(RankIndex);
183                 PRINT_DEBUG_MEM(", Size:");
184                 PRINT_DEBUG_MEM_HEX32(DramAttr->RankSize[RankIndex] >> 20);
185                 PRINT_DEBUG_MEM("\r");
186         }
187 #endif
188 }
189
190 /*===================================================================
191 Function   : DRAMSetRankMAType()
192 Precondition : 
193 Input       : 
194                   DramAttr: pointer point to  DRAMSYSATTR  which consist the DDR and Dimm information in MotherBoard
195 Output     : Void
196 Purpose   : set the matype Reg by MAMapTypeTbl, which the rule can be found in memoryinit
197 ===================================================================*/
198 void DRAMSetRankMAType(DRAM_SYS_ATTR * DramAttr)
199 {
200         u8 SlotNum, Data, j, Reg, or, and;
201         u8 ShiftBits[] = { 5, 1, 5, 1 };        /* Rank 0/1 MA Map Type is 7:5, Rank 2/3 MA Map Type is 3:1. See  Fun3Rx50. */
202         u8 MAMapTypeTbl[] = {   /* Table 12 of P4M800 Pro DataSheet. */
203                 2, 9, 0,        /* Bank Address Bits, Column Address Bits, Rank MA Map Type */
204                 2, 10, 1,
205                 2, 11, 2,
206                 2, 12, 3,
207                 3, 10, 5,
208                 3, 11, 6,
209                 3, 12, 7,
210                 0, 0, 0
211         };
212         Data = pci_read_config8(MEMCTRL, 0x50);
213         Data &= 0x1;
214         pci_write_config8(MEMCTRL, 0x50, Data);
215         // disable MA32/16 MA33/17 swap   in memory init it has this Reg fill
216         Data = pci_read_config8(MEMCTRL, 0x6b);
217         Data &= ~0x08;
218         pci_write_config8(MEMCTRL, 0x6b, Data);
219
220         Data = 0x00;
221         for (SlotNum = 0; SlotNum < MAX_DIMMS; SlotNum++) {
222                 if (DramAttr->DimmInfo[SlotNum].bPresence) {
223                         for (j = 0; MAMapTypeTbl[j] != 0; j += 3) {
224                                 if ((1 << MAMapTypeTbl[j]) ==
225                                     DramAttr->
226                                     DimmInfo[SlotNum].SPDDataBuf
227                                     [SPD_SDRAM_NO_OF_BANKS]
228                                     && MAMapTypeTbl[j + 1] ==
229                                     DramAttr->
230                                     DimmInfo[SlotNum].SPDDataBuf
231                                     [SPD_SDRAM_COL_ADDR]) {
232                                         break;
233                                 }
234                         }
235                         if (0 == MAMapTypeTbl[j]) {
236                                 PRINT_DEBUG_MEM
237                                     ("UNSUPPORTED Bank, Row and Column Addr Bits!\r");
238                                 return;
239                         }
240                         or = MAMapTypeTbl[j + 2] << ShiftBits[SlotNum];
241                         if (DramAttr->CmdRate == 1)
242                                 or |= 0x01 << (ShiftBits[SlotNum] - 1);
243
244                         Reg = SlotNum / 2;
245                         if ((SlotNum & 0x01) == 0x01) {
246                                 and = 0xf1;     // BUGBUG: it should be 0xf0
247                         } else {
248                                 and = 0x1f;     // BUGBUG: it should be 0x0f
249                         }
250                         Data = pci_read_config8(MEMCTRL, 0x50 + Reg);
251                         Data &= and;
252                         Data |= or;
253                         pci_write_config8(MEMCTRL, 0x50 + Reg, Data);
254                 }
255         }
256         //may have some Reg filling at add 3-52 11 and 3-53   in his function
257 }
258
259 /*===================================================================
260 Function   : DRAMSetEndingAddress()
261 Precondition : 
262 Input      :  
263                   DramAttr: pointer point to  DRAMSYSATTR  which consist the DDR and Dimm information in MotherBoard
264 Output     : Void
265 Purpose   : realize the Vrank 40...Reg (Start and Ending Regs). Vrank have  same order with phy Rank, Size is actual Size  
266 ===================================================================*/
267 void DRAMSetEndingAddress(DRAM_SYS_ATTR * DramAttr)
268 {
269         u8 Shift = 1, Data, RankNO, Size, Start = 0, End = 0, Vrank;
270         for (RankNO = 0; RankNO < 4; RankNO++) {
271                 if ((DramAttr->RankPresentMap & Shift) != 0) {
272                         Size = (u8) (DramAttr->RankSize[RankNO] >> 26); // current Size in the unit of 64M
273                         if (Size != 0) {
274
275                                 End = End + Size;       // calculate current ending address,   add the current Size to ending
276                                 Vrank = RankNO; // get virtual Rank
277                                 Data = End;     // set begin/End address register to correspondig virtual       Rank #
278                                 pci_write_config8(MEMCTRL, 0x40 + Vrank, Data);
279                                 Data = Start;
280                                 pci_write_config8(MEMCTRL, 0x48 + Vrank, Data);
281                                 PRINT_DEBUG_MEM("Rank: ");
282                                 PRINT_DEBUG_MEM_HEX8(Vrank);
283                                 PRINT_DEBUG_MEM(", Start:");
284                                 PRINT_DEBUG_MEM_HEX8(Start);
285                                 PRINT_DEBUG_MEM(", End:");
286                                 PRINT_DEBUG_MEM_HEX8(End);
287                                 PRINT_DEBUG_MEM("\r");
288
289                                 Start = End;
290                         }
291                 }
292                 Shift <<= 1;
293         }
294
295         if (DramAttr->RankNumChB > 0) {
296                 //this is a bug,fixed is to 2,so the max LL size is 128M
297                 Data = 0x02;
298                 pci_write_config8(MEMCTRL, 0x44, Data);
299         }
300         Data = End * 4;
301         pci_write_config8(PCI_DEV(0, 17, 7), 0x60, Data);
302         // We should directly write to south Bridge, not in north bridge
303         // program LOW TOP Address
304         Data = pci_read_config8(MEMCTRL, 0x88);
305         pci_write_config8(MEMCTRL, 0x85, Data);
306
307         // also program vlink mirror
308         // We should directly write to south Bridge, not in north bridge
309         pci_write_config8(PCI_DEV(0, 17, 7), 0xe5, Data);
310 }
311
312 /*===================================================================
313 Function   : DRAMPRToVRMapping()
314 Precondition : 
315 Input       : 
316                   DramAttr: pointer point to  DRAMSYSATTR  which consist the DDR and Dimm information in MotherBoard
317 Output     : Void
318 Purpose   : set the Vrank-prank map with the same order
319 ===================================================================*/
320 void DRAMPRToVRMapping(DRAM_SYS_ATTR * DramAttr)
321 {
322         u8 Shift, Data, and, or, DimmNO = 0, PhyRankNO, Reg;
323
324         for (Reg = 0x54; Reg <= 0x57; Reg++)    //clear the map-reg
325         {
326                 Data = 0;
327                 pci_write_config8(MEMCTRL, Reg, Data);
328         }
329
330         Shift = 1;
331         for (PhyRankNO = 0; PhyRankNO < MAX_RANKS; PhyRankNO++) {
332                 if ((DramAttr->RankPresentMap & Shift) != 0) {
333                         or = PhyRankNO; // get virtual Rank   ,same with PhyRank
334                         or |= 0x08;
335
336                         if ((PhyRankNO & 0x01) == 0x01) // get mask for register
337                                 and = 0xf0;
338                         else {
339                                 and = 0x0f;
340                                 or <<= 4;
341                         }
342                         DimmNO = (PhyRankNO >> 1);
343                         Data = pci_read_config8(MEMCTRL, 0x54 + DimmNO);
344                         Data &= and;
345                         Data |= or;
346                         pci_write_config8(MEMCTRL, 0x54 + DimmNO, Data);
347                 }
348                 Shift <<= 1;
349         }
350 }