blob: 473f57289deb6773cb9606b66adcc58f99e08f26 [file] [log] [blame]
Eric Biederman83b991a2003-10-11 06:20:25 +00001#include "linux_syscall.h"
2#include "linux_console.h"
3
Eric Biederman90089602004-05-28 14:11:54 +00004inline int log2(int value)
Eric Biederman83b991a2003-10-11 06:20:25 +00005{
6 /* __builtin_bsr is a exactly equivalent to the x86 machine
Stefan Reinauer14e22772010-04-27 06:56:47 +00007 * instruction with the exception that it returns -1
Eric Biederman83b991a2003-10-11 06:20:25 +00008 * when the value presented to it is zero.
9 * Otherwise __builtin_bsr returns the zero based index of
10 * the highest bit set.
11 */
12 return __builtin_bsr(value);
13}
14
15
16static int smbus_read_byte(unsigned device, unsigned address)
17{
18 static const unsigned char dimm[] = {
190x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
200x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
210x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
230xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
240xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
250xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
260xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
270xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
280xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
290xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
300xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
310xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
320xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
330xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
340xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
35
360x80, 0x08, 0x07, 0x0d, 0x0a, 0x02, 0x48, 0x00, 0x04, 0x60, 0x70, 0x02, 0x82, 0x08, 0x08, 0x01,
370x0e, 0x04, 0x0c, 0x01, 0x02, 0x20, 0x00, 0x75, 0x70, 0x00, 0x00, 0x48, 0x30, 0x48, 0x2a, 0x40,
380x80, 0x80, 0x45, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
390x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33,
400xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
410xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
420xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
430xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
440xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
450xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
460xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
470xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
480xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
490xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
500xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
510xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
52 };
53 return dimm[(device << 8) + address];
54}
55
56#define SMBUS_MEM_DEVICE_START 0x00
57#define SMBUS_MEM_DEVICE_END 0x01
58#define SMBUS_MEM_DEVICE_INC 1
59
60/* Function 2 */
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
68
69/* Function 3 */
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
83
84typedef unsigned char uint8_t;
85typedef unsigned int uint32_t;
86
87static unsigned spd_to_dimm(unsigned device)
88{
89 return (device - SMBUS_MEM_DEVICE_START);
90}
91
92static void disable_dimm(unsigned index)
93{
Stefan Reinauer14e22772010-04-27 06:56:47 +000094 print_debug("disabling dimm");
95 print_debug_hex8(index);
Eric Biederman83b991a2003-10-11 06:20:25 +000096 print_debug("\r\n");
97#if 0
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);
100#endif
101}
102
103
104struct mem_param {
105 uint8_t cycle_time;
106 uint32_t dch_memclk;
107};
108
109static const struct mem_param *get_mem_param(unsigned min_cycle_time)
110{
111 static const struct mem_param speed[] = {
112 {
113 .cycle_time = 0xa0,
114 .dch_memclk = DCH_MEMCLK_100MHZ << DCH_MEMCLK_SHIFT,
115 },
116 {
117 .cycle_time = 0x75,
118 .dch_memclk = DCH_MEMCLK_133MHZ << DCH_MEMCLK_SHIFT,
119 },
120 {
121 .cycle_time = 0x60,
122 .dch_memclk = DCH_MEMCLK_166MHZ << DCH_MEMCLK_SHIFT,
123 },
124 {
125 .cycle_time = 0x50,
126 .dch_memclk = DCH_MEMCLK_200MHZ << DCH_MEMCLK_SHIFT,
127 },
128 {
129 .cycle_time = 0x00,
130 },
131 };
132 const struct mem_param *param;
133 for(param = &speed[0]; param->cycle_time ; param++) {
134 if (min_cycle_time > (param+1)->cycle_time) {
135 break;
136 }
137 }
138 if (!param->cycle_time) {
139 die("min_cycle_time to low");
140 }
141 return param;
142}
143
144#if 1
145static void debug(int c)
146{
147 print_debug_char(c);
148 print_debug_char('\r');
149 print_debug_char('\n');
150}
151#endif
152static const struct mem_param *spd_set_memclk(void)
153{
154 /* Compute the minimum cycle time for these dimms */
155 const struct mem_param *param;
156 unsigned min_cycle_time, min_latency;
157 unsigned device;
158 uint32_t value;
159
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 */
166 };
167
168
169#if 0
170 value = pci_read_config32(PCI_DEV(0, 0x18, 3), NORTHBRIDGE_CAP);
171#else
172 value = 0x50;
173#endif
174 min_cycle_time = min_cycle_times[(value >> NBCAP_MEMCLK_SHIFT) & NBCAP_MEMCLK_MASK];
175 min_latency = 2;
176
177#if 1
Stefan Reinauer14e22772010-04-27 06:56:47 +0000178 print_debug("min_cycle_time: ");
179 print_debug_hex8(min_cycle_time);
Eric Biederman83b991a2003-10-11 06:20:25 +0000180 print_debug(" min_latency: ");
181 print_debug_hex8(min_latency);
182 print_debug("\r\n");
183#endif
184
185 /* Compute the least latency with the fastest clock supported
186 * by both the memory controller and the dimms.
187 */
188 for(device = SMBUS_MEM_DEVICE_START;
189 device <= SMBUS_MEM_DEVICE_END;
190 device += SMBUS_MEM_DEVICE_INC)
191 {
192 int new_cycle_time, new_latency;
193 int index;
194 int latencies;
195 int latency;
196
197 debug('A');
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
206 * bit 6 == TBD
207 * bit 7 == TBD
208 */
209 new_cycle_time = 0xa0;
210 new_latency = 5;
211
212 latencies = smbus_read_byte(device, 18);
213 if (latencies <= 0) continue;
214
215 debug('B');
216 /* Compute the lowest cas latency supported */
217 latency = log2(latencies) -2;
218
219 /* Loop through and find a fast clock with a low latency */
220 for(index = 0; index < 3; index++, latency++) {
221 int value;
222 debug('C');
223 if ((latency < 2) || (latency > 4) ||
224 (!(latencies & (1 << latency)))) {
225 continue;
226 }
227 debug('D');
228 value = smbus_read_byte(device, latency_indicies[index]);
229 if (value < 0) continue;
230
231 debug('E');
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;
236#if 1
237 print_debug("device: ");
238 print_debug_hex8(device);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000239 print_debug(" new_cycle_time: ");
240 print_debug_hex8(new_cycle_time);
Eric Biederman83b991a2003-10-11 06:20:25 +0000241 print_debug(" new_latency: ");
242 print_debug_hex8(new_latency);
243 print_debug("\r\n");
244#endif
245 }
246 debug('G');
247 }
248 debug('H');
249#if 1
250 print_debug("device: ");
251 print_debug_hex8(device);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000252 print_debug(" new_cycle_time: ");
253 print_debug_hex8(new_cycle_time);
Eric Biederman83b991a2003-10-11 06:20:25 +0000254 print_debug(" new_latency: ");
255 print_debug_hex8(new_latency);
256 print_debug("\r\n");
257#endif
258 if (new_latency > 4){
259 continue;
260 }
261 debug('I');
262 /* Does min_latency need to be increased? */
263 if (new_cycle_time > min_cycle_time) {
264 min_cycle_time = new_cycle_time;
265 }
266 /* Does min_cycle_time need to be increased? */
267 if (new_latency > min_latency) {
268 min_latency = new_latency;
269 }
270#if 1
271 print_debug("device: ");
272 print_debug_hex8(device);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000273 print_debug(" min_cycle_time: ");
274 print_debug_hex8(min_cycle_time);
Eric Biederman83b991a2003-10-11 06:20:25 +0000275 print_debug(" min_latency: ");
276 print_debug_hex8(min_latency);
277 print_debug("\r\n");
278#endif
279 }
280 /* Make a second pass through the dimms and disable
281 * any that cannot support the selected memclk and cas latency.
282 */
283 for(device = SMBUS_MEM_DEVICE_START;
284 device <= SMBUS_MEM_DEVICE_END;
285 device += SMBUS_MEM_DEVICE_INC)
286 {
287 int latencies;
288 int latency;
289 int index;
290 int value;
291 int dimm;
292 latencies = smbus_read_byte(device, 18);
293 if (latencies <= 0) {
294 goto dimm_err;
295 }
296
297 /* Compute the lowest cas latency supported */
298 latency = log2(latencies) -2;
299
300 /* Walk through searching for the selected latency */
301 for(index = 0; index < 3; index++, latency++) {
302 if (!(latencies & (1 << latency))) {
303 continue;
304 }
305 if (latency == min_latency)
306 break;
307 }
308 /* If I can't find the latency or my index is bad error */
309 if ((latency != min_latency) || (index >= 3)) {
310 goto dimm_err;
311 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000312
Eric Biederman83b991a2003-10-11 06:20:25 +0000313 /* Read the min_cycle_time for this latency */
314 value = smbus_read_byte(device, latency_indicies[index]);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000315
316 /* All is good if the selected clock speed
Eric Biederman83b991a2003-10-11 06:20:25 +0000317 * is what I need or slower.
318 */
319 if (value <= min_cycle_time) {
320 continue;
321 }
322 /* Otherwise I have an error, disable the dimm */
323 dimm_err:
324 disable_dimm(spd_to_dimm(device));
325 }
326#if 1
Stefan Reinauer14e22772010-04-27 06:56:47 +0000327 print_debug("min_cycle_time: ");
328 print_debug_hex8(min_cycle_time);
Eric Biederman83b991a2003-10-11 06:20:25 +0000329 print_debug(" min_latency: ");
330 print_debug_hex8(min_latency);
331 print_debug("\r\n");
332#endif
333 /* Now that I know the minimum cycle time lookup the memory parameters */
334 param = get_mem_param(min_cycle_time);
335
336#if 0
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);
342
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);
346 value &= ~7;
347 value |= latencies[min_latency - 2];
348 pci_write_config32(PCI_DEV(0, 0x18, 2), DRAM_CONFIG_LOW, value);
349#endif
Stefan Reinauer14e22772010-04-27 06:56:47 +0000350
Eric Biederman83b991a2003-10-11 06:20:25 +0000351 return param;
352}
353
354static void main(void)
355{
356 const struct mem_param *param;
357 param = spd_set_memclk();
358 _exit(0);
359}