/* Austin, TX 78741 http://www.amd.com/html/support/techsup.html*/
/* ============================================================================*/
+
#define OUTC(addr, val) *(unsigned char *)(addr) = (val)
+/* sadly, romcc can't quite handle what we want, so we do this ugly thing */
+#define drcctl (( volatile unsigned char *)0xfffef010)
+#define drcmctl (( volatile unsigned char *)0xfffef012)
+#define drccfg (( volatile unsigned char *)0xfffef014)
-void
-setupsc520(void){
- unsigned char *cp;
- unsigned short *sp;
- unsigned long *edi;
- unsigned long *par;
+#define drcbendadr (( volatile unsigned long *)0xfffef018)
+#define eccctl (( volatile unsigned char *)0xfffef020)
+#define dbctl (( volatile unsigned char *)0xfffef040)
+
+void setupsc520(void)
+{
+ volatile unsigned char *cp;
+ volatile unsigned short *sp;
+ volatile unsigned long *edi;
+
+ /* do this to see if MMCR will start acting right. we suspect
+ * you have to do SOMETHING to get things going. I'm really
+ * starting to hate this processor.
+ */
+
+ /* no, that did not help. I wonder what will?
+ * outl(0x800df0cb, 0xfffc);
+ */
+
+ /* well, this is special! You have to do SHORT writes to the
+ * locations, even though they are CHAR in size and CHAR aligned
+ * and technically, a SHORT write will result in -- yoo ha! --
+ * over writing the next location! Thanks to the u-boot guys
+ * for a reference code I can use. with these short pointers,
+ * it now reliably comes up after power cycle with printk. Ah yi
+ * yi.
+ */
/* turn off the write buffer*/
- cp = (unsigned char *)0xfffef040;
- *cp = 0;
+ /* per the note above, make this a short? Let's try it. */
+ sp = (unsigned short *)0xfffef040;
+ *sp = 0;
+
+ /* as per the book: */
+ /* PAR register setup */
+ /* set up the PAR registers as they are on the MSM586SEG */
+ /* moved to romstage.c by Stepan, Ron says: */
+ /* NOTE: move this to mainboard.c ASAP */
+ setup_pars();
+
+ /* CPCSF register */
+ sp = (unsigned short *)0xfffefc24;
+ *sp = 0xfe;
+ /* ADDDECTL */
+ sp = (unsigned short *)0xfffefc80;
+ *sp = 0x10;
+
+ /* byte writes in AMD assembly */
+ /* we do short anyway, since u-boot does ... */
/*set the GP CS offset*/
sp = (unsigned short *)0xfffefc08;
*sp = 0x00001;
/*set the GP CS width*/
sp = (unsigned short *)0xfffefc09;
*sp = 0x00003;
+
+ /* short writes in AMD assembly */
/*set the GP CS width*/
sp = (unsigned short *)0xfffefc0a;
*sp = 0x00001;
/*set the RD pulse width*/
sp = (unsigned short *)0xfffefc0b;
*sp = 0x00003;
- /*set the GP RD offse*/
+ /*set the GP RD offset */
sp = (unsigned short *)0xfffefc0c;
*sp = 0x00001;
/*set the GP WR pulse width*/
/*set the GP WR offset*/
sp = (unsigned short *)0xfffefc0e;
*sp = 0x00001;
+
+
/* set up the GP IO pins*/
/*set the GPIO directionreg*/
sp = (unsigned short *)0xfffefc2c;
sp = (unsigned short *)0xfffefc20;
*sp = 0x0FFFF;
-#ifdef NETSC520
-if NetSC520
-; set the PIO regs correctly.
- /*set the GPIO16-31 direction reg*/
- sp = (unsigned short *)0xfffefc2c;
- *sp = 0x000ff;
- /*set the PIODIR15_0 direction reg*/
- sp = (unsigned short *)0xfffefc2a;
- *sp = 0x00440;
- /*set the PIOPFS31_16 direction reg*/
- sp = (unsigned short *)0xfffefc22;
- *sp = 0x00600;
- /*set the PIOPFS15_0 direction reg*/
- sp = (unsigned short *)0xfffefc20;
- *sp = 0x0FBBF;
- /*set the PIODATA15_0 reg*/
- sp = (unsigned short *)0x0xfffefc30;
- *sp = 0x0f000;
- /*set the CSPFS reg*/
- sp = (unsigned short *)0xfffefc24;
- *sp = 0x0000;
-
-; The NetSC520 uses PIOs 16-23 for LEDs instead of port 80
-; output a 1 to the leds
- /*set the GPIO16-31 direction reg*/
- sp = (unsigned short *)0xfffefc32;
- mov al, not 1
-else
-#endif
- /* setup for the CDP*/
- /*set the GPIO directionreg*/
- sp = (unsigned short *)0xfffefc2c;
- *sp = 0x00000;
- /*set the GPIO directionreg*/
- sp = (unsigned short *)0xfffefc2a;
- *sp = 0x00000;
- /*set the GPIO pin function 31-16 reg*/
- sp = (unsigned short *)0xfffefc22;
- *sp = 0x0FFFF;
- /*set the GPIO pin function 15-0 reg*/
- sp = (unsigned short *)0xfffefc20;
- *sp = 0x0FFFF;
/* the 0x80 led should now be working*/
outb(0xaa, 0x80);
-/*
-; set up a PAR to allow access to the 680 leds
-; WriteMMCR( 0xc4,0x28000680); // PAR15
- */
- /*set PAR 15 for access to led 680*/
-/* skip hairy pci hack for now *
- sp = (unsigned short *)0xfffef0c4;
- mov eax,028000680h
- mov dx,0680h
- *sp = 0x02; ; output a 2 to led 680
- out dx,ax
-*/
-/*; set the uart baud rate clocks to the normal 1.8432 MHz.*/
+#if 0
+ /* wtf are 680 leds ... */
+ par = (unsigned long *) 0xfffef0c4;
+ *par = 0x28000680;
+ /* well? */
+ outb(0x55, 0x80);
+#endif
+
+ /* set the uart baud rate clocks to the normal 1.8432 MHz.*/
+ /* enable interrupts here? Why not? */
cp = (unsigned char *)0xfffefcc0;
- *cp = 4; /* uart 1 clock source */
+ *cp = 4 | 3; /* uart 1 clock source */
cp = (unsigned char *)0xfffefcc4;
- *cp = 4; /* uart 2 clock source */
+ *cp = 4; /* uart 2 clock source */
+
+#if 0
/*; set the interrupt mapping registers.*/
cp = (unsigned char *)0x0fffefd20;
*cp = 0x01;
-
+
cp = (unsigned char *)0x0fffefd28;
*cp = 0x0c;
-
+
cp = (unsigned char *)0x0fffefd29;
*cp = 0x0b;
-
+
cp = (unsigned char *)0x0fffefd30;
*cp = 0x07;
-
+
cp = (unsigned char *)0x0fffefd43;
*cp = 0x03;
-
+
cp = (unsigned char *)0x0fffefd51;
*cp = 0x02;
-
-/*; "enumerate" the PCI. Mainly set the interrupt bits on the PCnetFast. */
- outl(0xcf8, 0x08000683c);
- outl(0xcfc, 0xc); /* set the interrupt line */
-
-/*; Set the SC520 PCI host bridge to target mode to allow external*/
-/*; bus mastering events*/
-
- outl(0x0cf8,0x080000004); /*index the status command register on device 0*/
- outl(0xcfc, 0x2); /*set the memory access enable bit*/
- OUTC(0x0fffef072, 1); /* enable req bits in SYSARBMENB */
-
-
+#endif
- /* set up the PAR registers as they are on the MSM586SEG */
- par = (unsigned long *) 0xfffef080;
- *par++ = 0x607c00a0; /*PAR0: PCI:Base 0xa0000; size 0x1f000:*/
- *par++ = 0x480400d8; /*PAR1: GP BUS MEM:CS2:Base 0xd8, size 0x4:*/
- *par++ = 0x340100ea; /*PAR2: GP BUS IO:CS5:Base 0xea, size 0x1:*/
- *par++ = 0x380701f0; /*PAR3: GP BUS IO:CS6:Base 0x1f0, size 0x7:*/
- *par++ = 0x3c0003f6; /*PAR4: GP BUS IO:CS7:Base 0x3f6, size 0x0:*/
- *par++ = 0x35ff0400; /*PAR5: GP BUS IO:CS5:Base 0x400, size 0xff:*/
- *par++ = 0x35ff0600; /*PAR6: GP BUS IO:CS5:Base 0x600, size 0xff:*/
- *par++ = 0x35ff0800; /*PAR7: GP BUS IO:CS5:Base 0x800, size 0xff:*/
- *par++ = 0x35ff0a00; /*PAR8: GP BUS IO:CS5:Base 0xa00, size 0xff:*/
- *par++ = 0x35ff0e00; /*PAR9: GP BUS IO:CS5:Base 0xe00, size 0xff:*/
- *par++ = 0x34fb0104; /*PAR10: GP BUS IO:CS5:Base 0x104, size 0xfb:*/
- *par++ = 0x35af0200; /*PAR11: GP BUS IO:CS5:Base 0x200, size 0xaf:*/
- *par++ = 0x341f03e0; /*PAR12: GP BUS IO:CS5:Base 0x3e0, size 0x1f:*/
- *par++ = 0xe41c00c0; /*PAR13: SDRAM:code:cache:nowrite:Base 0xc0000, size 0x7000:*/
- *par++ = 0x545c00c8; /*PAR14: GP BUS MEM:CS5:Base 0xc8, size 0x5c:*/
- *par++ = 0x8a020200; /*PAR15: BOOTCS:code:nocache:write:Base 0x2000000, size 0x80000:*/
+/* Stepan says: This needs to go to the msm586seg code */
+/* "enumerate" the PCI. Mainly set the interrupt bits on the PCnetFast. */
+ outl(0x08000683c, 0xcf8);
+ outl(0xc, 0xcfc); /* set the interrupt line */
+ /* Set the SC520 PCI host bridge to target mode to
+ * allow external bus mastering events
+ */
+ /* index the status command register on device 0*/
+ outl(0x080000004, 0x0cf8);
+ outl(0x2, 0xcfc); /*set the memory access enable bit*/
+ OUTC(0x0fffef072, 1); /* enable req bits in SYSARBMENB */
}
-
+
/*
*
*
*/
-#define DRCCTL *(char*)0x0fffef010 /* DRAM control register*/
-#define DRCTMCTL *(char*)0x0fffef012 /* DRAM timing control register*/
-#define DRCCFG *(char*)0x0fffef014 /* DRAM bank configuration register*/
-#define DRCBENDADR *(char*)0x0fffef018 /* DRAM bank ending address register*/
-#define ECCCTL *(char*)0x0fffef020 /* DRAM ECC control register*/
-#define DBCTL *(char*)0x0fffef040 /* DRAM buffer control register*/
+
#define CACHELINESZ 0x00000010 /* size of our cache line (read buffer)*/
#define COL10_DATA 0x0a0a0a0a /* 10 col data*/
#define COL09_DATA 0x09090909 /* 9 col data*/
#define COL08_DATA 0x08080808 /* 8 col data*/
+
#define ROW14_DATA 0x3f3f3f3f /* 14 row data (MASK)*/
#define ROW13_DATA 0x1f1f1f1f /* 13 row data (MASK)*/
#define ROW12_DATA 0x0f0f0f0f /* 12 row data (MASK)*/
#define ROW11_DATA 0x07070707 /* 11 row data/also bank switch (MASK)*/
#define ROW10_DATA 0xaaaaaaaa /* 10 row data/also bank switch (MASK)*/
-#define dummy_write() *(short *)CACHELINESZ=0x1010
+void
+dummy_write(void){
+ volatile unsigned short *ptr = (volatile unsigned short *)CACHELINESZ;
+ *ptr = 0;
+}
+
+#include "pc80/udelay_io.c"
+
+static void dumpram(void){
+ print_err("ctl "); print_err_hex8(*drcctl); print_err("\n");
+ print_err("mctl "); print_err_hex8(*drcmctl); print_err("\n");
+ print_err("cfg "); print_err_hex8(*drccfg); print_err("\n");
-void udelay(int microseconds) {
- volatile int x;
- for(x = 0; x < 1000; x++)
- ;
+ print_err("bendadr0 "); print_err_hex8(*drcbendadr); print_err("\n");
+ print_err("bendadr1 "); print_err_hex8(*drcbendadr); print_err("\n");
+ print_err("bendadr2 "); print_err_hex8(*drcbendadr); print_err("\n");
+ print_err("bendadr3"); print_err_hex8(*drcbendadr); print_err("\n");
}
-int nextbank(int bank)
+/* there is a lot of silliness in the amd code, and it is
+ * causing romcc real headaches, so we're going to be be a little
+ * less silly.
+ * so, the order of ops is:
+ * for i in 3 to 0
+ * see if bank is there.
+ * if we can write a word, and read it back, to hell with paranoia
+ * the bank is there. So write the magic byte, read it back, and
+ * use that to get size, etc. Try to keep things very simple,
+ * so people can actually follow the damned code.
+ */
+
+/* cache is assumed to be disabled */
+int sizemem(void)
{
- int rows,banks, cols, i, ending_adr;
- /* this is really ugly, it is right from assembly code.
+ int rows,banks, cols, i, bank;
+ unsigned char al;
+ volatile unsigned long *lp = (volatile unsigned long *) CACHELINESZ;
+ unsigned long l;
+ /* initialize dram controller registers */
+ /* disable write buffer/read-ahead buffer */
+ *dbctl = 0;
+ /* no ecc interrupts of any kind. */
+ *eccctl = 0;
+ /* Set SDRAM timing for slowest speed. */
+ *drcmctl = 0x1e;
+
+ /* setup dram register for all banks
+ * with max cols and max banks
+ * this is the oldest trick in the book. You are going to set up for max rows
+ * and cols, then do a write, then see if the data is wrapped to low memory.
+ * you can actually tell by which data gets to which low memory,
+ * exactly how many rows and cols you have.
+ */
+ *drccfg=0xbbbb;
+
+ /* setup loop to do 4 external banks starting with bank 3 */
+ *drcbendadr=0x0ff000000;
+ /* for now, set it up for one loop of bank 0. Just to get it to go at all. */
+ *drcbendadr=0x0ff;
+
+ /* issue a NOP to all DRAMs */
+ /* Setup DRAM control register with Disable refresh,
+ * disable write buffer Test Mode and NOP command select
+ */
+ *drcctl=0x01;
+
+ /* dummy write for NOP to take effect */
+ dummy_write();
+ print_err("NOP\n");
+ /* 100? 200? */
+ udelay(100);
+ print_err("after udelay\n");
+
+ /* issue all banks precharge */
+ *drcctl=0x02;
+ print_err("set *drcctl to 2 \n");
+ dummy_write();
+ print_err("PRE\n");
+
+ /* issue 2 auto refreshes to all banks */
+ *drcctl=0x04;
+ dummy_write();
+ print_err("AUTO1\n");
+ dummy_write();
+ print_err("AUTO2\n");
+
+ /* issue LOAD MODE REGISTER command */
+ *drcctl=0x03;
+ dummy_write();
+ print_err("LOAD MODE REG\n");
+
+ *drcctl=0x04;
+ for (i=0; i<8; i++) /* refresh 8 times */{
+ dummy_write();
+ print_err("dummy write\n");
+ }
+ print_err("8 dummy writes\n");
+
+ /* set control register to NORMAL mode */
+ *drcctl=0x00;
+ print_err("normal\n");
+
+ print_err("HI done normal\n");
+
+ print_err("sizemem\n");
+ for(bank = 3; bank >= 0; bank--) {
+ print_err("Try to assign to l\n");
+ *lp = 0xdeadbeef;
+ print_err("assigned l ... \n");
+ if (*lp != 0xdeadbeef) {
+ print_err(" no memory at bank ");
+ // print_err_hex8(bank);
+ // print_err(" value "); print_err_hex32(*lp);
+ print_err("\n");
+ // continue;
+ }
+ *drcctl = 2;
+ dummy_write();
+ *drccfg = *drccfg >> 4;
+ l = *drcbendadr;
+ l >>= 8;
+ *drcbendadr = l;
+ print_err("loop around\n");
+ *drcctl = 0;
+ dummy_write();
+ }
+#if 0
+ /* enable last bank and setup ending address
+ * register for max ram in last bank
+ */
+ *drcbendadr=0x0ff000000;
+
+
+// dumpram();
+
+ /* issue a NOP to all DRAMs */
+ /* Setup DRAM control register with Disable refresh,
+ * disable write buffer Test Mode and NOP command select
+ */
+ *drcctl=0x01;
+
+ /* dummy write for NOP to take effect */
+ dummy_write();
+ print_err("NOP\n");
+ /* 100? 200? */
+ //udelay(100);
+ print_err("after udelay\n");
+
+ /* issue all banks precharge */
+ *drcctl=0x02;
+ print_err("set *drcctl to 2 \n");
+ dummy_write();
+ print_err("PRE\n");
+
+ /* issue 2 auto refreshes to all banks */
+ *drcctl=0x04;
+ dummy_write();
+ print_err("AUTO1\n");
+ dummy_write();
+ print_err("AUTO2\n");
+
+ /* issue LOAD MODE REGISTER command */
+ *drcctl=0x03;
+ dummy_write();
+ print_err("LOAD MODE REG\n");
+
+ *drcctl=0x04;
+ for (i=0; i<8; i++) /* refresh 8 times */{
+ dummy_write();
+ print_err("dummy write\n");
+ }
+ print_err("8 dummy writes\n");
+
+ /* set control register to NORMAL mode */
+ *drcctl=0x00;
+ print_err("normal\n");
+
+ print_err("HI done normal\n");
+ bank = 3;
+
+
+ /* this is really ugly, it is right from assembly code.
* we need to clean it up later
*/
-
+
start:
/* write col 11 wrap adr */
COL11_ADR=COL11_DATA;
if (rows>ROW14_DATA)
goto bad_ram;
/* verify all 4 bytes of dword same */
+/*
if(rows&0xffff!=(rows>>16)&0xffff)
goto bad_ram;
if(rows&0xff!=(rows>>8)&0xff)
goto bad_ram;
-
+*/
+ /* now just get one of them */
+ rows &= 0xff;
print_err("rows"); print_err_hex32(rows); print_err("\n");
/* validate column data */
cols=COL11_ADR;
if (cols>COL11_DATA)
goto bad_ram;
/* verify all 4 bytes of dword same */
+/*
if(cols&0xffff!=(cols>>16)&0xffff)
goto bad_ram;
if(cols&0xff!=(cols>>8)&0xff)
goto bad_ram;
+*/
print_err("cols"); print_err_hex32(cols); print_err("\n");
cols -= COL08_DATA;
- i = cols + rows;
+ /* cols now is in the range of 0 1 2 3 ...
+ */
+ i = cols&3;
+ // i = cols + rows;
/* wacky end addr calculation */
/*
al -= (i & 0xff);k
*/
-
+ /* what a fookin' mess this is */
if(banks==4)
i+=8; /* <-- i holds merged value */
-
+ /* i now has the col width in bits 0-1 and the bank count (2 or 4)
+ * in bit 3.
+ * this is the format for the drccfg register
+ */
+
/* fix ending addr mask*/
/*FIXME*/
/* let's just go with this to start ... see if we can get ANYWHERE */
- ending_adr=0xff;
+ /* need to get end addr. Need to do it with the bank in mind. */
+/*
+ al = 3;
+ al -= i&3;
+ *drcbendaddr = rows >> al;
+ print_err("computed ending_adr = "); print_err_hex8(ending_adr);
+ print_err("\n");
-bad_reint:
+*/
+bad_reinit:
/* issue all banks recharge */
- DRCCTL=0x02;
+ *drcctl=0x02;
dummy_write();
/* update ending address register */
- DRCBENDADR=ending_adr;
-
+// *drcbendadr = ending_adr;
+
/* update config register */
- DRCCFG = (banks = 4 ? 8 : 0) | cols & 3;
+ *drccfg &= ~(0xff << bank*4);
+ if (ending_adr)
+ *drccfg = ((banks == 4 ? 8 : 0) | cols & 3)<< (bank*4);
+// dumpram();
/* skip the rest for now */
- bank = 0;
-// DRCCFG=DRCCFG&YYY|ZZZZ;
+ // bank = 0;
+ // *drccfg=*drccfg&YYY|ZZZZ;
if(bank!=0) {
bank--;
- //*(&DRCBENDADR+XXYYXX)=0xff;
+// drcbendaddr--;
+ *drcbendaddr = 0xff000000;
+ //*(&*drcbendadr+XXYYXX)=0xff;
goto start;
}
/* set control register to NORMAL mode */
- DRCCTL=0x00;
+ *drcctl=0x18;
dummy_write();
return bank;
-
+
bad_ram:
- print_info("bad ram!\r\n");
+ print_info("bad ram!\n");
+ /* you are here because the read-after-write failed,
+ * in most cases because: no ram in that bank!
+ * set badbank to 1 and go to reinit
+ */
+ ending_adr = 0;
+ goto bad_reinit;
+ while(1)
+ print_err("DONE NEXTBANK\n");
+#endif
}
-/* cache is assumed to be disabled */
-int sizemem(void)
+/* note: based on AMD code*/
+/* This code is known to work on the digital logic board and on the technologic
+ * systems ts5300
+ */
+int staticmem(void)
{
- int i;
- /* initialize dram controller registers */
-
- DBCTL=0; /* disable write buffer/read-ahead buffer */
- ECCCTL=0; /* disable ECC */
- DRCTMCTL=0x1e; /* Set SDRAM timing for slowest speed. */
-
- /* setup loop to do 4 external banks starting with bank 3 */
- print_err("sizemem\n");
- /* enable last bank and setup ending address
- * register for max ram in last bank
- */
- DRCBENDADR=0x0ff000000;
- /* setup dram register for all banks
- * with max cols and max banks
- */
- DRCCFG=0xbbbb;
-
- /* issue a NOP to all DRAMs */
-
- /* Asetup DRAM control register with Disable refresh,
- * disable write buffer Test Mode and NOP command select
- */
- DRCCTL=0x01;
-
- /* dummy write for NOP to take effect */
- dummy_write();
-
- print_err("NOP\n");
- /* 100? 200? */
- udelay(100);
-
- /* issue all banks precharge */
- DRCCTL=0x02;
- dummy_write();
- print_err("PRE\n");
-
- /* issue 2 auto refreshes to all banks */
- DRCCTL=0x04;
- dummy_write();
- print_err("AUTO1\n");
- dummy_write();
- print_err("AUTO2\n");
-
- /* issue LOAD MODE REGISTER command */
- DRCCTL=0x03;
- dummy_write();
- print_err("LOAD MODE REG\n");
-
- DRCCTL=0x04;
- for (i=0; i<8; i++) /* refresh 8 times */
- dummy_write();
- print_err("8 dummy writes\n");
-
- /* set control register to NORMAL mode */
- DRCCTL=0x00;
- print_err("normal\n");
-
- nextbank(3);
-
-}
+ volatile unsigned long *zero = (unsigned long *) CACHELINESZ;
+
+ /* set up 0x18 .. **/
+ *drcbendadr = 0x88;
+ *drcmctl = 0x1e;
+ *drccfg = 0x9;
+ /* nop mode */
+ *drcctl = 0x1;
+ /* do the dummy write */
+ *zero = 0;
+
+ /* precharge */
+ *drcctl = 2;
+ *zero = 0;
+
+ /* two autorefreshes */
+ *drcctl = 4;
+ *zero = 0;
+ print_debug("one zero out on refresh\n");
+ *zero = 0;
+ print_debug("two zero out on refresh\n");
+
+ /* load mode register */
+ *drcctl = 3;
+ *zero = 0;
+ print_debug("DONE the load mode reg\n");
+
+ /* normal mode */
+ *drcctl = 0x0;
+ *zero = 0;
+ print_debug("DONE one last write and then turn on refresh etc\n");
+ *drcctl = 0x18;
+ *zero = 0;
+ print_debug("DONE the normal\n");
+ *zero = 0xdeadbeef;
+ if (*zero != 0xdeadbeef)
+ print_debug("NO LUCK\n");
+ else
+ print_debug("did a store and load ...\n");
+ //print_err_hex32(*zero);
+ // print_err(" zero is now "); print_err_hex32(*zero); print_err("\n");
+}