/* * (C) Copyright 2003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this * project. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #include <common.h> #include <command.h> #include <asm/inca-ip.h> #include <asm/regdef.h> #include <asm/mipsregs.h> #include <asm/addrspace.h> #include <asm/cacheops.h> #include "sconsole.h" #define cache_unroll(base,op) \ __asm__ __volatile__(" \ .set noreorder; \ .set mips3; \ cache %1, (%0); \ .set mips0; \ .set reorder" \ : \ : "r" (base), \ "i" (op)); typedef void (*FUNCPTR)(ulong *source, ulong *destination, ulong nlongs); extern void asc_serial_init (void); extern void asc_serial_putc (char); extern void asc_serial_puts (const char *); extern int asc_serial_getc (void); extern int asc_serial_tstc (void); extern void asc_serial_setbrg (void); static void sdram_timing_init (ulong size) { register uint pass; register uint done; register uint count; register uint p0, p1, p2, p3, p4; register uint addr; #define WRITE_MC_IOGP_1 *(uint *)0xbf800800 = (p1<<14)+(p2<<13)+(p4<<8)+(p0<<4)+p3; #define WRITE_MC_IOGP_2 *(uint *)0xbf800800 = (p1<<14)+(p2<<13)+((p4-16)<<8)+(p0<<4)+p3; done = 0; p0 = 2; while (p0 < 4 && done == 0) { p1 = 0; while (p1 < 2 && done == 0) { p2 = 0; while (p2 < 2 && done == 0) { p3 = 0; while (p3 < 16 && done == 0) { count = 0; p4 = 0; while (p4 < 32 && done == 0) { WRITE_MC_IOGP_1; for (addr = KSEG1 + 0x4000; addr < KSEG1ADDR (size); addr = addr + 4) { *(uint *) addr = 0xaa55aa55; } pass = 1; for (addr = KSEG1 + 0x4000; addr < KSEG1ADDR (size) && pass == 1; addr = addr + 4) { if (*(uint *) addr != 0xaa55aa55) pass = 0; } if (pass == 1) { count++; } else { count = 0; } if (count == 32) { WRITE_MC_IOGP_2; done = 1; } p4++; } p3++; } p2++; } p1++; } p0++; if (p0 == 1) p0++; } } long int initdram(int board_type) { /* The only supported number of SDRAM banks is 4. */ #define CFG_NB 4 ulong cfgpb0 = *INCA_IP_SDRAM_MC_CFGPB0; ulong cfgdw = *INCA_IP_SDRAM_MC_CFGDW; int cols = cfgpb0 & 0xF; int rows = (cfgpb0 & 0xF0) >> 4; int dw = cfgdw & 0xF; ulong size = (1 << (rows + cols)) * (1 << (dw - 1)) * CFG_NB; void (* sdram_init) (ulong); sdram_init = (void (*)(ulong)) KSEG0ADDR(&sdram_timing_init); sdram_init(0x10000); return size; } int checkboard (void) { unsigned long chipid = *(unsigned long *)0xB800C800; printf ("Board: Purple PLB 2800 chip version %ld, ", chipid & 0xF); printf("CPU Speed %d MHz\n", CPU_CLOCK_RATE/1000000); return 0; } int misc_init_r (void) { asc_serial_init (); sconsole_putc = asc_serial_putc; sconsole_puts = asc_serial_puts; sconsole_getc = asc_serial_getc; sconsole_tstc = asc_serial_tstc; sconsole_setbrg = asc_serial_setbrg; sconsole_flush (); return (0); } /******************************************************************************* * * copydwords - copy one buffer to another a long at a time * * This routine copies the first <nlongs> longs from <source> to <destination>. */ static void copydwords (ulong *source, ulong *destination, ulong nlongs) { ulong temp,temp1; ulong *dstend = destination + nlongs; while (destination < dstend) { temp = *source++; /* dummy read from sdram */ temp1 = *(ulong *)0xa0000000; /* avoid optimization from compliler */ *(ulong *)0xbf0081f8 = temp1 + temp; *destination++ = temp; } } /******************************************************************************* * * copyLongs - copy one buffer to another a long at a time * * This routine copies the first <nlongs> longs from <source> to <destination>. */ static void copyLongs (ulong *source, ulong *destination, ulong nlongs) { FUNCPTR absEntry; absEntry = (FUNCPTR)(0xbf008000+((ulong)copydwords & 0x7)); absEntry(source, destination, nlongs); } /******************************************************************************* * * programLoad - load program into ram * * This routine load copydwords into ram * */ static void programLoad(void) { FUNCPTR absEntry; ulong *src,*dst; src = (ulong *)(TEXT_BASE + 0x428); dst = (ulong *)0xbf0081d0; absEntry = (FUNCPTR)(TEXT_BASE + 0x400); absEntry(src,dst,0x6); src = (ulong *)((ulong)copydwords & 0xfffffff8); dst = (ulong *)0xbf008000; absEntry(src,dst,0x38); } /******************************************************************************* * * copy_code - copy u-boot image from flash to RAM * * This routine is needed to solve flash problems on this board * */ void copy_code (ulong dest_addr) { extern long uboot_end_data; unsigned long start; unsigned long end; /* load copydwords into ram */ programLoad(); /* copy u-boot code */ copyLongs((ulong *)CFG_MONITOR_BASE, (ulong *)dest_addr, ((ulong)&uboot_end_data - CFG_MONITOR_BASE + 3) / 4); /* flush caches */ start = KSEG0; end = start + CFG_DCACHE_SIZE; while(start < end) { cache_unroll(start,Index_Writeback_Inv_D); start += CFG_CACHELINE_SIZE; } start = KSEG0; end = start + CFG_ICACHE_SIZE; while(start < end) { cache_unroll(start,Index_Invalidate_I); start += CFG_CACHELINE_SIZE; } }