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
51 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
53 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
57 * clear mach and page tables
59 MOVW $PADDR(MACHADDR), R1
60 MOVW $PADDR(KTZERO), R2
69 * start stack at top of mach (physical addr)
70 * set up page tables for kernel
72 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
99 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
101 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
105 * enable caches, mmu, and high vectors
107 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
108 ORR $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
109 MCR CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
113 * switch SB, SP, and PC into KZERO space
115 MOVW $setR12(SB), R12
116 MOVW $(MACHADDR+MACHSIZE-4), R13
117 MOVW $_startpg(SB), R15
119 TEXT _startpg(SB), 1, $-4
122 * enable cycle counter
125 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
127 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
130 * call main and loop forever if it returns
135 BL _div(SB) /* hack to load _div, etc. */
138 * startup entry for cpu(s) other than 0
140 TEXT cpureset(SB), 1, $-4
143 * load physical base for SB addressing while mmu is off
145 MOVW $setR12(SB), R12
150 * SVC mode, interrupts disabled
155 * disable the mmu and caches
157 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
158 BIC $(CpCdcache|CpCicache|CpCmmu), R1
159 ORR $(CpCsbo|CpCsw), R1
161 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpMainctl
167 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
169 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
173 * find Mach for this cpu
175 MRC CpSC, 0, R2, C(CpID), C(CpIDidct), CpIDmpid
176 AND $(MAXMACH-1), R2 /* mask out non-cpu-id bits */
177 SLL $2, R2 /* convert to word index */
178 MOVW $machaddr(SB), R0
181 ADD R2, R0 /* R0 = &machaddr[cpuid] */
182 MOVW (R0), R0 /* R0 = machaddr[cpuid] */
184 BEQ 0(PC) /* must not be zero */
185 SUB $KZERO, R0, R(MACH) /* m = PADDR(machaddr[cpuid]) */
188 * start stack at top of local Mach
190 ADD $(MACHSIZE-4), R(MACH), R13
195 * set up domain access control and page table base
198 MCR CpSC, 0, R1, C(CpDAC), C(0)
199 MOVW 12(R(MACH)), R1 /* m->mmul1 */
200 SUB $KZERO, R1 /* phys addr */
201 ORR $(CpTTBs|CpTTBowba|CpTTBiwba), R1
202 MCR CpSC, 0, R1, C(CpTTB), C(0)
203 MCR CpSC, 0, R1, C(CpTTB), C(0), CpTTB1 /* cortex has two */
206 * invalidate my caches before enabling
215 MRC CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
217 MCR CpSC, 0, R1, C(CpCONTROL), C(0), CpAuxctl
221 * enable caches, mmu, and high vectors
223 MRC CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
224 ORR $(CpChv|CpCdcache|CpCicache|CpCmmu), R0
225 MCR CpSC, 0, R0, C(CpCONTROL), C(0), CpMainctl
229 * switch MACH, SB, SP, and PC into KZERO space
232 MOVW $setR12(SB), R12
234 MOVW $_startpg2(SB), R15
236 TEXT _startpg2(SB), 1, $-4
239 * enable cycle counter
242 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenacyc
244 MCR CpSC, 0, R1, C(CpCLD), C(CpCLDena), CpCLDenapmnc
247 * call cpustart and loop forever if it returns
249 MRC CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDmpid
250 AND $(MAXMACH-1), R0 /* mask out non-cpu-id bits */
255 * get into SVC mode with interrupts disabled
256 * raspberry pi firmware since 29 Sept 2015 starts in HYP mode
258 TEXT svcmode(SB), 1, $-4
263 MOVW $(PsrDirq|PsrDfiq|PsrMsvc), R1
265 MSR(1, 1, 1, 0xe) /* MOVW R1, SPSR_HYP */
266 MSR(0, 14, 1, 0xe) /* MOVW R14, ELR_HYP */
272 TEXT cpidget(SB), 1, $-4 /* main ID */
273 MRC CpSC, 0, R0, C(CpID), C(0), CpIDid
276 TEXT fsrget(SB), 1, $-4 /* data fault status */
277 MRC CpSC, 0, R0, C(CpFSR), C(0), CpFSRdata
280 TEXT ifsrget(SB), 1, $-4 /* instruction fault status */
281 MRC CpSC, 0, R0, C(CpFSR), C(0), CpFSRinst
284 TEXT farget(SB), 1, $-4 /* fault address */
285 MRC CpSC, 0, R0, C(CpFAR), C(0x0)
288 TEXT cpctget(SB), 1, $-4 /* cache type */
289 MRC CpSC, 0, R0, C(CpID), C(CpIDidct), CpIDct
292 TEXT lcycles(SB), 1, $-4
293 MRC CpSC, 0, R0, C(CpCLD), C(CpCLDcyc), 0
296 TEXT splhi(SB), 1, $-4
297 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
299 MOVW CPSR, R0 /* turn off irqs (but not fiqs) */
300 ORR $(PsrDirq), R0, R1
304 TEXT splfhi(SB), 1, $-4
305 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
307 MOVW CPSR, R0 /* turn off irqs and fiqs */
308 ORR $(PsrDirq|PsrDfiq), R0, R1
312 TEXT splflo(SB), 1, $-4
313 MOVW CPSR, R0 /* turn on fiqs */
314 BIC $(PsrDfiq), R0, R1
318 TEXT spllo(SB), 1, $-4
319 MOVW CPSR, R0 /* turn on irqs and fiqs */
322 MOVW.NE R1, 4(R(MACH)) /* clear m->splpc */
323 BIC $(PsrDirq|PsrDfiq), R0, R1
327 TEXT splx(SB), 1, $-4
328 MOVW R14, 4(R(MACH)) /* save caller pc in m->splpc */
330 MOVW R0, R1 /* reset interrupt level */
335 TEXT spldone(SB), 1, $0 /* end marker for devkprof.c */
338 TEXT islo(SB), 1, $-4
364 TEXT _tas(SB), $-4 /* _tas(ulong *) */
365 /* returns old (R0) after modifying (R0) */
369 MOVW $1,R2 /* new value of (R0) */
373 CMP.S $0, R7 /* old value non-zero (lock taken)? */
374 BNE lockbusy /* we lose */
379 BNE tas1 /* strex failed? try again */
387 MOVW R7, R0 /* return old value */
390 TEXT setlabel(SB), 1, $-4
391 MOVW R13, 0(R0) /* sp */
392 MOVW R14, 4(R0) /* pc */
396 TEXT gotolabel(SB), 1, $-4
397 MOVW 0(R0), R13 /* sp */
398 MOVW 4(R0), R14 /* pc */
402 TEXT getcallerpc(SB), 1, $-4
406 TEXT idlehands(SB), $-4
408 ORR $(PsrDirq|PsrDfiq), R3, R1 /* splfhi */
417 MOVW R3, CPSR /* splx */
421 TEXT coherence(SB), $-4
432 TEXT mmuinvalidate(SB), 1, $-4
435 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinv
440 * mmuinvalidateaddr(va)
441 * invalidate tlb entry for virtual page address va, ASID 0
443 TEXT mmuinvalidateaddr(SB), 1, $-4
445 MCR CpSC, 0, R0, C(CpTLB), C(CpTLBinvu), CpTLBinvse
450 * `single-element' cache operations.
451 * in arm arch v7, if effective to PoC, they operate on all cache levels, so separate
452 * l2 functions are unnecessary.
455 TEXT cachedwbse(SB), $-4 /* D writeback SE */
461 BARRIERS /* force outstanding stores to cache */
464 ADD R0, R1 /* R1 is end address */
465 BIC $(CACHELINESZ-1), R0 /* cache line start */
467 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEse
468 /* can't have a BARRIER here since it zeroes R0 */
475 * TLB on armv7 loads from cache, so no need for writeback
477 TEXT cachedwbtlb(SB), $-4
482 TEXT cachedwbinvse(SB), $-4 /* D writeback+invalidate SE */
488 BARRIERS /* force outstanding stores to cache */
491 ADD R0, R1 /* R1 is end address */
492 BIC $(CACHELINESZ-1), R0 /* cache line start */
494 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEse
495 /* can't have a BARRIER here since it zeroes R0 */
499 _wait: /* drain write buffer */
502 MOVW R3, CPSR /* splx */
505 TEXT cachedinvse(SB), $-4 /* D invalidate SE */
511 BARRIERS /* force outstanding stores to cache */
514 ADD R0, R1 /* R1 is end address */
515 BIC $(CACHELINESZ-1), R0 /* cache line start */
517 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEse
518 /* can't have a BARRIER here since it zeroes R0 */
524 #include "cache.v7.s"