Chameleon

Chameleon Svn Source Tree

Root/branches/meklortOld/i386/modules/Memory/spd.c

Source at commit 1166 created 13 years 10 days ago.
By meklort, Fixed recent Makefile changes. Please do not use /Users/evan/SourceCode/tmp/chameleon/trunk or VPATH. the *only* time you should use /Users/evan/SourceCode/tmp/chameleon/trunk is when setting the SRCROOT variable. Also note that very soon make pkg is going to be removed. The pkg build script in trunk is very out of date. Instead please use the package maker at http://forge.voodooprojects.org/p/chameleonApplications/. Once this is ready for trunk it will be merged.
1/*
2 * spd.c - serial presence detect memory information
3 *
4 * Originally restored from pcefi10.5
5 * Dynamic mem detection original impl. by Rekursor
6 * System profiler fix and other fixes by Mozodojo.
7 */
8
9#include "libsaio.h"
10#include "pci.h"
11#include "platform.h"
12#include "spd.h"
13#include "saio_internal.h"
14#include "bootstruct.h"
15#include "memvendors.h"
16
17#ifndef DEBUG_SPD
18#define DEBUG_SPD 0
19#endif
20
21#if DEBUG_SPD
22#define DBG(x...)printf(x)
23#else
24#define DBG(x...)
25#endif
26
27const char *spd_memory_types[] =
28{
29"RAM", /* 00h Undefined */
30"FPM", /* 01h FPM */
31"EDO", /* 02h EDO */
32"",/* 03h PIPELINE NIBBLE */
33"SDRAM", /* 04h SDRAM */
34"",/* 05h MULTIPLEXED ROM */
35"DDR SGRAM",/* 06h SGRAM DDR */
36"DDR SDRAM",/* 07h SDRAM DDR */
37"DDR2 SDRAM", /* 08h SDRAM DDR 2 */
38"",/* 09h Undefined */
39"",/* 0Ah Undefined */
40"DDR3 SDRAM" /* 0Bh SDRAM DDR 3 */
41};
42
43#define UNKNOWN_MEM_TYPE 2
44uint8_t spd_mem_to_smbios[] =
45{
46UNKNOWN_MEM_TYPE, /* 00h Undefined */
47UNKNOWN_MEM_TYPE, /* 01h FPM */
48UNKNOWN_MEM_TYPE, /* 02h EDO */
49UNKNOWN_MEM_TYPE, /* 03h PIPELINE NIBBLE */
50SMB_MEM_TYPE_SDRAM, /* 04h SDRAM */
51SMB_MEM_TYPE_ROM, /* 05h MULTIPLEXED ROM */
52SMB_MEM_TYPE_SGRAM, /* 06h SGRAM DDR */
53SMB_MEM_TYPE_DDR, /* 07h SDRAM DDR */
54SMB_MEM_TYPE_DDR2, /* 08h SDRAM DDR 2 */
55UNKNOWN_MEM_TYPE, /* 09h Undefined */
56UNKNOWN_MEM_TYPE, /* 0Ah Undefined */
57SMB_MEM_TYPE_DDR3 /* 0Bh SDRAM DDR 3 */
58};
59#define SPD_TO_SMBIOS_SIZE (sizeof(spd_mem_to_smbios)/sizeof(uint8_t))
60
61#define rdtsc(low,high) \
62__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
63
64#define SMBHSTSTS 0
65#define SMBHSTCNT 2
66#define SMBHSTCMD 3
67#define SMBHSTADD 4
68#define SMBHSTDAT 5
69#define SBMBLKDAT 7
70
71/** Read one byte from the intel i2c, used for reading SPD on intel chipsets only. */
72unsigned char smb_read_byte_intel(uint32_t base, uint8_t adr, uint8_t cmd)
73{
74 int l1 = 0;
75int l2 = 0;
76int h1 = 0;
77int h2 = 0;
78 unsigned long long t;
79
80 outb(base + SMBHSTSTS, 0x1f);// reset SMBus Controller
81 outb(base + SMBHSTDAT, 0xff);
82
83 while( inb(base + SMBHSTSTS) & 0x01);
84
85 outb(base + SMBHSTCMD, cmd);
86 outb(base + SMBHSTADD, (adr << 1) | 0x01 );
87 outb(base + SMBHSTCNT, 0x48 );
88
89 rdtsc(l1, h1);
90
91 while (!( inb(base + SMBHSTSTS) & 0x02))// wait til command finished
92{
93rdtsc(l2, h2);
94t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / (Platform->CPU.TSCFrequency / 100);
95if (t > 5)
96break;// break after 5ms
97 }
98 return inb(base + SMBHSTDAT);
99}
100
101/* SPD i2c read optimization: prefetch only what we need, read non prefetcheable bytes on the fly */
102#define READ_SPD(spd, base, slot, x) spd[x] = smb_read_byte_intel(base, 0x50 + slot, x)
103
104int spd_indexes[] = {
105SPD_MEMORY_TYPE,
106SPD_DDR3_MEMORY_BANK,
107SPD_DDR3_MEMORY_CODE,
108SPD_NUM_ROWS,
109SPD_NUM_COLUMNS,
110SPD_NUM_DIMM_BANKS,
111SPD_NUM_BANKS_PER_SDRAM,
1124,7,8,9,12,64, /* TODO: give names to these values */
11395,96,97,98, 122,123,124,125 /* UIS */
114};
115#define SPD_INDEXES_SIZE (sizeof(spd_indexes) / sizeof(int))
116
117/** Read from spd *used* values only*/
118static void init_spd(char * spd, uint32_t base, int slot)
119{
120int i;
121for (i=0; i< SPD_INDEXES_SIZE; i++) {
122READ_SPD(spd, base, slot, spd_indexes[i]);
123}
124}
125
126/** Get Vendor Name from spd, 2 cases handled DDR3 and DDR2,
127 have different formats, always return a valid ptr.*/
128const char * getVendorName(RamSlotInfo_t* slot, uint32_t base, int slot_num)
129{
130 uint8_t bank = 0;
131 uint8_t code = 0;
132 int i = 0;
133 uint8_t * spd = (uint8_t *) slot->spd;
134
135 if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) { // DDR3
136 bank = (spd[SPD_DDR3_MEMORY_BANK] & 0x07f); // constructors like Patriot use b7=1
137 code = spd[SPD_DDR3_MEMORY_CODE];
138 for (i=0; i < VEN_MAP_SIZE; i++)
139 if (bank==vendorMap[i].bank && code==vendorMap[i].code)
140 return vendorMap[i].name;
141 }
142 else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
143 if(spd[64]==0x7f) {
144 for (i=64; i<72 && spd[i]==0x7f;i++) {
145bank++;
146READ_SPD(spd, base, slot_num,i+1); // prefetch next spd byte to read for next loop
147}
148READ_SPD(spd, base, slot_num,i);
149 code = spd[i];
150 } else {
151 code = spd[64];
152 bank = 0;
153 }
154 for (i=0; i < VEN_MAP_SIZE; i++)
155 if (bank==vendorMap[i].bank && code==vendorMap[i].code)
156 return vendorMap[i].name;
157 }
158 /* OK there is no vendor id here lets try to match the partnum if it exists */
159 if (strstr(slot->PartNo,"GU332") == slot->PartNo) // Unifosa fingerprint
160 return "Unifosa";
161 return "NoName";
162}
163
164/** Get Default Memory Module Speed (no overclocking handled) */
165int getDDRspeedMhz(const char * spd)
166{
167 if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) {
168 switch(spd[12]) {
169case 0x0f:
170return 1066;
171case 0x0c:
172return 1333;
173case 0x0a:
174return 1600;
175case 0x14:
176default:
177return 800;
178 }
179 }
180 else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
181 switch(spd[9]) {
182case 0x50:
183return 400;
184case 0x3d:
185return 533;
186case 0x30:
187return 667;
188case 0x25:
189default:
190return 800;
191 }
192 }
193 return 800; // default freq for unknown types
194}
195
196#define SMST(a) ((uint8_t)((spd[a] & 0xf0) >> 4))
197#define SLST(a) ((uint8_t)(spd[a] & 0x0f))
198
199/** Get DDR3 or DDR2 serial number, 0 most of the times, always return a valid ptr */
200char asciiSerial[16];
201const char *getDDRSerial(const char* spd)
202{
203
204 if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) // DDR3
205 {
206sprintf(asciiSerial, "%X%X%X%X%X%X%X%X", SMST(122) /*& 0x7*/, SLST(122), SMST(123), SLST(123), SMST(124), SLST(124), SMST(125), SLST(125));
207 }
208 else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) // DDR2 or DDR
209 {
210sprintf(asciiSerial, "%X%X%X%X%X%X%X%X", SMST(95) /*& 0x7*/, SLST(95), SMST(96), SLST(96), SMST(97), SLST(97), SMST(98), SLST(98));
211 }
212
213 return strdup(asciiSerial);
214}
215
216/** Get DDR3 or DDR2 Part Number, always return a valid ptr */
217char asciiPartNo[32];
218const char * getDDRPartNum(char* spd, uint32_t base, int slot)
219{
220int i, start=0, index = 0;
221
222 if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) {
223start = 128;
224}
225 else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
226start = 73;
227}
228
229 // Check that the spd part name is zero terminated and that it is ascii:
230 bzero(asciiPartNo, sizeof(asciiPartNo));
231char c;
232for (i=start; i < start + sizeof(asciiPartNo); i++) {
233READ_SPD(spd, base, slot, i); // only read once the corresponding model part (ddr3 or ddr2)
234c = spd[i];
235if (isalpha(c) || isdigit(c) || ispunct(c)) // It seems that System Profiler likes only letters and digits...
236asciiPartNo[index++] = c;
237else if (!isascii(c))
238break;
239}
240
241return strdup(asciiPartNo);
242 return NULL;
243}
244
245int mapping []= {0,2,1,3,4,6,5,7,8,10,9,11};
246
247
248/** Read from smbus the SPD content and interpret it for detecting memory attributes */
249static void read_smb_intel(pci_dt_t *smbus_dev)
250{
251 int i, speed;
252 uint8_t spd_size, spd_type;
253 uint32_t base;
254 bool dump = false;
255 RamSlotInfo_t* slot;
256
257 base = pci_config_read16(smbus_dev->dev.addr, 0x20) & 0xFFFE;
258 DBG("Scanning smbus_dev <%04x, %04x> ...\n",smbus_dev->vendor_id, smbus_dev->device_id);
259
260 getBoolForKey("DumpSPD", &dump, &bootInfo->bootConfig);
261 bool fullBanks = // needed at least for laptops
262Platform->DMI.MemoryModules == Platform->DMI.MaxMemorySlots;
263// Search MAX_RAM_SLOTS slots
264char spdbuf[256];
265
266 for (i = 0; i < MAX_RAM_SLOTS; i++){
267DBG("Scanning slot %d\n", i);
268 slot = &Platform->RAM.DIMM[i];
269 spd_size = smb_read_byte_intel(base, 0x50 + i, 0);
270 // Check spd is present
271 if (spd_size && (spd_size != 0xff) ) {
272slot->spd = spdbuf;
273 slot->InUse = true;
274
275 bzero(slot->spd, spd_size);
276
277 // Copy spd data into buffer
278
279//for (x = 0; x < spd_size; x++) slot->spd[x] = smb_read_byte_intel(base, 0x50 + i, x);
280 init_spd(slot->spd, base, i);
281
282 switch (slot->spd[SPD_MEMORY_TYPE]) {
283case SPD_MEMORY_TYPE_SDRAM_DDR2:
284
285slot->ModuleSize = ((1 << (slot->spd[SPD_NUM_ROWS] & 0x0f) + (slot->spd[SPD_NUM_COLUMNS] & 0x0f) - 17) *
286((slot->spd[SPD_NUM_DIMM_BANKS] & 0x7) + 1) * slot->spd[SPD_NUM_BANKS_PER_SDRAM]);
287break;
288
289case SPD_MEMORY_TYPE_SDRAM_DDR3:
290
291slot->ModuleSize = ((slot->spd[4] & 0x0f) + 28 ) + ((slot->spd[8] & 0x7) + 3 );
292slot->ModuleSize -= (slot->spd[7] & 0x7) + 25;
293slot->ModuleSize = ((1 << slot->ModuleSize) * (((slot->spd[7] >> 3) & 0x1f) + 1));
294
295break;
296 }
297
298 spd_type = (slot->spd[SPD_MEMORY_TYPE] < ((char) 12) ? slot->spd[SPD_MEMORY_TYPE] : 0);
299 slot->Type = spd_mem_to_smbios[spd_type];
300 slot->PartNo = getDDRPartNum(slot->spd, base, i);
301 slot->Vendor = getVendorName(slot, base, i);
302 slot->SerialNo = getDDRSerial(slot->spd);
303
304 // determine spd speed
305 speed = getDDRspeedMhz(slot->spd);
306 if (slot->Frequency<speed) slot->Frequency = speed;
307
308// pci memory controller if available, is more reliable
309if (Platform->RAM.Frequency > 0) {
310uint32_t freq = (uint32_t)Platform->RAM.Frequency / 500000;
311// now round off special cases
312uint32_t fmod100 = freq %100;
313switch(fmod100) {
314case 1:freq--;break;
315case 32:freq++;break;
316case 65:freq++; break;
317case 98:freq+=2;break;
318case 99:freq++; break;
319}
320slot->Frequency = freq;
321}
322
323verbose("Slot: %d Type %d %dMB (%s) %dMHz Vendor=%s\n PartNo=%s SerialNo=%s\n",
324i,
325(int)slot->Type,
326slot->ModuleSize,
327spd_memory_types[spd_type],
328slot->Frequency,
329slot->Vendor,
330slot->PartNo,
331slot->SerialNo);
332if(DEBUG_SPD) {
333dumpPhysAddr("spd content: ",slot->spd, spd_size);
334getc();
335 }
336 }
337 // laptops sometimes show slot 0 and 2 with slot 1 empty when only 2 slots are presents so:
338 Platform->DMI.DIMM[i]=
339i>0 && Platform->RAM.DIMM[1].InUse==false && fullBanks && Platform->DMI.MaxMemorySlots==2 ?
340mapping[i] : i; // for laptops case, mapping setup would need to be more generic than this
341
342slot->spd = NULL;
343
344 } // for
345}
346
347struct smbus_controllers_t smbus_controllers[] = {
348
349{0x8086, 0x269B, "ESB2", read_smb_intel },
350{0x8086, 0x25A4, "6300ESB", read_smb_intel },
351{0x8086, 0x24C3, "ICH4", read_smb_intel },
352{0x8086, 0x24D3, "ICH5", read_smb_intel },
353{0x8086, 0x266A, "ICH6", read_smb_intel },
354{0x8086, 0x27DA, "ICH7", read_smb_intel },
355{0x8086, 0x283E, "ICH8", read_smb_intel },
356{0x8086, 0x2930, "ICH9", read_smb_intel },
357{0x8086, 0x3A30, "ICH10R", read_smb_intel },
358{0x8086, 0x3A60, "ICH10B", read_smb_intel },
359{0x8086, 0x3B30, "P55", read_smb_intel },
360{0x8086, 0x5032, "EP80579", read_smb_intel }
361
362};
363
364
365bool is_smbus_controller(pci_dt_t* pci_dt)
366{
367int i = 0;
368for ( ; i < sizeof(smbus_controllers) / sizeof(smbus_controllers[0]); i++ )
369{
370if (pci_dt->vendor_id == smbus_controllers[i].vendor &&
371pci_dt->device_id == smbus_controllers[i].device)
372{
373return true;
374}
375}
376return false;
377}
378
379void scan_spd(PlatformInfo_t *p, pci_dt_t* smbus_controller_dev)
380{
381int i = 0;
382for ( ; i < sizeof(smbus_controllers) / sizeof(smbus_controllers[0]); i++ )
383{
384if (smbus_controller_dev->vendor_id == smbus_controllers[i].vendor &&
385smbus_controller_dev->device_id == smbus_controllers[i].device)
386{
387smbus_controllers[i].read_smb(smbus_controller_dev); // read smb
388}
389}
390}
391

Archive Download this file

Revision: 1166