2 * Broadcom bcm2836 SoC, as used in Raspberry Pi 2
3 * 4 x Cortex-A7 processor (armv7)
9 #define ICACHELINESZ 32
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 */
22 /* tas/cas strex debugging limits; started at 10000 */
25 TEXT armstart(SB), 1, $-4
28 * if not cpu0, go to secondary startup
34 * go to SVC mode, interrupts disabled
39 * disable the mmu and caches
41 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
42 BIC $(CpCdcache|CpCicache|CpCmmu), R1
43 ORR $(CpCsbo|CpCsw), R1
45 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
49 * clear mach and page tables
51 MOVW $PADDR(MACHADDR), R1
52 MOVW $PADDR(KTZERO), R2
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
67 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
71 * start stack at top of mach (physical addr)
72 * set up page tables for kernel
74 MOVW $PADDR(MACHADDR+MACHSIZE-4), R13
79 * set up domain access control and page table base
82 MCR CpSC, 0, R1, C(CpDAC), C(0)
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 */
89 * invalidate my caches before enabling
97 * enable caches, mmu, and high vectors
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
106 * switch SB, SP, and PC into KZERO space
108 MOVW $setR12(SB), R12
109 MOVW $(MACHADDR+MACHSIZE-4), R13
110 MOVW $_startpg(SB), R15
112 TEXT _startpg(SB), 1, $-4
115 * enable cycle counter
118 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
120 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
123 * call main and loop forever if it returns
128 BL _div(SB) /* hack to load _div, etc. */
131 * startup entry for cpu(s) other than 0
133 TEXT cpureset(SB), 1, $-4
136 * load physical base for SB addressing while mmu is off
137 * keep a handy zero in R0 until first function call
139 MOVW $setR12(SB), R12
145 * SVC mode, interrupts disabled
150 * disable the mmu and caches
152 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
153 BIC $(CpCdcache|CpCicache|CpCmmu), R1
154 ORR $(CpCsbo|CpCsw), R1
156 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
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
167 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
171 * find Mach for this cpu
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] */
180 BEQ 0(PC) /* must not be zero */
181 SUB $KZERO, R0, R(MACH) /* m = PADDR(machaddr[cpuid]) */
184 * start stack at top of local Mach
186 ADD $(MACHSIZE-4), R(MACH), R13
189 * set up domain access control and page table base
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 */
200 * invalidate my caches before enabling
207 * enable caches, mmu, and high vectors
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
215 * switch MACH, SB, SP, and PC into KZERO space
218 MOVW $setR12(SB), R12
220 MOVW $_startpg2(SB), R15
222 TEXT _startpg2(SB), 1, $-4
225 * enable cycle counter
228 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
230 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
233 * call cpustart and loop forever if it returns
235 MRC CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDmpid
236 AND $(MAXMACH-1), R0 /* mask out non-cpu-id bits */
241 * get into SVC mode with interrupts disabled
242 * raspberry pi firmware since 29 Sept 2015 starts in HYP mode
244 TEXT svcmode(SB), 1, $-4
249 MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
251 MSR(1, 1, 1, 0xe) /* MOVW R1, SPSR_HYP */
252 MSR(0, 14, 1, 0xe) /* MOVW R14, ELR_HYP */
258 TEXT cpidget(SB), 1, $-4 /* main ID */
259 MRC CpSC, 0, R0, C(CpID), C(0), CpIDid
262 TEXT fsrget(SB), 1, $-4 /* data fault status */
263 MRC CpSC, 0, R0, C(CpFSR), C(0), CpFSRdata
266 TEXT ifsrget(SB), 1, $-4 /* instruction fault status */
267 MRC CpSC, 0, R0, C(CpFSR), C(0), CpFSRinst
270 TEXT farget(SB), 1, $-4 /* fault address */
271 MRC CpSC, 0, R0, C(CpFAR), C(0x0)
274 TEXT cpctget(SB), 1, $-4 /* cache type */
275 MRC CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDct
278 TEXT lcycles(SB), 1, $-4
279 MRC CpSC, 0, R0, C(CpCLD), C(CpCLDcyc), 0
282 TEXT splhi(SB), 1, $-4
283 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
285 MOVW CPSR, R0 /* turn off irqs (but not fiqs) */
286 ORR $(PsrDirq), R0, R1
290 TEXT splfhi(SB), 1, $-4
291 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
293 MOVW CPSR, R0 /* turn off irqs and fiqs */
294 ORR $(PsrDirq|PsrDfiq), R0, R1
298 TEXT splflo(SB), 1, $-4
299 MOVW CPSR, R0 /* turn on fiqs */
300 BIC $(PsrDfiq), R0, R1
304 TEXT spllo(SB), 1, $-4
305 MOVW CPSR, R0 /* turn on irqs and fiqs */
308 MOVW.NE R1, 4(R(MACH)) /* clear m->splpc */
309 BIC $(PsrDirq|PsrDfiq), R0, R1
313 TEXT splx(SB), 1, $-4
314 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
316 MOVW R0, R1 /* reset interrupt level */
321 TEXT spldone(SB), 1, $0 /* end marker for devkprof.c */
324 TEXT islo(SB), 1, $-4
350 TEXT _tas(SB), $-4 /* _tas(ulong *) */
351 /* returns old (R0) after modifying (R0) */
355 MOVW $1,R2 /* new value of (R0) */
359 CMP.S $0, R7 /* old value non-zero (lock taken)? */
360 BNE lockbusy /* we lose */
365 BNE tas1 /* strex failed? try again */
373 MOVW R7, R0 /* return old value */
376 TEXT setlabel(SB), 1, $-4
377 MOVW R13, 0(R0) /* sp */
378 MOVW R14, 4(R0) /* pc */
382 TEXT gotolabel(SB), 1, $-4
383 MOVW 0(R0), R13 /* sp */
384 MOVW 4(R0), R14 /* pc */
388 TEXT getcallerpc(SB), 1, $-4
392 TEXT idlehands(SB), $-4
394 ORR $(PsrDirq|PsrDfiq), R3, R1 /* splfhi */
403 MOVW R3, CPSR /* splx */
407 TEXT coherence(SB), $-4
418 TEXT mmuinvalidate(SB), 1, $-4
421 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
426 * mmuinvalidateaddr(va)
427 * invalidate tlb entry for virtual page address va, ASID 0
429 TEXT mmuinvalidateaddr(SB), 1, $-4
431 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse
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.
441 TEXT cachedwbse(SB), $-4 /* D writeback SE */
447 BARRIERS /* force outstanding stores to cache */
450 ADD R0, R1 /* R1 is end address */
451 BIC $(CACHELINESZ-1), R0 /* cache line start */
453 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEse
454 /* can't have a BARRIER here since it zeroes R0 */
461 * TLB on armv7 loads from cache, so no need for writeback
463 TEXT cachedwbtlb(SB), $-4
468 TEXT cachedwbinvse(SB), $-4 /* D writeback+invalidate SE */
474 BARRIERS /* force outstanding stores to cache */
477 ADD R0, R1 /* R1 is end address */
478 BIC $(CACHELINESZ-1), R0 /* cache line start */
480 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEse
481 /* can't have a BARRIER here since it zeroes R0 */
485 _wait: /* drain write buffer */
488 MOVW R3, CPSR /* splx */
491 TEXT cachedinvse(SB), $-4 /* D invalidate SE */
497 BARRIERS /* force outstanding stores to cache */
500 ADD R0, R1 /* R1 is end address */
501 BIC $(CACHELINESZ-1), R0 /* cache line start */
503 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEse
504 /* can't have a BARRIER here since it zeroes R0 */
510 #include "cache.v7.s"