1/*
2 *
3 * This file is subject to the terms and conditions of the GNU General Public
4 * License.  See the file "COPYING" in the main directory of this archive
5 * for more details.
6 *
7 *   (Code copied from or=ther files)
8 * Copyright (C) 1998-2000 Hewlett-Packard Co
9 * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
10 *
11 * Copyright (C) 2000-2003 Silicon Graphics, Inc. All rights reserved.
12 */
13
14
15
16#define __ASSEMBLY__ 1
17#include <linux/config.h>
18#include <asm/processor.h>
19#include <asm/sn/addrs.h>
20#include <asm/sn/sn2/shub_mmr.h>
21
22/*
23 * This file contains additional set up code that is needed to get going on
24 * Medusa.  This code should disappear once real hw is available.
25 *
26 * On entry to this routine, the following register values are assumed:
27 *
28 *	gr[8]	- BSP cpu
29 *	pr[9]	- kernel entry address
30 *	pr[10]	- cpu number on the node
31 *
32 * NOTE:
33 *   This FPROM may be loaded/executed at an address different from the
34 *   address that it was linked at. The FPROM is linked to run on node 0
35 *   at address 0x100000. If the code in loaded into another node, it
36 *   must be loaded at offset 0x100000 of the node. In addition, the
37 *   FPROM does the following things:
38 *		- determine the base address of the node it is loaded on
39 *		- add the node base to _gp.
40 *		- add the node base to all addresses derived from "movl"
41 *		  instructions. (I couldnt get GPREL addressing to work)
42 *		  (maybe newer versions of the tools will support this)
43 *		- scan the .got section and add the node base to all
44 *		  pointers in this section.
45 *		- add the node base to all physical addresses in the
46 *		  SAL/PAL/EFI table built by the C code. (This is done
47 *		  in the C code - not here)
48 *		- add the node base to the TLB entries for vmlinux
49 */
50
51#define KERNEL_BASE	0xe000000000000000
52#define BOOT_PARAM_ADDR 0x40000
53
54
55/*
56 * ar.k0 gets set to IOPB_PA value, on 460gx chipset it should
57 * be 0x00000ffffc000000, but on snia we use the (inverse swizzled)
58 * IOSPEC_BASE value
59 */
60#ifdef SGI_SN2
61#define IOPB_PA		0xc000000fcc000000
62#endif
63
64#define RR_RID		8
65
66
67
68// ====================================================================================
69        .text
70        .align 16
71	.global _start
72	.proc _start
73_start:
74
75// Setup psr and rse for system init
76	mov		psr.l = r0;;
77	srlz.d;;
78	invala
79	mov		ar.rsc = r0;;
80	loadrs
81	;;
82
83// Isolate node number we are running on.
84	mov		r6 = ip;;
85#ifdef SGI_SN2
86	shr		r5 = r6,38			// r5 = node number
87	dep		r6 = 0,r6,0,36			// r6 = base memory address of node
88
89#endif
90
91
92// Set & relocate gp.
93	movl		r1= __gp;;			// Add base memory address
94	or 		r1 = r1,r6			// Relocate to boot node
95
96// Lets figure out who we are & put it in the LID register.
97#ifdef SGI_SN2
98// On SN2, we (currently) pass the cpu number in r10 at boot
99	and		r25=3,r10;;
100	movl		r16=0x8000008110000400		// Allow IPIs
101	mov		r17=-1;;
102	st8		[r16]=r17
103	movl		r16=0x8000008110060580;;	// SHUB_ID
104	ld8		r27=[r16];;
105	extr.u		r27=r27,32,11;;
106	shl 		r26=r25,28;;			// Align local cpu# to lid.eid
107	shl 		r27=r27,16;;			// Align NASID to lid.id
108	or  		r26=r26,r27;;			// build the LID
109#else
110// The BR_PI_SELF_CPU_NUM register gives us a value of 0-3.
111// This identifies the cpu on the node.
112// Merge the cpu number with the NASID to generate the LID.
113	movl		r24=0x80000a0001000020;;	// BR_PI_SELF_CPU_NUM
114	ld8 		r25=[r24]			// Fetch PI_SELF
115	movl		r27=0x80000a0001600000;;	// Fetch REVID to get local NASID
116	ld8 		r27=[r27];;
117	extr.u		r27=r27,32,8;;
118	shl 		r26=r25,16;;			// Align local cpu# to lid.eid
119	shl 		r27=r27,24;;			// Align NASID to lid.id
120	or  		r26=r26,r27;;			// build the LID
121#endif
122	mov 		cr.lid=r26			// Now put in in the LID register
123
124	movl		r2=FPSR_DEFAULT;;
125	mov 		ar.fpsr=r2
126	movl		sp = bootstacke-16;;
127	or 		sp = sp,r6			// Relocate to boot node
128
129// Save the NASID that we are loaded on.
130	movl		r2=base_nasid;;			// Save base_nasid for C code
131	or 		r2 = r2,r6;;			// Relocate to boot node
132  	st8 		[r2]=r5				// Uncond st8 - same on all cpus
133
134// Save the kernel entry address. It is passed in r9 on one of
135// the cpus.
136	movl		r2=bsp_entry_pc
137	cmp.ne		p6,p0=r9,r0;;
138	or 		r2 = r2,r6;;			// Relocate to boot node
139(p6)  	st8 		[r2]=r9				// Uncond st8 - same on all cpus
140
141
142// The following can ONLY be done by 1 cpu. Lets set a lock - the
143// cpu that gets it does the initilization. The rest just spin waiting
144// til initilization is complete.
145	movl		r22 = initlock;;
146	or		r22 = r22,r6			// Relocate to boot node
147	mov		r23 = 1;;
148	xchg8		r23 = [r22],r23;;
149	cmp.eq 		p6,p0 = 0,r23
150(p6)	br.cond.spnt.few init
1511:	ld4		r23 = [r22];;
152	cmp.eq		p6,p0 = 1,r23
153(p6)	br.cond.sptk	1b
154	br		initx
155
156// Add base address of node memory to each pointer in the .got section.
157init:	movl		r16 = _GLOBAL_OFFSET_TABLE_;;
158	or		r16 = r16,r6;;			// Relocate to boot node
1591: 	ld8		r17 = [r16];;
160	cmp.eq		p6,p7=0,r17
161(p6)	br.cond.sptk.few.clr 2f;;
162	or		r17 = r17,r6;;			// Relocate to boot node
163	st8		[r16] = r17,8
164	br		1b
1652:
166	mov		r23 = 2;;			// All done, release the spinning cpus
167	st4		[r22] = r23
168initx:
169
170//
171//	I/O-port space base address:
172//
173	movl		r2 = IOPB_PA;;
174	mov		ar.k0 = r2
175
176
177// Now call main & pass it the current LID value.
178	alloc 		r2=ar.pfs,0,0,2,0
179	mov    		r32=r26
180	mov   		r33=r8;;
181	br.call.sptk.few rp=fmain
182
183// Initialize Region Registers
184//
185        mov             r10 = r0
186        mov             r2 = (13<<2)
187        mov             r3 = r0;;
1881:      cmp4.gtu        p6,p7 = 7, r3
189        dep             r10 = r3, r10, 61, 3
190        dep             r2 = r3, r2, RR_RID, 4;;
191(p7)    dep             r2 = 0, r2, 0, 1;;
192(p6)    dep             r2 = -1, r2, 0, 1;;
193        mov             rr[r10] = r2
194        add             r3 = 1, r3;;
195        srlz.d;;
196        cmp4.gtu        p6,p0 = 8, r3
197(p6)    br.cond.sptk.few.clr 1b
198
199//
200// Return value indicates if we are the BSP or AP.
201// 	   1 = BSP, 0 = AP
202	mov             cr.tpr=r0;;
203	cmp.eq		p6,p0=r8,r0
204(p6)	br.cond.spnt	slave
205
206//
207// Go to kernel C startup routines
208//	Need to do a "rfi" in order set "it" and "ed" bits in the PSR.
209//	This is the only way to set them.
210
211	movl		r28=BOOT_PARAM_ADDR
212	movl		r2=bsp_entry_pc;;
213	or 		r28 = r28,r6;;			// Relocate to boot node
214	or 		r2 = r2,r6;;			// Relocate to boot node
215	ld8		r2=[r2];;
216	or		r2=r2,r6;;
217	dep		r2=0,r2,61,3;;			// convert to phys mode
218
219//
220// Turn on address translation, interrupt collection, psr.ed, protection key.
221// Interrupts (PSR.i) are still off here.
222//
223
224        movl            r3 = (  IA64_PSR_BN | \
225                                IA64_PSR_AC | \
226                                IA64_PSR_DB | \
227                                IA64_PSR_DA | \
228                                IA64_PSR_IC   \
229                             )
230        ;;
231        mov             cr.ipsr = r3
232
233//
234// Go to kernel C startup routines
235//      Need to do a "rfi" in order set "it" and "ed" bits in the PSR.
236//      This is the only way to set them.
237
238	mov		r8=r28;;
239	bsw.1		;;
240	mov		r28=r8;;
241	bsw.0		;;
242        mov             cr.iip = r2
243        srlz.d;;
244        rfi;;
245
246	.endp		_start
247
248
249
250// Slave processors come here to spin til they get an interrupt. Then they launch themselves to
251// the place ap_entry points. No initialization is necessary - the kernel makes no
252// assumptions about state on this entry.
253//	Note: should verify that the interrupt we got was really the ap_wakeup
254//	      interrupt but this should not be an issue on medusa
255slave:
256	mov		r8=cr.irr0;;			// Check for interrupt pending.
257	cmp.eq		p6,p0=r8,r0
258	;;
259(p6)	nop.i		0x8beef				// Medusa - put cpu to sleep til interrupt occurs
260(p6)	br.cond.sptk	slave;;
261
262	mov		r8=cr.ivr;;			// Got one. Must read ivr to accept it
263	srlz.d;;
264	mov		cr.eoi=r0;;			// must write eoi to clear
265	movl		r8=ap_entry;;			// now jump to kernel entry
266	or 		r8 = r8,r6;;			// Relocate to boot node
267	ld8		r9=[r8],8;;
268	ld8		r1=[r8]
269	mov		b0=r9;;
270	br		b0
271
272// Here is the kernel stack used for the fake PROM
273	.bss
274	.align		16384
275bootstack:
276	.skip		16384
277bootstacke:
278initlock:
279	data4
280
281
282
283//////////////////////////////////////////////////////////////////////////////////////////////////////////
284// This code emulates the PAL. Only essential interfaces are emulated.
285
286
287	.text
288	.global	pal_emulator
289	.proc	pal_emulator
290pal_emulator:
291	mov	r8=-1
292
293	mov	r9=256
294	;;
295	cmp.gtu p6,p7=r9,r28		/* r28 <= 255? */
296(p6)	br.cond.sptk.few static
297	;;
298	mov	r9=512
299	;;
300	cmp.gtu p6,p7=r9,r28
301(p6)	br.cond.sptk.few stacked
302	;;
303
304static:	cmp.eq	p6,p7=6,r28		/* PAL_PTCE_INFO */
305(p7)	br.cond.sptk.few 1f
306	movl	r8=0				/* status = 0 */
307	movl	r9=0x100000000			/* tc.base */
308	movl	r10=0x0000000200000003		/* count[0], count[1] */
309	movl	r11=0x1000000000002000		/* stride[0], stride[1] */
310	;;
311
3121:	cmp.eq	p6,p7=14,r28		/* PAL_FREQ_RATIOS */
313(p7)	br.cond.sptk.few 1f
314	movl	r8=0				/* status = 0 */
315	movl	r9 =0x100000064			/* proc_ratio (1/100) */
316	movl	r10=0x100000100			/* bus_ratio<<32 (1/256) */
317	movl	r11=0x10000000a			/* itc_ratio<<32 (1/100) */
318	;;
319
3201:	cmp.eq	p6,p7=8,r28		/* PAL_VM_SUMMARY */
321(p7)	br.cond.sptk.few 1f
322	movl	r8=0
323#ifdef SGI_SN2
324	movl	r9=0x0203083001151065
325	movl	r10=0x183f
326#endif
327	movl	r11=0
328	;;
329
3301:	cmp.eq	p6,p7=19,r28		/* PAL_RSE_INFO */
331(p7)	br.cond.sptk.few 1f
332	movl	r8=0
333	movl	r9=0x60
334	movl	r10=0x0
335	movl	r11=0
336	;;
337
3381:	cmp.eq	p6,p7=15,r28		/* PAL_PERF_MON_INFO */
339(p7)	br.cond.sptk.few 1f
340	movl	r8=0
341	movl	r9=0x08122004
342	movl	r10=0x0
343	movl	r11=0
344	mov	r2=ar.lc
345	mov	r3=16;;
346	mov	ar.lc=r3
347	mov	r3=r29;;
3485:	st8	[r3]=r0,8
349	br.cloop.sptk.few 5b;;
350	mov	ar.lc=r2
351	mov	r3=r29
352	movl	r2=0x1fff;;			/* PMC regs */
353	st8	[r3]=r2
354	add	r3=32,r3
355	movl	r2=0x3ffff;;			/* PMD regs */
356	st8	[r3]=r2
357	add	r3=32,r3
358	movl	r2=0xf0;;			/* cycle regs */
359	st8	[r3]=r2
360	add	r3=32,r3
361	movl	r2=0x10;;			/* retired regs */
362	st8	[r3]=r2
363	;;
364
3651:	cmp.eq	p6,p7=34,r28		/* PAL_VM_PAGE_SIZE */
366(p7)	br.cond.sptk.few 1f
367	movl	r8=0				/* status = 0 */
368	movl	r9=0x015557000			/* insertable page sizes */
369	movl	r10=0x115557000			/* purgeable page sizes */
370	movl	r11=0
371
3721:	cmp.eq	p6,p7=19,r28		/* PAL_RSE_INFO */
373(p7)	br.cond.sptk.few 1f
374	movl	r8=0				/* status = 0 */
375	movl	r9=96				/* num phys stacked */
376	movl	r10=0				/* hints */
377	movl	r11=0
378	;;
379
3801:	cmp.eq	p6,p7=1,r28		/* PAL_CACHE_FLUSH */
381(p7)	br.cond.sptk.few 1f
382	mov	r9=ar.lc
383	movl	r8=524288				/* flush 512k million cache lines (16MB) */
384	;;
385	mov	ar.lc=r8
386	movl	r8=0xe000000000000000
387	;;
388.loop:	fc	r8
389	add	r8=32,r8
390	br.cloop.sptk.few .loop
391	sync.i
392	;;
393	srlz.i
394	;;
395	mov	ar.lc=r9
396	mov	r8=r0
3971:	br.cond.sptk.few rp
398
399stacked:
400	br.ret.sptk.few rp
401
402	.endp pal_emulator
403
404