1/*  *********************************************************************
2    *  Broadcom Common Firmware Environment (CFE)
3    *
4    *  API entry module				File: apientry.S
5    *
6    *  Low-level API entry point routines and some other misc stuff.
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    ********************************************************************* */
46
47
48#include "sbmips.h"
49#include "exception.h"
50
51#include "bsp_config.h"
52#include "cpu_config.h"
53
54#ifdef _CFE_
55#include "cfe_devfuncs.h"
56#else
57
58#if (CFG_BIENDIAN) && defined(__MIPSEB)
59#define CFE_EPTSEAL_REV 0x31454643
60#endif
61#define CFE_EPTSEAL 0x43464531
62
63#define cfe_command_restart 0
64#endif
65
66#ifndef CFG_STACK_SIZE
67#error "CFG_STACK_SIZE not defined"
68#else
69#define STACK_SIZE	((CFG_STACK_SIZE+1023) & ~1023)
70#endif
71
72#include "segtable.h"
73
74#if defined(_ZIPSTART_)
75#error "This should not be part of zipstart."
76#endif
77
78/*  *********************************************************************
79    *  Macros
80    ********************************************************************* */
81
82#include "mipsmacros.h"
83
84/*  *********************************************************************
85    *  Data
86    ********************************************************************* */
87
88#if CFG_MULTI_CPUS
89
90		.sdata
91		.globl	cfe_spinlock
92cfe_spinlock:	.word 0
93#endif
94
95
96/*  *********************************************************************
97    *  Code starts here
98    ********************************************************************* */
99
100
101		.text
102
103
104/*  *********************************************************************
105    *  cpu_apientry(handle,iocb)
106    *
107    *  API entry point for external apps.
108    *
109    *  Input parameters:
110    *  	   a0 - firmware handle (used to determine the location of
111    *  	        our relocated data)
112    *  	   a1 - pointer to IOCB to execute
113    *
114    *  Return value:
115    *  	   v0 - return code, 0 if ok
116    ********************************************************************* */
117
118#define _regidx(x)    ((x)*8)
119
120#define CAE_SRSAVE     _regidx(0)
121#define CAE_GPSAVE     _regidx(1)
122#define CAE_RASAVE     _regidx(2)
123#define CAE_S0SAVE     _regidx(3)
124#define CAE_S1SAVE     _regidx(4)
125#define CAE_S2SAVE     _regidx(5)
126#define CAE_S3SAVE     _regidx(6)
127#define CAE_S4SAVE     _regidx(7)
128#define CAE_S5SAVE     _regidx(8)
129#define CAE_S6SAVE     _regidx(9)
130#define CAE_S7SAVE     _regidx(10)
131#define CAE_K0SAVE     _regidx(11)
132#define CAE_K1SAVE     _regidx(12)
133
134#define CAE_STKSIZE    _regidx(14)
135
136#if defined(__MIPSEB)
137#define ENDIANOFFSET	4
138#else
139#define ENDIANOFFSET	0
140#endif
141
142#define R_XIOCB_FCODE  (8*0+ENDIANOFFSET)
143#define R_XIOCB_FLAGS  (8*3+ENDIANOFFSET)
144#define R_XIOCB_XSTAT  (8*5+ENDIANOFFSET)
145
146#define CFE_CMD_FW_RESTART	1
147#define CFE_FLG_WARMSTART     0x00000001
148
149LEAF(cpu_apientry)
150
151	/*
152	 * Gross: Make an explicit check here for a warm firmware restart,
153	 * to avoid setting up the stack and doing other nasty things
154	 * when we're just going to return to the firmware anyway.
155	 */
156
157		lw	t0,R_XIOCB_FCODE(a1)
158		bne	t0,CFE_CMD_FW_RESTART,notwarm
159		lw	t0,R_XIOCB_FLAGS(a1)
160		and	t0,CFE_FLG_WARMSTART
161		bne	t0,CFE_FLG_WARMSTART,notwarm
162
163	 /*
164	  * Disable interrupts before warm restart.  Don't bother
165	  * to save the results on the stack, we aren't going back.
166	  */
167
168		mfc0	t0,C0_SR		# Get current interrupt flag
169		and	t0,~M_SR_IE
170		mtc0	t0,C0_SR
171		HAZARD
172
173	 /*
174	  * Transfer control back to CFE, passing exit status.
175	  */
176
177		move	gp,a0			# Reset our GP
178		lw	a0,R_XIOCB_XSTAT(a1)	# Exit status
179		b	_cfe_warmstart
180
181	 /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
182
183  	 /*
184	  * Not a warm restart, run on the caller's stack.
185	  */
186
187notwarm:	sub	sp,CAE_STKSIZE		# Make room for our stuff
188
189		mfc0	v0,C0_SR		# Get current interrupt flag
190		SREG	v0,CAE_SRSAVE(sp)	# save on stack
191		li	t0,M_SR_IE		# master interrupt control
192		not	t0			# disable interrupts
193		and	v0,t0			# SR now has IE=0
194#if CPUCFG_REGS64
195		or	v0,M_SR_KX
196#endif
197		mtc0	v0,C0_SR		# put back into CP0
198		HAZARD
199
200		SREG	gp,CAE_GPSAVE(sp)	# save GP
201		SREG	ra,CAE_RASAVE(sp)	# and old RA
202
203		SREG	s0,CAE_S0SAVE(sp)
204		SREG	s1,CAE_S1SAVE(sp)
205		SREG	s2,CAE_S2SAVE(sp)
206		SREG	s3,CAE_S3SAVE(sp)
207		SREG	s4,CAE_S4SAVE(sp)
208		SREG	s5,CAE_S5SAVE(sp)
209		SREG	s6,CAE_S6SAVE(sp)
210		SREG	s7,CAE_S7SAVE(sp)
211		SREG	k0,CAE_K0SAVE(sp)
212		SREG	k1,CAE_K1SAVE(sp)
213
214		move	gp,a0			# set up new GP
215		move	a0,a1			# A0 points at IOCB
216
217#if CFG_MULTI_CPUS
218		SPIN_LOCK(cfe_spinlock,t0,t1)
219#endif
220
221		JAL(cfe_doxreq)
222
223#if CFG_MULTI_CPUS
224		SPIN_UNLOCK(cfe_spinlock,t0)
225#endif
226
227		#
228		# Restore the saved registers.
229		#
230
231		LREG	k1,CAE_K1SAVE(sp)
232		LREG	k0,CAE_K0SAVE(sp)
233		LREG	s7,CAE_S7SAVE(sp)
234		LREG	s6,CAE_S6SAVE(sp)
235		LREG	s5,CAE_S5SAVE(sp)
236		LREG	s4,CAE_S4SAVE(sp)
237		LREG	s3,CAE_S3SAVE(sp)
238		LREG	s2,CAE_S2SAVE(sp)
239		LREG	s1,CAE_S1SAVE(sp)
240		LREG	s0,CAE_S0SAVE(sp)
241
242		LREG	ra,CAE_RASAVE(sp)	# unwind the stack
243		LREG	gp,CAE_GPSAVE(sp)
244
245		LREG	t0,CAE_SRSAVE(sp)	# old interrupt mask
246
247		add	sp,CAE_STKSIZE		# restore old stack pointer
248
249		mtc0	t0,C0_SR		# restore interrupts
250		HAZARD
251		j	ra
252		nop
253END(cpu_apientry)
254
255
256
257/*  *********************************************************************
258    *  CFE_WARMSTART
259    *
260    *  Restart the command interpreter
261    *
262    *  Input parameters:
263    *      A0 - command status
264    *  	   nothing (GP has already been set up for us)
265    *
266    *  Return value:
267    *  	   nothing
268    ********************************************************************* */
269
270LEAF(cfe_warmstart)
271
272_cfe_warmstart:
273	/*
274	 * Reset the stack pointer.
275	 */
276
277		LR	sp,mem_heapstart
278		ADD	sp,((CFG_HEAP_SIZE*1024)+STACK_SIZE - 8)
279
280
281	/*
282	 * Undo any CP0 setup the calling program left behind.
283	 */
284
285		SR	a0,0(sp)
286		JAL(CPUCFG_CPURESTART)
287		LR	a0,0(sp)
288
289	 /*
290	  * If this is the 64-bit version, turn on the KX bit
291	  * to allow 64-bit accesses.
292	  */
293
294#if CPUCFG_REGS64
295		mfc0	t0,C0_SR
296		or	t0,t0,M_SR_KX
297		mtc0	t0,C0_SR
298		HAZARD
299#endif
300
301
302
303#ifdef notused
304		LR	v0,cfe_pagetable		# reestablish
305		dsll	v0,v0,13			# see mips_arena.c for this
306		dmtc0	v0,C0_CTEXT			# boot area TLBs
307
308		la	t9,sb1_cp0_init
309		jalr	t9
310#endif
311
312	/*
313	 * If someone called the API to do a warm start, clear the
314	 * spin lock, since the call will never return.
315	 */
316
317#if CFG_MULTI_CPUS
318		SPIN_UNLOCK(cfe_spinlock,t0)
319#endif
320
321	 /*
322	  * Switch back to using RAM vectors.
323	  */
324
325		mfc0	t0,C0_SR
326		and	t0,t0,~M_SR_BEV
327		mtc0	t0,C0_SR
328		HAZARD
329
330		JAL(cfe_command_restart)
331
332END(cfe_warmstart)
333
334
335
336/*  *********************************************************************
337    *  _GETSTATUS()
338    *
339    *  Read the STATUS register into v0
340    *
341    *  Input parameters:
342    *  	   nothing
343    *
344    *  Return value:
345    *  	   v0 - Status register
346    ********************************************************************* */
347
348LEAF(_getstatus)
349
350		mfc0	v0,C0_SR
351		j	ra
352END(_getstatus)
353
354/*  *********************************************************************
355    *  _SETSTATUS()
356    *
357    *  Set the STATUS register to the value in a0
358    *
359    *  Input parameters:
360    *  	   nothing
361    *
362    *  Return value:
363    *  	   v0 - Status register
364    ********************************************************************* */
365
366LEAF(_setstatus)
367
368		mtc0	a0,C0_SR
369		j	ra
370END(_setstatus)
371
372
373/*  *********************************************************************
374    *  _GETCAUSE()
375    *
376    *  Read the CAUSE register into v0
377    *
378    *  Input parameters:
379    *  	   nothing
380    *
381    *  Return value:
382    *  	   v0 - Cause register
383    ********************************************************************* */
384
385LEAF(_getcause)
386
387		mfc0	v0,C0_CAUSE
388		j	ra
389END(_getcause)
390
391
392/*  *********************************************************************
393    *  _GETTICKS()
394    *
395    *  Read the COUNT register into v0
396    *
397    *  Input parameters:
398    *  	   nothing
399    *
400    *  Return value:
401    *  	   v0 - count register
402    ********************************************************************* */
403
404LEAF(_getticks)
405
406		mfc0	v0,C0_COUNT
407		j	ra
408END(_getticks)
409
410
411/*  *********************************************************************
412    *  _SETALARM(ticks)
413    *
414    *  Set the C0_Compare register from a0
415    *
416    *  Input parameters:
417    *  	   a0 - compare register
418    *
419    *  Return value:
420    *  	   none
421    ********************************************************************* */
422
423LEAF(_setalarm)
424
425		mtc0	a0,C0_COMPARE
426		j	ra
427END(_setalarm)
428
429
430/*  *********************************************************************
431    *  _SETCONTEXT()
432    *
433    *  Set the CONTEXT register.
434    *
435    *  Input parameters:
436    *  	   a0 - context
437    *
438    *  Return value:
439    *  	   nothing
440    ********************************************************************* */
441
442LEAF(_setcontext)
443
444		MTC0	a0,C0_CTEXT
445		j	ra
446END(_setcontext)
447
448/*  *********************************************************************
449    *  _GETSEGTBL()
450    *
451    *  Return the address of the segment table.  We use this
452    *  to display the startup messages.
453    *
454    *  You can't just address the table from C because it lives
455    *  in the text segment.
456    *
457    *  Input parameters:
458    *  	   nothing
459    *
460    *  Return value:
461    *      address of table
462    ********************************************************************* */
463
464
465LEAF(_getsegtbl)
466		la	v0,segment_table
467		j	ra
468END(_getsegtbl)
469
470
471/*  *********************************************************************
472    *  _wbflush()
473    *
474    *  Flush the write buffer.  This is probably not necessary
475    *  on SiByte CPUs, but we have it for completeness.
476    *
477    *  Input parameters:
478    *  	   nothing
479    *
480    *  Return value:
481    *  	   nothing
482    ********************************************************************* */
483
484LEAF(_wbflush)
485
486		sync			/* drain the buffers */
487		la	t0,__junk	/* do an uncached read to force it out */
488		or	t0,K1BASE
489		lw	zero,0(t0)
490		j	ra
491
492END(_wbflush)
493
494
495/*  *********************************************************************
496    *  CFE_FLUSHCACHE
497    *
498    *  Perform certain cache operations
499    *
500    *  Input parameters:
501    *  	   a0 - flags (CFE_CACHE_xxx flags, or zero for a default)
502    *      a1,a2 - start/end of range for "range invalidate" operations
503    *      (not used otherwise)
504    *
505    *  Return value:
506    *  	   nothing
507    ********************************************************************* */
508
509LEAF(_cfe_flushcache)
510
511		sub	sp,56
512		SREG	ra,0(sp)
513		SREG	a0,8(sp)
514		SREG	s0,16(sp)
515		SREG	v1,24(sp)
516		SREG	s1,32(sp)
517		SREG	s2,40(sp)
518		SREG	s3,48(sp)
519		SREG	s4,56(sp)
520
521		JAL(CPUCFG_CACHEOPS)
522
523		LREG	s4,56(sp)
524		LREG	s3,48(sp)
525		LREG	s2,40(sp)
526		LREG	s1,32(sp)
527		LREG	v1,24(sp)
528		LREG	s0,16(sp)
529		LREG	a0,8(sp)
530		LREG	ra,0(sp)
531		add	sp,56
532		j	ra
533
534END(_cfe_flushcache)
535
536
537/*  *********************************************************************
538    *  End
539    ********************************************************************* */
540