Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/libsaio/spd.c

1/*
2 * spd.c - serial presence detect memory information
3 * (restored from pcefi10.5)
4 */
5
6#include "libsaio.h"
7#include "pci.h"
8#include "platform.h"
9#include "spd.h"
10#include "saio_internal.h"
11#include "bootstruct.h"
12
13#ifndef DEBUG_SPD
14#define DEBUG_SPD 0
15#endif
16
17#if DEBUG_SPD
18#define DBG(x...)printf(x)
19#else
20#define DBG(x...)
21#endif
22
23static const char *spd_memory_types[] =
24{
25"RAM", /* 00h Undefined */
26"FPM", /* 01h FPM */
27"EDO", /* 02h EDO */
28"",/* 03h PIPELINE NIBBLE */
29"SDRAM", /* 04h SDRAM */
30"",/* 05h MULTIPLEXED ROM */
31"DDR SGRAM",/* 06h SGRAM DDR */
32"DDR SDRAM",/* 07h SDRAM DDR */
33"DDR2 SDRAM", /* 08h SDRAM DDR 2 */
34"",/* 09h Undefined */
35"",/* 0Ah Undefined */
36"DDR3 SDRAM" /* 0Bh SDRAM DDR 3 */
37};
38
39#define UNKNOWN_MEM_TYPE 2
40static uint8_t spd_mem_to_smbios[] =
41{
42UNKNOWN_MEM_TYPE, /* 00h Undefined */
43UNKNOWN_MEM_TYPE, /* 01h FPM */
44UNKNOWN_MEM_TYPE, /* 02h EDO */
45UNKNOWN_MEM_TYPE, /* 03h PIPELINE NIBBLE */
46SMB_MEM_TYPE_SDRAM, /* 04h SDRAM */
47SMB_MEM_TYPE_ROM, /* 05h MULTIPLEXED ROM */
48SMB_MEM_TYPE_SGRAM, /* 06h SGRAM DDR */
49SMB_MEM_TYPE_DDR, /* 07h SDRAM DDR */
50SMB_MEM_TYPE_DDR2, /* 08h SDRAM DDR 2 */
51UNKNOWN_MEM_TYPE, /* 09h Undefined */
52UNKNOWN_MEM_TYPE, /* 0Ah Undefined */
53SMB_MEM_TYPE_DDR3 /* 0Bh SDRAM DDR 3 */
54};
55#define SPD_TO_SMBIOS_SIZE (sizeof(spd_mem_to_smbios)/sizeof(uint8_t))
56
57typedef struct _vidTag {
58 uint16_t code;
59 const char* name;
60} VenIdName;
61
62VenIdName vendorMap[] = {
63 {0xCD04, "G Skill Intl"}, // id=CD Bank=5
64 {0xB004, "OCZ"}, // id=B0 Bank=5
65 {0x9801, "Kingston"}, // id=98 Bank=2
66 {0x9E02, "Corsair"}, // id=9E Bank=3
67 {0x0205, "Patriot Memory"}, // id=02 Bank=6
68 {0x9B05, "Crucial Technology"}, // id=9B Bank=6
69 {0xBA01, "PNY Electronics"}, // id=BA Bank=2
70 {0x4F01, "Transcend Information"}, // id=4F Bank=2
71 {0x1903, "Centon Electronics"}, // id=19 Bank=4
72 {0x4001, "Viking Components"} // id=40 Bank=2
73};
74#define VEN_MAP_SIZE (sizeof(vendorMap)/sizeof(VenIdName))
75
76#define rdtsc(low,high) \
77__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
78
79#define SMBHSTSTS 0
80#define SMBHSTCNT 2
81#define SMBHSTCMD 3
82#define SMBHSTADD 4
83#define SMBHSTDAT 5
84
85
86const char * getVendorName(const char * spd)
87{
88 uint16_t code = *((uint16_t*) &spd[0x75]);
89 int i;
90 uint16_t bank=0;
91
92 if (spd[2]==0x0b) { // DDR3
93 for (i=0; i < VEN_MAP_SIZE; i++)
94 if (code==vendorMap[i].code)
95 return vendorMap[i].name;
96 }
97 else if (spd[2]==0x08 || spd[2]==0x07) { // DDR2 or DDR
98 for (i=64; i<72 && spd[i]==0x7f;i++) bank++;
99 code = bank+((uint16_t)spd[i])*256;
100 for (i=0; i < VEN_MAP_SIZE; i++)
101 if (code==vendorMap[i].code)
102 return vendorMap[i].name;
103 }
104
105 return "No Name";
106}
107
108int getDDRspeedMhz(const char * spd)
109{
110 if (spd[2]==0x0b) { // DDR3
111 switch(spd[12]) {
112 case 0x0f:
113 return 1066;
114 case 0x0c:
115 return 1333;
116 case 0x0a:
117 return 1600;
118 case 0x14:
119 default:
120 return 800;
121 }
122 }
123 else if (spd[2]==0x08) { // DDR2
124 switch(spd[9]) {
125 case 0x50:
126 return 400;
127 case 0x3d:
128 return 533;
129 case 0x30:
130 return 667;
131 case 0x25:
132 default:
133 return 800;
134 }
135 }
136 return 800; // default freq for unknown types
137}
138
139#define UIS(a) ((uint32_t)spd[a])
140uint32_t getDDRSerial(const char* spd)
141{
142 uint32_t ret=0;
143
144 if (spd[2]==0x0b) // DDR3
145 // assume it is lsb to msb
146 ret = UIS(122) | (UIS(123)<<8) | (UIS(124)<<16) | (UIS(125)<<24);
147 else if (spd[2]==0x08 || spd[2]==0x07) // DDR2 or DDR
148 ret = UIS(95) | (UIS(96)<<8) | (UIS(97)<<16) | (UIS(98)<<24);
149 return ret;
150}
151
152char * getDDRPartNum(const char* spd)
153{
154 if (spd[2]==0x0b) // DDR3
155 return &spd[128];
156 else if (spd[2]==0x08 || spd[2]==0x07) // DDR2 or DDR
157 return &spd[73];
158 return "";
159}
160unsigned char smb_read_byte_intel(uint32_t base, uint8_t adr, uint8_t cmd)
161{
162int l1, h1, l2, h2;
163 unsigned long long t;
164
165 outb(base + SMBHSTSTS, 0x1f);// reset SMBus Controller
166 outb(base + SMBHSTDAT, 0xff);
167
168 while( inb(base + SMBHSTSTS) & 0x01);// wait until ready
169
170 outb(base + SMBHSTCMD, cmd);
171 outb(base + SMBHSTADD, (adr << 1) | 0x01 );
172 outb(base + SMBHSTCNT, 0x48 );
173
174 rdtsc(l1, h1);
175
176 while (!( inb(base + SMBHSTSTS) & 0x02))// wait til command finished
177{
178rdtsc(l2, h2);
179t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / (Platform.CPU.TSCFrequency / 40);
180if (t > 10)
181break;// break after 10ms
182 }
183 return inb(base + SMBHSTDAT);
184}
185
186int mapping []={0,1,2,3,4,5}; // linear mapping for now, check me
187
188static void read_smb_intel(pci_dt_t *smbus_dev)
189{
190 static int serialnum=0;
191 int i, x, ser;
192 uint8_tspd_size, spd_type;
193 uint32_tbase;
194 bool dump = false;
195 RamSlotInfo_t* slot;
196
197 base = pci_config_read16(smbus_dev->dev.addr, 0x20) & 0xFFFE;
198 DBG("Scanning smbus_dev <%04x, %04x> ...\n",smbus_dev->vendor_id, smbus_dev->device_id);
199
200 getBoolForKey("DumpSPD", &dump, &bootInfo->bootConfig);
201
202 // Search MAX_RAM_SLOTS slots
203 for (i = 0; i < 6; i++){
204 slot = &Platform.RAM.DIMM[i];
205 Platform.DMI.DIMM[i]=mapping[i]; // for now no special mapping
206 spd_size = smb_read_byte_intel(base, 0x50 + i, 0);
207
208 // Check spd is present
209 if (spd_size && spd_size != 0xff)
210 {
211 slot->InUse = true;
212
213 slot->spd = malloc(spd_size);
214 if (slot->spd) {
215 bzero(slot->spd, spd_size);
216
217 // Copy spd data into buffer
218 for (x = 0; x < spd_size; x++)
219 slot->spd[x] = smb_read_byte_intel(base, 0x50 + i, x);
220
221 switch (slot->spd[SPD_MEMORY_TYPE]) {
222 case SPD_MEMORY_TYPE_SDRAM_DDR2:
223
224 slot->ModuleSize = ((1 << (slot->spd[SPD_NUM_ROWS] & 0x0f) + (slot->spd[SPD_NUM_COLUMNS] & 0x0f) - 17) *
225 ((slot->spd[SPD_NUM_DIMM_BANKS] & 0x7) + 1) * slot->spd[SPD_NUM_BANKS_PER_SDRAM]);
226 break;
227
228 case SPD_MEMORY_TYPE_SDRAM_DDR3:
229
230 slot->ModuleSize = ((slot->spd[4] & 0x0f) + 28 ) + ((slot->spd[8] & 0x7) + 3 );
231 slot->ModuleSize -= (slot->spd[7] & 0x7) + 25;
232 slot->ModuleSize = ((1 << slot->ModuleSize) * (((slot->spd[7] >> 3) & 0x1f) + 1));
233
234 break;
235 }
236 }
237
238 spd_type = (slot->spd[SPD_MEMORY_TYPE] < ((char) 12) ? slot->spd[SPD_MEMORY_TYPE] : 0);
239 slot->Type = spd_mem_to_smbios[spd_type];
240 strncpy(slot->PartNo, getDDRPartNum(slot->spd), 64);
241 strncpy(slot->Vendor, getVendorName(slot->spd), 64);
242
243 ser = getDDRSerial(slot->spd);
244 if (ser==0) {
245 sprintf(slot->SerialNo, "10000000%d", serialnum);
246 serialnum++;
247 }
248 else
249 sprintf(slot->SerialNo, "%d", ser);
250 // determine speed
251 slot->Frequency = getDDRspeedMhz(slot->spd);
252 if(dump) {
253 printf("Slot %d Type %d %dMB (%s) %dMHz Vendor=%s, PartNo=%s SerialNo=%s\n",
254 i,
255 (int)slot->Type,
256 slot->ModuleSize,
257 spd_memory_types[spd_type],
258 slot->Frequency,
259 slot->Vendor,
260 slot->PartNo,
261 slot->SerialNo);
262 dumpPhysAddr("spd content: ",slot->spd, spd_size);
263 getc();
264 }
265 }
266 }
267#if DEBUG_SPD
268 printf("Press a key to continue\n");
269 getc();
270#endif
271}
272
273static struct smbus_controllers_t smbus_controllers[] = {
274
275{0x8086, 0x269B, "ESB2", read_smb_intel },
276{0x8086, 0x25A4, "6300ESB", read_smb_intel },
277{0x8086, 0x24C3, "ICH4", read_smb_intel },
278{0x8086, 0x24D3, "ICH5", read_smb_intel },
279{0x8086, 0x266A, "ICH6", read_smb_intel },
280{0x8086, 0x27DA, "ICH7", read_smb_intel },
281{0x8086, 0x283E, "ICH8", read_smb_intel },
282{0x8086, 0x2930, "ICH9", read_smb_intel },
283{0x8086, 0x3A30, "ICH10R", read_smb_intel },
284{0x8086, 0x3A60, "ICH10B", read_smb_intel },
285{0x8086, 0x3B30, "P55", read_smb_intel },
286{0x8086, 0x5032, "EP80579", read_smb_intel }
287
288};
289
290void scan_smbus_controller(pci_dt_t *smbus_dev)
291{
292inti;
293
294for( i = 1; i < sizeof(smbus_controllers) / sizeof(smbus_controllers[0]); i++ )
295if (( smbus_controllers[i].vendor == smbus_dev->vendor_id)
296&& ( smbus_controllers[i].device == smbus_dev->device_id))
297{
298verbose("%s%s SMBus Controller [%4x:%4x] at %02x:%02x.%x\n",
299 (smbus_dev->vendor_id == 0x8086) ? "Intel(R) " : "",
300 smbus_controllers[i].name,
301 smbus_dev->vendor_id, smbus_dev->device_id,
302 smbus_dev->dev.bits.bus, smbus_dev->dev.bits.dev, smbus_dev->dev.bits.func);
303
304smbus_controllers[i].read_smb(smbus_dev);
305
306}
307
308}
309
310// initial call : pci_dt = root_pci_dev;
311// find_and_read_smbus_controller(root_pci_dev);
312bool find_and_read_smbus_controller(pci_dt_t* pci_dt)
313{
314 pci_dt_t*current = pci_dt;
315 int i;
316
317 while (current) {
318#if DEBUG_SPD
319 printf("%02x:%02x.%x [%04x] [%04x:%04x] :: %s\n",
320 current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func,
321 current->class_id, current->vendor_id, current->device_id,
322 get_pci_dev_path(current));
323#endif
324for ( i = 0; i < sizeof(smbus_controllers) / sizeof(smbus_controllers[0]); i++ )
325 {
326 if (current->vendor_id == smbus_controllers[i].vendor &&
327 current->device_id == smbus_controllers[i].device)
328 {
329 smbus_controllers[i].read_smb(current); // read smb
330 return true;
331 }
332 }
333 find_and_read_smbus_controller(current->children);
334 current = current->next;
335 }
336 return false; // not found
337}
338
339void scan_spd(PlatformInfo_t *p)
340{
341 find_and_read_smbus_controller(root_pci_dev);
342}
343

Archive Download this file

Revision: 91