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