1 #include "linux_syscall.h"
2 #include "linux_console.h"
4 inline int log2(int value)
6 /* __builtin_bsr is a exactly equivalent to the x86 machine
7 * instruction with the exception that it returns -1
8 * when the value presented to it is zero.
9 * Otherwise __builtin_bsr returns the zero based index of
10 * the highest bit set.
12 return __builtin_bsr(value);
16 static int smbus_read_byte(unsigned device, unsigned address)
18 static const unsigned char dimm[] = {
19 0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
20 0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
21 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
23 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
24 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
25 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
26 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
27 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
28 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
29 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
30 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
31 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
32 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
33 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
36 0x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
37 0x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
38 0x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
40 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
45 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
46 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
47 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
48 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
49 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
50 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
51 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
53 return dimm[(device << 8) + address];
56 #define SMBUS_MEM_DEVICE_START 0x00
57 #define SMBUS_MEM_DEVICE_END 0x01
58 #define SMBUS_MEM_DEVICE_INC 1
61 #define DRAM_CONFIG_HIGH 0x94
62 #define DCH_MEMCLK_SHIFT 20
63 #define DCH_MEMCLK_MASK 7
64 #define DCH_MEMCLK_100MHZ 0
65 #define DCH_MEMCLK_133MHZ 2
66 #define DCH_MEMCLK_166MHZ 5
67 #define DCH_MEMCLK_200MHZ 7
70 #define NORTHBRIDGE_CAP 0xE8
71 #define NBCAP_128Bit 0x0001
72 #define NBCAP_MP 0x0002
73 #define NBCAP_BIG_MP 0x0004
74 #define NBCAP_ECC 0x0004
75 #define NBCAP_CHIPKILL_ECC 0x0010
76 #define NBCAP_MEMCLK_SHIFT 5
77 #define NBCAP_MEMCLK_MASK 3
78 #define NBCAP_MEMCLK_100MHZ 3
79 #define NBCAP_MEMCLK_133MHZ 2
80 #define NBCAP_MEMCLK_166MHZ 1
81 #define NBCAP_MEMCLK_200MHZ 0
82 #define NBCAP_MEMCTRL 0x0100
84 typedef unsigned char uint8_t;
85 typedef unsigned int uint32_t;
87 static unsigned spd_to_dimm(unsigned device)
89 return (device - SMBUS_MEM_DEVICE_START);
92 static void disable_dimm(unsigned index)
94 print_debug("disabling dimm");
95 print_debug_hex8(index);
98 pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+0)<<2), 0);
99 pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CSBASE + (((index << 1)+1)<<2), 0);
109 static const struct mem_param *get_mem_param(unsigned min_cycle_time)
111 static const struct mem_param speed[] = {
114 .dch_memclk = DCH_MEMCLK_100MHZ << DCH_MEMCLK_SHIFT,
118 .dch_memclk = DCH_MEMCLK_133MHZ << DCH_MEMCLK_SHIFT,
122 .dch_memclk = DCH_MEMCLK_166MHZ << DCH_MEMCLK_SHIFT,
126 .dch_memclk = DCH_MEMCLK_200MHZ << DCH_MEMCLK_SHIFT,
132 const struct mem_param *param;
133 for(param = &speed[0]; param->cycle_time ; param++) {
134 if (min_cycle_time > (param+1)->cycle_time) {
138 if (!param->cycle_time) {
139 die("min_cycle_time to low");
145 static void debug(int c)
148 print_debug_char('\r');
149 print_debug_char('\n');
152 static const struct mem_param *spd_set_memclk(void)
154 /* Compute the minimum cycle time for these dimms */
155 const struct mem_param *param;
156 unsigned min_cycle_time, min_latency;
160 static const int latency_indicies[] = { 26, 23, 9 };
161 static const unsigned char min_cycle_times[] = {
162 [NBCAP_MEMCLK_200MHZ] = 0x50, /* 5ns */
163 [NBCAP_MEMCLK_166MHZ] = 0x60, /* 6ns */
164 [NBCAP_MEMCLK_133MHZ] = 0x75, /* 7.5ns */
165 [NBCAP_MEMCLK_100MHZ] = 0xa0, /* 10ns */
170 value = pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP);
174 min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK];
178 print_debug("min_cycle_time: ");
179 print_debug_hex8(min_cycle_time);
180 print_debug(" min_latency: ");
181 print_debug_hex8(min_latency);
185 /* Compute the least latency with the fastest clock supported
186 * by both the memory controller and the dimms.
188 for(device = SMBUS_MEM_DEVICE_START;
189 device <= SMBUS_MEM_DEVICE_END;
190 device += SMBUS_MEM_DEVICE_INC)
192 int new_cycle_time, new_latency;
198 /* First find the supported CAS latencies
199 * Byte 18 for DDR SDRAM is interpreted:
200 * bit 0 == CAS Latency = 1.0
201 * bit 1 == CAS Latency = 1.5
202 * bit 2 == CAS Latency = 2.0
203 * bit 3 == CAS Latency = 2.5
204 * bit 4 == CAS Latency = 3.0
205 * bit 5 == CAS Latency = 3.5
209 new_cycle_time = 0xa0;
212 latencies = smbus_read_byte(device, 18);
213 if (latencies <= 0) continue;
216 /* Compute the lowest cas latency supported */
217 latency = log2(latencies) -2;
219 /* Loop through and find a fast clock with a low latency */
220 for(index = 0; index < 3; index++, latency++) {
223 if ((latency < 2) || (latency > 4) ||
224 (!(latencies & (1 << latency)))) {
228 value = smbus_read_byte(device, latency_indicies[index]);
229 if (value < 0) continue;
232 /* Only increase the latency if we decreas the clock */
233 if ((value >= min_cycle_time) && (value < new_cycle_time)) {
234 new_cycle_time = value;
235 new_latency = latency;
237 print_debug("device: ");
238 print_debug_hex8(device);
239 print_debug(" new_cycle_time: ");
240 print_debug_hex8(new_cycle_time);
241 print_debug(" new_latency: ");
242 print_debug_hex8(new_latency);
250 print_debug("device: ");
251 print_debug_hex8(device);
252 print_debug(" new_cycle_time: ");
253 print_debug_hex8(new_cycle_time);
254 print_debug(" new_latency: ");
255 print_debug_hex8(new_latency);
258 if (new_latency > 4){
262 /* Does min_latency need to be increased? */
263 if (new_cycle_time > min_cycle_time) {
264 min_cycle_time = new_cycle_time;
266 /* Does min_cycle_time need to be increased? */
267 if (new_latency > min_latency) {
268 min_latency = new_latency;
271 print_debug("device: ");
272 print_debug_hex8(device);
273 print_debug(" min_cycle_time: ");
274 print_debug_hex8(min_cycle_time);
275 print_debug(" min_latency: ");
276 print_debug_hex8(min_latency);
280 /* Make a second pass through the dimms and disable
281 * any that cannot support the selected memclk and cas latency.
283 for(device = SMBUS_MEM_DEVICE_START;
284 device <= SMBUS_MEM_DEVICE_END;
285 device += SMBUS_MEM_DEVICE_INC)
292 latencies = smbus_read_byte(device, 18);
293 if (latencies <= 0) {
297 /* Compute the lowest cas latency supported */
298 latency = log2(latencies) -2;
300 /* Walk through searching for the selected latency */
301 for(index = 0; index < 3; index++, latency++) {
302 if (!(latencies & (1 << latency))) {
305 if (latency == min_latency)
308 /* If I can't find the latency or my index is bad error */
309 if ((latency != min_latency) || (index >= 3)) {
313 /* Read the min_cycle_time for this latency */
314 value = smbus_read_byte(device, latency_indicies[index]);
316 /* All is good if the selected clock speed
317 * is what I need or slower.
319 if (value <= min_cycle_time) {
322 /* Otherwise I have an error, disable the dimm */
324 disable_dimm(spd_to_dimm(device));
327 print_debug("min_cycle_time: ");
328 print_debug_hex8(min_cycle_time);
329 print_debug(" min_latency: ");
330 print_debug_hex8(min_latency);
333 /* Now that I know the minimum cycle time lookup the memory parameters */
334 param = get_mem_param(min_cycle_time);
337 /* Update DRAM Config High with our selected memory speed */
338 value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH);
339 value &= ~(DCH_MEMCLK_MASK << DCH_MEMCLK_SHIFT);
340 value |= param->dch_memclk;
341 pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_HIGH, value);
343 static const unsigned latencies[] = { 1, 5, 2 };
344 /* Update DRAM Timing Low wiht our selected cas latency */
345 value = pci_read_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW);
347 value |= latencies[min_latency - 2];
348 pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW, value);
354 static void main(void)
356 const struct mem_param *param;
357 param = spd_set_memclk();