RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / arch / mips / cpu / sb1250 / src / sb1250_altcpu.S
blob167f169c45f927f5ce3cae0a8dabc354ec9ad480
1 /*  *********************************************************************
2     *  Broadcom Common Firmware Environment (CFE)
3     *  
4     *  CPU init module                          File: sb1250_altcpu.S
5     *
6     *  Secondary core startup routines for CFE
7     *  
8     *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
9     *  
10     *********************************************************************  
11     *
12     *  Copyright 2000,2001,2002,2003
13     *  Broadcom Corporation. All rights reserved.
14     *  
15     *  This software is furnished under license and may be used and 
16     *  copied only in accordance with the following terms and 
17     *  conditions.  Subject to these conditions, you may download, 
18     *  copy, install, use, modify and distribute modified or unmodified 
19     *  copies of this software in source and/or binary form.  No title 
20     *  or ownership is transferred hereby.
21     *  
22     *  1) Any source code used, modified or distributed must reproduce 
23     *     and retain this copyright notice and list of conditions 
24     *     as they appear in the source file.
25     *  
26     *  2) No right is granted to use any trade name, trademark, or 
27     *     logo of Broadcom Corporation.  The "Broadcom Corporation" 
28     *     name may not be used to endorse or promote products derived 
29     *     from this software without the prior written permission of 
30     *     Broadcom Corporation.
31     *  
32     *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33     *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34     *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
35     *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 
36     *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 
37     *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38     *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
39     *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40     *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41     *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
42     *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
43     *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 
44     *     THE POSSIBILITY OF SUCH DAMAGE.
45     ********************************************************************* */
47 #include "sbmips.h"
48 #include "exception.h"
50 #include "bsp_config.h"
52 #ifdef _CFE_
53 #include "cfe_devfuncs.h"
54 #else
55 #define CFE_EPTSEAL 0x43464531
56 #endif
58 #include "sb1250_defs.h"
59 #include "sb1250_regs.h"
60 #include "sb1250_scd.h"
62 #include "cpu_config.h"
64 /*  *********************************************************************
65     *  Macros
66     ********************************************************************* */
68 #include "mipsmacros.h"
70 #define SETLEDS1(a,b,c,d)                     \
71        li     a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ;    \
72        CALLINIT_KSEG1(altcpu_table,R_ALT_SETLEDS)
73 #define SETLEDS(a,b,c,d)                     \
74        li     a0,(((a)<<24)|((b)<<16)|((c)<<8)|(d)) ;    \
75        CALLINIT_KSEG0(altcpu_table,R_ALT_SETLEDS)
78 /*  *********************************************************************
79     *  Initialized Data
80     ********************************************************************* */
82                 .sdata
85  * Initial start addresses for secondary CPUs
86  */
88                 .globl cpu_startvectors
89 cpu_startvectors:
90                 _VECT_  0                       # cpu #0 (not used)
91                 _VECT_  0                       # cpu #1
92                 _VECT_  0                       # cpu #2
93                 _VECT_  0                       # cpu #3
96  * Initial values for SP, GP, and A1 (user argument) 
97  */
99 cpu_start_spvals:
100                 _VECT_  0                       # cpu #0 (not used)
101                 _VECT_  0                       # cpu #1
102                 _VECT_  0                       # cpu #2
103                 _VECT_  0                       # cpu #3
105 cpu_start_gpvals:
106                 _VECT_  0                       # cpu #0 (not used)
107                 _VECT_  0                       # cpu #1
108                 _VECT_  0                       # cpu #2
109                 _VECT_  0                       # cpu #3
111 cpu_start_args:
112                 _VECT_  0                       # cpu #0 (not used)
113                 _VECT_  0                       # cpu #1
114                 _VECT_  0                       # cpu #2
115                 _VECT_  0                       # cpu #3
118                 .extern mem_datareloc
121 /*  *********************************************************************
122     *  Linkage Tables
123     * 
124     *  This table contains pointers to routines in other modules.
125     *  we do things this way so we can stay position-independent and
126     *  also avoid problems with the limitations of relative branching.
127     ********************************************************************* */
129                 .text
131                 .set mips64
133 #define R_ALT_CPUINIT   _TBLIDX(0)
134 #define R_ALT_L1CINIT   _TBLIDX(1)
135 #define R_ALT_SETLEDS   _TBLIDX(2)
136 #define R_ALT_GP        _TBLIDX(3)
137 #define R_ALT_APIENTRY  _TBLIDX(4)
139 altcpu_table:   
140                 _LONG_  sb1_cpu_init            # [  0] R_ALT_CPUINIT
141                 _LONG_  sb1250_l1cache_init     # [  1] R_ALT_L1CINIT
142                 _LONG_  board_setleds           # [  2] R_ALT_SETLEDS
143                 _LONG_  _gp                     # [  3] R_ALT_GP
144                 _LONG_  cpu_apientry            # [  4] R_ALT_APIENTRY
147 /*  *********************************************************************
148     *  ALTCPU_KSEG1_SWITCH
149     *  
150     *  Hack the return address so we will come back in KSEG1 (uncached)
151     *  
152     *  Input parameters: 
153     *      nothing
154     *      
155     *  Return value:
156     *      nothing
157     ********************************************************************* */
159 LEAF(altcpu_kseg1_switch)
161                 and     ra,(K0SIZE-1)
162                 or      ra,K1BASE
163                 jr      ra
165 END(altcpu_kseg1_switch)
167 /*  *********************************************************************
168     *  ALTCPU_KSEG0_SWITCH
169     *  
170     *  Hack the return address so we will come back in KSEG0
171     *  
172     *  Input parameters: 
173     *      nothing
174     *      
175     *  Return value:
176     *      nothing
177     ********************************************************************* */
179 LEAF(altcpu_kseg0_switch)
181                 and     ra,(K0SIZE-1)
182                 or      ra,K0BASE
183                 jr      ra
185 END(altcpu_kseg0_switch)
187 /*  *********************************************************************
188     *  SB1250_ALTCPU_START1
189     *  
190     *  Start secondary processor(s).  These processors will start
191     *  running the code at ALTCPU_RESET (see below).  We wait here
192     *  for the secondary processor(s) to finish their cache
193     *  initialization and then  return.
194     *
195     *  This routine is normally run from KSEG1
196     *  
197     *  Input parameters: 
198     *      nothing
199     *      
200     *  Return value:
201     *      nothing
202     ********************************************************************* */
204 LEAF(sb1250_altcpu_start1)
206         /*
207          * Don't do this if we have only one CPU.  This way we can
208          * support running the multiprocessor version of CFE
209          * with only one core.
210          */
212                 la      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
213                 ld      t0,(t0)                 # Get system revision
214                 dsrl    t0,S_SYS_PART           # Shift part # to low bits
215                 dsrl    t0,8                    # isolate CPU part of number
216                 and     t0,0x0F                 # T0 = number of CPUs
217                 bgt     t0,1,1f                 # Keep going if more than one CPU
218                 j       ra                      # Go back home, nothing to do
221         /*
222          * Clear out our mailbox registers (both CPUs)
223          */
225                 la      a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CLR_CPU))
226                 dli     t0,-1                   # clear all 64 bits
227                 sd      t0,(a0)
228                 la      a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_CLR_CPU))
229                 sd      t0,(a0)
232                 la      a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG)
233                 ld      t0,0(a0)
234                 dli     t1,M_SYS_CPU_RESET_1    # Reset mask
235                 not     t1                      # clear this bit
236                 and     t0,t1                   # New value to write
237                 sd      t0,0(a0)                # CPU1 is now running
239         /*
240          * Wait for the other CPU to ring our doorbell
241          */
244 1:              la      a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CPU));
245                 ld      t0,(a0)                 # Read mailbox
246                 beq     t0,zero,1b              # Loop till the bit is set
248         /*
249          * Clear the mailbox to dismiss the pending interrupts
250          */
252                 la      a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_CLR_CPU))
253                 dli     t0,-1                   # clear all 64 bits
254                 sd      t0,(a0)
256         /*
257          * Okay, it's safe to return
258          */
260                 j       ra
262 END(sb1250_altcpu_start1)
264 /*  *********************************************************************
265     *  SB1250_ALTCPU_START2
266     *  
267     *  Finish startup of secondary processor(s) - we pass the relocation
268     *  offset to the other CPUs here, and the CPUs relocate their
269     *  data segments and go to the idle loop.
270     *
271     *  This routine is normally run from KSEG0
272     *  
273     *  Input parameters: 
274     *      a0 - data relocation offset (0=none)
275     *      
276     *  Return value:
277     *      nothing
278     ********************************************************************* */
280 LEAF(sb1250_altcpu_start2)
282         /*
283          * Don't do this if we have only one CPU. 
284          */
286                 la      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
287                 ld      t0,(t0)                 # Get system revision
288                 dsrl    t0,S_SYS_PART           # Shift part # to low bits
289                 dsrl    t0,8                    # isolate CPU part of number
290                 and     t0,0x0F                 # T0 = number of CPUs
291                 bgt     t0,1,1f                 # Keep going if more than one CPU
292                 j       ra                      # Go back home, nothing to do
295         /*
296          * Let secondary CPU(s) run their idle loops.  Set the 
297          * mailbox register to our relocation factor so we can read
298          * it out of the mailbox register and relocate GP properly.
299          */
301                 la      t1,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_SET_CPU))
302                 or      t0,a0,1         # hack - make sure reloc is nonzero
303                 sd      t0,0(t1)        # Write to mailbox register
305                 j       ra      
307 END(sb1250_altcpu_start2)
309 /*  *********************************************************************
310     *  SB1250_ALTCPU_KILL
311     *  
312     *  Kill a secondary CPU, causing it to return to the idle
313     *  loop.  We do this by switching to uncached mode, 
314     *  asserting RESET on the other CPU, and then re-run
315     *  ALTCPU_START again.
316     *  
317     *  Input parameters: 
318     *      nothing
319     *      
320     *  Return value:
321     *      nothing
322     ********************************************************************* */
324 LEAF(sb1250_altcpu_kill)
326         /*
327          * Don't do this if we have only one CPU. 
328          */
330                 la      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
331                 ld      t0,(t0)                 # Get system revision
332                 dsrl    t0,S_SYS_PART           # Shift part # to low bits
333                 dsrl    t0,8                    # isolate CPU part of number
334                 and     t0,0x0F                 # T0 = number of CPUs
335                 bgt     t0,1,1f                 # Keep going if more than one CPU
336                 j       ra                      # Go back home, nothing to do
339         /*
340          * More than one CPU, go ahead...
341          */
343                 move    t7,ra                   # save RA, we'll make calls
345 #ifdef _SB1250_PASS1_WORKAROUNDS_
346        #
347        # Not sure what we need to do here wrt cacheability of
348        # the genbus space, if anything.  Some portion of CPU1's
349        # istream will come from L1, but the data should all be from
350        # DRAM.  These references will be cacheable noncoherent,
351        # should we worry if cpu0 is coherent shared at this time?
352        # probably.
353        #
354 #endif
356         #
357         # XXX For now, this only works on dual-CPU machines.
358         # XXX some work needs to be done to handle more than 2 cores.
359         #
361                 move    t0,zero                 # zero the start address
362                 la      t1,cpu_startvectors
363                 SR      t0,REGSIZE(t1)          # Reset address of CPU1
365         #
366         # Flush the D cache to ensure that the write above made it 
367         # out of our L1.
368         #
370                 jal     sb1250_l1cache_flush_d  # uses t0, t2, t3
372         #
373         # Switch to KSEG1 to quiesce our cache activity.
374         #
376                 bal     altcpu_kseg1_switch     # switch to uncached mode
378         #
379         # Force CPU1 into reset
380         #
382                 li      a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG)
383                 ld      t0,0(a0)
384                 dli     t1,M_SYS_CPU_RESET_1    # Reset mask
385                 or      t0,t1                   # New value to write
386                 sd      t0,0(a0)                # CPU1 is now in reset
388         #
389         # Not sure how long we're supposed to wait.
390         #
391                 ssnop
392                 ssnop
393                 ssnop
394                 ssnop
396         #
397         # Now restart CPU1
398         #
400                 bal     sb1250_altcpu_start1
402         #
403         # It's safe to be cached again.
404         #
406                 bal     altcpu_kseg0_switch
408         #
409         # At this point, CPU1 is waiting for us to indicate that it's
410         # okay to use memory again.  Ring its doorbell.
411         #
413                 la      a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_SET_CPU))
414                 LR      t0,mem_datareloc
415                 or      t0,1
416                 sd      t0,0(a0)
418         #
419         # CPU1 is back in our control.
420         #
422                 move    ra,t7
423                 move    v0,zero
425                 j       ra
428 END(sb1250_altcpu_kill)
431 /*  *********************************************************************
432     *  ALTCPU_RESET
433     *  
434     *  Start address for secondary CPU(s) - do the initialization of
435     *  the local CPU and then notify CPU0 that we're done.
436     *
437     *  This routine is called in KSEG1.
438     *  
439     *  Input parameters: 
440     *      t0 - CPU identifier
441     *      
442     *  Return value:
443     *      nothing
444     ********************************************************************* */
447 LEAF(sb1250_altcpu_reset)
450                 mfc0    t0,C0_PRID              # get CPU PRID register
451                 and     t0,t0,0xe000000         # determine cpu number
452                 beq     t0,zero,iscpu0          # go if  on CPU0
454         /*
455          * Note: we should never get to the CPU1 code if we're
456          * with only one CPU.  Theoretically, nobody got past the
457          * check in altcpu_start.  But, just in case, if we
458          * get here and we're on CPU1, and we supposedly only
459          * have one CPU, reset CPU1.
460          */
462                 la      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
463                 ld      t0,(t0)                 # Get system revision
464                 dsrl    t0,S_SYS_PART           # Shift part # to low bits
465                 dsrl    t0,8                    # isolate CPU part of number
466                 and     t0,0x0F                 # T0 = number of CPUs
467                 beq     t0,1,iscpu0             # If only one CPU, kill off CPU1
470         /*
471          * Initialize CPU registers.
472          */
474                 CALLINIT_KSEG1(altcpu_table,R_ALT_CPUINIT)
476 #ifdef _SB1250_PASS1_WORKAROUNDS_
478                 SETCCAMODE(v0,K_CFG_K0COH_CACHEABLE) /* cacheable NONCOHERENT */
479 #endif
481                 SETLEDS1('C','P','U','1')
483         /*
484          * Initialize the L1 cache
485          */
487 #if CFG_INIT_L1
488                 CALLINIT_KSEG1(altcpu_table,R_ALT_L1CINIT)
489 #endif
492         /*
493          * Notify the SCD that we're done initializing.  Do this by 
494          * ringing CPU0's doorbell.
495          */
497                 la      a0,PHYS_TO_K1(A_IMR_REGISTER(0,R_IMR_MAILBOX_SET_CPU));
499                 mfc0    t0,C0_PRID              # get processor number
500                 srl     t0,t0,25                # shift CPU bits into low
501                 and     t0,t0,7                 # keep only low 3 bits
502                 li      t1,1                    # make a bit mask depending on CPU
503                 sll     t1,t1,t0                # calculate t1 = 1 shl cpu number
504                 sd      t1,0(a0)                # set corresponding bit in mailbox
507          /*
508           * Go to the idle loop
509           */
511                 b       altcpu_idle             # go to idle loop               
513          /*
514           * We get here if we were running on CPU0.  Make things
515           * pretty for the reset of CPU initialization.
516           */
519 iscpu0:         
521         /*
522          * If we are on CPU0, then force CPU1 into reset.  This is needed
523          * for the case where the firmware has crashed and we need to get
524          * control of the system again.
525          */
527                 li      a0,PHYS_TO_K1(A_SCD_SYSTEM_CFG)
528                 ld      t0,0(a0)
529                 dli     t1,M_SYS_CPU_RESET_1    # Reset mask
530                 or      t0,t1                   # New value to write
531                 sd      t0,0(a0)                # CPU1 is now in reset
533                 j       ra                      # return (we were on CPU 0)
535 END(sb1250_altcpu_reset)
538 /*  *********************************************************************
539     *  ALTCPU_CMD_START(cpu,addr)
540     *  
541     *  Start an alternate CPU.
542     *  
543     *  Input parameters: 
544     *      a0 - cpu number (must be 1 for the SB1250)
545     *      a1 - pointer to start parameters (four 64-bit values)
546     *             array[0] = start address (PC)
547     *             array[1] = start stack pointer (SP)
548     *             array[2] = start global pointer (GP)
549     *             array[3] = start user argument (A1)
550     *      
551     *  Return value:
552     *      v0 - 0 if ok
553     *      else -1 if request could not be handled
554     ********************************************************************* */
556 #define R_CPUSTART_PCVAL  0
557 #define R_CPUSTART_SPVAL  8
558 #define R_CPUSTART_GPVAL  16
559 #define R_CPUSTART_A1VAL  24
561 LEAF(altcpu_cmd_start)
563                 li      v0,-1           /* assume failure */
564                 bne     a0,1,1f         /* go if not CPU 1 */
566         /*
567          * Return an error if running in uniprocessor mode.
568          */
570                 la      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
571                 ld      t0,(t0)                 # Get system revision
572                 dsrl    t0,S_SYS_PART           # Shift part # to low bits
573                 dsrl    t0,8                    # isolate CPU part of number
574                 and     t0,0x0F                 # T0 = number of CPUs
575                 beq     t0,1,1f                 # If only one CPU, error.
577         /*
578          * Multiprocessor mode, start the other CPU
579          */
581                 move    t0,a0           /* get CPU number */
582                 sll     t0,BPWSIZE      /* multiply by 8/4 for 64/32-bit offset */
584                 la      t1,cpu_start_gpvals
585                 add     t1,t0           /* copy the GP value */
586                 ld      t2,R_CPUSTART_GPVAL(a1)
587                 SR      t2,0(t1)
589                 la      t1,cpu_start_spvals
590                 add     t1,t0           /* copy the SP value */
591                 ld      t2,R_CPUSTART_SPVAL(a1)
592                 SR      t2,0(t1)
594                 la      t1,cpu_start_args
595                 add     t1,t0           /* copy the A1 value */
596                 ld      t2,R_CPUSTART_A1VAL(a1)
597                 SR      t2,0(t1)
599                 la      t1,cpu_startvectors
600                 add     t1,t0           /* copy the PC value */
601                 ld      t2,R_CPUSTART_PCVAL(a1)
602                 SR      t2,0(t1)
604                 move    v0,zero         /* success */
606 1:              j       ra
608 END(altcpu_cmd_start)
610 /*  *********************************************************************
611     *  ALTCPU_CMD_STOP(cpu)
612     *  
613     *  Stop the specified CPU.
614     *  
615     *  We don't really support this at the moment.
616     *  
617     *  Input parameters: 
618     *      a0 - cpu number
619     *      
620     *  Return value:
621     *      v0 - 0 if ok, else error code
622     ********************************************************************* */
624 LEAF(altcpu_cmd_stop)
626                 li      v0,-1           /* assume failure */
627                 bne     a0,1,1f         /* go if not CPU 1 */
629         /*
630          * Return an error if running in uniprocessor mode.
631          */
633                 la      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
634                 ld      t0,(t0)                 # Get system revision
635                 dsrl    t0,S_SYS_PART           # Shift part # to low bits
636                 dsrl    t0,8                    # isolate CPU part of number
637                 and     t0,0x0F                 # T0 = number of CPUs
638                 beq     t0,1,1f                 # If only one CPU, error.
640         /*
641          * Multiprocessor mode, stop the other CPU
642          */
644                 b       sb1250_altcpu_kill      /* kill the CPU */
646 1:              j       ra
648 END(altcpu_cmd_stop)
650 /*  *********************************************************************
651     *  ALTCPU_IDLE
652     *  
653     *  Loop forever waiting for someone to tell us where to go.
654     *  
655     *  Input parameters: 
656     *      nothing.
657     *      
658     *  Return value:
659     *      nothing
660     ********************************************************************* */
662 altcpu_idle:    
664         /*
665          * Switch to KSEG0 (cached)
666          */
668                 bal     altcpu_kseg0_switch
670                 SETLEDS('c','p','u','1')
674 1:              la      a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_CPU))
675                 ld      t0,(a0)                 # Read mailbox
676                 beq     t0,zero,1b              # Loop till the bit is set
678         /*
679          * Clear all the bits in the mailbox register to dismiss the 
680          * pending interrupt 
681          */
683                 la      a0,PHYS_TO_K1(A_IMR_REGISTER(1,R_IMR_MAILBOX_CLR_CPU))
684                 li      t1,-1
685                 sd      t1,0(a0)
688         /*
689          * We may need GP, especially in relocated version
690          *
691          * Yucky hack: The relocation factor was passed to us in
692          * the mailbox register, which is conveniently in t0 right now.
693          * (except the lower bit is set just in case the reloc was
694          * zero, so clear that first).
695          */
697                 li      t1,1                    # 1
698                 not     t1                      # FFFFFFFFE
699                 and     t0,t1                   # clear lower bit.
701                 LOADREL(a0,altcpu_table)
702                 LR      gp,R_ALT_GP(a0)
703                 ADD     gp,t0                   # relocate GP.
705 #if CFG_EMBEDDED_PIC
706         /* 
707          * Now that we can talk to memory again, get the "text relocation"
708          * and move the loop into DRAM.
709          */
711 __AltCpuGoRel:
712                 LR      t1,mem_textreloc        # will get from GP-relative addr
713                 LOADREL(t0,altcpu_gorel)        # get addr of next instruction
714                 add     t0,t1                   # add in relocation factor
715                 j       t0
716 altcpu_gorel:   nop
717 #endif
720         /*
721          * Get our processor number
722          */
724                 mfc0    t0,C0_PRID              # Get PRID (for processor id)
726                 srl     t0,t0,25                # shift CPU bits into low
727                 and     t0,t0,7                 # keep only low 3 bits
728                 sll     t0,t0,BPWSIZE           # mult by 8/4 for 64/32-bit offset
730         /*
731          * Set up registers like we were launching a program.
732          */
734                 LR      a2,R_ALT_APIENTRY(a0) # A2 = firmware entry vector
735                 move    a0,gp           # A0 = handle
736                 li      a3,CFE_EPTSEAL  # A3 = entrypoint signature
739 #ifdef _SB1250_PASS1_WORKAROUNDS_
740         /*
741          * Okay, it's safe now to be coherent.  
742          * Flush the D cache to invalidate all the lines we have,
743          * then change the config register back.
744          *
745          * Danger! It's imperative that *no stores to memory* be done
746          * prior to this point, otherwise flushing the cache
747          * will race with core 0, which will also be flushing
748          * lines at this time.
749          */
750                 move    k0,t0
751                 jal     sb1250_l1cache_flush_d
752                 SETCCAMODE(v0,K_CFG_K0COH_COHERENT) /* cacheable coherent */
753                 move    t0,k0
754 #endif
756         /*
757          * Read the start address from the CPU restart table
758          * and jump to it.  For an idle CPU, the address in the
759          * table below will be the zero, causing
760          * the CPU to loop forever.  To start a secondary CPU,
761          * just write an address in cpu_startvectors[cpu_id]
762          *
763          * Warning: This kind of assumes that this code will 
764          * live in cacheable space.  If it doesn't, it will
765          * probably cause lots of unwanted bus traffic.
766          */
767                 li      s4,0
769 loop_forever:   LR      t1,cpu_startvectors(t0) # Load address of routine
770                 beq     t1,zero,loop_forever
771                 LR      a1,cpu_start_args(t0)   # Load user argument (A1)
772                 LR      sp,cpu_start_spvals(t0) # Load stack pointer
773                 LR      t2,cpu_start_gpvals(t0) # Load global pointer
774                 move    gp,t2                   # and put in real register
775                 j       t1                      # jump to start address
778 /*  *********************************************************************
779     *  End
780     ********************************************************************* */