Chameleon Applications

Chameleon Applications Svn Source Tree

Root/branches/iFabio/Chameleon/i386/libsaio/spd.c

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

Archive Download this file

Revision: 307