BCM WL 6.30.102.9 (r366174)
[tomato.git] / release / src-rt / cfe / cfe / arch / mips / cpu / rm7000 / src / rm7000_cpu.S
blobed45d243b9beb29a6c56e2184931ab909d0381c3
1 /*  *********************************************************************
2     *  P5064 Board Support Package
3     *  
4     *  CPU initialization                       File: rm7000_cpuinit.S
5     *  
6     *  This module contains code to initialize the CPU.
7     *  
8     *  Note: all the routines in this module rely on registers only,
9     *        since DRAM may not be active yet.
10     *
11     *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
12     *  
13     *********************************************************************  
14     *
15     *  Copyright 2000,2001,2002,2003
16     *  Broadcom Corporation. All rights reserved.
17     *  
18     *  This software is furnished under license and may be used and 
19     *  copied only in accordance with the following terms and 
20     *  conditions.  Subject to these conditions, you may download, 
21     *  copy, install, use, modify and distribute modified or unmodified 
22     *  copies of this software in source and/or binary form.  No title 
23     *  or ownership is transferred hereby.
24     *  
25     *  1) Any source code used, modified or distributed must reproduce 
26     *     and retain this copyright notice and list of conditions 
27     *     as they appear in the source file.
28     *  
29     *  2) No right is granted to use any trade name, trademark, or 
30     *     logo of Broadcom Corporation.  The "Broadcom Corporation" 
31     *     name may not be used to endorse or promote products derived 
32     *     from this software without the prior written permission of 
33     *     Broadcom Corporation.
34     *  
35     *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
36     *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
37     *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
38     *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 
39     *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 
40     *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
41     *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
42     *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
43     *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44     *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
45     *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
46     *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 
47     *     THE POSSIBILITY OF SUCH DAMAGE.
48     ********************************************************************* */
50 #include "sbmips.h"
51 #include "bsp_config.h"
52 #include "mipsmacros.h"
53 #include "exception.h"
56                 .text
57                 .set mips64
60 /*  *********************************************************************
61     *  Macros
62     ********************************************************************* */
64 #define CFG_BE          0x00008000      /* Big Endian */
65 #define CFG_EPMASK      0x0f000000      /* Transmit data pattern */
66 #define CFG_EPD         0x00000000      /* D */
67 #define NTLBENTRIES 64
68 #define LINESIZE 32
71 #define CACHEOP(cachename,op) ((cachename) | ((op) << 2))
73 #define CACHE_OP_IDXINVAL     0
74 #define CACHE_OP_IDXLOADTAG   1
75 #define CACHE_OP_IDXSTORETAG  2
76 #define CACHE_OP_IMPLRSVD     3
77 #define CACHE_OP_HITINVAL     4
78 #define CACHE_OP_FILL         5
79 #define CACHE_OP_HITWRITEBACK_INVAL  5
80 #define CACHE_OP_HITWRITEBACK 6
81 #define CACHE_OP_FETCHLOCK    7
83 #define L2C                 3
84 #define L1C_I               0
85 #define L1C_D               1
89  * Duplicates from cfe_iocb.h -- warning!
90  */
92 #define CFE_CACHE_FLUSH_D       1
93 #define CFE_CACHE_INVAL_I       2
94 #define CFE_CACHE_INVAL_D       4
95 #define CFE_CACHE_INVAL_L2      8
96 #define CFE_CACHE_FLUSH_L2      16
97 #define CFE_CACHE_INVAL_RANGE   32
98 #define CFE_CACHE_FLUSH_RANGE   64
100 /*  *********************************************************************
101     *  Linkage tables
102     ********************************************************************* */
104 #define R_CPU_CP0INIT   _TBLIDX(0)
105 #define R_CPU_L1CINIT   _TBLIDX(1)
106 #define R_CPU_L2CINIT   _TBLIDX(2)
107 #define R_CPU_SETLEDS   _TBLIDX(3)
109 cpuinit_table:
110                 _LONG_  rm7000_cp0_init         # [  0] R_CPU_CP0INIT
111                 _LONG_  rm7000_l1cache_init     # [  1] R_CPU_L1CINIT
112                 _LONG_  rm7000_l2cache_init     # [  1] R_CPU_L2CINIT
113                 _LONG_  board_setleds           # [  3] R_CPU_SETLEDS
115 #define SETLEDS1(a,b,c,d)                     \
116        li     a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ;    \
117        CALLINIT_KSEG1(cpuinit_table,R_CPU_SETLEDS)
118 #define SETLEDS(a,b,c,d)                     \
119        li     a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ;    \
120        CALLINIT_KSEG0(cpuinit_table,R_CPU_SETLEDS)
124 /*  *********************************************************************
125     *  RM7000_CP0_INIT
126     *  
127     *  Initialize CP0 registers for an RM7000 core.
128     *  
129     *  Input parameters: 
130     *      nothing
131     *      
132     *  Return value:
133     *      nothing
134     ********************************************************************* */
136 LEAF(rm7000_cp0_init)
138         /*
139          * Set SR and CAUSE to something sensible.
140          */
141                 
142                 .set noreorder
143                 mfc0    t0,C0_PRID
144                 mfc0    v0,C0_SR
145                 mtc0    zero,C0_WATCHLO
146                 mtc0    zero,C0_WATCHHI
147                 li      t1,-1
148                 mtc0    t1,C0_COMPARE
149                 and     v0,M_SR_SR              # preserve Soft Reset
150                 or      v0,M_SR_BEV             # set Boot Exceptions
151                 mtc0    zero,C0_CAUSE           # Must clear WP before
152                 mtc0    v0,C0_SR                # writing STATUS register.
153                 .set reorder
155         
156                 mfc0    t1,C0_CONFIG
158                 mtc0    zero,C0_WATCHLO
159                 mtc0    zero,C0_WATCHHI
161         /* 
162          * make KSEG0 cacheable 
163          */
165                 and     t1,~M_CFG_K0COH
166                 or      t1,V_CFG_K0COH(K_CFG_K0COH_CACHEABLE)
167                 or      t1,0x08                 /* enable SCache */
168                 and     t1,~(1<<12)             /* disable TCache */
169         
170         /* 
171          * set DDDD rate for CPUs that aren't hardware configured 
172          */
174                 and     t1,~CFG_EPMASK
175                 or      t1,CFG_EPD
177 #ifdef __MIPSEB
178                 or      t1,CFG_BE       
179 #else
180                 and     t1,~CFG_BE      
181 #endif
182                 mtc0    t1,C0_CONFIG
185         /* 
186          * initialize tlb 
187          */
188                 mtc0    zero,C0_TLBLO0          /* tlblo0 = invalid */
189                 mtc0    zero,C0_TLBLO1          /* tlblo1 = invalid */
190                 mtc0    zero,C0_PGMASK
191                 li      t8,K1BASE               /* tlbhi  = impossible vpn */
192                 li      t9,(NTLBENTRIES-1)      /* index */
193                 
195                 .set noreorder
196                 nop
197 1:              mtc0    t8,C0_TLBHI
198                 mtc0    t9,C0_INX
199                 addu    t8,0x2000               /* inc vpn */
200                 tlbwi
201                 bnez    t9,1b
202                 subu    t9,1                    # BDSLOT
203                 .set reorder
205                 j       ra
207 END(rm7000_cp0_init)
210 /*  *********************************************************************
211     *  RM7000_NULL_INIT
212     *  
213     *  This stub routine is used by initialization functions that
214     *  we leave unimplemented.
215     *  
216     *  Input parameters: 
217     *      nothing
218     *      
219     *  Return value:
220     *      nothing
221     ********************************************************************* */
223 LEAF(rm7000_null_init)
224                 j       ra
225 END(rm7000_null_init)
229 /*  *********************************************************************
230     *  RM7000_CPUINIT
231     *  
232     *  Initialize the CPU core.
233     *  
234     *  Input parameters: 
235     *      nothing
236     *      
237     *  Return value:
238     *      nothing
239     ********************************************************************* */
241 LEAF(rm7000_cpuinit)
243                 move    k0,ra                   /* will be trashing RA */
245         /*
246          * Basic CPU initialization
247          */
249                 CALLINIT_KSEG1(cpuinit_table,R_CPU_CP0INIT)
251         /*
252          * CP0 registers
253          */
256 #------------------------------------------------------------------------------
258         /*
259          * Init the L1 cache.  
260          */
262 #if CFG_INIT_L1
263                 SETLEDS1('L','1','C','I')
264                 CALLINIT_KSEG1(cpuinit_table,R_CPU_L1CINIT)
265 #endif
267         /*
268          * Init the L2 cache
269          */
270 #if CFG_INIT_L1
271                 SETLEDS1('L','2','C','I')
272                 CALLINIT_KSEG1(cpuinit_table,R_CPU_L2CINIT)
273 #endif
275                 move    ra,k0                   /* saved return address */
276                 j       ra
279 END(rm7000_cpuinit)
281 /*  *********************************************************************
282     *  RM7000_CPURESTART
283     *  
284     *  'Restart' the CPU (reset things back to some sane state after
285     *  a program returns to the firmware)
286     *  
287     *  Input parameters: 
288     *      nothing
289     *      
290     *  Return value:
291     *      nothing
292     ********************************************************************* */
294 LEAF(rm7000_cpurestart)
296                 move    k0,ra
298                 CALLINIT_KSEG0(cpuinit_table,R_CPU_CP0INIT)
300                 LR      v0,cfe_pagetable                # reestablish 
301                 dsll    v0,v0,13                        # see mips_arena.c for this
302                 dmtc0   v0,C0_CTEXT                     # boot area TLBs
304                 move    ra,k0
305                 j       ra
307 END(rm7000_cpurestart)
310 LEAF(rm7000_cacheops)
312                 move    s0,ra
314                 move    v1,a0
316         /*
317          * With no flags, we flush L1D and invalid L1I
318          */
320                 bne     v1,zero,1f
321                 li      v1,CFE_CACHE_FLUSH_D | CFE_CACHE_INVAL_I
324         /*
325          * Flush the D-Cache, since the program we loaded is "data".
326          */
328                 and     a0,v1,CFE_CACHE_FLUSH_D
329                 beq     a0,zero,1f
330                 jal     rm7000_l1cache_flush_d
333         /*
334          * Invalidate the I-Cache, so that addresses in the program
335          * region will miss and need to be filled from the data we 
336          * just flushed above.
337          */
339                 and     a0,v1,CFE_CACHE_INVAL_I
340                 beq     a0,zero,1f
341                 jal     rm7000_l1cache_inval_i
345         /*
346          * Invalidate the L2, if requested.  Use this cautiously,
347          * since it invalidates both I and D!
348          */
350                 and     a0,v1,CFE_CACHE_INVAL_L2
351                 beq     a0,zero,1f
352                 jal     rm7000_l2cache_init
355         /*
356          * Invalidate the L2, if requested.  Use this cautiously,
357          * since it invalidates both I and D!
358          */
360                 and     a0,v1,CFE_CACHE_FLUSH_L2
361                 beq     a0,zero,1f
362                 jal     rm7000_l2cache_flush    /* Trashes T0..T7, V0, A0 */
365         /*
366          * Invalidate cache range
367          */
369                 and     a0,v1,CFE_CACHE_INVAL_RANGE
370                 beq     a0,zero,2f
372                 move    t0,a1
373 1:              cache   CACHEOP(L2C,CACHE_OP_HITINVAL),0(t0)
374                 add     t0,LINESIZE
375                 blt     t0,a2,1b
377                 move    t0,a1
378 1:              cache   CACHEOP(L1C_D,CACHE_OP_HITINVAL),0(t0)
379                 add     t0,LINESIZE
380                 blt     t0,a2,1b
382         /*
383          * Flush cache range
384          */
385                 
388                 and     a0,v1,CFE_CACHE_FLUSH_RANGE
389                 beq     a0,zero,2f
391                 move    t0,a1
392 1:              cache   CACHEOP(L1C_D,CACHE_OP_HITWRITEBACK_INVAL),0(t0)
393                 add     t0,LINESIZE
394                 blt     t0,a2,1b
395                 move    t0,a1
396 1:              cache   CACHEOP(L2C,CACHE_OP_HITWRITEBACK_INVAL),0(t0)
397                 add     t0,LINESIZE
398                 blt     t0,a2,1b
402                 move    ra,s0
403                 j       ra
405 END(rm7000_cacheops)
407 /*  *********************************************************************
408     *  RM7000_TLBHANDLER
409     *  
410     *  This is the TLB exception handler for the RM7000
411     *  
412     *  Note: only K0 and K1 are available to us at this time.
413     *  
414     *  Input parameters: 
415     *      nothing
416     *      
417     *  Return value:
418     *      nothing
419     ********************************************************************* */
422 LEAF(rm7000_tlbhandler)
423                 .set    noreorder
424                 .set    noat
427  * This requires a bit of explanation:  We only support 256KB
428  * of mapped space for the boot program.  This space will be 
429  * mapped from 0x2000_0000 to 0x2004_0000 to some physical 
430  * memory allocated by the firmware.  This is 64 pages
431  * of 4KB each.
433  * We know our BadVPN2 will be in the range
434  * 0x100000 to 0x1001F0, since the memory is mapped from
435  * 0x2000_0000 to 0x2004_0000.  BadVPN2 plus the four bits
436  * of zeroes at the end are bits 31..9
437  * 
438  * We also want to place the PTEbase on something other than
439  * a 16MB boundary.  Each entry is 16 bytes, and there
440  * are 64 entries, so we need only 10 bits to address
441  * the entire table (it can therefore be aligned on a
442  * 1KB boundary).
444  * To make this work, we'll shift PTEbase to the right, leaving
445  * the bottom ten bits for the page number, as:
447  *    Bits 31..10: PTEbase
448  *    Bits 9..4:   BadVPN
449  *    Bits 3..0:   16 bytes for table entry
451  * Therefore:
452  *    PTEbase gets shifted right 13 bits.
453  *    BadVPN  gets masked at 6 bits (mask is 0x3F0)
454  *    The bottom 4 bits are zero.
456  * To range check the address, we can shift the Bad VPN
457  * right by 9 bits, and check for values of 0x1000 and
458  * 0x1001.
459  */
462         /*
463          * This part range checks the VPN2 field in the 
464          * context register.  We only handle
465          * VPN2s in the range 0x100000 to 0x1001F0
466          */
467                 dmfc0   k0,C0_TLBHI
469                 dmfc0   k0,C0_CTEXT             # Get context
470                 dsra    k0,8                    # keep hi part
471                 and     k0,0x1FFF               # of VPN2
472                 li      k1,0x1000               # 0x1000 is ok
473                 beq     k0,k1,1f                #
474                 nop                             # BDSLOT
475                 li      k1,0x1001               # 0x1001 is ok
476                 beq     k0,k1,1f                #
477                 nop                             # BDSLOT
479                 li      k0,XTYPE_TLBFILL        # all other bits are not
480                 j       _exc_entry
481                 nop                             # BDSLOT
483 1:              dmfc0   k0,C0_CTEXT             # Get context
484                 dsra    k0,13                   # Shift PTEbase 
485                 li      k1,0x3FF                # Generate mask to kill 
486                 not     k1                      # BadVPN2 bits
487                 and     k0,k1                   # keep only PTEBase part.
489                 dmfc0   k1,C0_CTEXT             # Get Context
490                 and     k1,0x3F0                # Keep only BadVPN2 bits
491                 or      k1,k0                   # Replace PTEBase
493                 ld      k0,0(k1)                # Load entrylo0
494                 ld      k1,8(k1)                # Load entrylo1
495                 mtc0    k0,C0_TLBLO0            # and write to CP0
496                 mtc0    k1,C0_TLBLO1
497                 tlbwr                           # put it in the TLB
498                 eret
499                 nop
501                 .set    reorder
502                 .set    at
504 END(rm7000_tlbhandler)
506 /*  *********************************************************************
507     *  End
508     ********************************************************************* */