]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/bcm/armv7.s
bcm: import changes for raspi2/3 from richard miller
[plan9front.git] / sys / src / 9 / bcm / armv7.s
1 /*
2  * Broadcom bcm2836 SoC, as used in Raspberry Pi 2
3  * 4 x Cortex-A7 processor (armv7)
4  */
5
6 #include "arm.s"
7
8 #define CACHELINESZ     64
9 #define ICACHELINESZ    32
10
11 #undef DSB
12 #undef DMB
13 #undef ISB
14 #define DSB     WORD    $0xf57ff04f     /* data synch. barrier; last f = SY */
15 #define DMB     WORD    $0xf57ff05f     /* data mem. barrier; last f = SY */
16 #define ISB     WORD    $0xf57ff06f     /* instr. sync. barrier; last f = SY */
17 #define WFI     WORD    $0xe320f003     /* wait for interrupt */
18 #define WFI_EQ  WORD    $0x0320f003     /* wait for interrupt if eq */
19 #define ERET    WORD    $0xe160006e     /* exception return from HYP */
20 #define SEV     WORD    $0xe320f004     /* send event */
21
22 /* tas/cas strex debugging limits; started at 10000 */
23 #define MAXSC 1000000
24
25 TEXT armstart(SB), 1, $-4
26
27         /*
28          * if not cpu0, go to secondary startup
29          */
30         CPUID(R1)
31         BNE     reset
32
33         /*
34          * go to SVC mode, interrupts disabled
35          */
36         BL      svcmode(SB)
37
38         /*
39          * disable the mmu and caches
40          */
41         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
42         BIC     $(CpCdcache|CpCicache|CpCmmu), R1
43         ORR     $(CpCsbo|CpCsw), R1
44         BIC     $CpCsbz, R1
45         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
46         BARRIERS
47
48         /*
49          * clear mach and page tables
50          */
51         MOVW    $PADDR(MACHADDR), R1
52         MOVW    $PADDR(KTZERO), R2
53 _ramZ:
54         MOVW    R0, (R1)
55         ADD     $4, R1
56         CMP     R1, R2
57         BNE     _ramZ
58
59         /*
60          * turn SMP on
61          * invalidate tlb
62          */
63         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
64         ORR     $CpACsmp, R1            /* turn SMP on */
65         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
66         BARRIERS
67         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
68         BARRIERS
69
70         /*
71          * start stack at top of mach (physical addr)
72          * set up page tables for kernel
73          */
74         MOVW    $PADDR(MACHADDR+MACHSIZE-4), R13
75         MOVW    $PADDR(L1), R0
76         BL      mmuinit(SB)
77
78         /*
79          * set up domain access control and page table base
80          */
81         MOVW    $Client, R1
82         MCR     CpSC, 0, R1, C(CpDAC), C(0)
83         MOVW    $PADDR(L1), R1
84         ORR     $(CpTTBs|CpTTBowba|CpTTBiwba), R1
85         MCR     CpSC, 0, R1, C(CpTTB), C(0)
86         MCR     CpSC, 0, R1, C(CpTTB), C(0), CpTTB1     /* cortex has two */
87
88         /*
89          * invalidate my caches before enabling
90          */
91         BL      cachedinv(SB)
92         BL      cacheiinv(SB)
93         BL      l2cacheuinv(SB)
94         BARRIERS
95
96         /*
97          * enable caches, mmu, and high vectors
98          */
99
100         MRC     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
101         ORR     $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
102         MCR     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
103         BARRIERS
104
105         /*
106          * switch SB, SP, and PC into KZERO space
107          */
108         MOVW    $setR12(SB), R12
109         MOVW    $(MACHADDR+MACHSIZE-4), R13
110         MOVW    $_startpg(SB), R15
111
112 TEXT _startpg(SB), 1, $-4
113
114         /*
115          * enable cycle counter
116          */
117         MOVW    $(1<<31), R1
118         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
119         MOVW    $1, R1
120         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
121
122         /*
123          * call main and loop forever if it returns
124          */
125         BL      ,main(SB)
126         B       ,0(PC)
127
128         BL      _div(SB)                /* hack to load _div, etc. */
129
130 /*
131  * startup entry for cpu(s) other than 0
132  */
133 TEXT cpureset(SB), 1, $-4
134 reset:
135         /*
136          * load physical base for SB addressing while mmu is off
137          * keep a handy zero in R0 until first function call
138          */
139         MOVW    $setR12(SB), R12
140         SUB     $KZERO, R12
141         ADD     $PHYSDRAM, R12
142         MOVW    $0, R0
143
144         /*
145          * SVC mode, interrupts disabled
146          */
147         BL      svcmode(SB)
148
149         /*
150          * disable the mmu and caches
151          */
152         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
153         BIC     $(CpCdcache|CpCicache|CpCmmu), R1
154         ORR     $(CpCsbo|CpCsw), R1
155         BIC     $CpCsbz, R1
156         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
157         BARRIERS
158
159         /*
160          * turn SMP on
161          * invalidate tlb
162          */
163         MRC     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
164         ORR     $CpACsmp, R1            /* turn SMP on */
165         MCR     CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
166         BARRIERS
167         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
168         BARRIERS
169
170         /*
171          * find Mach for this cpu
172          */
173         MRC     CpSC, 0, R2, C(CpID), C(CpIDidct), CpIDmpid
174         AND     $(MAXMACH-1), R2        /* mask out non-cpu-id bits */
175         SLL     $2, R2                  /* convert to word index */
176         MOVW    $machaddr(SB), R0
177         ADD     R2, R0                  /* R0 = &machaddr[cpuid] */
178         MOVW    (R0), R0                /* R0 = machaddr[cpuid] */
179         CMP     $0, R0
180         BEQ     0(PC)                   /* must not be zero */
181         SUB     $KZERO, R0, R(MACH)     /* m = PADDR(machaddr[cpuid]) */
182
183         /*
184          * start stack at top of local Mach
185          */
186         ADD     $(MACHSIZE-4), R(MACH), R13
187
188         /*
189          * set up domain access control and page table base
190          */
191         MOVW    $Client, R1
192         MCR     CpSC, 0, R1, C(CpDAC), C(0)
193         MOVW    12(R(MACH)), R1 /* m->mmul1 */
194         SUB     $KZERO, R1              /* phys addr */
195         ORR     $(CpTTBs|CpTTBowba|CpTTBiwba), R1
196         MCR     CpSC, 0, R1, C(CpTTB), C(0)
197         MCR     CpSC, 0, R1, C(CpTTB), C(0), CpTTB1     /* cortex has two */
198
199         /*
200          * invalidate my caches before enabling
201          */
202         BL      cachedinv(SB)
203         BL      cacheiinv(SB)
204         BARRIERS
205
206         /*
207          * enable caches, mmu, and high vectors
208          */
209         MRC     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
210         ORR     $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
211         MCR     CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
212         BARRIERS
213
214         /*
215          * switch MACH, SB, SP, and PC into KZERO space
216          */
217         ADD     $KZERO, R(MACH)
218         MOVW    $setR12(SB), R12
219         ADD     $KZERO, R13
220         MOVW    $_startpg2(SB), R15
221
222 TEXT _startpg2(SB), 1, $-4
223
224         /*
225          * enable cycle counter
226          */
227         MOVW    $(1<<31), R1
228         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
229         MOVW    $1, R1
230         MCR     CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
231
232         /*
233          * call cpustart and loop forever if it returns
234          */
235         MRC     CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDmpid
236         AND     $(MAXMACH-1), R0                /* mask out non-cpu-id bits */
237         BL      ,cpustart(SB)
238         B       ,0(PC)
239
240 /*
241  * get into SVC mode with interrupts disabled
242  * raspberry pi firmware since 29 Sept 2015 starts in HYP mode
243  */
244 TEXT svcmode(SB), 1, $-4
245         MOVW    CPSR, R1
246         AND     $PsrMask, R1
247         MOVW    $PsrMhyp, R2
248         CMP     R2, R1
249         MOVW    $(PsrDirq|PsrDfiq|PsrMsvc), R1
250         BNE     nothyp
251         MSR(1, 1, 1, 0xe)       /* MOVW R1, SPSR_HYP */
252         MSR(0, 14, 1, 0xe)      /* MOVW R14, ELR_HYP */
253         ERET
254 nothyp:
255         MOVW    R1, CPSR
256         RET
257
258 TEXT cpidget(SB), 1, $-4                        /* main ID */
259         MRC     CpSC, 0, R0, C(CpID), C(0), CpIDid
260         RET
261
262 TEXT fsrget(SB), 1, $-4                         /* data fault status */
263         MRC     CpSC, 0, R0, C(CpFSR), C(0), CpFSRdata
264         RET
265
266 TEXT ifsrget(SB), 1, $-4                        /* instruction fault status */
267         MRC     CpSC, 0, R0, C(CpFSR), C(0), CpFSRinst
268         RET
269
270 TEXT farget(SB), 1, $-4                         /* fault address */
271         MRC     CpSC, 0, R0, C(CpFAR), C(0x0)
272         RET
273
274 TEXT cpctget(SB), 1, $-4                        /* cache type */
275         MRC     CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDct
276         RET
277
278 TEXT lcycles(SB), 1, $-4
279         MRC     CpSC, 0, R0, C(CpCLD), C(CpCLDcyc), 0
280         RET
281
282 TEXT splhi(SB), 1, $-4
283         MOVW    R14, 4(R(MACH))         /* save caller pc in m->splpc */
284
285         MOVW    CPSR, R0                        /* turn off irqs (but not fiqs) */
286         ORR     $(PsrDirq), R0, R1
287         MOVW    R1, CPSR
288         RET
289
290 TEXT splfhi(SB), 1, $-4
291         MOVW    R14, 4(R(MACH))         /* save caller pc in m->splpc */
292
293         MOVW    CPSR, R0                        /* turn off irqs and fiqs */
294         ORR     $(PsrDirq|PsrDfiq), R0, R1
295         MOVW    R1, CPSR
296         RET
297
298 TEXT splflo(SB), 1, $-4
299         MOVW    CPSR, R0                        /* turn on fiqs */
300         BIC     $(PsrDfiq), R0, R1
301         MOVW    R1, CPSR
302         RET
303
304 TEXT spllo(SB), 1, $-4
305         MOVW    CPSR, R0                        /* turn on irqs and fiqs */
306         MOVW    $0, R1
307         CMP.S   R1, R(MACH)
308         MOVW.NE R1, 4(R(MACH))                  /* clear m->splpc */
309         BIC     $(PsrDirq|PsrDfiq), R0, R1
310         MOVW    R1, CPSR
311         RET
312
313 TEXT splx(SB), 1, $-4
314         MOVW    R14, 4(R(MACH))         /* save caller pc in m->splpc */
315
316         MOVW    R0, R1                          /* reset interrupt level */
317         MOVW    CPSR, R0
318         MOVW    R1, CPSR
319         RET
320
321 TEXT spldone(SB), 1, $0                         /* end marker for devkprof.c */
322         RET
323
324 TEXT islo(SB), 1, $-4
325         MOVW    CPSR, R0
326         AND     $(PsrDirq), R0
327         EOR     $(PsrDirq), R0
328         RET
329
330 TEXT cas(SB), $0
331 TEXT cmpswap(SB), $0
332         MOVW    ov+4(FP), R1
333         MOVW    nv+8(FP), R2
334 spincas:
335         LDREX   (R0), R3
336         CMP.S   R3, R1
337         BNE     fail
338         STREX   R2, (R0), R4
339         CMP.S   $0, R4
340         BNE     spincas
341         MOVW    $1, R0
342         DMB
343         RET
344 fail:
345         CLREX
346         MOVW    $0, R0
347         RET
348
349 TEXT    tas(SB), $-4
350 TEXT    _tas(SB), $-4                   /* _tas(ulong *) */
351         /* returns old (R0) after modifying (R0) */
352         MOVW    R0,R5
353         DMB
354
355         MOVW    $1,R2           /* new value of (R0) */
356         MOVW    $MAXSC, R8
357 tas1:
358         LDREX (R5), R7
359         CMP.S   $0, R7          /* old value non-zero (lock taken)? */
360         BNE     lockbusy        /* we lose */
361         SUB.S   $1, R8
362         BEQ     lockloop2
363         STREX R2,(R5),R4
364         CMP.S   $0, R4
365         BNE     tas1            /* strex failed? try again */
366         DMB
367         B       tas0
368 lockloop2:
369         BL      abort(SB)
370 lockbusy:
371         CLREX
372 tas0:
373         MOVW    R7, R0          /* return old value */
374         RET
375
376 TEXT setlabel(SB), 1, $-4
377         MOVW    R13, 0(R0)              /* sp */
378         MOVW    R14, 4(R0)              /* pc */
379         MOVW    $0, R0
380         RET
381
382 TEXT gotolabel(SB), 1, $-4
383         MOVW    0(R0), R13              /* sp */
384         MOVW    4(R0), R14              /* pc */
385         MOVW    $1, R0
386         RET
387
388 TEXT getcallerpc(SB), 1, $-4
389         MOVW    0(R13), R0
390         RET
391
392 TEXT idlehands(SB), $-4
393         MOVW    CPSR, R3
394         ORR     $(PsrDirq|PsrDfiq), R3, R1              /* splfhi */
395         MOVW    R1, CPSR
396
397         DSB
398         MOVW    nrdy(SB), R0
399         CMP     $0, R0
400         WFI_EQ
401         DSB
402
403         MOVW    R3, CPSR                        /* splx */
404         RET
405
406
407 TEXT coherence(SB), $-4
408         BARRIERS
409         RET
410
411 TEXT sev(SB), $-4
412         SEV
413         RET
414
415 /*
416  * invalidate tlb
417  */
418 TEXT mmuinvalidate(SB), 1, $-4
419         DSB
420         MOVW    $0, R0
421         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
422         BARRIERS
423         RET
424
425 /*
426  * mmuinvalidateaddr(va)
427  *   invalidate tlb entry for virtual page address va, ASID 0
428  */
429 TEXT mmuinvalidateaddr(SB), 1, $-4
430         DSB
431         MCR     CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse
432         BARRIERS
433         RET
434
435 /*
436  * `single-element' cache operations.
437  * in arm arch v7, if effective to PoC, they operate on all cache levels, so separate
438  * l2 functions are unnecessary.
439  */
440
441 TEXT cachedwbse(SB), $-4                        /* D writeback SE */
442         MOVW    R0, R2
443
444         MOVW    CPSR, R3
445         CPSID                                   /* splhi */
446
447         BARRIERS                        /* force outstanding stores to cache */
448         MOVW    R2, R0
449         MOVW    4(FP), R1
450         ADD     R0, R1                          /* R1 is end address */
451         BIC     $(CACHELINESZ-1), R0            /* cache line start */
452 _dwbse:
453         MCR     CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEse
454         /* can't have a BARRIER here since it zeroes R0 */
455         ADD     $CACHELINESZ, R0
456         CMP.S   R0, R1
457         BGT     _dwbse
458         B       _wait
459
460 /*
461  * TLB on armv7 loads from cache, so no need for writeback
462  */
463 TEXT cachedwbtlb(SB), $-4
464         DSB
465         ISB
466         RET
467
468 TEXT cachedwbinvse(SB), $-4                     /* D writeback+invalidate SE */
469         MOVW    R0, R2
470
471         MOVW    CPSR, R3
472         CPSID                                   /* splhi */
473
474         BARRIERS                        /* force outstanding stores to cache */
475         MOVW    R2, R0
476         MOVW    4(FP), R1
477         ADD     R0, R1                          /* R1 is end address */
478         BIC     $(CACHELINESZ-1), R0            /* cache line start */
479 _dwbinvse:
480         MCR     CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEse
481         /* can't have a BARRIER here since it zeroes R0 */
482         ADD     $CACHELINESZ, R0
483         CMP.S   R0, R1
484         BGT     _dwbinvse
485 _wait:                                          /* drain write buffer */
486         BARRIERS
487
488         MOVW    R3, CPSR                        /* splx */
489         RET
490
491 TEXT cachedinvse(SB), $-4                       /* D invalidate SE */
492         MOVW    R0, R2
493
494         MOVW    CPSR, R3
495         CPSID                                   /* splhi */
496
497         BARRIERS                        /* force outstanding stores to cache */
498         MOVW    R2, R0
499         MOVW    4(FP), R1
500         ADD     R0, R1                          /* R1 is end address */
501         BIC     $(CACHELINESZ-1), R0            /* cache line start */
502 _dinvse:
503         MCR     CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEse
504         /* can't have a BARRIER here since it zeroes R0 */
505         ADD     $CACHELINESZ, R0
506         CMP.S   R0, R1
507         BGT     _dinvse
508         B       _wait
509
510 #include "cache.v7.s"