summaryrefslogtreecommitdiffstats
path: root/cfe/cfe/arch/mips/common/src/init_mips.S
diff options
context:
space:
mode:
Diffstat (limited to 'cfe/cfe/arch/mips/common/src/init_mips.S')
-rwxr-xr-xcfe/cfe/arch/mips/common/src/init_mips.S683
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
+ ********************************************************************* */
+
+