diff options
Diffstat (limited to 'cfe/cfe/arch/mips/common/src/init_mips.S')
-rwxr-xr-x | cfe/cfe/arch/mips/common/src/init_mips.S | 683 |
1 files changed, 683 insertions, 0 deletions
diff --git a/cfe/cfe/arch/mips/common/src/init_mips.S b/cfe/cfe/arch/mips/common/src/init_mips.S new file mode 100755 index 0000000..3f59539 --- /dev/null +++ b/cfe/cfe/arch/mips/common/src/init_mips.S @@ -0,0 +1,683 @@ +/* ********************************************************************* + * Broadcom Common Firmware Environment (CFE) + * + * CPU init module File: init_mips.S + * + * This module contains the vectors and lowest-level CPU startup + * functions for CFE. + * + * Author: Mitch Lichtenberg (mpl@broadcom.com) + * + ********************************************************************* + * + * Copyright 2000,2001,2002,2003 + * Broadcom Corporation. All rights reserved. + * + * This software is furnished under license and may be used and + * copied only in accordance with the following terms and + * conditions. Subject to these conditions, you may download, + * copy, install, use, modify and distribute modified or unmodified + * copies of this software in source and/or binary form. No title + * or ownership is transferred hereby. + * + * 1) Any source code used, modified or distributed must reproduce + * and retain this copyright notice and list of conditions + * as they appear in the source file. + * + * 2) No right is granted to use any trade name, trademark, or + * logo of Broadcom Corporation. The "Broadcom Corporation" + * name may not be used to endorse or promote products derived + * from this software without the prior written permission of + * Broadcom Corporation. + * + * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT + * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN + * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + ********************************************************************* */ + + +#include "sbmips.h" +#include "exception.h" + +#include "bsp_config.h" +#include "cpu_config.h" + +#ifdef _CFE_ +#include "cfe_devfuncs.h" +#else + +#define cfe_command_restart 0 +#endif + +/* BCM63XX specific change. */ +#include "bcm_hwdefs.h" + +/* ********************************************************************* + * Macros + ********************************************************************* */ + +#include "mipsmacros.h" + + +/* ********************************************************************* + * SETLEDS(a,b,c,d) + * SETLEDS1(a,b,c,d) + * + * Sets the on-board LED display (if present). Two variants + * of this routine are provided. If you're running KSEG1, + * call the SETLEDS1 variant, else call SETLEDS. + * + * Input parameters: + * a,b,c,d - four ASCII characters (literal constants) + * + * Return value: + * a0,k1,ra trashed + ********************************************************************* */ + +#define SETLEDS(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + CALLINIT_KSEG0(init_table,R_INIT_SETLEDS) + +#define SETLEDS1(a,b,c,d) \ + li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \ + CALLINIT_KSEG1(init_table,R_INIT_SETLEDS) + + +/* ********************************************************************* + * Other constants + ********************************************************************* */ + +/* + * This is the size of the stack, rounded to KByte boundaries. + */ + +#ifndef CFG_STACK_SIZE +#error "CFG_STACK_SIZE not defined" +#else +#define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023) +#endif + +#ifdef __MIPSEB +#define TEXTSECTION 0x2e746578 # ".tex", big-endian +#else +#define TEXTSECTION 0x7865742e # ".tex", little-endian +#endif + +/* + * Duplicates from cfe_iocb.h -- warning! + */ + +#define CFE_CACHE_FLUSH_D 1 +#define CFE_CACHE_INVAL_I 2 +#define CFE_CACHE_INVAL_D 4 +#define CFE_CACHE_INVAL_L2 8 +#define CFE_CACHE_FLUSH_L2 16 +#define CFE_CACHE_INVAL_RANGE 32 +#define CFE_CACHE_FLUSH_RANGE 64 + + +/* + * To make life easier reading this code, define "KSEGBASE" + * to either K0BASE or K1BASE depending on whether we're running + * uncached. + */ + +#if CFG_RUNFROMKSEG0 +#define KSEGBASE K0BASE +#else +#define KSEGBASE K1BASE +#endif + + +/* ********************************************************************* + * Names of registers used in this module + ********************************************************************* */ + +#define RELOCOFFSET s8 /* $30 (fp) */ +#define TEXTOFFSET t9 /* $25 (t9) */ +#define MEMTOP t8 /* $24 (t8) */ +#define TEXTBASE s7 /* $23 (s7) */ +#undef BOOT_OFFSET +#define BOOT_OFFSET s6 /* $22 (s6) */ + + .sdata + +#include "initdata.h" /* declare variables we use here */ + +#if CFG_MULTI_CPUS + .globl cfe_spinlock +cfe_spinlock: .word 0 +#endif + + .extern _fdata + .extern _edata + .extern _etext + +/* ********************************************************************* + * uninitialized data + ********************************************************************* */ + + .bss + + .comm __junk,4 + +/* ********************************************************************* + * Exception Vectors + ********************************************************************* */ + + .text + + .set noreorder + +/* + * Declare the actual vectors. This expands to code that + * must be at the very beginning of the text segment. + */ + +DECLARE_VECTOR(0x0000,vec_reset,cpu_reset) + + .set reorder + +/* ********************************************************************* + * Some offsets depend on our current configuration + ********************************************************************* */ + +#define RUNTIME_RELOC_START 0 +#define RUNTIME_RELOC_STOP 0 + +/* ********************************************************************* + * Segment Table. + * + * Addresses of data segments and of certain routines we're going + * to call from KSEG1. These are here mostly for the embedded + * PIC case, since we can't count on the 'la' instruction to + * do the expected thing (the assembler expands it into a macro + * for doing GP-relative stuff, and the code is NOT GP-relative. + * So, we (relocatably) get the offset of this table and then + * index within it. + * + * Pointer values in this segment will be relative to KSEG0 for + * cached versions of CFE, so we need to OR in K1BASE in the + * case of calling to a uncached address. + * + * The LOADREL macro handles most of the nastiness here. + ********************************************************************* */ + +#include "segtable.h" +#include "cfe.h" + + .org 0x570 + .byte 'c','f','e','-','v',CFE_VER_MAJOR,CFE_VER_MINOR,CFE_VER_BUILD,BCM63XX_MAJOR,BCM63XX_MINOR # CFE version info for applications + .org 0x580 # move past exception vectors + + /* + * BCM963XX NVRAM Data Storage + */ + + .globl nvram_data_storage +nvram_data_storage: + .word NVRAM_DATA_ID + .space 0x400 + + .globl segment_table +segment_table: + _LONG_ _etext # [ 0] End of text (R_SEG_ETEXT) + _LONG_ _fdata # [ 1] Beginning of data (R_SEG_FDATA) + _LONG_ _edata # [ 2] End of data (R_SEG_EDATA) + _LONG_ _end # [ 3] End of BSS (R_SEG_END) + _LONG_ _ftext # [ 4] Beginning of text (R_SEG_FTEXT) + _LONG_ _fbss # [ 5] Beginning of BSS (R_SEG_FBSS) + _LONG_ _gp # [ 6] Global Pointer (R_SEG_GP) + _LONG_ 0 # [ 7] Beginning of reloc entries + _LONG_ 0 # [ 8] End of reloc entries + _LONG_ 0 # [ 9] R_SEG_APIENTRY + +/* ********************************************************************* + * Init Table. + * + * This is like segment_table except it contains pointers to + * routines used during initialization. It serves both as a + * table for doing PIC stuff and also to separate out + * machine-specific init routines. + * + * The CALLINIT_xxx macros are used to call routines in this table. + ********************************************************************* */ + + + .globl init_table +init_table: + _LONG_ board_earlyinit # [ 0] R_INIT_EARLYINIT + _LONG_ board_setleds # [ 1] R_INIT_SETLEDS + _LONG_ board_draminfo # [ 2] R_INIT_DRAMINFO + _LONG_ CPUCFG_CPUINIT # [ 3] R_INIT_CPUINIT + _LONG_ CPUCFG_ALTCPU_START1 # [ 4] R_INIT_ALTCPU_START1 + _LONG_ CPUCFG_ALTCPU_START2 # [ 5] R_INIT_ALTCPU_START2 + _LONG_ CPUCFG_ALTCPU_RESET # [ 6] R_INIT_ALTCPU_RESET + _LONG_ CPUCFG_CPURESTART # [ 7] R_INIT_CPURESTART + _LONG_ CPUCFG_DRAMINIT # [ 8] R_INIT_DRAMINIT + _LONG_ CPUCFG_CACHEOPS # [ 9] R_INIT_CACHEOPS + _LONG_ CPUCFG_TLBHANDLER # [ 10] R_INIT_TLBHANDLER + _LONG_ cfe_main # [ 11] R_INIT_CMDSTART + _LONG_ cfe_command_restart # [ 12] R_INIT_CMDRESTART + _LONG_ cfe_doxreq # [ 13] R_INIT_DOXREQ + _LONG_ CPUCFG_TP1_SWITCH # [ 14] R_INIT_TP1_SWITCH + _LONG_ cfe_size_ram # [ 15] R_INIT_SIZERAM + +/* ********************************************************************* + * CPU Startup Code + ********************************************************************* */ + +cpu_reset: + + /* + * Start with GP as zero. Nobody should touch + * this or set it to any other value until we're ready + * to use it. This is used to tell when we should start + * using relocated references in the init table, + * so beware! (see CALLINIT_RELOC in mipsmacros.h) + */ + + move gp,zero # start with no GP. + + .set noreorder + bal 1f + nop +1: nop + .set reorder + li BOOT_OFFSET, 0x1fff0000 + and BOOT_OFFSET, ra + +#------------------------------------------------------------------------------ + + /* + * Do low-level board initialization. This is our first + * chance to customize the startup sequence. + */ + move a0, BOOT_OFFSET + + CALLINIT_KSEG1(init_table,R_INIT_EARLYINIT) + + SETLEDS1('H','E','L','O') + + CALLINIT_KSEG1(init_table,R_INIT_CPUINIT) + +#------------------------------------------------------------------------------ + + /* + * Now, switch from KSEG1 to KSEG0 + */ + +#if CFG_RUNFROMKSEG0 + bal cpu_kseg0_switch +#endif + +#------------------------------------------------------------------------------ + /* + * Now running on cpu0 in K0SEG. + */ + +#if CFG_CMT + /* + * Check if the thread switch is required. If we are already + * running on thread 1 this function will do nothing and just return + * If we are running on thread 0 this function will take thread 1 + * out of reset and put thread 0 to sleep waiting for singnal from + * thread 1. + */ + CALLINIT_KSEG0(init_table,R_INIT_TP1_SWITCH) +#endif + +#if CFG_INIT_DRAM + SETLEDS('D','R','A','M') + + CALLINIT_KSEG0(init_table,R_INIT_DRAMINFO) + + move a0,v0 # pass these params + CALLINIT_KSEG0(init_table,R_INIT_DRAMINIT) + CALLINIT_KSEG0(init_table,R_INIT_SIZERAM) + move k0,v0 # Save in k0 for now +#else + li k0,(CFG_DRAM_SIZE * 1024) +#endif + +#------------------------------------------------------------------------------ + +#if CFG_BOOTRAM + b have_ram # No RAM is ok if using emulator RAM +#endif + + bne k0,zero,have_ram + + SETLEDS('R','A','M','X') # die here if no ram + +die1: b die1 + +have_ram: + + /* + * If this is the 64-bit version, turn on the KX bit + * to allow 64-bit accesses. + */ + +#ifdef __long64 + mfc0 t0,C0_SR + or t0,t0,M_SR_KX + mtc0 t0,C0_SR +#endif + +#------------------------------------------------------------------------------ + /* + * K0 contains the RAM size (and therefore the top of RAM + * offset). Start there, and subtract the amount of memory + * we expect to use. If we have more than 256MB of + * physical memory, work backwards from the 256MB + * boundary. + */ + +__CalcMemTop: li MEMTOP,256 # 256MB boundary + bgt k0,MEMTOP,1f # use 256MB if k0 is greater + move MEMTOP,k0 # otherwise keep top +1: sll MEMTOP,20 # make into byte amount + + li RELOCOFFSET,0 # not relocating, no offset + li TEXTOFFSET,0 + + /* + * DRAM is now running, and we're alive in cacheable memory + * on cpu0 in K0SEG. Set up GP. + */ + + LOADREL(a0,segment_table) + LR gp,R_SEG_GP(a0) + add gp,RELOCOFFSET + +#------------------------------------------------------------------------------ + /* + * Zero BSS + */ + + SETLEDS('Z','B','S','S') + + LOADREL(a0,segment_table) +__ZeroBss: + + LR v0,R_SEG_FBSS(a0) + LR v1,R_SEG_END(a0) + ADD v0,RELOCOFFSET # Relocate to actual data segment + ADD v1,RELOCOFFSET + +1: SR zero,0(v0) # Zero one cacheline at a time + SR zero,(REGSIZE*1)(v0) + SR zero,(REGSIZE*2)(v0) + SR zero,(REGSIZE*3)(v0) + add v0,REGSIZE*4 + blt v0,v1,1b + +#------------------------------------------------------------------------------ + /* + * Copy code + */ + + SETLEDS('C','O','D','E') + + LOADREL(a0,segment_table) +__CopyCode: + + LR t1,R_SEG_FTEXT(a0) # destination address + move TEXTBASE,t1 + + LR t2,R_SEG_FTEXT(a0) # Source address + FIXUP (t2); + LR t3,R_SEG_ETEXT(a0) + FIXUP (t3); + +1: LR t4,0(t2) # read one cache line + LR t5,(REGSIZE*1)(t2) + LR t6,(REGSIZE*2)(t2) + LR t7,(REGSIZE*3)(t2) + SR t4,0(t1) # write one cache line + SR t5,(REGSIZE*1)(t1) + SR t6,(REGSIZE*2)(t1) + SR t7,(REGSIZE*3)(t1) + add t1,REGSIZE*4 + add t2,REGSIZE*4 + bltu t2,t3,1b + +#------------------------------------------------------------------------------ + /* + * Copy initialized data + */ + +#if (CFG_BOOTRAM == 0) + + SETLEDS('D','A','T','A') + + LOADREL(a0,segment_table) + +__CopyData: + LR t1,R_SEG_FDATA(a0) + FIXUP (t1); + li t0,15 + add t1,t0 + not t0 + and t1,t0 # t1 = _etext rounded up to 16-byte boundary + + LR t2,R_SEG_FDATA(a0) + LR t3,R_SEG_EDATA(a0) + ADD t2,RELOCOFFSET # Relocate to actual data segment + ADD t3,RELOCOFFSET + +1: LR t4,0(t1) # read one cache line + LR t5,(REGSIZE*1)(t1) + LR t6,(REGSIZE*2)(t1) + LR t7,(REGSIZE*3)(t1) + SR t4,0(t2) # write one cache line + SR t5,(REGSIZE*1)(t2) + SR t6,(REGSIZE*2)(t2) + SR t7,(REGSIZE*3)(t2) + add t1,(REGSIZE*4) + add t2,(REGSIZE*4) + bltu t2,t3,1b + +#endif + +#------------------------------------------------------------------------------ + + /* + * Flush the cache, then switch to relocated code + * We need to flush the cache since we just moved the code and + * it may still live in our L1 DCache. We also need to + * flush L2, since there are some rare times we run + * uncached from DRAM, like when we start/stop a CPU. + * + * In the case of running completely uncached, don't flush the + * cache. It should not have any dirty lines in it, but you + * never know... + */ + +__GoRelo: + +#if CFG_RUNFROMKSEG0 + SETLEDS('L','1','2','F') + + li a0,CFE_CACHE_FLUSH_D | CFE_CACHE_FLUSH_L2 + CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) + li a0,CFE_CACHE_INVAL_I + CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS) +#endif /* CFG_RUNFROMKSEG0 */ + + la t0,gorelo # Now jump to an address code was compiled for + j t0 # and go there +gorelo: nop + li BOOT_OFFSET, 0 # no longer running at offset + + /* + * Remember total amount of memory. This is *still* in k0 + * after all this time. Hopefully. + */ + +__MemVars: + SR k0,mem_totalsize + SR RELOCOFFSET,mem_datareloc + + move v0,zero + + LOADREL(a0,segment_table) # trashed by l2 cache flush + LR v0,R_SEG_FDATA(a0) + ADD v0,RELOCOFFSET + LR v1,R_SEG_END(a0) + ADD v1,RELOCOFFSET + + SR v0,mem_bottomofmem + SR v1,mem_heapstart + + add v1,(CFG_HEAP_SIZE*1024) # Otherwise + add v1,STACK_SIZE + SR v1,mem_topofmem + + SR TEXTOFFSET,mem_textreloc + + /* At this point it's safe to use the CALLINIT_RELOC macro */ + + LR t1,R_SEG_FTEXT(a0) + FIXUP (t1); + LR t0,R_SEG_ETEXT(a0) + FIXUP (t0); + sub t0,t0,t1 + SR t0,mem_textsize + add t1,TEXTOFFSET + SR t1,mem_textbase + + +#------------------------------------------------------------------------------ + + /* + * Stash away some config register stuff + */ + + mfc0 v0,C0_PRID + SR v0,cpu_prid + + +#------------------------------------------------------------------------------ + + /* + * Set up the "C" stack and jump to the main routine. + */ + + SETLEDS('M','A','I','N') + + LR sp,mem_heapstart + ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8) + li a0,0 # call as "cfe_main(0,0)" + li a1,0 + + CALLINIT_RELOC(init_table,R_INIT_CMDSTART) # should not return + +/* ********************************************************************* + * CFE_LAUNCH + * + * Start the user program. The program is passed a handle + * that must be passed back when calling the firmware. + * + * Parameters passed to the called program are as follows: + * + * a0 - CFE handle + * a1 - entry vector + * a2 - reserved, will be 0 + * a3 - entrypoint signature. + * + * Input parameters: + * a0 - entry vector + * + * Return value: + * does not return + ********************************************************************* */ + +LEAF(cfe_launch) + + sub sp,8 + SR a0,0(sp) + + /* + * This function runs in RAM so BOOT_OFFSET is 0. It is called from + * C which could have modified the BOOT_OFFSET register, s6. + */ + li BOOT_OFFSET, 0 + + + /* + * Mask all interrupts. + */ + mfc0 v0,C0_SR # Get current interrupt flag + li v1,M_SR_IE # master interrupt control + not v1 # disable interrupts + and v0,v1 # SR now has IE=0 + mtc0 v0,C0_SR # put back into CP0 + + + /* + * Flush the D-Cache, since the program we loaded is "data". + * Invalidate the I-Cache, so that addresses in the program + * region will miss and need to be filled from the data we + * just flushed above. + */ + + li a0,CFE_CACHE_FLUSH_D|CFE_CACHE_INVAL_I + CALLINIT_RELOC(init_table,R_INIT_CACHEOPS) + + + /* + * Set things up for launching the program. Pass the + * handle in A0 - apps need to remember that and pass it + * back. + */ + + j RunProgram + +END(cfe_launch) + + /* + * This is a nice place to set a breakpoint. + */ +LEAF(RunProgram) + LR t0,0(sp) # entry point + + j t0 # go for it. +END(RunProgram) + +/* ********************************************************************* + * CPU_KSEG0_SWITCH + * + * Hack the return address so we will come back in KSEG0 + * + * Input parameters: + * nothing + * + * Return value: + * nothing + ********************************************************************* */ + +LEAF(cpu_kseg0_switch) + + and ra,(K0SIZE-1) + or ra,K0BASE + jr ra + +END(cpu_kseg0_switch) + +/* ********************************************************************* + * End + ********************************************************************* */ + + |