1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * CPU init module File: init_ram.S
6 * This module contains the vectors and lowest-level CPU startup
9 * This is very similar to "init_mips.S" but is used when
10 * you want to locate CFE in DRAM, loading it like an
11 * application program.
13 * Author: Mitch Lichtenberg (mpl@broadcom.com)
15 *********************************************************************
17 * Copyright 2000,2001,2002,2003
18 * Broadcom Corporation. All rights reserved.
20 * This software is furnished under license and may be used and
21 * copied only in accordance with the following terms and
22 * conditions. Subject to these conditions, you may download,
23 * copy, install, use, modify and distribute modified or unmodified
24 * copies of this software in source and/or binary form. No title
25 * or ownership is transferred hereby.
27 * 1) Any source code used, modified or distributed must reproduce
28 * and retain this copyright notice and list of conditions
29 * as they appear in the source file.
31 * 2) No right is granted to use any trade name, trademark, or
32 * logo of Broadcom Corporation. The "Broadcom Corporation"
33 * name may not be used to endorse or promote products derived
34 * from this software without the prior written permission of
35 * Broadcom Corporation.
37 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
38 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
39 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
40 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
41 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
42 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
43 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
44 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
45 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
46 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
47 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
48 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
49 * THE POSSIBILITY OF SUCH DAMAGE.
50 ********************************************************************* */
54 #include "exception.h"
56 #include "bsp_config.h"
57 #include "cpu_config.h"
59 #include "cfe_devfuncs.h"
61 /* *********************************************************************
63 ********************************************************************* */
66 #error "RAM version is not compatible with relocation."
68 #if !CFG_RUNFROMKSEG0 && !defined(JTAG_RAM_BOOT)
69 #error "RAM version should be run cached"
73 #error "Multiple CPUs not compatible with RAM version"
77 /* *********************************************************************
79 ********************************************************************* */
81 #include "mipsmacros.h"
84 /* *********************************************************************
87 * Sets the on-board LED display (if present).
90 * a,b,c,d - four ASCII characters (literal constants)
94 ********************************************************************* */
97 #define SETLEDS(a,b,c,d) \
98 li a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ; \
102 /* *********************************************************************
104 ********************************************************************* */
107 * This is the size of the stack, rounded to KByte boundaries.
110 #ifndef CFG_STACK_SIZE
111 #error "CFG_STACK_SIZE not defined"
113 #define STACK_SIZE ((CFG_STACK_SIZE+1023) & ~1023)
117 * Duplicates from cfe_iocb.h -- warning!
120 #define CFE_CACHE_FLUSH_D 1
121 #define CFE_CACHE_INVAL_I 2
122 #define CFE_CACHE_INVAL_D 4
123 #define CFE_CACHE_INVAL_L2 8
124 #define CFE_CACHE_FLUSH_L2 16
125 #define CFE_CACHE_INVAL_RANGE 32
126 #define CFE_CACHE_FLUSH_RANGE 64
130 * To make life easier reading this code, define "KSEGBASE"
131 * to either K0BASE or K1BASE depending on whether we're running
135 #define KSEGBASE K1BASE /* JTAG RAM version always uncached */
137 #define KSEGBASE K0BASE /* RAM version always cached */
138 #endif /* JTAG_RAM_BOOT */
140 /* *********************************************************************
141 * Names of registers used in this module
142 ********************************************************************* */
146 #include "initdata.h" /* declare variables we use here */
150 cfe_spinlock: .word 0
157 /* *********************************************************************
159 ********************************************************************* */
170 /* *********************************************************************
171 * CFE Entry Point (used by OS boot loaders and such)
172 ********************************************************************* */
178 vec_reset: b cpu_reset
182 vec_apientry: b cpu_apientry
190 /* *********************************************************************
193 * Addresses of data segments and of certain routines we're going
194 * to call from KSEG1. These are here mostly for the embedded
195 * PIC case, since we can't count on the 'la' instruction to
196 * do the expected thing (the assembler expands it into a macro
197 * for doing GP-relative stuff, and the code is NOT GP-relative.
198 * So, we (relocatably) get the offset of this table and then
201 * Pointer values in this segment will be relative to KSEG0 for
202 * cached versions of CFE, so we need to OR in K1BASE in the
203 * case of calling to a uncached address.
205 * The LOADREL macro handles most of the nastiness here.
206 ********************************************************************* */
209 #include "segtable.h"
213 _LONG_ _etext # [ 0] End of text (R_SEG_ETEXT)
214 _LONG_ _fdata # [ 1] Beginning of data (R_SEG_FDATA)
215 _LONG_ _edata # [ 2] End of data (R_SEG_EDATA)
216 _LONG_ _end # [ 3] End of BSS (R_SEG_END)
217 _LONG_ _ftext # [ 4] Beginning of text (R_SEG_FTEXT)
218 _LONG_ _fbss # [ 5] Beginning of BSS (R_SEG_FBSS)
219 _LONG_ _gp # [ 6] Global Pointer (R_SEG_GP)
220 _LONG_ 0 # [ 7] Beginning of reloc entries
221 _LONG_ 0 # [ 8] End of reloc entries
222 _LONG_ cpu_apientry # [ 9] R_SEG_APIENTRY
225 /* *********************************************************************
228 * This is like segment_table except it contains pointers to
229 * routines used during initialization. It serves both as a
230 * table for doing PIC stuff and also to separate out
231 * machine-specific init routines.
233 * The CALLINIT_xxx macros are used to call routines in this table.
234 ********************************************************************* */
239 _LONG_ board_earlyinit # [ 0] R_INIT_EARLYINIT
240 _LONG_ board_setleds # [ 1] R_INIT_SETLEDS
241 _LONG_ board_draminfo # [ 2] R_INIT_DRAMINFO
242 _LONG_ CPUCFG_CPUINIT # [ 3] R_INIT_CPUINIT
243 _LONG_ CPUCFG_ALTCPU_START1 # [ 4] R_INIT_ALTCPU_START1
244 _LONG_ CPUCFG_ALTCPU_START2 # [ 5] R_INIT_ALTCPU_START2
245 _LONG_ CPUCFG_ALTCPU_RESET # [ 6] R_INIT_ALTCPU_RESET
246 _LONG_ CPUCFG_CPURESTART # [ 7] R_INIT_CPURESTART
247 _LONG_ CPUCFG_DRAMINIT # [ 8] R_INIT_DRAMINIT
248 _LONG_ CPUCFG_CACHEOPS # [ 9] R_INIT_CACHEOPS
249 _LONG_ CPUCFG_TLBHANDLER # [ 10] R_INIT_TLBHANDLER
250 _LONG_ cfe_main # [ 11] R_INIT_CMDSTART
251 _LONG_ cfe_command_restart # [ 12] R_INIT_CMDRESTART
252 _LONG_ cfe_doxreq # [ 13] R_INIT_DOXREQ
254 /* *********************************************************************
256 ********************************************************************* */
261 #------------------------------------------------------------------------------
264 * Do low-level board initialization. This is our first
265 * chance to customize the startup sequence.
268 CALLINIT_KSEG0(init_table,R_INIT_EARLYINIT)
270 SETLEDS('H','E','L','O')
272 #------------------------------------------------------------------------------
275 * DRAM is now running, and we're alive in cacheable memory
276 * on cpu0 in K0SEG. Set up GP.
279 LOADREL(a0,segment_table)
282 #------------------------------------------------------------------------------
287 SETLEDS('Z','B','S','S')
289 LOADREL(a0,segment_table)
295 1: SR zero,0(v0) # Zero one cacheline at a time
296 SR zero,(REGSIZE*1)(v0)
297 SR zero,(REGSIZE*2)(v0)
298 SR zero,(REGSIZE*3)(v0)
303 #------------------------------------------------------------------------------
305 li k0,256 # memory size in megabytes
314 #------------------------------------------------------------------------------
317 * Remember total amount of memory. This is *still* in k0
318 * after all this time. Hopefully.
323 SR zero,mem_datareloc
327 LOADREL(a0,segment_table) # trashed by l2 cache flush
328 LR v0,R_SEG_FTEXT(a0) # bottom = beginning of text
331 SR v0,mem_bottomofmem
334 add v1,(CFG_HEAP_SIZE*1024) # Otherwise
338 SR zero,mem_textreloc
341 LR t1,R_SEG_FTEXT(a0)
342 LR t0,R_SEG_ETEXT(a0)
348 #------------------------------------------------------------------------------
352 * Let secondary CPU(s) run their idle loops. Set the
353 * mailbox register to our relocation factor so we can read
354 * it out of the mailbox register and relocate GP properly.
358 CALLINIT_KSEG0(init_table,R_INIT_ALTCPU_START2)
362 * Stash away some config register stuff
369 #------------------------------------------------------------------------------
372 * Set up the "C" stack and jump to the main routine.
375 SETLEDS('M','A','I','N')
378 ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8)
379 li a0,0 # call as "cfe_main(0,0)"
382 CALLINIT_KSEG0(init_table,R_INIT_CMDSTART) # should not return
386 * Terminate the simulator.
396 /* *********************************************************************
399 * Restart the command interpreter
402 * A0 - command status
403 * nothing (GP has already been set up for us)
407 ********************************************************************* */
411 SR a0,0(sp) # store on old stack
412 LOADREL(v0,init_table)
413 LR v0,R_INIT_CPURESTART(v0)
414 jal v0 # had better not trash GP or K1
418 ADD sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8)
421 * If someone called the API to do a warm start, clear the
422 * spin lock, since the call will never return.
426 SPIN_UNLOCK(cfe_spinlock,t0)
429 CALLINIT_KSEG0(init_table,R_INIT_CMDRESTART) # should not return
433 /* *********************************************************************
436 * Perform certain cache operations
439 * a0 - flags (CFE_CACHE_xxx flags, or zero for a default)
440 * a1,a2 - start/end of range for "range invalidate" operations
441 * (not used otherwise)
445 ********************************************************************* */
447 LEAF(_cfe_flushcache)
448 #ifndef JTAG_RAM_BOOT
456 CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS)
468 /* *********************************************************************
471 * Start the user program. The program is passed a handle
472 * that must be passed back when calling the firmware.
474 * Parameters passed to the called program are as follows:
478 * a2 - reserved, will be 0
479 * a3 - entrypoint signature.
486 ********************************************************************* */
494 * Mask all interrupts.
496 mfc0 v0,C0_SR # Get current interrupt flag
497 li v1,M_SR_IE # master interrupt control
498 not v1 # disable interrupts
499 and v0,v1 # SR now has IE=0
500 mtc0 v0,C0_SR # put back into CP0
502 #ifndef JTAG_RAM_BOOT
504 * Flush the D-Cache, since the program we loaded is "data".
505 * Invalidate the I-Cache, so that addresses in the program
506 * region will miss and need to be filled from the data we
507 * just flushed above.
509 li a0,CFE_CACHE_FLUSH_D|CFE_CACHE_INVAL_I
510 CALLINIT_KSEG0(init_table,R_INIT_CACHEOPS)
513 * Set things up for launching the program. Pass the
514 * handle in A0 - apps need to remember that and pass it
523 * This is a nice place to set a breakpoint.
527 LOADREL(a2,segment_table)
528 LR a2,R_SEG_APIENTRY(a2) # A2 = code entry
530 move a1,zero # A1 = 0
531 move a0,gp # A0 = handle
532 li a3,CFE_EPTSEAL # A3 = entrypoint signature
533 LR t0,0(sp) # entry point
540 /* *********************************************************************
543 * Set the on-board LEDs.
550 ********************************************************************* */
554 j board_setleds # jump to BSP routine
558 /* *********************************************************************
559 * TLB Fill Exeption Handler
560 ********************************************************************* */
563 move k0,ra # Save, we're about to trash
564 LOADREL(k1,init_table) # Load offset of init table
565 LR k1,R_INIT_TLBHANDLER(k1) # Get entry from table
566 move ra,k0 # restore trashed ra
567 j k1 # Dispatch to handler
569 /* *********************************************************************
570 * XTLB Fill Exception Handler
571 ********************************************************************* */
576 /* *********************************************************************
577 * Cache Error Exception Handler
578 ********************************************************************* */
584 /* *********************************************************************
585 * General Exception Handler
586 ********************************************************************* */
592 /* *********************************************************************
593 * General Interrupt Handler
594 ********************************************************************* */
600 /* *********************************************************************
601 * EJTAG Debug Exception Handler
602 ********************************************************************* */
607 /* *********************************************************************
608 * cpu_apientry(handle,iocb)
610 * API entry point for external apps.
613 * a0 - firmware handle (used to determine the location of
614 * our relocated data)
615 * a1 - pointer to IOCB to execute
618 * v0 - return code, 0 if ok
619 ********************************************************************* */
621 #define _regidx(x) ((x)*8)
623 #define CAE_SRSAVE _regidx(0)
624 #define CAE_GPSAVE _regidx(1)
625 #define CAE_RASAVE _regidx(2)
626 #define CAE_S0SAVE _regidx(3)
627 #define CAE_S1SAVE _regidx(4)
628 #define CAE_S2SAVE _regidx(5)
629 #define CAE_S3SAVE _regidx(6)
630 #define CAE_S4SAVE _regidx(7)
631 #define CAE_S5SAVE _regidx(8)
632 #define CAE_S6SAVE _regidx(9)
633 #define CAE_S7SAVE _regidx(10)
635 #define CAE_STKSIZE _regidx(11)
639 sub sp,CAE_STKSIZE # Make room for our stuff
641 mfc0 v0,C0_SR # Get current interrupt flag
642 SR v0,CAE_SRSAVE(sp) # save on stack
643 li t0,M_SR_IE # master interrupt control
644 not t0 # disable interrupts
645 and v0,t0 # SR now has IE=0
646 mtc0 v0,C0_SR # put back into CP0
648 SR gp,CAE_GPSAVE(sp) # save GP
649 SR ra,CAE_RASAVE(sp) # and old RA
660 move gp,a0 # set up new GP
661 move a0,a1 # A0 points at IOCB
665 SPIN_LOCK(cfe_spinlock,t0,t1)
668 CALLINIT_KSEG0(init_table,R_INIT_DOXREQ) # should not return
671 SPIN_UNLOCK(cfe_spinlock,t0)
675 # Restore the saved registers.
687 LR ra,CAE_RASAVE(sp) # unwind the stack
690 LR t0,CAE_SRSAVE(sp) # old interrupt mask
692 add sp,CAE_STKSIZE # restore old stack pointer
694 mtc0 t0,C0_SR # restore interrupts
701 /* *********************************************************************
704 * Hack the return address so we will come back in KSEG0
711 ********************************************************************* */
713 LEAF(cpu_kseg0_switch)
719 END(cpu_kseg0_switch)
724 /* *********************************************************************
727 * Read the STATUS register into v0
733 * v0 - Status register
734 ********************************************************************* */
743 /* *********************************************************************
746 * Set the STATUS register to the value in a0
752 * v0 - Status register
753 ********************************************************************* */
761 /* *********************************************************************
764 * Read the CAUSE register into v0
770 * v0 - Cause register
771 ********************************************************************* */
780 /* *********************************************************************
783 * Read the COUNT register into v0
789 * v0 - count register
790 ********************************************************************* */
799 /* *********************************************************************
802 * Set the C0_Compare register from a0
805 * a0 - compare register
809 ********************************************************************* */
818 /* *********************************************************************
821 * Set the CONTEXT register.
828 ********************************************************************* */
836 /* *********************************************************************
839 * Return the address of the segment table. We use this
840 * to display the startup messages.
842 * You can't just address the table from C because it lives
843 * in the text segment.
850 ********************************************************************* */
855 LOADREL(v0,segment_table)
861 /* *********************************************************************
864 * Flush the write buffer. This is probably not necessary
865 * on SiByte CPUs, but we have it for completeness.
872 ********************************************************************* */
876 sync /* drain the buffers */
877 la t0,__junk /* do an uncached read to force it out */
885 /* *********************************************************************
887 ********************************************************************* */