6bbfef0168509e0094106d2a8b8183c540187a44
[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 = {0x50, 0x51},
23 };
24
25 #define SMBUS_ADDR_CH_A_1       0xA0    /* Dimmx */
26 #define SMBUS_ADDR_CH_A_2       0xA2    /* Dimmx */
27 #define SMBUS_ADDR_CH_B_1       0xA4    /* Dimmx */
28 #define SMBUS_ADDR_CH_B_2       0xA6    /* Dimmx */
29
30 /* read data */
31 CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 *Buf);
32 void DRAMCmdRate(DRAM_SYS_ATTR *DramAttr);
33 CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR *DramAttr);
34
35 CB_STATUS GetSPDData(u8 Slot, u8 Length, u8 *Buf)
36 {
37         // CB_STATUS Status = CB_NOT_READY;
38         u8 Val, 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  *
75  * To enable 1T command rate, the system will satisfy the following
76  * three conditions:
77  *
78  *   1. Each DRAM channel may have 1 or 2 ranks of DIMM. 3/4 ranks can not
79  *      support 1T command rate. It's for loading issue. 1T can supports
80  *       (a) only one socket with two ranks, OR
81  *       (b) two sockets each with 1 rank.
82  *   2. User wishes to enable 1T command rate mode and turn on by setup menu.
83  *   3. If 1T command rate can be enabled, just set EBP bit here.
84  */
85 void DRAMCmdRate(DRAM_SYS_ATTR *DramAttr)
86 {
87         u8 Data;
88
89         // 5.1t/2t command rate, use the stable set
90         //offset50
91         DramAttr->CmdRate = 2;
92         Data = pci_read_config8(MEMCTRL, 0x50);
93         Data = (u8) (Data & 0xEE);
94         pci_write_config8(MEMCTRL, 0x50, Data);
95 }
96
97 /*
98  * Get SPD data and set RANK presence map.
99  *
100  * Sockets0,1 is Channel A / Sockets2,3 is Channel B.
101  *
102  * Socket0 SPD device address 0x50 / socket1 SPD device address 0x51
103  * Socket2 SPD device address 0x52 / socket3 SPD device address 0x53
104  */
105 CB_STATUS GetInfoFromSPD(DRAM_SYS_ATTR *DramAttr)
106 {
107         CB_STATUS Status;
108         u8 *pSPDDataBuf;
109         u8 ModuleDataWidth, ChipWidth, RankNum, LoadNum, Sockets, i;
110         BOOLEAN bFind;  /* FIXME: We don't have/want BOOLEAN. */
111
112         bFind = FALSE;  /* FIXME: We don't have/want FALSE. */
113         Status = CB_DEVICE_ERROR;
114
115         for (Sockets = 0; Sockets < MAX_SOCKETS; Sockets++) {
116                 pSPDDataBuf = DramAttr->DimmInfo[Sockets].SPDDataBuf;
117                 pSPDDataBuf[SPD_MEMORY_TYPE] =
118                     get_spd_data(ctrl.channel0[Sockets], SPD_MEMORY_TYPE);
119                 if (pSPDDataBuf[SPD_MEMORY_TYPE] == 0) {
120                         Status = CB_NOT_READY;
121                 } else {
122                         Status =
123                             GetSPDData(Sockets, SPD_DATA_SIZE, pSPDDataBuf);
124                         PRINT_DEBUG_MEM("SPD : \r");
125                         for (i = 0; i < SPD_DATA_SIZE; i++) {
126                                 PRINT_DEBUG_MEM(" ");
127                                 PRINT_DEBUG_MEM_HEX8(pSPDDataBuf[i]);
128                         }
129                 }
130                 if (CB_SUCCESS == Status) {
131                         /*
132                          * If DRAM controller detected type not same as the
133                          * type got from SPD, there are ERROR.
134                          */
135                         if (pSPDDataBuf[SPD_MEMORY_TYPE] != DramAttr->DramType) {
136                                 Status = CB_DEVICE_ERROR; /* memory int error */
137                                 PRINT_DEBUG_MEM("Memory Device ERROR: DRAM "
138                                                 "controller detected type != "
139                                                 "type got from SPD\r");
140                                 break;
141                         }
142                         DramAttr->DimmInfo[Sockets].bPresence = TRUE;
143
144                         /* Calculate load number (chips number). */
145                         ModuleDataWidth = (u8) (DramAttr->
146                                   DimmInfo[Sockets].SPDDataBuf
147                                   [SPD_SDRAM_MOD_DATA_WIDTH + 1]);
148                         ModuleDataWidth = (u8) (ModuleDataWidth << 8);
149                         ModuleDataWidth |= (u8) (DramAttr->
150                                   DimmInfo[Sockets].SPDDataBuf
151                                   [SPD_SDRAM_MOD_DATA_WIDTH]);
152                         ChipWidth = (u8) ((DramAttr->
153                                    DimmInfo[Sockets].SPDDataBuf
154                                    [SPD_SDRAM_WIDTH]) & 0x7F);
155                         LoadNum = (u8) (ModuleDataWidth / ChipWidth);
156
157                         /* Set the RANK map. */
158                         /* Get bit0,1, the most number of supported RANK is 2. */
159                         RankNum = (u8) (pSPDDataBuf[SPD_SDRAM_DIMM_RANKS] & 0x3);
160                         if (RAMTYPE_SDRAMDDR2 == DramAttr->DramType)
161                                 /*
162                                  * For DDR bit[0,1]: 01->1 RANK, 10->2 RANK
163                                  * For DDR2 bit[0,1]: 00->1 RANK, 01->2 RANK
164                                  */
165                                 RankNum++;
166
167                         /* Every DIMM have 1 or 2 ranks. */
168                         if (RankNum != 2 && RankNum != 1) {
169                                 Status = CB_DEVICE_ERROR;
170                                 PRINT_DEBUG_MEM("Memory Device ERROR: Number "
171                                                 "of RANK not supported!\r");
172                                 break;
173                         }
174
175                         if (Sockets < 2) { /* Sockets0,1 is channel A */
176                                 DramAttr->RankNumChA =
177                                     (u8) (DramAttr->RankNumChA + RankNum);
178                                 DramAttr->DimmNumChA++;
179                                 DramAttr->LoadNumChA =
180                                     (u8) (DramAttr->LoadNumChA * LoadNum *
181                                           RankNum);
182                         } else { /* Sockets2,3 is channel B */
183                                 DramAttr->RankNumChB =
184                                     (u8) (DramAttr->RankNumChB + RankNum);
185                                 DramAttr->DimmNumChB++;
186                                 DramAttr->LoadNumChB =
187                                     (u8) (DramAttr->LoadNumChB * LoadNum *
188                                           RankNum);;
189                         }
190                         RankNum |= 1; /* Set rank map. */
191                         DramAttr->RankPresentMap |= (RankNum << (Sockets * 2));
192                         bFind = TRUE;
193                 }
194         }
195
196         PRINT_DEBUG_MEM("Rank Present Map:");
197         PRINT_DEBUG_MEM_HEX8(DramAttr->RankPresentMap);
198         PRINT_DEBUG_MEM("\r");
199
200         if (bFind)
201                 Status = CB_SUCCESS;
202
203         return Status;
204 }