Some more DIMM0 related cleanups and deduplication.
[coreboot.git] / src / northbridge / via / 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 /* FIXME this should go away */
21 static const struct mem_controller ctrl = {
22         .channel0 = {DIMM0, DIMM1},
23 };
24
25 /* read data */
26 CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 *Buf);
27 void DRAMCmdRate(DRAM_SYS_ATTR *DramAttr);
28 CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR *DramAttr);
29
30 CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 *Buf)
31 {
32         // CB_STATUS Status = CB_NOT_READY;
33         u8 Val, i;
34
35         if (1 > Length || NULL == Buf)
36                 return CB_INVALID_PARAMETER;
37
38         for (i = 0; i < Length; i++) {
39                 Val = get_spd_data(ctrl.channel0[Slot], i);
40                 *(Buf + i) = Val;
41         }
42         return CB_SUCCESS;
43 }
44
45 CB_STATUS DRAMDetect(DRAM_SYS_ATTR *DramAttr)
46 {
47         CB_STATUS Status = CB_SUCCESS;
48
49         PRINT_DEBUG_MEM("DRAM detection \r");
50
51         /* Read D0F3Rx6C, detect memory type DDR1 or DDR2. */
52         /* 353 supports DDR2 only */
53         DramAttr->DramType = RAMTYPE_SDRAMDDR2;
54         /* Get information for SPD. */
55         Status = GetInfoFromSPD(DramAttr);
56         if (CB_SUCCESS == Status) {
57                 /* 64bit or 128Bit */
58
59                 // if (RAMTYPE_SDRAMDDR == DramAttr->DramType)
60
61                 /* Select command rate. */
62                 DRAMCmdRate(DramAttr);
63         }
64         return Status;
65 }
66
67 /*
68  * Determine 1T or 2T command rate.
69  *
70  * To enable 1T command rate, the system will satisfy the following
71  * three conditions:
72  *
73  *   1. Each DRAM channel may have 1 or 2 ranks of DIMM. 3/4 ranks can not
74  *      support 1T command rate. It's for loading issue. 1T can supports
75  *       (a) only one socket with two ranks, OR
76  *       (b) two sockets each with 1 rank.
77  *   2. User wishes to enable 1T command rate mode and turn on by setup menu.
78  *   3. If 1T command rate can be enabled, just set EBP bit here.
79  */
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 /*
93  * Get SPD data and set RANK presence map.
94  *
95  * Sockets0,1 is Channel A / Sockets2,3 is Channel B.
96  *
97  * Socket0 SPD device address 0x50 / socket1 SPD device address 0x51
98  * Socket2 SPD device address 0x52 / socket3 SPD device address 0x53
99  */
100 CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR *DramAttr)
101 {
102         CB_STATUS Status;
103         u8 *pSPDDataBuf;
104         u8 ModuleDataWidth, ChipWidth, RankNum, LoadNum, Sockets, i;
105         BOOLEAN bFind;  /* FIXME: We don't have/want BOOLEAN. */
106
107         bFind = FALSE;  /* FIXME: We don't have/want FALSE. */
108         Status = CB_DEVICE_ERROR;
109
110         for (Sockets = 0; Sockets < MAX_SOCKETS; Sockets++) {
111                 pSPDDataBuf = DramAttr->DimmInfo[Sockets].SPDDataBuf;
112                 pSPDDataBuf[SPD_MEMORY_TYPE] =
113                     get_spd_data(ctrl.channel0[Sockets], SPD_MEMORY_TYPE);
114                 if (pSPDDataBuf[SPD_MEMORY_TYPE] == 0) {
115                         Status = CB_NOT_READY;
116                 } else {
117                         Status =
118                             GetSPDData(Sockets, SPD_DATA_SIZE, pSPDDataBuf);
119                         PRINT_DEBUG_MEM("SPD : \r");
120                         for (i = 0; i < SPD_DATA_SIZE; i++) {
121                                 PRINT_DEBUG_MEM(" ");
122                                 PRINT_DEBUG_MEM_HEX8(pSPDDataBuf[i]);
123                         }
124                 }
125                 if (CB_SUCCESS == Status) {
126                         /*
127                          * If DRAM controller detected type not same as the
128                          * type got from SPD, there are ERROR.
129                          */
130                         if (pSPDDataBuf[SPD_MEMORY_TYPE] != DramAttr->DramType) {
131                                 Status = CB_DEVICE_ERROR; /* memory int error */
132                                 PRINT_DEBUG_MEM("Memory Device ERROR: DRAM "
133                                                 "controller detected type != "
134                                                 "type got from SPD\r");
135                                 break;
136                         }
137                         DramAttr->DimmInfo[Sockets].bPresence = TRUE;
138
139                         /* Calculate load number (chips number). */
140                         ModuleDataWidth = (u8) (DramAttr->
141                                   DimmInfo[Sockets].SPDDataBuf
142                                   [SPD_SDRAM_MOD_DATA_WIDTH + 1]);
143                         ModuleDataWidth = (u8) (ModuleDataWidth << 8);
144                         ModuleDataWidth |= (u8) (DramAttr->
145                                   DimmInfo[Sockets].SPDDataBuf
146                                   [SPD_SDRAM_MOD_DATA_WIDTH]);
147                         ChipWidth = (u8) ((DramAttr->
148                                    DimmInfo[Sockets].SPDDataBuf
149                                    [SPD_SDRAM_WIDTH]) & 0x7F);
150                         LoadNum = (u8) (ModuleDataWidth / ChipWidth);
151
152                         /* Set the RANK map. */
153                         /* Get bit0,1, the most number of supported RANK is 2. */
154                         RankNum = (u8) (pSPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x3);
155                         if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
156                                 /*
157                                  * For DDR bit[0,1]: 01->1 RANK, 10->2 RANK
158                                  * For DDR2 bit[0,1]: 00->1 RANK, 01->2 RANK
159                                  */
160                                 RankNum++;
161
162                         /* Every DIMM have 1 or 2 ranks. */
163                         if (RankNum != 2 && RankNum != 1) {
164                                 Status = CB_DEVICE_ERROR;
165                                 PRINT_DEBUG_MEM("Memory Device ERROR: Number "
166                                                 "of RANK not supported!\r");
167                                 break;
168                         }
169
170                         if (Sockets < 2) { /* Sockets0,1 is channel A */
171                                 DramAttr->RankNumChA =
172                                     (u8) (DramAttr->RankNumChA + RankNum);
173                                 DramAttr->DimmNumChA++;
174                                 DramAttr->LoadNumChA =
175                                     (u8) (DramAttr->LoadNumChA * LoadNum *
176                                           RankNum);
177                         } else { /* Sockets2,3 is channel B */
178                                 DramAttr->RankNumChB =
179                                     (u8) (DramAttr->RankNumChB + RankNum);
180                                 DramAttr->DimmNumChB++;
181                                 DramAttr->LoadNumChB =
182                                     (u8) (DramAttr->LoadNumChB * LoadNum *
183                                           RankNum);;
184                         }
185                         RankNum |= 1; /* Set rank map. */
186                         DramAttr->RankPresentMap |= (RankNum << (Sockets * 2));
187                         bFind = TRUE;
188                 }
189         }
190
191         PRINT_DEBUG_MEM("Rank Present Map:");
192         PRINT_DEBUG_MEM_HEX8(DramAttr->RankPresentMap);
193         PRINT_DEBUG_MEM("\r");
194
195         if (bFind)
196                 Status = CB_SUCCESS;
197
198         return Status;
199 }