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
85const char * getVendorName(const char * spd)
86{
87 uint16_t code = *((uint16_t*) &spd[0x75]);
88 int i;
89 for (i=0; i < VEN_MAP_SIZE; i++)
90 if (code==vendorMap[i].code)
91 return vendorMap[i].name;
92 return "No Name";
93}
94
95int getDDRspeedMhz(const char * spd)
96{
97 if (spd[2]==0x0b) { // DDR3
98 switch(spd[12]) {
99 case 0x0f:
100 return 1066;
101 case 0x0c:
102 return 1333;
103 case 0x0a:
104 return 1600;
105 case 0x14:
106 default:
107 return 800;
108 }
109 }
110 else if (spd[2]==0x08) { // DDR2
111 switch(spd[9]) {
112 case 0x50:
113 return 400;
114 case 0x3d:
115 return 533;
116 case 0x30:
117 return 667;
118 case 0x25:
119 default:
120 return 800;
121 }
122 }
123 return 800; // default freq for unknown types
124}
125
126#define UIS(a) ((uint32_t)spd[a])
127uint32_t getDDRSerial(const char* spd)
128{
129 uint32_t ret=0;
130
131 if (spd[2]==0x0b) // DDR3
132 // assume it is lsb to msb
133 ret = UIS(122) | (UIS(123)<<8) | (UIS(124)<<16) | (UIS(125)<<24);
134 else if (spd[2]==0x08 || spd[2]==0x07) // DDR2 or DDR
135 ret = UIS(95) | (UIS(96)<<8) | (UIS(97)<<16) | (UIS(98)<<24);
136 return ret;
137}
138
139unsigned char smb_read_byte_intel(uint32_t base, uint8_t adr, uint8_t cmd)
140{
141int l1, h1, l2, h2;
142 unsigned long long t;
143
144 outb(base + SMBHSTSTS, 0x1f);// reset SMBus Controller
145 outb(base + SMBHSTDAT, 0xff);
146
147 while( inb(base + SMBHSTSTS) & 0x01);// wait until ready
148
149 outb(base + SMBHSTCMD, cmd);
150 outb(base + SMBHSTADD, (adr << 1) | 0x01 );
151 outb(base + SMBHSTCNT, 0x48 );
152
153 rdtsc(l1, h1);
154
155 while (!( inb(base + SMBHSTSTS) & 0x02))// wait til command finished
156{
157rdtsc(l2, h2);
158t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / (Platform.CPU.TSCFrequency / 40);
159if (t > 10)
160break;// break after 10ms
161 }
162 return inb(base + SMBHSTDAT);
163}
164
165int mapping []={0,1,2,3,4,5}; // linear mapping for now, check me
166
167static void read_smb_intel(pci_dt_t *smbus_dev)
168{
169 static int serialnum=0;
170 int i, x, ser;
171 uint8_tspd_size, spd_type;
172 uint32_tbase;
173 bool dump = false;
174 RamSlotInfo_t* slot;
175
176 base = pci_config_read16(smbus_dev->dev.addr, 0x20) & 0xFFFE;
177 DBG("Scanning smbus_dev <%04x, %04x> ...\n",smbus_dev->vendor_id, smbus_dev->device_id);
178
179 getBoolForKey("DumpSPD", &dump, &bootInfo->bootConfig);
180
181 // Search MAX_RAM_SLOTS slots
182 for (i = 0; i < 6; i++){
183 slot = &Platform.RAM.DIMM[i];
184 Platform.DMI.DIMM[i]=mapping[i]; // for now no special mapping
185 spd_size = smb_read_byte_intel(base, 0x50 + i, 0);
186
187 // Check spd is present
188 if (spd_size != 0xff)
189 {
190 slot->InUse = true;
191
192 slot->spd = malloc(spd_size);
193 if (slot->spd) {
194 bzero(slot->spd, spd_size);
195
196 // Copy spd data into buffer
197 for (x = 0; x < spd_size; x++)
198 slot->spd[x] = smb_read_byte_intel(base, 0x50 + i, x);
199
200 switch (slot->spd[SPD_MEMORY_TYPE]) {
201 case SPD_MEMORY_TYPE_SDRAM_DDR2:
202
203 slot->ModuleSize = ((1 << (slot->spd[SPD_NUM_ROWS] & 0x0f) + (slot->spd[SPD_NUM_COLUMNS] & 0x0f) - 17) *
204 ((slot->spd[SPD_NUM_DIMM_BANKS] & 0x7) + 1) * slot->spd[SPD_NUM_BANKS_PER_SDRAM]);
205 break;
206
207 case SPD_MEMORY_TYPE_SDRAM_DDR3:
208
209 slot->ModuleSize = ((slot->spd[4] & 0x0f) + 28 ) + ((slot->spd[8] & 0x7) + 3 );
210 slot->ModuleSize -= (slot->spd[7] & 0x7) + 25;
211 slot->ModuleSize = ((1 << slot->ModuleSize) * (((slot->spd[7] >> 3) & 0x1f) + 1));
212
213 break;
214 }
215 }
216
217 spd_type = (slot->spd[SPD_MEMORY_TYPE] < ((char) 12) ? slot->spd[SPD_MEMORY_TYPE] : 0);
218 slot->Type = spd_mem_to_smbios[spd_type];
219 strncpy(slot->PartNo, &slot->spd[0x80], 64);
220 strncpy(slot->Vendor, getVendorName(slot->spd), 64);
221
222 ser = getDDRSerial(slot->spd);
223 if (ser==0) {
224 sprintf(slot->SerialNo, "10000000%d", serialnum);
225 serialnum++;
226 }
227 else
228 sprintf(slot->SerialNo, "%d", ser);
229 // determine speed
230 slot->Frequency = getDDRspeedMhz(slot->spd);
231 verbose("Slot %d Type %d %dMB (%s) %dMHz Vendor=%s, PartNo=%s SerialNo=%s\n",
232 i,
233 (int)slot->Type,
234 slot->ModuleSize,
235 spd_memory_types[spd_type],
236 slot->Frequency,
237 slot->Vendor,
238 slot->PartNo,
239 slot->SerialNo);
240 if(dump) {
241 dumpPhysAddr("spd content: ",slot->spd, spd_size);
242 getc();
243 }
244 }
245 }
246}
247
248static struct smbus_controllers_t smbus_controllers[] = {
249
250{0x8086, 0x5032, "EP80579", read_smb_intel },
251{0x8086, 0x269B, "ESB2", read_smb_intel },
252{0x8086, 0x25A4, "6300ESB", read_smb_intel },
253{0x8086, 0x24C3, "ICH4", read_smb_intel },
254{0x8086, 0x24D3, "ICH5", read_smb_intel },
255{0x8086, 0x266A, "ICH6", read_smb_intel },
256{0x8086, 0x27DA, "ICH7", read_smb_intel },
257{0x8086, 0x283E, "ICH8", read_smb_intel },
258{0x8086, 0x2930, "ICH9", read_smb_intel },
259{0x8086, 0x3A30, "ICH10R", read_smb_intel },
260{0x8086, 0x3A60, "ICH10B", read_smb_intel },
261{0x8086, 0x3B30, "P55", read_smb_intel }
262
263};
264
265void scan_smbus_controller(pci_dt_t *smbus_dev)
266{
267inti;
268
269for( i = 1; i < sizeof(smbus_controllers) / sizeof(smbus_controllers[0]); i++ )
270if (( smbus_controllers[i].vendor == smbus_dev->vendor_id)
271&& ( smbus_controllers[i].device == smbus_dev->device_id))
272{
273verbose("%s%s SMBus Controller [%4x:%4x] at %02x:%02x.%x\n",
274 (smbus_dev->vendor_id == 0x8086) ? "Intel(R) " : "",
275 smbus_controllers[i].name,
276 smbus_dev->vendor_id, smbus_dev->device_id,
277 smbus_dev->dev.bits.bus, smbus_dev->dev.bits.dev, smbus_dev->dev.bits.func);
278
279smbus_controllers[i].read_smb(smbus_dev);
280
281}
282
283}
284
285// initial call : pci_dt = root_pci_dev;
286// find_and_read_smbus_controller(root_pci_dev);
287bool find_and_read_smbus_controller(pci_dt_t* pci_dt)
288{
289 pci_dt_t*current = pci_dt;
290 int i;
291
292 while (current) {
293#if DEBUG_SPD
294 printf("%02x:%02x.%x [%04x] [%04x:%04x] :: %s\n",
295 current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func,
296 current->class_id, current->vendor_id, current->device_id,
297 get_pci_dev_path(current));
298#endif
299for ( i = 0; i < sizeof(smbus_controllers) / sizeof(smbus_controllers[0]); i++ )
300 {
301 if (current->vendor_id == smbus_controllers[i].vendor &&
302 current->device_id == smbus_controllers[i].device)
303 {
304 smbus_controllers[i].read_smb(current); // read smb
305 return true;
306 }
307 }
308 find_and_read_smbus_controller(current->children);
309 current = current->next;
310 }
311 return false; // not found
312}
313
314void scan_spd(PlatformInfo_t *p)
315{
316 find_and_read_smbus_controller(root_pci_dev);
317}
318

Archive Download this file

Revision: 90