2c9c60389239d4816c17977f67b99cffbdf33a24
[linux-flexiantxendom0-3.2.10.git] / arch / ia64 / sn / fakeprom / fpromasm.S
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-2002 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 CONFIG_IA64_SGI_SN1
61 #define IOPB_PA         0xc0000FFFFC000000
62 #else
63 #define IOPB_PA         0xc000000fcc000000
64 #endif
65
66 #define RR_RID          8
67
68
69
70 // ==================================================================================== 
71         .text
72         .align 16
73         .global _start
74         .proc _start
75 _start:
76
77 // Setup psr and rse for system init
78         mov             psr.l = r0;;
79         srlz.d;;
80         invala
81         mov             ar.rsc = r0;;
82         loadrs
83         ;;
84
85 // Isolate node number we are running on.
86         mov             r6 = ip;;
87 #ifdef CONFIG_IA64_SGI_SN1
88         shr             r5 = r6,33;;                    // r5 = node number
89         shl             r6 = r5,33                      // r6 = base memory address of node
90 #else
91         shr             r5 = r6,38                      // r5 = node number
92         dep             r6 = 0,r6,0,36                  // r6 = base memory address of node
93
94 #endif
95
96
97 // Set & relocate gp.
98         movl            r1= __gp;;                      // Add base memory address
99         or              r1 = r1,r6                      // Relocate to boot node
100
101 // Lets figure out who we are & put it in the LID register.
102 #ifdef CONFIG_IA64_SGI_SN2
103 // On SN2, we (currently) pass the cpu number in r10 at boot
104         and             r25=3,r10;;
105         movl            r16=0x8000008110000400          // Allow IPIs
106         mov             r17=-1;;
107         st8             [r16]=r17
108         movl            r16=0x8000008110060580;;        // SHUB_ID
109         ld8             r27=[r16];;
110         extr.u          r27=r27,32,11;;
111         shl             r26=r25,28;;                    // Align local cpu# to lid.eid
112         shl             r27=r27,16;;                    // Align NASID to lid.id
113         or              r26=r26,r27;;                   // build the LID
114 #else
115 // The BR_PI_SELF_CPU_NUM register gives us a value of 0-3.
116 // This identifies the cpu on the node. 
117 // Merge the cpu number with the NASID to generate the LID.
118         movl            r24=0x80000a0001000020;;        // BR_PI_SELF_CPU_NUM
119         ld8             r25=[r24]                       // Fetch PI_SELF
120         movl            r27=0x80000a0001600000;;        // Fetch REVID to get local NASID
121         ld8             r27=[r27];;
122         extr.u          r27=r27,32,8;;
123         shl             r26=r25,16;;                    // Align local cpu# to lid.eid
124         shl             r27=r27,24;;                    // Align NASID to lid.id
125         or              r26=r26,r27;;                   // build the LID
126 #endif
127         mov             cr.lid=r26                      // Now put in in the LID register
128
129         movl            r2=FPSR_DEFAULT;;
130         mov             ar.fpsr=r2
131         movl            sp = bootstacke-16;;
132         or              sp = sp,r6                      // Relocate to boot node                        
133
134 // Save the NASID that we are loaded on.
135         movl            r2=base_nasid;;                 // Save base_nasid for C code
136         or              r2 = r2,r6;;                    // Relocate to boot node
137         st8             [r2]=r5                         // Uncond st8 - same on all cpus
138
139 // Save the kernel entry address. It is passed in r9 on one of
140 // the cpus.
141         movl            r2=bsp_entry_pc
142         cmp.ne          p6,p0=r9,r0;;
143         or              r2 = r2,r6;;                    // Relocate to boot node
144 (p6)    st8             [r2]=r9                         // Uncond st8 - same on all cpus
145
146
147 // The following can ONLY be done by 1 cpu. Lets set a lock - the
148 // cpu that gets it does the initilization. The rest just spin waiting
149 // til initilization is complete.
150         movl            r22 = initlock;;
151         or              r22 = r22,r6                    // Relocate to boot node
152         mov             r23 = 1;;
153         xchg8           r23 = [r22],r23;;
154         cmp.eq          p6,p0 = 0,r23
155 (p6)    br.cond.spnt.few init
156 1:      ld4             r23 = [r22];;
157         cmp.eq          p6,p0 = 1,r23
158 (p6)    br.cond.sptk    1b
159         br              initx
160
161 // Add base address of node memory to each pointer in the .got section.
162 init:   movl            r16 = _GLOBAL_OFFSET_TABLE_;;
163         or              r16 = r16,r6;;                  // Relocate to boot node
164 1:      ld8             r17 = [r16];;
165         cmp.eq          p6,p7=0,r17
166 (p6)    br.cond.sptk.few.clr 2f;;
167         or              r17 = r17,r6;;                  // Relocate to boot node
168         st8             [r16] = r17,8
169         br              1b
170 2:
171         mov             r23 = 2;;                       // All done, release the spinning cpus
172         st4             [r22] = r23
173 initx:
174
175 //
176 //      I/O-port space base address:
177 //
178         movl            r2 = IOPB_PA;;
179         mov             ar.k0 = r2
180
181
182 // Now call main & pass it the current LID value.
183         alloc           r2=ar.pfs,0,0,2,0
184         mov             r32=r26
185         mov             r33=r8;;
186         br.call.sptk.few rp=fmain
187         
188 // Initialize Region Registers
189 //
190         mov             r10 = r0
191         mov             r2 = (13<<2)
192         mov             r3 = r0;;
193 1:      cmp4.gtu        p6,p7 = 7, r3
194         dep             r10 = r3, r10, 61, 3
195         dep             r2 = r3, r2, RR_RID, 4;;
196 (p7)    dep             r2 = 0, r2, 0, 1;;
197 (p6)    dep             r2 = -1, r2, 0, 1;;
198         mov             rr[r10] = r2
199         add             r3 = 1, r3;;
200         srlz.d;;
201         cmp4.gtu        p6,p0 = 8, r3
202 (p6)    br.cond.sptk.few.clr 1b
203
204 //
205 // Return value indicates if we are the BSP or AP.
206 //         1 = BSP, 0 = AP
207         mov             cr.tpr=r0;;
208         cmp.eq          p6,p0=r8,r0
209 (p6)    br.cond.spnt    slave
210
211 //
212 // Go to kernel C startup routines
213 //      Need to do a "rfi" in order set "it" and "ed" bits in the PSR.
214 //      This is the only way to set them.
215
216         movl            r28=BOOT_PARAM_ADDR
217         movl            r2=bsp_entry_pc;;
218         or              r28 = r28,r6;;                  // Relocate to boot node
219         or              r2 = r2,r6;;                    // Relocate to boot node
220         ld8             r2=[r2];;
221         or              r2=r2,r6;;
222         dep             r2=0,r2,61,3;;                  // convert to phys mode
223
224 //
225 // Turn on address translation, interrupt collection, psr.ed, protection key.
226 // Interrupts (PSR.i) are still off here.
227 //
228
229         movl            r3 = (  IA64_PSR_BN | \
230                                 IA64_PSR_AC | \
231                                 IA64_PSR_DB | \
232                                 IA64_PSR_DA | \
233                                 IA64_PSR_IC   \
234                              )
235         ;;
236         mov             cr.ipsr = r3
237
238 //
239 // Go to kernel C startup routines
240 //      Need to do a "rfi" in order set "it" and "ed" bits in the PSR.
241 //      This is the only way to set them.
242
243         mov             r8=r28;;
244         bsw.1           ;;
245         mov             r28=r8;;
246         bsw.0           ;;
247         mov             cr.iip = r2
248         srlz.d;;
249         rfi;;
250
251         .endp           _start
252
253
254
255 // Slave processors come here to spin til they get an interrupt. Then they launch themselves to
256 // the place ap_entry points. No initialization is necessary - the kernel makes no
257 // assumptions about state on this entry.
258 //      Note: should verify that the interrupt we got was really the ap_wakeup
259 //            interrupt but this should not be an issue on medusa
260 slave:
261         nop.i           0x8beef                         // Medusa - put cpu to sleep til interrupt occurs
262         mov             r8=cr.irr0;;                    // Check for interrupt pending.
263         cmp.eq          p6,p0=r8,r0
264 (p6)    br.cond.sptk    slave;;
265
266         mov             r8=cr.ivr;;                     // Got one. Must read ivr to accept it
267         srlz.d;;
268         mov             cr.eoi=r0;;                     // must write eoi to clear
269         movl            r8=ap_entry;;                   // now jump to kernel entry
270         or              r8 = r8,r6;;                    // Relocate to boot node
271         ld8             r9=[r8],8;;
272         ld8             r1=[r8]
273         mov             b0=r9;;
274         br              b0
275
276 // Here is the kernel stack used for the fake PROM
277         .bss
278         .align          16384
279 bootstack:
280         .skip           16384
281 bootstacke:
282 initlock:
283         data4
284
285
286
287 //////////////////////////////////////////////////////////////////////////////////////////////////////////
288 // This code emulates the PAL. Only essential interfaces are emulated.
289
290
291         .text
292         .global pal_emulator
293         .proc   pal_emulator
294 pal_emulator:
295         mov     r8=-1
296
297         mov     r9=256
298         ;;
299         cmp.gtu p6,p7=r9,r28            /* r28 <= 255? */
300 (p6)    br.cond.sptk.few static
301         ;;
302         mov     r9=512
303         ;;
304         cmp.gtu p6,p7=r9,r28
305 (p6)    br.cond.sptk.few stacked
306         ;;
307
308 static: cmp.eq  p6,p7=6,r28             /* PAL_PTCE_INFO */
309 (p7)    br.cond.sptk.few 1f
310         movl    r8=0                            /* status = 0 */
311         movl    r9=0x100000000                  /* tc.base */
312         movl    r10=0x0000000200000003          /* count[0], count[1] */
313         movl    r11=0x1000000000002000          /* stride[0], stride[1] */
314         ;;
315
316 1:      cmp.eq  p6,p7=14,r28            /* PAL_FREQ_RATIOS */
317 (p7)    br.cond.sptk.few 1f
318         movl    r8=0                            /* status = 0 */
319         movl    r9 =0x100000064                 /* proc_ratio (1/100) */
320         movl    r10=0x100000100                 /* bus_ratio<<32 (1/256) */
321         movl    r11=0x10000000a                 /* itc_ratio<<32 (1/100) */
322         ;;
323
324 1:      cmp.eq  p6,p7=8,r28             /* PAL_VM_SUMMARY */
325 (p7)    br.cond.sptk.few 1f
326         movl    r8=0
327 #ifdef CONFIG_IA64_SGI_SN1
328         movl    r9=0x0203083001151059
329         movl    r10=0x1232
330 #else
331         movl    r9=0x0203083001151065
332         movl    r10=0x183f
333 #endif
334         movl    r11=0
335         ;;
336
337 1:      cmp.eq  p6,p7=19,r28            /* PAL_RSE_INFO */
338 (p7)    br.cond.sptk.few 1f
339         movl    r8=0
340         movl    r9=0x60
341         movl    r10=0x0
342         movl    r11=0
343         ;;
344
345 1:      cmp.eq  p6,p7=15,r28            /* PAL_PERF_MON_INFO */
346 (p7)    br.cond.sptk.few 1f
347         movl    r8=0
348         movl    r9=0x08122004
349         movl    r10=0x0
350         movl    r11=0
351         mov     r2=ar.lc
352         mov     r3=16;;
353         mov     ar.lc=r3
354         mov     r3=r29;;
355 5:      st8     [r3]=r0,8
356         br.cloop.sptk.few 5b;;
357         mov     ar.lc=r2
358         mov     r3=r29
359         movl    r2=0x1fff;;                     /* PMC regs */
360         st8     [r3]=r2
361         add     r3=32,r3
362         movl    r2=0x3ffff;;                    /* PMD regs */
363         st8     [r3]=r2
364         add     r3=32,r3
365         movl    r2=0xf0;;                       /* cycle regs */
366         st8     [r3]=r2
367         add     r3=32,r3
368         movl    r2=0x10;;                       /* retired regs */
369         st8     [r3]=r2
370         ;;
371
372 1:      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
380 1:      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
397 1:      br.cond.sptk.few rp
398
399 stacked:
400         br.ret.sptk.few rp
401
402         .endp pal_emulator
403