1 /* this setupcpu function comes from: */
2 /*==============================================================================*/
3 /* FILE : start16.asm*/
5 /* DESC : A 16 bit mode assembly language startup program, intended for*/
6 /* use with on Aspen SC520 platforms.*/
8 /* 11/16/2000 Added support for the NetSC520*/
9 /* 12/28/2000 Modified to boot linux image*/
11 /* =============================================================================*/
13 /* Copyright 2000 Advanced Micro Devices, Inc. */
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. */
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.*/
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.*/
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. */
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 /* ============================================================================*/
49 #define OUTC(addr, val) *(unsigned char *)(addr) = (val)
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)
56 #define drcbendadr (( volatile unsigned long *)0xfffef018)
57 #define eccctl (( volatile unsigned char *)0xfffef020)
58 #define dbctl (( volatile unsigned char *)0xfffef040)
61 volatile unsigned char *cp;
62 volatile unsigned short *sp;
63 volatile unsigned long *edi;
64 volatile unsigned long *par;
66 /* do this to see if MMCR will start acting right.
67 * we suspect you have to do SOMETHING to get things going.
68 * I'm really starting to hate this processor.
70 /* no, that did not help. I wonder what will?
71 * outl(0x800df0cb, 0xfffc);
73 /* well, this is special! You have to do SHORT writes to the locations,
74 * even though they are CHAR in size and CHAR aligned and technically, a
75 * SHORT write will result in -- yoo ha! -- over writing the next location!
76 * Thanks to the u-boot guys for a reference code I can use.
77 * with these short pointers, it now reliably comes up after power cycle
78 * with printk. Ah yi yi.
80 /* turn off the write buffer*/
81 /* per the note above, make this a short? Let's try it.
83 sp = (unsigned short *)0xfffef040;
86 /* as per the book: */
87 /* PAR register setup */
88 /* set up the PAR registers as they are on the MSM586SEG */
89 par = (unsigned long *) 0xfffef088;
91 /* NOTE: move this to mainboard.c ASAP */
95 *par++ = 0x607c00a0; /*PAR0: PCI:Base 0xa0000; size 0x1f000:*/
96 *par++ = 0x480400d8; /*PAR1: GP BUS MEM:CS2:Base 0xd8, size 0x4:*/
97 *par++ = 0x340100ea; /*PAR2: GP BUS IO:CS5:Base 0xea, size 0x1:*/
98 *par++ = 0x380701f0; /*PAR3: GP BUS IO:CS6:Base 0x1f0, size 0x7:*/
99 *par++ = 0x3c0003f6; /*PAR4: GP BUS IO:CS7:Base 0x3f6, size 0x0:*/
100 *par++ = 0x35ff0400; /*PAR5: GP BUS IO:CS5:Base 0x400, size 0xff:*/
101 *par++ = 0x35ff0600; /*PAR6: GP BUS IO:CS5:Base 0x600, size 0xff:*/
102 *par++ = 0x35ff0800; /*PAR7: GP BUS IO:CS5:Base 0x800, size 0xff:*/
103 *par++ = 0x35ff0a00; /*PAR8: GP BUS IO:CS5:Base 0xa00, size 0xff:*/
104 *par++ = 0x35ff0e00; /*PAR9: GP BUS IO:CS5:Base 0xe00, size 0xff:*/
105 *par++ = 0x34fb0104; /*PAR10: GP BUS IO:CS5:Base 0x104, size 0xfb:*/
106 *par++ = 0x35af0200; /*PAR11: GP BUS IO:CS5:Base 0x200, size 0xaf:*/
107 *par++ = 0x341f03e0; /*PAR12: GP BUS IO:CS5:Base 0x3e0, size 0x1f:*/
108 *par++ = 0xe41c00c0; /*PAR13: SDRAM:code:cache:nowrite:Base 0xc0000, size 0x7000:*/
109 *par++ = 0x545c00c8; /*PAR14: GP BUS MEM:CS5:Base 0xc8, size 0x5c:*/
113 *par++ = 0x8a020200; /*PAR15: BOOTCS:code:nocache:write:Base 0x2000000, size 0x80000:*/
118 sp = (unsigned short *)0xfffefc24;
122 sp = (unsigned short *)0xfffefc80;
125 /* byte writes in AMD assembly */
126 /* we do short anyway, since u-boot does ... */
127 /*set the GP CS offset*/
128 sp = (unsigned short *)0xfffefc08;
130 /*set the GP CS width*/
131 sp = (unsigned short *)0xfffefc09;
134 /* short writes in AMD assembly */
135 /*set the GP CS width*/
136 sp = (unsigned short *)0xfffefc0a;
138 /*set the RD pulse width*/
139 sp = (unsigned short *)0xfffefc0b;
141 /*set the GP RD offset */
142 sp = (unsigned short *)0xfffefc0c;
144 /*set the GP WR pulse width*/
145 sp = (unsigned short *)0xfffefc0d;
147 /*set the GP WR offset*/
148 sp = (unsigned short *)0xfffefc0e;
152 /* set up the GP IO pins*/
153 /*set the GPIO directionreg*/
154 sp = (unsigned short *)0xfffefc2c;
156 /*set the GPIO directionreg*/
157 sp = (unsigned short *)0xfffefc2a;
159 /*set the GPIO pin function 31-16 reg*/
160 sp = (unsigned short *)0xfffefc22;
162 /*set the GPIO pin function 15-0 reg*/
163 sp = (unsigned short *)0xfffefc20;
167 /* the 0x80 led should now be working*/
170 /* wtf are 680 leds ... */
171 par = (unsigned long *) 0xfffef0c4;
177 /*; set the uart baud rate clocks to the normal 1.8432 MHz.*/
178 /* enable interrupts here? Why not? */
179 cp = (unsigned char *)0xfffefcc0;
180 *cp = 4 | 3; /* uart 1 clock source */
181 cp = (unsigned char *)0xfffefcc4;
182 *cp = 4; /* uart 2 clock source */
185 /*; set the interrupt mapping registers.*/
186 cp = (unsigned char *)0x0fffefd20;
189 cp = (unsigned char *)0x0fffefd28;
192 cp = (unsigned char *)0x0fffefd29;
195 cp = (unsigned char *)0x0fffefd30;
198 cp = (unsigned char *)0x0fffefd43;
201 cp = (unsigned char *)0x0fffefd51;
204 /*; "enumerate" the PCI. Mainly set the interrupt bits on the PCnetFast. */
205 outl(0xcf8, 0x08000683c);
206 outl(0xcfc, 0xc); /* set the interrupt line */
208 /*; Set the SC520 PCI host bridge to target mode to allow external*/
209 /*; bus mastering events*/
211 outl(0x0cf8,0x080000004); /*index the status command register on device 0*/
212 outl(0xcfc, 0x2); /*set the memory access enable bit*/
213 OUTC(0x0fffef072, 1); /* enable req bits in SYSARBMENB */
227 #define CACHELINESZ 0x00000010 /* size of our cache line (read buffer)*/
229 #define COL11_ADR *(unsigned int *)0x0e001e00 /* 11 col addrs*/
230 #define COL10_ADR *(unsigned int *)0x0e000e00 /* 10 col addrs*/
231 #define COL09_ADR *(unsigned int *)0x0e000600 /* 9 col addrs*/
232 #define COL08_ADR *(unsigned int *)0x0e000200 /* 8 col addrs*/
234 #define ROW14_ADR *(unsigned int *)0x0f000000 /* 14 row addrs*/
235 #define ROW13_ADR *(unsigned int *)0x07000000 /* 13 row addrs*/
236 #define ROW12_ADR *(unsigned int *)0x03000000 /* 12 row addrs*/
237 #define ROW11_ADR *(unsigned int *)0x01000000 /* 11 row addrs/also bank switch*/
238 #define ROW10_ADR *(unsigned int *)0x00000000 /* 10 row addrs/also bank switch*/
240 #define COL11_DATA 0x0b0b0b0b /* 11 col addrs*/
241 #define COL10_DATA 0x0a0a0a0a /* 10 col data*/
242 #define COL09_DATA 0x09090909 /* 9 col data*/
243 #define COL08_DATA 0x08080808 /* 8 col data*/
245 #define ROW14_DATA 0x3f3f3f3f /* 14 row data (MASK)*/
246 #define ROW13_DATA 0x1f1f1f1f /* 13 row data (MASK)*/
247 #define ROW12_DATA 0x0f0f0f0f /* 12 row data (MASK)*/
248 #define ROW11_DATA 0x07070707 /* 11 row data/also bank switch (MASK)*/
249 #define ROW10_DATA 0xaaaaaaaa /* 10 row data/also bank switch (MASK)*/
253 volatile unsigned short *ptr = (volatile unsigned short *)CACHELINESZ;
257 void sc520_udelay(int microseconds) {
259 for(x = 0; x < 1000; x++)
263 /* looks like we define this now */
265 udelay(int microseconds) {
266 sc520_udelay(microseconds);
270 static void dumpram(void){
271 print_err("ctl "); print_err_hex8(*drcctl); print_err("\r\n");
272 print_err("mctl "); print_err_hex8(*drcmctl); print_err("\r\n");
273 print_err("cfg "); print_err_hex8(*drccfg); print_err("\r\n");
275 print_err("bendadr0 "); print_err_hex8(*drcbendadr); print_err("\r\n");
276 print_err("bendadr1 "); print_err_hex8(*drcbendadr); print_err("\r\n");
277 print_err("bendadr2 "); print_err_hex8(*drcbendadr); print_err("\r\n");
278 print_err("bendadr3"); print_err_hex8(*drcbendadr); print_err("\r\n");
281 /* there is a lot of silliness in the amd code, and it is
282 * causing romcc real headaches, so we're going to be be a little
284 * so, the order of ops is:
286 * see if bank is there.
287 * if we can write a word, and read it back, to hell with paranoia
288 * the bank is there. So write the magic byte, read it back, and
289 * use that to get size, etc. Try to keep things very simple,
290 * so people can actually follow the damned code.
293 /* cache is assumed to be disabled */
297 int rows,banks, cols, i, bank;
299 volatile unsigned long *lp = (volatile unsigned long *) CACHELINESZ;
301 /* initialize dram controller registers */
302 /* disable write buffer/read-ahead buffer */
304 /* no ecc interrupts of any kind. */
306 /* Set SDRAM timing for slowest speed. */
309 /* setup dram register for all banks
310 * with max cols and max banks
311 * this is the oldest trick in the book. You are going to set up for max rows
312 * and cols, then do a write, then see if the data is wrapped to low memory.
313 * you can actually tell by which data gets to which low memory,
314 * exactly how many rows and cols you have.
318 /* setup loop to do 4 external banks starting with bank 3 */
319 *drcbendadr=0x0ff000000;
320 /* for now, set it up for one loop of bank 0. Just to get it to go at all. */
323 /* issue a NOP to all DRAMs */
324 /* Setup DRAM control register with Disable refresh,
325 * disable write buffer Test Mode and NOP command select
329 /* dummy write for NOP to take effect */
334 print_err("after sc520_udelay\r\n");
336 /* issue all banks precharge */
338 print_err("set *drcctl to 2 \r\n");
342 /* issue 2 auto refreshes to all banks */
345 print_err("AUTO1\n");
347 print_err("AUTO2\n");
349 /* issue LOAD MODE REGISTER command */
352 print_err("LOAD MODE REG\n");
355 for (i=0; i<8; i++) /* refresh 8 times */{
357 print_err("dummy write\r\n");
359 print_err("8 dummy writes\n");
361 /* set control register to NORMAL mode */
363 print_err("normal\n");
365 print_err("HI done normal\r\n");
367 print_err("sizemem\n");
368 for(bank = 3; bank >= 0; bank--) {
369 print_err("Try to assign to l\r\n");
371 print_err("assigned l ... \r\n");
372 if (*lp != 0xdeadbeef) {
373 print_err(" no memory at bank ");
374 // print_err_hex8(bank);
375 // print_err(" value "); print_err_hex32(*lp);
381 *drccfg = *drccfg >> 4;
385 print_err("loop around\r\n");
390 /* enable last bank and setup ending address
391 * register for max ram in last bank
393 *drcbendadr=0x0ff000000;
398 /* issue a NOP to all DRAMs */
399 /* Setup DRAM control register with Disable refresh,
400 * disable write buffer Test Mode and NOP command select
404 /* dummy write for NOP to take effect */
409 print_err("after sc520_udelay\r\n");
411 /* issue all banks precharge */
413 print_err("set *drcctl to 2 \r\n");
417 /* issue 2 auto refreshes to all banks */
420 print_err("AUTO1\n");
422 print_err("AUTO2\n");
424 /* issue LOAD MODE REGISTER command */
427 print_err("LOAD MODE REG\n");
430 for (i=0; i<8; i++) /* refresh 8 times */{
432 print_err("dummy write\r\n");
434 print_err("8 dummy writes\n");
436 /* set control register to NORMAL mode */
438 print_err("normal\n");
440 print_err("HI done normal\r\n");
444 /* this is really ugly, it is right from assembly code.
445 * we need to clean it up later
449 /* write col 11 wrap adr */
450 COL11_ADR=COL11_DATA;
451 if(COL11_ADR!=COL11_DATA)
455 /* write col 10 wrap adr */
456 COL10_ADR=COL10_DATA;
457 if(COL10_ADR!=COL10_DATA)
461 /* write col 9 wrap adr */
462 COL09_ADR=COL09_DATA;
463 if(COL09_ADR!=COL09_DATA)
467 /* write col 8 wrap adr */
468 COL08_ADR=COL08_DATA;
469 if(COL08_ADR!=COL08_DATA)
473 /* write row 14 wrap adr */
474 ROW14_ADR=ROW14_DATA;
475 if(ROW14_ADR!=ROW14_DATA)
479 /* write row 13 wrap adr */
480 ROW13_ADR=ROW13_DATA;
481 if(ROW13_ADR!=ROW13_DATA)
485 /* write row 12 wrap adr */
486 ROW12_ADR=ROW12_DATA;
487 if(ROW12_ADR!=ROW12_DATA)
491 /* write row 11 wrap adr */
492 ROW11_ADR=ROW11_DATA;
493 if(ROW11_ADR!=ROW11_DATA)
497 /* write row 10 wrap adr */
498 ROW10_ADR=ROW10_DATA;
499 if(ROW10_ADR!=ROW10_DATA)
504 * read data @ row 12 wrap adr to determine # banks,
505 * and read data @ row 14 wrap adr to determine # rows.
506 * if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM.
507 * if data @ row 12 wrap == AA, we only have 2 banks, NOT 4
508 * if data @ row 12 wrap == 11 or 12, we have 4 banks
512 if (ROW12_ADR != ROW10_DATA) {
515 if(ROW12_ADR != ROW11_DATA) {
516 if(ROW12_ADR != ROW12_DATA)
521 /* validate row mask */
527 /* verify all 4 bytes of dword same */
529 if(rows&0xffff!=(rows>>16)&0xffff)
531 if(rows&0xff!=(rows>>8)&0xff)
534 /* now just get one of them */
536 print_err("rows"); print_err_hex32(rows); print_err("\n");
537 /* validate column data */
543 /* verify all 4 bytes of dword same */
545 if(cols&0xffff!=(cols>>16)&0xffff)
547 if(cols&0xff!=(cols>>8)&0xff)
550 print_err("cols"); print_err_hex32(cols); print_err("\n");
553 /* cols now is in the range of 0 1 2 3 ...
558 /* wacky end addr calculation */
564 /* what a fookin' mess this is */
566 i+=8; /* <-- i holds merged value */
567 /* i now has the col width in bits 0-1 and the bank count (2 or 4)
569 * this is the format for the drccfg register
572 /* fix ending addr mask*/
574 /* let's just go with this to start ... see if we can get ANYWHERE */
575 /* need to get end addr. Need to do it with the bank in mind. */
579 *drcbendaddr = rows >> al;
580 print_err("computed ending_adr = "); print_err_hex8(ending_adr);
585 /* issue all banks recharge */
589 /* update ending address register */
590 // *drcbendadr = ending_adr;
592 /* update config register */
593 *drccfg &= ~(0xff << bank*4);
595 *drccfg = ((banks == 4 ? 8 : 0) | cols & 3)<< (bank*4);
597 /* skip the rest for now */
599 // *drccfg=*drccfg&YYY|ZZZZ;
604 *drcbendaddr = 0xff000000;
605 //*(&*drcbendadr+XXYYXX)=0xff;
609 /* set control register to NORMAL mode */
615 print_info("bad ram!\r\n");
616 /* you are here because the read-after-write failed,
617 * in most cases because: no ram in that bank!
618 * set badbank to 1 and go to reinit
623 print_err("DONE NEXTBANK\r\n");
627 /* note: based on AMD code*/
628 /* This code is known to work on the digital logic board and on the technologic
633 volatile unsigned long *zero = (unsigned long *) CACHELINESZ;
634 /* set up 0x18 .. **/
640 /* do the dummy write */
647 /* two autorefreshes */
650 print_err("one zero out on refresh\r\n");
652 print_err("two zero out on refresh\r\n");
654 /* load mode register */
657 print_err("DONE the load mode reg\r\n");
662 print_err("DONE one last write and then turn on refresh etc\r\n");
665 print_err("DONE the normal\r\n");
667 if (*zero != 0xdeadbeef)
668 print_err("NO LUCK\r\n");
670 print_err("did a store and load ...\r\n");
671 //print_err_hex32(*zero);
672 // print_err(" zero is now "); print_err_hex32(*zero); print_err("\r\n");