Here's the VIA vx800 patch from OLPC.
[coreboot.git] / src / northbridge / via / vx800 / ddr2init / vx800 / Detection.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 #define SMBUS_ADDR_CH_A_1         0xA0  // Dimmx
21 #define SMBUS_ADDR_CH_A_2         0xA2  // Dimmx
22 #define SMBUS_ADDR_CH_B_1         0xA4  // Dimmx
23 #define SMBUS_ADDR_CH_B_2         0xA6  // Dimmx
24
25 /*read data*/
26 CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 * Buf);
27
28 void DRAMCmdRate(DRAM_SYS_ATTR * DramAttr);
29
30
31
32 CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR * DramAttr);
33
34 CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 * Buf)
35 {
36         // CB_STATUS Status = CB_NOT_READY;
37         u8 Val;
38         u8 i;
39
40         if (1 > Length || NULL == Buf)
41                 return CB_INVALID_PARAMETER;
42
43         for (i = 0; i < Length; i++) {
44                 Val = get_spd_data(ctrl.channel0[Slot], i);
45                 *(Buf + i) = Val;
46         }
47         return CB_SUCCESS;
48 }
49
50 CB_STATUS DRAMDetect(DRAM_SYS_ATTR * DramAttr)
51 {
52         CB_STATUS Status = CB_SUCCESS;
53
54         PRINT_DEBUG_MEM("Dram Detection \r");
55
56         /*Read D0F3Rx6C , detect memory type DDR1 or DDR2 */
57         // 353 supports DDR2 only
58         DramAttr->DramType = RAMTYPE_SDRAMDDR2;
59         /*get information for SPD */
60         Status = GetInfoFromSPD(DramAttr);
61         if (CB_SUCCESS == Status) {
62                 /*64bit or 128Bit */
63                 //
64                 //  if (RAMTYPE_SDRAMDDR == DramAttr->DramType)
65
66                 /*select command rate */
67                 DRAMCmdRate(DramAttr);
68         }
69         return Status;
70 }
71
72
73 // Determine 1T or 2T Command Rate:
74 // To enable 1T command Rate, the       system will satisfy the following 3 conditions:
75 // 1. Each DRAM channel may have 1 or 2 ranks of DIMM. 3/4 ranks can not support 1T command rate
76 //    It's for loading issue. 1T can supports (a). only one socket with two ranks OR
77 //    (b). two sockets each with 1 rank.
78 // 2. User wishes       to enable 1T command rate mode and turn on by Setup menu
79 // 3. If 1T command rate can    be enabled, just set EBP bit here.
80 void DRAMCmdRate(DRAM_SYS_ATTR * DramAttr)
81 {
82         u8 Data;
83
84         // 5.1t/2t command rate, use the stable set
85         //offset50
86         DramAttr->CmdRate = 2;
87         Data = pci_read_config8(MEMCTRL, 0x50);
88         Data = (u8) (Data & 0xEE);
89         pci_write_config8(MEMCTRL, 0x50, Data);
90 }
91
92 /*get SPD data and set RANK presence map*/
93 /*
94 Sockets0,1 is Channel A / Sockets2,3 is Channel B
95 socket0 SPD device address 0x50 / socket1 SPD device address 0x51
96 socket2 SPD device address 0x52 / socket3 SPD device address 0x53
97 */
98 CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR * DramAttr)
99 {
100         CB_STATUS Status;
101         u8 *pSPDDataBuf;
102         u8 ModuleDataWidth;
103         u8 ChipWidth;
104         u8 RankNum;
105         u8 LoadNum;
106         u8 Sockets, i;
107         BOOLEAN bFind;
108         bFind = FALSE;
109         Status = CB_DEVICE_ERROR;
110
111         for (Sockets = 0; Sockets < MAX_SOCKETS; Sockets++) {
112                 pSPDDataBuf = DramAttr->DimmInfo[Sockets].SPDDataBuf;
113                 pSPDDataBuf[SPD_MEMORY_TYPE] =
114                     get_spd_data(ctrl.channel0[Sockets], SPD_MEMORY_TYPE);
115                 if (pSPDDataBuf[SPD_MEMORY_TYPE] == 0) {
116                         Status = CB_NOT_READY;
117                 } else {
118                         Status =
119                             GetSPDData(Sockets, SPD_DATA_SIZE,
120                                        pSPDDataBuf);
121                         PRINT_DEBUG_MEM("SPD : \r");
122                         for (i = 0; i < SPD_DATA_SIZE; i++) {
123                                 PRINT_DEBUG_MEM(" ");
124                                 PRINT_DEBUG_MEM_HEX8(pSPDDataBuf[i]);
125                         }
126                 }
127                 if (CB_SUCCESS == Status) {
128                         /*if Dram Controller detected type not same as the type got from SPD, There are ERROR */
129                         if (pSPDDataBuf[SPD_MEMORY_TYPE] !=
130                             DramAttr->DramType) {
131                                 Status = CB_DEVICE_ERROR;       /*Memory int error */
132                                 PRINT_DEBUG_MEM
133                                     ("Memory Device ERROR: Dram Controller detected type != type got from SPD \r");
134                                 break;
135                         }
136                         DramAttr->DimmInfo[Sockets].bPresence = TRUE;
137                         /*calculate load number (chips number) */
138                         ModuleDataWidth =
139                             (u8) (DramAttr->DimmInfo[Sockets].
140                                   SPDDataBuf[SPD_SDRAM_MOD_DATA_WIDTH +
141                                              1]);
142                         ModuleDataWidth = (u8) (ModuleDataWidth << 8);
143                         ModuleDataWidth |=
144                             (u8) (DramAttr->DimmInfo[Sockets].
145                                   SPDDataBuf[SPD_SDRAM_MOD_DATA_WIDTH]);
146                         ChipWidth =
147                             (u8) ((DramAttr->DimmInfo[Sockets].
148                                    SPDDataBuf[SPD_SDRAM_WIDTH]) & 0x7F);
149                         LoadNum = (u8) (ModuleDataWidth / ChipWidth);
150
151                         /*set the RANK map */
152                         RankNum = (u8) (pSPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x3);       /*get bit0,1, the Most number of supported RANK is 2 */
153                         if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
154                                 RankNum++;      /*for DDR bit[0,1] 01->1 RANK  10->2 RANK; for DDR2 bit[0,1] = 00 -> 1 RANK  01 -> 2 RANK */
155                         if (RankNum != 2 && RankNum != 1) {     /*every DIMM have 1 or 2 ranks */
156                                 Status = CB_DEVICE_ERROR;
157                                 PRINT_DEBUG_MEM
158                                     ("Memory Device ERROR: the number of RANK not support!\r");
159                                 break;
160                         }
161
162                         if (Sockets < 2) {      /*sockets0,1 is channel A */
163                                 DramAttr->RankNumChA =
164                                     (u8) (DramAttr->RankNumChA + RankNum);
165                                 DramAttr->DimmNumChA++;
166                                 DramAttr->LoadNumChA =
167                                     (u8) (DramAttr->LoadNumChA * LoadNum *
168                                           RankNum);
169                         } else {        /*sockets2,3 is channel B */
170
171                                 DramAttr->RankNumChB =
172                                     (u8) (DramAttr->RankNumChB + RankNum);
173                                 DramAttr->DimmNumChB++;
174                                 DramAttr->LoadNumChB =
175                                     (u8) (DramAttr->LoadNumChB * LoadNum *
176                                           RankNum);;
177                         }
178                         RankNum |= 1;   /*set rank map */
179                         DramAttr->RankPresentMap |=
180                             (RankNum << (Sockets * 2));
181                         bFind = TRUE;
182                 }
183         }
184         PRINT_DEBUG_MEM("Rank Present Map:");
185         PRINT_DEBUG_MEM_HEX8(DramAttr->RankPresentMap);
186         PRINT_DEBUG_MEM("\r");
187
188         if (bFind)
189                 Status = CB_SUCCESS;
190
191         return Status;
192 }