Apparently I'm not the only one who forgets which way the outb and
[coreboot.git] / src / cpu / amd / sc520 / raminit.c
1 /* this setupcpu function comes from: */
2 /*==============================================================================*/
3 /* FILE   :  start16.asm*/
4 /**/
5 /* DESC   : A  16 bit mode assembly language startup program, intended for*/
6 /*          use with on Aspen SC520 platforms.*/
7 /**/
8 /* 11/16/2000 Added support for the NetSC520*/
9 /* 12/28/2000 Modified to boot linux image*/
10 /**/
11 /* =============================================================================*/
12 /*                                                                             */
13 /*  Copyright 2000 Advanced Micro Devices, Inc.                                */
14 /*                                                                             */
15 /* This software is the property of Advanced Micro Devices, Inc  (AMD)  which */
16 /* specifically grants the user the right to modify, use and distribute this */
17 /* software provided this COPYRIGHT NOTICE is not removed or altered.  All */
18 /* other rights are reserved by AMD.                                                       */
19 /*                                                                            */
20 /* THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY */
21 /* OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF */
22 /* THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE.*/
23 /* IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER*/
24 /* (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS*/
25 /* INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR INABILITY*/
26 /* TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF*/
27 /* SUCH DAMAGES.  BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR*/
28 /* LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE*/
29 /* LIMITATION MAY NOT APPLY TO YOU.*/
30 /**/
31 /* AMD does not assume any responsibility for any errors that may appear in*/
32 /* the Materials nor any responsibility to support or update the Materials.*/
33 /* AMD retains the right to make changes to its test specifications at any*/
34 /* time, without notice.*/
35 /**/
36 /* So that all may benefit from your experience, please report  any  problems */
37 /* or suggestions about this software back to AMD.  Please include your name, */
38 /* company,  telephone number,  AMD product requiring support and question or */
39 /* problem encountered.                                                       */
40 /*                                                                            */
41 /* Advanced Micro Devices, Inc.         Worldwide support and contact           */
42 /* Embedded Processor Division            information available at:               */
43 /* Systems Engineering                       epd.support@amd.com*/
44 /* 5204 E. Ben White Blvd.                          -or-*/
45 /* Austin, TX 78741                http://www.amd.com/html/support/techsup.html*/
46 /* ============================================================================*/
47
48
49 #define OUTC(addr, val) *(unsigned char *)(addr) = (val)
50
51 /* sadly, romcc can't quite handle what we want, so we do this ugly thing */
52 #define drcctl   (( volatile unsigned char *)0xfffef010)
53 #define drcmctl   (( volatile unsigned char *)0xfffef012)
54 #define drccfg   (( volatile unsigned char *)0xfffef014)
55
56 #define drcbendadr   (( volatile unsigned long *)0xfffef018)
57 #define eccctl   (( volatile unsigned char *)0xfffef020)
58 #define dbctl   (( volatile unsigned char *)0xfffef040)
59
60 void setupsc520(void)
61 {
62         volatile unsigned char *cp;
63         volatile unsigned short *sp;
64         volatile unsigned long *edi;
65
66         /* do this to see if MMCR will start acting right. we suspect
67          * you have to do SOMETHING to get things going. I'm really
68          * starting to hate this processor. 
69          */
70         
71         /* no, that did not help. I wonder what will?  
72          * outl(0x800df0cb, 0xfffc);
73          */
74         
75         /* well, this is special! You have to do SHORT writes to the
76          * locations, even though they are CHAR in size and CHAR aligned
77          * and technically, a SHORT write will result in -- yoo ha! --
78          * over writing the next location! Thanks to the u-boot guys
79          * for a reference code I can use. with these short pointers,
80          * it now reliably comes up after power cycle with printk. Ah yi
81          * yi.
82          */
83         
84         /* turn off the write buffer*/
85         /* per the note above, make this a short? Let's try it. */
86         sp = (unsigned short *)0xfffef040;
87         *sp = 0;
88
89         /* as per the book: */
90         /* PAR register setup */
91         /* set up the PAR registers as they are on the MSM586SEG */
92         /*    moved to auto.c by Stepan, Ron says: */
93         /* NOTE: move this to mainboard.c ASAP */
94         setup_pars();
95   
96         /* CPCSF register */
97         sp =  (unsigned short *)0xfffefc24;
98         *sp = 0xfe;
99
100         /* ADDDECTL */
101         sp =  (unsigned short *)0xfffefc80;
102         *sp = 0x10;
103
104         /* byte writes in AMD assembly */
105         /* we do short anyway, since u-boot does ... */
106         /*set the GP CS offset*/
107         sp =  (unsigned short *)0xfffefc08;
108         *sp = 0x00001;
109         /*set the GP CS width*/
110         sp =  (unsigned short *)0xfffefc09;
111         *sp = 0x00003;
112
113         /* short writes in AMD assembly */
114         /*set the GP CS width*/
115         sp =  (unsigned short *)0xfffefc0a;
116         *sp = 0x00001;
117         /*set the RD pulse width*/
118         sp =  (unsigned short *)0xfffefc0b;
119         *sp = 0x00003;
120         /*set the GP RD offset */
121         sp =  (unsigned short *)0xfffefc0c;
122         *sp = 0x00001;
123         /*set the GP WR pulse width*/ 
124         sp =  (unsigned short *)0xfffefc0d;
125         *sp = 0x00003;
126         /*set the GP WR offset*/
127         sp =  (unsigned short *)0xfffefc0e;
128         *sp = 0x00001;
129
130
131         /* set up the GP IO pins*/
132         /*set the GPIO directionreg*/
133         sp =  (unsigned short *)0xfffefc2c;
134         *sp = 0x00000;
135         /*set the GPIO directionreg*/
136         sp =  (unsigned short *)0xfffefc2a;
137         *sp = 0x00000;
138         /*set the GPIO pin function 31-16 reg*/
139         sp =  (unsigned short *)0xfffefc22;
140         *sp = 0x0FFFF;
141         /*set the GPIO pin function 15-0 reg*/
142         sp =  (unsigned short *)0xfffefc20;
143         *sp = 0x0FFFF;
144
145
146         /* the 0x80 led should now be working*/
147         outb(0xaa, 0x80);
148 #if 0
149         /* wtf are 680 leds ... */
150         par = (unsigned long *) 0xfffef0c4;
151         *par = 0x28000680;
152         /* well? */
153         outb(0x55, 0x80);
154 #endif
155
156         /* set the uart baud rate clocks to the normal 1.8432 MHz.*/
157         /* enable interrupts here? Why not? */
158         cp = (unsigned char *)0xfffefcc0;
159         *cp = 4 | 3;                    /* uart 1 clock source */
160         cp = (unsigned char *)0xfffefcc4;
161         *cp = 4;                        /* uart 2 clock source */
162
163 #if 0
164 /*; set the interrupt mapping registers.*/
165         cp = (unsigned char *)0x0fffefd20;
166         *cp = 0x01;
167         
168         cp = (unsigned char *)0x0fffefd28;
169         *cp = 0x0c;
170         
171         cp = (unsigned char *)0x0fffefd29;
172         *cp = 0x0b;
173         
174         cp = (unsigned char *)0x0fffefd30;
175         *cp = 0x07;
176         
177         cp = (unsigned char *)0x0fffefd43;
178         *cp = 0x03;
179         
180         cp = (unsigned char *)0x0fffefd51;
181         *cp = 0x02;
182 #endif
183
184 /* Stepan says: This needs to go to the msm586seg code */
185 /* "enumerate" the PCI. Mainly set the interrupt bits on the PCnetFast. */
186         outl(0x08000683c, 0xcf8);
187         outl(0xc, 0xcfc); /* set the interrupt line */
188
189         
190         /* Set the SC520 PCI host bridge to target mode to 
191          * allow external bus mastering events
192          */
193         /* index the status command register on device 0*/
194         outl(0x080000004, 0x0cf8);
195         outl(0x2, 0xcfc);               /*set the memory access enable bit*/
196         OUTC(0x0fffef072, 1);           /* enable req bits in SYSARBMENB */
197 }
198         
199
200 /*
201  *
202  *
203  */
204
205
206
207 #define CACHELINESZ   0x00000010  /*  size of our cache line (read buffer)*/
208
209 #define COL11_ADR  *(unsigned int *)0x0e001e00 /* 11 col addrs*/
210 #define COL10_ADR  *(unsigned int *)0x0e000e00 /* 10 col addrs*/
211 #define COL09_ADR  *(unsigned int *)0x0e000600 /*  9 col addrs*/
212 #define COL08_ADR  *(unsigned int *)0x0e000200 /*  8 col addrs*/
213
214 #define ROW14_ADR  *(unsigned int *)0x0f000000 /* 14 row addrs*/
215 #define ROW13_ADR  *(unsigned int *)0x07000000 /* 13 row addrs*/
216 #define ROW12_ADR  *(unsigned int *)0x03000000 /* 12 row addrs*/
217 #define ROW11_ADR  *(unsigned int *)0x01000000 /* 11 row addrs/also bank switch*/
218 #define ROW10_ADR  *(unsigned int *)0x00000000 /* 10 row addrs/also bank switch*/
219
220 #define COL11_DATA 0x0b0b0b0b   /*  11 col addrs*/
221 #define COL10_DATA 0x0a0a0a0a   /*  10 col data*/
222 #define COL09_DATA 0x09090909   /*   9 col data*/
223 #define COL08_DATA 0x08080808   /*   8 col data*/
224
225 #define ROW14_DATA 0x3f3f3f3f   /*  14 row data (MASK)*/
226 #define ROW13_DATA 0x1f1f1f1f   /*  13 row data (MASK)*/
227 #define ROW12_DATA 0x0f0f0f0f   /*  12 row data (MASK)*/
228 #define ROW11_DATA 0x07070707   /*  11 row data/also bank switch (MASK)*/
229 #define ROW10_DATA 0xaaaaaaaa   /*  10 row data/also bank switch (MASK)*/
230
231 void 
232 dummy_write(void){
233   volatile unsigned short *ptr = (volatile unsigned short *)CACHELINESZ;
234   *ptr = 0;
235 }
236
237 void sc520_udelay(int microseconds) {
238         volatile int x;
239         for(x = 0; x < 1000; x++)
240                 ;
241 }
242
243 /* looks like we define this now */
244 void
245 udelay(int microseconds) {
246         sc520_udelay(microseconds);
247 }
248
249
250 static void dumpram(void){
251   print_err("ctl "); print_err_hex8(*drcctl); print_err("\r\n");
252   print_err("mctl "); print_err_hex8(*drcmctl); print_err("\r\n");
253   print_err("cfg "); print_err_hex8(*drccfg); print_err("\r\n");
254
255   print_err("bendadr0 "); print_err_hex8(*drcbendadr); print_err("\r\n");
256   print_err("bendadr1 "); print_err_hex8(*drcbendadr); print_err("\r\n");
257   print_err("bendadr2 "); print_err_hex8(*drcbendadr); print_err("\r\n");
258   print_err("bendadr3"); print_err_hex8(*drcbendadr); print_err("\r\n");
259 }
260
261 /* there is a lot of silliness in the amd code, and it is 
262  * causing romcc real headaches, so we're going to be be a little 
263  * less silly.
264  * so, the order of ops is: 
265  * for i in 3 to 0
266  * see if bank is there. 
267  * if we can write a word, and read it back, to hell with paranoia
268  * the bank is there. So write the magic byte, read it back, and 
269  * use that to get size, etc. Try to keep things very simple, 
270  * so people can actually follow the damned code. 
271  */
272
273 /* cache is assumed to be disabled */
274 int sizemem(void)
275 {
276
277         int rows,banks, cols, i, bank;
278         unsigned char al;
279         volatile unsigned long *lp = (volatile unsigned long *) CACHELINESZ;
280         unsigned long l;
281         /* initialize dram controller registers */
282         /* disable write buffer/read-ahead buffer */
283         *dbctl = 0;
284         /* no ecc interrupts of any kind. */
285         *eccctl = 0;
286         /* Set SDRAM timing for slowest speed. */
287         *drcmctl = 0x1e; 
288
289         /* setup dram register for all banks
290          * with max cols and max banks
291          * this is the oldest trick in the book. You are going to set up for max rows
292          * and cols, then do a write, then see if the data is wrapped to low memory. 
293          * you can actually tell by which data gets to which low memory, 
294          * exactly how many rows and cols you have. 
295          */
296         *drccfg=0xbbbb;
297
298         /* setup loop to do 4 external banks starting with bank 3 */
299         *drcbendadr=0x0ff000000;
300         /* for now, set it up for one loop of bank 0. Just to get it to go at all. */
301         *drcbendadr=0x0ff;
302
303         /* issue a NOP to all DRAMs */
304         /* Setup DRAM control register with Disable refresh,
305          * disable write buffer Test Mode and NOP command select
306          */
307         *drcctl=0x01;
308
309         /* dummy write for NOP to take effect */
310         dummy_write();
311         print_err("NOP\n");
312         /* 100? 200? */
313         udelay(100);
314         print_err("after sc520_udelay\r\n");
315
316         /* issue all banks precharge */
317         *drcctl=0x02;
318         print_err("set *drcctl to 2 \r\n");
319         dummy_write();
320         print_err("PRE\n");
321
322         /* issue 2 auto refreshes to all banks */
323         *drcctl=0x04;
324         dummy_write();
325         print_err("AUTO1\n");
326         dummy_write();
327         print_err("AUTO2\n");
328
329         /* issue LOAD MODE REGISTER command */
330         *drcctl=0x03;
331         dummy_write();
332         print_err("LOAD MODE REG\n");
333
334         *drcctl=0x04;
335         for (i=0; i<8; i++) /* refresh 8 times */{
336                 dummy_write();
337                 print_err("dummy write\r\n");
338         }
339         print_err("8 dummy writes\n");
340
341         /* set control register to NORMAL mode */
342         *drcctl=0x00;
343         print_err("normal\n");
344
345         print_err("HI done normal\r\n");
346
347         print_err("sizemem\n");
348         for(bank = 3; bank >= 0; bank--) {
349           print_err("Try to assign to l\r\n");
350           *lp = 0xdeadbeef;
351           print_err("assigned l ... \r\n");
352           if (*lp != 0xdeadbeef) {
353             print_err(" no memory at bank "); 
354             // print_err_hex8(bank); 
355             //   print_err(" value "); print_err_hex32(*lp);
356             print_err("\r\n"); 
357             //      continue;
358           }
359           *drcctl = 2;
360           dummy_write();
361           *drccfg = *drccfg >> 4;
362           l = *drcbendadr;
363           l >>= 8; 
364           *drcbendadr = l;
365           print_err("loop around\r\n");
366           *drcctl = 0;
367           dummy_write();
368         }
369 #if 0
370         /* enable last bank and setup ending address 
371          * register for max ram in last bank
372          */
373         *drcbendadr=0x0ff000000;
374
375
376 //      dumpram();
377
378         /* issue a NOP to all DRAMs */
379         /* Setup DRAM control register with Disable refresh,
380          * disable write buffer Test Mode and NOP command select
381          */
382         *drcctl=0x01;
383
384         /* dummy write for NOP to take effect */
385         dummy_write();
386         print_err("NOP\n");
387         /* 100? 200? */
388         //sc520_udelay(100);
389         print_err("after sc520_udelay\r\n");
390
391         /* issue all banks precharge */
392         *drcctl=0x02;
393         print_err("set *drcctl to 2 \r\n");
394         dummy_write();
395         print_err("PRE\n");
396
397         /* issue 2 auto refreshes to all banks */
398         *drcctl=0x04;
399         dummy_write();
400         print_err("AUTO1\n");
401         dummy_write();
402         print_err("AUTO2\n");
403
404         /* issue LOAD MODE REGISTER command */
405         *drcctl=0x03;
406         dummy_write();
407         print_err("LOAD MODE REG\n");
408
409         *drcctl=0x04;
410         for (i=0; i<8; i++) /* refresh 8 times */{
411                 dummy_write();
412                 print_err("dummy write\r\n");
413         }
414         print_err("8 dummy writes\n");
415
416         /* set control register to NORMAL mode */
417         *drcctl=0x00;
418         print_err("normal\n");
419
420         print_err("HI done normal\r\n");
421         bank = 3;
422
423
424         /* this is really ugly, it is right from assembly code. 
425          * we need to clean it up later
426          */
427         
428 start:
429         /* write col 11 wrap adr */
430         COL11_ADR=COL11_DATA;
431         if(COL11_ADR!=COL11_DATA)
432                 goto bad_ram;
433
434 print_err("11\n");
435         /* write col 10 wrap adr */
436         COL10_ADR=COL10_DATA;
437         if(COL10_ADR!=COL10_DATA)
438                 goto bad_ram;
439 print_err("10\n");
440
441         /* write col 9 wrap adr */
442         COL09_ADR=COL09_DATA;
443         if(COL09_ADR!=COL09_DATA)
444                 goto bad_ram;
445 print_err("9\n");
446
447         /* write col 8 wrap adr */
448         COL08_ADR=COL08_DATA;
449         if(COL08_ADR!=COL08_DATA)
450                 goto bad_ram;
451 print_err("8\n");
452
453         /* write row 14 wrap adr */
454         ROW14_ADR=ROW14_DATA;
455         if(ROW14_ADR!=ROW14_DATA)
456                 goto bad_ram;
457 print_err("14\n");
458
459         /* write row 13 wrap adr */
460         ROW13_ADR=ROW13_DATA;
461         if(ROW13_ADR!=ROW13_DATA)
462                 goto bad_ram;
463 print_err("13\n");
464
465         /* write row 12 wrap adr */
466         ROW12_ADR=ROW12_DATA;
467         if(ROW12_ADR!=ROW12_DATA)
468                 goto bad_ram;
469 print_err("12\n");
470
471         /* write row 11 wrap adr */
472         ROW11_ADR=ROW11_DATA;
473         if(ROW11_ADR!=ROW11_DATA)
474                 goto bad_ram;
475 print_err("11\n");
476
477         /* write row 10 wrap adr */
478         ROW10_ADR=ROW10_DATA;
479         if(ROW10_ADR!=ROW10_DATA)
480                 goto bad_ram;
481 print_err("10\n");
482
483 /*
484  * read data @ row 12 wrap adr to determine # banks,
485  *  and read data @ row 14 wrap adr to determine # rows.
486  *  if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM.
487  * if data @ row 12 wrap == AA, we only have 2 banks, NOT 4
488  * if data @ row 12 wrap == 11 or 12, we have 4 banks
489  */
490
491         banks=2;
492         if (ROW12_ADR != ROW10_DATA) {
493                 banks=4;
494 print_err("4b\n");
495                 if(ROW12_ADR != ROW11_DATA) {
496                         if(ROW12_ADR != ROW12_DATA)
497                                 goto bad_ram;
498                 }
499         }
500
501         /* validate row mask */
502         rows=ROW14_ADR;
503         if (rows<ROW11_DATA)
504                 goto bad_ram;
505         if (rows>ROW14_DATA)
506                 goto bad_ram;
507         /* verify all 4 bytes of dword same */
508 /*
509         if(rows&0xffff!=(rows>>16)&0xffff)
510                 goto bad_ram;
511         if(rows&0xff!=(rows>>8)&0xff)
512                 goto bad_ram;
513 */
514         /* now just get one of them */
515         rows &= 0xff;
516         print_err("rows"); print_err_hex32(rows); print_err("\n");
517         /* validate column data */
518         cols=COL11_ADR;
519         if(cols<COL08_DATA)
520                 goto bad_ram;
521         if (cols>COL11_DATA)
522                 goto bad_ram;
523         /* verify all 4 bytes of dword same */
524 /*
525         if(cols&0xffff!=(cols>>16)&0xffff)
526                 goto bad_ram;
527         if(cols&0xff!=(cols>>8)&0xff)
528                 goto bad_ram;
529 */
530         print_err("cols"); print_err_hex32(cols); print_err("\n");
531         cols -= COL08_DATA;
532
533         /* cols now is in the range of 0 1 2 3 ... 
534          */
535         i = cols&3;
536         //      i = cols + rows;
537
538         /* wacky end addr calculation */
539 /*
540         al = 3;
541         al -= (i & 0xff);k
542  */
543
544         /* what a fookin' mess this is */
545         if(banks==4)
546                 i+=8; /* <-- i holds merged value */
547         /* i now has the col width in bits 0-1 and the bank count (2 or 4) 
548          * in bit 3.
549          * this is the format for the drccfg register 
550          */
551         
552         /* fix ending addr mask*/
553         /*FIXME*/
554         /* let's just go with this to start ... see if we can get ANYWHERE */
555         /* need to get end addr. Need to do it with the bank in mind. */
556 /*
557         al = 3; 
558         al -= i&3;
559         *drcbendaddr = rows >> al;
560         print_err("computed ending_adr = "); print_err_hex8(ending_adr); 
561         print_err("\r\n");
562         
563 */
564 bad_reinit:
565         /* issue all banks recharge */
566         *drcctl=0x02;
567         dummy_write();
568
569         /* update ending address register */
570 //      *drcbendadr = ending_adr;
571         
572         /* update config register */
573         *drccfg &= ~(0xff << bank*4);
574         if (ending_adr)
575           *drccfg = ((banks == 4 ? 8 : 0) | cols & 3)<< (bank*4);
576 //      dumpram();
577         /* skip the rest for now */
578         //      bank = 0;
579         //      *drccfg=*drccfg&YYY|ZZZZ;
580
581         if(bank!=0) {
582                 bank--;
583 //              drcbendaddr--;
584                 *drcbendaddr = 0xff000000;
585                 //*(&*drcbendadr+XXYYXX)=0xff;
586                 goto start;
587         }
588
589         /* set control register to NORMAL mode */
590         *drcctl=0x18;
591         dummy_write();
592         return bank;
593         
594 bad_ram:
595         print_info("bad ram!\r\n");
596         /* you are here because the read-after-write failed, 
597          * in most cases because: no ram in that bank! 
598          * set badbank to 1 and go to reinit
599          */
600         ending_adr = 0;
601         goto bad_reinit;
602         while(1)
603         print_err("DONE NEXTBANK\r\n");
604 #endif
605 }       
606
607 /* note: based on AMD code*/
608 /* This code is known to work on the digital logic board and on the technologic
609  * systems ts5300
610  */
611 int staticmem(void)
612 {
613         volatile unsigned long *zero = (unsigned long *) CACHELINESZ;
614         
615         /* set up 0x18 .. **/
616         *drcbendadr = 0x88;
617         *drcmctl = 0x1e;
618         *drccfg = 0x9;
619         /* nop mode */
620         *drcctl = 0x1;
621         /* do the dummy write */
622         *zero = 0;
623         
624         /* precharge */
625         *drcctl = 2;
626         *zero = 0;
627
628         /* two autorefreshes */
629         *drcctl = 4;
630         *zero = 0;
631         print_debug("one zero out on refresh\r\n");
632         *zero = 0;
633         print_debug("two zero out on refresh\r\n");
634
635         /* load mode register */
636         *drcctl = 3;
637         *zero = 0;
638         print_debug("DONE the load mode reg\r\n");
639         
640         /* normal mode */
641         *drcctl = 0x0;
642         *zero = 0;
643         print_debug("DONE one last write and then turn on refresh etc\r\n");
644         *drcctl = 0x18;
645         *zero = 0;
646         print_debug("DONE the normal\r\n");
647         *zero = 0xdeadbeef;
648         if (*zero != 0xdeadbeef) 
649           print_debug("NO LUCK\r\n");
650         else
651           print_debug("did a store and load ...\r\n");
652         //print_err_hex32(*zero);
653         //      print_err(" zero is now "); print_err_hex32(*zero); print_err("\r\n");
654 }