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