Clean up some comments and white space in gx2/northbridgeinit.c
[coreboot.git] / src / northbridge / amd / gx2 / raminit.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2007 Advanced Micro Devices, Inc.
5  * Copyright (C) 2010 Nils Jacobs
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include <cpu/amd/gx2def.h>
22 #include <spd.h>
23
24 static const unsigned char NumColAddr[] = {
25         0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x07,
26         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
27 };
28
29 static void banner(const char *s)
30 {
31         printk(BIOS_DEBUG, " * %s\n", s);
32 }
33
34 static void hcf(void)
35 {
36         print_emerg("DIE\n");
37         /* this guarantees we flush the UART fifos (if any) and also
38          * ensures that things, in general, keep going so no debug output
39          * is lost
40          */
41         while (1)
42                 print_emerg_char(0);
43 }
44
45 static void auto_size_dimm(unsigned int dimm)
46 {
47         uint32_t dimm_setting;
48         uint16_t dimm_size;
49         uint8_t spd_byte;
50         msr_t msr;
51
52         dimm_setting = 0;
53
54         banner("Check present");
55         /* Check that we have a dimm */
56         if (spd_read_byte(dimm, SPD_MEMORY_TYPE) == 0xFF) {
57                 return;
58         }
59
60         banner("MODBANKS");
61         /* Field: Module Banks per DIMM */
62         /* EEPROM byte usage: (5) Number of DIMM Banks */
63         spd_byte = spd_read_byte(dimm, SPD_NUM_DIMM_BANKS);
64         if ((MIN_MOD_BANKS > spd_byte) || (spd_byte > MAX_MOD_BANKS)) {
65                 print_emerg("Number of module banks not compatible\n");
66                 post_code(ERROR_BANK_SET);
67                 hcf();
68         }
69         dimm_setting |= (spd_byte >> 1) << CF07_UPPER_D0_MB_SHIFT;
70         banner("FIELDBANKS");
71
72         /* Field: Banks per SDRAM device */
73         /* EEPROM byte usage: (17) Number of Banks on SDRAM Device */
74         spd_byte = spd_read_byte(dimm, SPD_NUM_BANKS_PER_SDRAM);
75         if ((MIN_DEV_BANKS > spd_byte) || (spd_byte > MAX_DEV_BANKS)) {
76                 print_emerg("Number of device banks not compatible\n");
77                 post_code(ERROR_BANK_SET);
78                 hcf();
79         }
80         dimm_setting |= (spd_byte >> 2) << CF07_UPPER_D0_CB_SHIFT;
81         banner("SPDNUMROWS");
82
83         /* Field: DIMM size
84          * EEPROM byte usage:
85          *   (3)  Number of Row Addresses
86          *   (4)  Number of Column Addresses
87          *   (5)  Number of DIMM Banks
88          *   (31) Module Bank Density
89          * Size = Module Density * Module Banks
90          */
91         if ((spd_read_byte(dimm, SPD_NUM_ROWS) & 0xF0)
92             || (spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF0)) {
93                 print_emerg("Assymetirc DIMM not compatible\n");
94                 post_code(ERROR_UNSUPPORTED_DIMM);
95                 hcf();
96         }
97         banner("SPDBANKDENSITY");
98
99         dimm_size = spd_read_byte(dimm, SPD_BANK_DENSITY);
100         banner("DIMMSIZE");
101         dimm_size |= (dimm_size << 8);  /* align so 1GB(bit0) is bit 8, this is a little weird to get gcc to not optimize this out */
102         dimm_size &= 0x01FC;    /* and off 2GB DIMM size : not supported and the 1GB size we just moved up to bit 8 as well as all the extra on top */
103
104         /* Module Density * Module Banks */
105         dimm_size <<= (dimm_setting >> CF07_UPPER_D0_MB_SHIFT) & 1;     /* shift to multiply by # DIMM banks */
106         banner("BEFORT CTZ");
107         dimm_size = __builtin_ctz(dimm_size);
108         banner("TEST DIMM SIZE>7");
109         if (dimm_size > 7) {    /* 7 is 512MB only support 512MB per DIMM */
110                 print_emerg("Only support up to 512MB per DIMM\n");
111                 post_code(ERROR_DENSITY_DIMM);
112                 hcf();
113         }
114         dimm_setting |= dimm_size << CF07_UPPER_D0_SZ_SHIFT;
115         banner("PAGESIZE");
116
117 /*
118  * Field: PAGE size
119  * EEPROM byte usage: (4)  Number of Column Addresses
120  * PageSize = 2^# Column Addresses * Data width in bytes
121  *                                   (should be 8bytes for a normal DIMM)
122  *
123  * But this really works by magic.
124  * If ma[11:0] is the memory address pins, and pa[13:0] is the physical column
125  * address that MC generates, here is how the MC assigns the pa onto the
126  * ma pins:
127  *
128  * ma  11 10 09 08 07 06 05 04 03 02 01 00
129  * ---------------------------------------
130  * pa                 09 08 07 06 05 04 03  (7 col addr bits = 1K page size)
131  * pa              10 09 08 07 06 05 04 03  (8 col addr bits = 2K page size)
132  * pa           11 10 09 08 07 06 05 04 03  (9 col addr bits = 4K page size)
133  * pa        12 11 10 09 08 07 06 05 04 03  (10 col addr bits = 8K page size)
134  * pa  13 AP 12 11 10 09 08 07 06 05 04 03  (11 col addr bits = 16K page size)
135  *
136  * (AP = autoprecharge bit)
137  *
138  * Remember that pa[2:0] are zeroed out since it's a 64-bit data bus (8 bytes),
139  * so lower 3 address bits are dont_cares. So from the table above,
140  * it's easier to see what the old code is doing: if for example,
141  * #col_addr_bits=7(06h), it adds 3 to get 10, then does 2^10=1K.
142  */
143
144         spd_byte = NumColAddr[spd_read_byte(dimm, SPD_NUM_COLUMNS) & 0xF];
145         banner("MAXCOLADDR");
146         if (spd_byte > MAX_COL_ADDR) {
147                 print_emerg("DIMM page size not compatible\n");
148                 post_code(ERROR_SET_PAGE);
149                 hcf();
150         }
151         banner(">11address test");
152         spd_byte -= 7;
153         if (spd_byte > 4) {     /* if the value is above 4 it means >11 col address lines */
154                 spd_byte = 7;   /* which means >16k so set to disabled */
155         }
156         dimm_setting |= spd_byte << CF07_UPPER_D0_PSZ_SHIFT;    /* 0=1k,1=2k,2=4k,etc */
157
158         banner("RDMSR CF07");
159         msr = rdmsr(MC_CF07_DATA);
160         banner("WRMSR CF07");
161         if (dimm == DIMM0) {
162                 msr.hi &= 0xFFFF0000;
163                 msr.hi |= dimm_setting;
164         } else {
165                 msr.hi &= 0x0000FFFF;
166                 msr.hi |= dimm_setting << 16;
167         }
168         wrmsr(MC_CF07_DATA, msr);
169         banner("ALL DONE");
170 }
171
172 static void checkDDRMax(void)
173 {
174         uint8_t spd_byte0, spd_byte1;
175         uint16_t speed;
176
177         /* PC133 identifier */
178         spd_byte0 = spd_read_byte(DIMM0, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
179         if (spd_byte0 == 0xFF) {
180                 spd_byte0 = 0;
181         }
182         spd_byte1 = spd_read_byte(DIMM1, SPD_MIN_CYCLE_TIME_AT_CAS_MAX);
183         if (spd_byte1 == 0xFF) {
184                 spd_byte1 = 0;
185         }
186
187         /* Use the slowest DIMM */
188         if (spd_byte0 < spd_byte1) {
189                 spd_byte0 = spd_byte1;
190         }
191
192         /* Turn SPD ns time into MHZ. Check what the asm does to this math. */
193         speed = 20000 / (((spd_byte0 >> 4) * 10) + (spd_byte0 & 0x0F));
194
195         /* current speed > max speed? */
196         if (GeodeLinkSpeed() > speed) {
197                 print_emerg("DIMM overclocked. Check GeodeLink Speed\n");
198                 post_code(POST_PLL_MEM_FAIL);
199                 hcf();
200         }
201 }
202
203 const uint16_t REF_RATE[] = { 15, 3, 7, 31, 62, 125 };  /* ns */
204
205 static void set_refresh_rate(void)
206 {
207         uint8_t spd_byte0, spd_byte1;
208         uint16_t rate0, rate1;
209         msr_t msr;
210
211         spd_byte0 = spd_read_byte(DIMM0, SPD_REFRESH);
212         spd_byte0 &= 0xF;
213         if (spd_byte0 > 5) {
214                 spd_byte0 = 5;
215         }
216         rate0 = REF_RATE[spd_byte0];
217
218         spd_byte1 = spd_read_byte(DIMM1, SPD_REFRESH);
219         spd_byte1 &= 0xF;
220         if (spd_byte1 > 5) {
221                 spd_byte1 = 5;
222         }
223         rate1 = REF_RATE[spd_byte1];
224
225         /* Use the faster rate (lowest number) */
226         if (rate0 > rate1) {
227                 rate0 = rate1;
228         }
229
230         msr = rdmsr(MC_CF07_DATA);
231         msr.lo |= ((rate0 * (GeodeLinkSpeed() / 2)) / 16)
232                         << CF07_LOWER_REF_INT_SHIFT;
233         wrmsr(MC_CF07_DATA, msr);
234 }
235
236 const uint8_t CASDDR[] = { 5, 5, 2, 6, 0 };     /* 1(1.5), 1.5, 2, 2.5, 0 */
237
238 static u8 getcasmap(u32 dimm, u16 glspeed)
239 {
240         u16 dimm_speed;
241         u8 spd_byte, casmap, casmap_shift=0;
242
243         /**************************      DIMM0  **********************************/
244         casmap = spd_read_byte(dimm, SPD_ACCEPTABLE_CAS_LATENCIES);
245         if (casmap != 0xFF) {
246                 /* IF -.5 timing is supported, check -.5 timing > GeodeLink */
247                 spd_byte = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_2ND);
248                 if (spd_byte != 0) {
249                         /* Turn SPD ns time into MHZ. Check what the asm does to this math. */
250                         dimm_speed = 20000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F));
251                         if (dimm_speed >= glspeed) {
252                                 casmap_shift = 1; /* -.5 is a shift of 1 */
253                                 /* IF -1 timing is supported, check -1 timing > GeodeLink */
254                                 spd_byte = spd_read_byte(dimm, SPD_SDRAM_CYCLE_TIME_3RD);
255                                 if (spd_byte != 0) {
256                                         /* Turn SPD ns time into MHZ. Check what the asm does to this math. */
257                                         dimm_speed = 20000 / (((spd_byte >> 4) * 10) + (spd_byte & 0x0F));
258                                         if (dimm_speed >= glspeed) {
259                                                 casmap_shift = 2; /* -1 is a shift of 2 */
260                                         }
261                                 }       /* SPD_SDRAM_CYCLE_TIME_3RD (-1) !=0 */
262                         } else {
263                                 casmap_shift = 0;
264                         }
265                 }       /* SPD_SDRAM_CYCLE_TIME_2ND (-.5) !=0 */
266                 /* set the casmap based on the shift to limit possible CAS settings */
267                 spd_byte = 31 - __builtin_clz((uint32_t) casmap);
268                 /* just want bits in the lower byte since we have to cast to a 32 */
269                 casmap &= 0xFF << (spd_byte - casmap_shift);
270         } else {                /* No DIMM */
271                 casmap = 0;
272         }
273         return casmap;
274 }
275
276 static void setCAS(void)
277 {
278 /*
279  *      setCAS
280  *      EEPROM byte usage: (18) SDRAM device attributes - CAS latency
281  *      EEPROM byte usage: (23) SDRAM Minimum Clock Cycle Time @ CLX -.5
282  *      EEPROM byte usage: (25) SDRAM Minimum Clock Cycle Time @ CLX -1
283  *
284  *      The CAS setting is based on the information provided in each DIMMs SPD.
285  *       The speed at which a DIMM can run is described relative to the slowest
286  *       CAS the DIMM supports. Each speed for the relative CAS settings is
287  *       checked that it is within the GeodeLink speed. If it isn't within the GeodeLink
288  *       speed, the CAS setting  is removed from the list of good settings for
289  *       the DIMM. This is done for both DIMMs and the lists are compared to
290  *       find the lowest common CAS latency setting. If there are no CAS settings
291  *       in common we out a ERROR_DIFF_DIMMS (78h) to port 80h and halt.
292  *
293  *      Entry:
294  *      Exit: Set fastest CAS Latency based on GeodeLink speed and SPD information.
295  *      Destroys: We really use everything !
296  */
297         uint16_t glspeed;
298         uint8_t spd_byte, casmap0, casmap1;
299         msr_t msr;
300
301         glspeed = GeodeLinkSpeed();
302
303         casmap0 = getcasmap(DIMM0, glspeed);
304         casmap1 = getcasmap(DIMM1, glspeed);
305
306         /* CAS_LAT MAP COMPARE */
307         if (casmap0 == 0) {
308                 spd_byte = CASDDR[__builtin_ctz(casmap1)];
309         } else if (casmap1 == 0) {
310                 spd_byte = CASDDR[__builtin_ctz(casmap0)];
311         } else if ((casmap0 &= casmap1)) {
312                 spd_byte = CASDDR[__builtin_ctz(casmap0)];
313         } else {
314                 print_emerg("DIMM CAS Latencies not compatible\n");
315                 post_code(ERROR_DIFF_DIMMS);
316                 hcf();
317         }
318
319         msr = rdmsr(MC_CF8F_DATA);
320         msr.lo &= ~(7 << CF8F_LOWER_CAS_LAT_SHIFT);
321         msr.lo |= spd_byte << CF8F_LOWER_CAS_LAT_SHIFT;
322         wrmsr(MC_CF8F_DATA, msr);
323 }
324
325 static void set_latencies(void)
326 {
327         uint32_t memspeed, dimm_setting;
328         uint8_t spd_byte0, spd_byte1;
329         msr_t msr;
330
331         memspeed = GeodeLinkSpeed() / 2;
332         dimm_setting = 0;
333
334         /* MC_CF8F setup */
335         /* tRAS */
336         spd_byte0 = spd_read_byte(DIMM0, SPD_tRAS);
337         if (spd_byte0 == 0xFF) {
338                 spd_byte0 = 0;
339         }
340         spd_byte1 = spd_read_byte(DIMM1, SPD_tRAS);
341         if (spd_byte1 == 0xFF) {
342                 spd_byte1 = 0;
343         }
344         if (spd_byte0 < spd_byte1) {
345                 spd_byte0 = spd_byte1;
346         }
347         /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
348         spd_byte1 = (spd_byte0 * memspeed) / 1000;
349         if (((spd_byte0 * memspeed) % 1000)) {
350                 ++spd_byte1;
351         }
352         if (spd_byte1 > 6) {
353                 --spd_byte1;
354         }
355         dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2PRE_SHIFT;
356
357         /* tRP */
358         spd_byte0 = spd_read_byte(DIMM0, SPD_tRP);
359         if (spd_byte0 == 0xFF) {
360                 spd_byte0 = 0;
361         }
362         spd_byte1 = spd_read_byte(DIMM1, SPD_tRP);
363         if (spd_byte1 == 0xFF) {
364                 spd_byte1 = 0;
365         }
366         if (spd_byte0 < spd_byte1) {
367                 spd_byte0 = spd_byte1;
368         }
369         /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
370         spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
371         if ((((spd_byte0 >> 2) * memspeed) % 1000)) {
372                 ++spd_byte1;
373         }
374         dimm_setting |= spd_byte1 << CF8F_LOWER_PRE2ACT_SHIFT;
375
376         /* tRCD */
377         spd_byte0 = spd_read_byte(DIMM0, SPD_tRCD);
378         if (spd_byte0 == 0xFF) {
379                 spd_byte0 = 0;
380         }
381         spd_byte1 = spd_read_byte(DIMM1, SPD_tRCD);
382         if (spd_byte1 == 0xFF) {
383                 spd_byte1 = 0;
384         }
385         if (spd_byte0 < spd_byte1) {
386                 spd_byte0 = spd_byte1;
387         }
388         /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
389         spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
390         if ((((spd_byte0 >> 2) * memspeed) % 1000)) {
391                 ++spd_byte1;
392         }
393         dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2CMD_SHIFT;
394
395         /* tRRD */
396         spd_byte0 = spd_read_byte(DIMM0, SPD_tRRD);
397         if (spd_byte0 == 0xFF) {
398                 spd_byte0 = 0;
399         }
400         spd_byte1 = spd_read_byte(DIMM1, SPD_tRRD);
401         if (spd_byte1 == 0xFF) {
402                 spd_byte1 = 0;
403         }
404         if (spd_byte0 < spd_byte1) {
405                 spd_byte0 = spd_byte1;
406         }
407         /* (ns/(1/MHz) = (us*MHZ)/1000 = clocks/1000 = clocks) */
408         spd_byte1 = ((spd_byte0 >> 2) * memspeed) / 1000;
409         if ((((spd_byte0 >> 2) * memspeed) % 1000)) {
410                 ++spd_byte1;
411         }
412         dimm_setting |= spd_byte1 << CF8F_LOWER_ACT2ACT_SHIFT;
413
414         /* tRC = tRP + tRAS */
415         dimm_setting |= (((dimm_setting >> CF8F_LOWER_ACT2PRE_SHIFT) & 0x0F) +
416                         ((dimm_setting >> CF8F_LOWER_PRE2ACT_SHIFT) & 0x07))
417                                 << CF8F_LOWER_REF2ACT_SHIFT;
418
419         msr = rdmsr(MC_CF8F_DATA);
420         msr.lo &= 0xF00000FF;
421         msr.lo |= dimm_setting;
422         msr.hi |= CF8F_UPPER_REORDER_DIS_SET;
423         wrmsr(MC_CF8F_DATA, msr);
424         printk(BIOS_DEBUG, "MSR MC_CF8F_DATA (%08x) value is %08x:%08x\n",
425         MC_CF8F_DATA, msr.hi, msr.lo);
426 }
427
428 static void set_extended_mode_registers(void)
429 {
430         uint8_t spd_byte0, spd_byte1;
431         msr_t msr;
432         spd_byte0 = spd_read_byte(DIMM0, SPD_DEVICE_ATTRIBUTES_GENERAL);
433         if (spd_byte0 == 0xFF) {
434                 spd_byte0 = 0;
435         }
436         spd_byte1 = spd_read_byte(DIMM1, SPD_DEVICE_ATTRIBUTES_GENERAL);
437         if (spd_byte1 == 0xFF) {
438                 spd_byte1 = 0;
439         }
440         spd_byte1 &= spd_byte0;
441
442         msr = rdmsr(MC_CF07_DATA);
443         if (spd_byte1 & 1) {    /* Drive Strength Control */
444                 msr.lo |= CF07_LOWER_EMR_DRV_SET;
445         }
446         if (spd_byte1 & 2) {    /* FET Control */
447                 msr.lo |= CF07_LOWER_EMR_QFC_SET;
448         }
449         wrmsr(MC_CF07_DATA, msr);
450 }
451
452 static void sdram_set_registers(const struct mem_controller *ctrl)
453 {
454         msr_t msr;
455         uint32_t msrnum;
456
457         /* Set Refresh Staggering */
458         msrnum = MC_CF07_DATA;
459         msr = rdmsr(msrnum);
460         msr.lo &= ~0xC0;
461         msr.lo |= 0x0;          /* set refresh to 4SDRAM clocks */
462         wrmsr(msrnum, msr);
463
464         /* Memory Interleave: Set HOI here otherwise default is LOI */
465         /* msrnum = MC_CF8F_DATA;
466            msr = rdmsr(msrnum);
467            msr.hi |= CF8F_UPPER_HOI_LOI_SET;
468            wrmsr(msrnum, msr); */
469 }
470
471 static void sdram_set_spd_registers(const struct mem_controller *ctrl)
472 {
473         uint8_t spd_byte;
474
475         banner("sdram_set_spd_register");
476         post_code(POST_MEM_SETUP);      /* post_70h */
477
478         spd_byte = spd_read_byte(DIMM0, SPD_MODULE_ATTRIBUTES);
479         banner("Check DIMM 0");
480         /* Check DIMM is not Register and not Buffered DIMMs. */
481         if ((spd_byte != 0xFF) && (spd_byte & 3)) {
482                 print_emerg("DIMM0 NOT COMPATIBLE\n");
483                 post_code(ERROR_UNSUPPORTED_DIMM);
484                 hcf();
485         }
486         banner("Check DIMM 1");
487         spd_byte = spd_read_byte(DIMM1, SPD_MODULE_ATTRIBUTES);
488         if ((spd_byte != 0xFF) && (spd_byte & 3)) {
489                 print_emerg("DIMM1 NOT COMPATIBLE\n");
490                 post_code(ERROR_UNSUPPORTED_DIMM);
491                 hcf();
492         }
493
494         post_code(POST_MEM_SETUP2);     /* post_72h */
495         banner("Check DDR MAX");
496
497         /* Check that the memory is not overclocked. */
498         checkDDRMax();
499
500         /* Size the DIMMS */
501         post_code(POST_MEM_SETUP3);     /* post_73h */
502         banner("AUTOSIZE DIMM 0");
503         auto_size_dimm(DIMM0);
504         post_code(POST_MEM_SETUP4);     /* post_74h */
505         banner("AUTOSIZE DIMM 1");
506         auto_size_dimm(DIMM1);
507
508         /* Set CAS latency */
509         banner("set cas latency");
510         post_code(POST_MEM_SETUP5);     /* post_75h */
511         setCAS();
512
513         /* Set all the other latencies here (tRAS, tRP....) */
514         banner("set all latency");
515         set_latencies();
516
517         /* Set Extended Mode Registers */
518         banner("set emrs");
519         set_extended_mode_registers();
520
521         banner("set ref rate");
522         /* Set Memory Refresh Rate */
523         set_refresh_rate();
524 }
525
526 /* Section 6.1.3, LX processor databooks, BIOS Initialization Sequence
527  * Section 4.1.4, GX/CS5535 GeodeROM Porting guide */
528 static void sdram_enable(int controllers, const struct mem_controller *ctrl)
529 {
530         int i;
531         msr_t msr;
532
533         /* 2. clock gating for PMode */
534         msr = rdmsr(MC_GLD_MSR_PM);
535         msr.lo &= ~0x04;
536         msr.lo |=  0x01;
537         wrmsr(MC_GLD_MSR_PM, msr);
538         /* undocmented bits in GX, in LX there are
539          * 8 bits in PM1_UP_DLY */
540         msr = rdmsr(MC_CF1017_DATA);
541         msr.lo = 0x0101;
542         wrmsr(MC_CF1017_DATA, msr);
543         //print_debug("sdram_enable step 2\n");
544
545         /* 3. release CKE mask to enable CKE */
546         msr = rdmsr(MC_CFCLK_DBUG);
547         msr.lo &= ~(0x03 << 8);
548         wrmsr(MC_CFCLK_DBUG, msr);
549         //print_debug("sdram_enable step 3\n");
550
551         /* 4. set and clear REF_TST 16 times, more shouldn't hurt
552          * why this is before EMRS and MRS ? */
553         for (i = 0; i < 19; i++) {
554                 msr = rdmsr(MC_CF07_DATA);
555                 msr.lo |=  (0x01 << 3);
556                 wrmsr(MC_CF07_DATA, msr);
557                 msr.lo &= ~(0x01 << 3);
558                 wrmsr(MC_CF07_DATA, msr);
559         }
560         //print_debug("sdram_enable step 4\n");
561
562         /* 6. enable DLL, load Extended Mode Register by set and clear PROG_DRAM */
563         msr = rdmsr(MC_CF07_DATA);
564         msr.lo |=  ((0x01 << 28) | 0x01);
565         wrmsr(MC_CF07_DATA, msr);
566         msr.lo &= ~((0x01 << 28) | 0x01);
567         wrmsr(MC_CF07_DATA, msr);
568         //print_debug("sdram_enable step 6\n");
569
570         /* 7. Reset DLL, Bit 27 is undocumented in GX datasheet,
571          * it is documented in LX datasheet */
572         /* load Mode Register by set and clear PROG_DRAM */
573         msr = rdmsr(MC_CF07_DATA);
574         msr.lo |=  ((0x01 << 27) | 0x01);
575         wrmsr(MC_CF07_DATA, msr);
576         msr.lo &= ~((0x01 << 27) | 0x01);
577         wrmsr(MC_CF07_DATA, msr);
578         //print_debug("sdram_enable step 7\n");
579
580         /* 8. load Mode Register by set and clear PROG_DRAM */
581         msr = rdmsr(MC_CF07_DATA);
582         msr.lo |=  0x01;
583         wrmsr(MC_CF07_DATA, msr);
584         msr.lo &= ~0x01;
585         wrmsr(MC_CF07_DATA, msr);
586         //print_debug("sdram_enable step 8\n");
587
588         /* wait 200 SDCLKs */
589         for (i = 0; i < 200; i++)
590                 outb(0xaa, 0x80);
591
592         /* load RDSYNC */
593         msr = rdmsr(MC_CF_RDSYNC);
594         msr.hi = 0x000ff310;
595         /* the above setting is supposed to be good for "slow" ram. We have found that for
596          * some dram, at some clock rates, e.g. hynix at 366/244, this will actually
597          * cause errors. The fix is to just set it to 0x310. Tested on 3 boards
598          * with 3 different type of dram -- Hynix, PSC, infineon.
599          * I am leaving this comment here so that at some future time nobody is tempted
600          * to mess with this setting -- RGM, 9/2006
601          */
602         msr.hi = 0x00000310;
603         msr.lo = 0x00000000;
604         wrmsr(MC_CF_RDSYNC, msr);
605
606         /* set delay control */
607         msr = rdmsr(GLCP_DELAY_CONTROLS);
608         msr.hi = 0x830d415a;
609         msr.lo = 0x8ea0ad6a;
610         wrmsr(GLCP_DELAY_CONTROLS, msr);
611
612         /* The RAM dll needs a write to lock on so generate a few dummy writes */
613         /* Note: The descriptor needs to be enabled to point at memory */
614         volatile unsigned long *ptr;
615         for (i = 0; i < 5; i++) {
616                 ptr = (void *)i;
617                 *ptr = (unsigned long)i;
618         }
619
620         print_info("RAM DLL lock\n");
621
622 }