@ -18,6 +18,7 @@
* /
# include < c o n f i g . h >
# include < a s m / g i c . h >
# include < a s m / p s c i . h >
# include < a s m / a r c h / c p u . h >
@ -38,6 +39,8 @@
# define O N E _ M S ( C O N F I G _ S Y S _ C L K _ F R E Q / 1 0 0 0 )
# define T E N _ M S ( 1 0 * O N E _ M S )
# define G I C D _ B A S E 0 x1 c81 0 0 0
# define G I C C _ B A S E 0 x1 c82 0 0 0
.macro timer_wait reg, t i c k s
@ Program CNTP_TVAL
@ -61,7 +64,27 @@
.globl psci_arch_init
psci_arch_init :
movw r4 , #( G I C D _ B A S E & 0xffff )
movt r4 , #( G I C D _ B A S E > > 16 )
ldr r5 , [ r4 , #G I C D _ I G R O U P R n ]
bic r5 , r5 , #( 1 < < 1 5 ) @ SGI15 as Group-0
str r5 , [ r4 , #G I C D _ I G R O U P R n ]
mov r5 , #0 @ Set SGI15 priority to 0
strb r5 , [ r4 , #( G I C D _ I P R I O R I T Y R n + 15 ) ]
add r4 , r4 , #0x1000 @ GICC address
mov r5 , #0xff
str r5 , [ r4 , #G I C C _ P M R ] @ B e c o o l w i t h n o n - s e c u r e
ldr r5 , [ r4 , #G I C C _ C T L R ]
orr r5 , r5 , #( 1 < < 3 ) @ Switch FIQEn on
str r5 , [ r4 , #G I C C _ C T L R ]
mrc p15 , 0 , r5 , c1 , c1 , 0 @ Read SCR
orr r5 , r5 , #4 @ Enable FIQ in monitor mode
bic r5 , r5 , #1 @ Secure mode
mcr p15 , 0 , r5 , c1 , c1 , 0 @ Write SCR
isb
@ -79,6 +102,78 @@ psci_arch_init:
bx l r
.globl psci_fiq_enter
psci_fiq_enter :
push { r0 - r12 }
@ Switch to secure
mrc p15 , 0 , r7 , c1 , c1 , 0
bic r8 , r7 , #1
mcr p15 , 0 , r8 , c1 , c1 , 0
isb
@ Validate reason based on IAR and acknowledge
movw r8 , #( G I C C _ B A S E & 0xffff )
movt r8 , #( G I C C _ B A S E > > 16 )
ldr r9 , [ r8 , #G I C C _ I A R ]
movw r10 , #0x3ff
movt r10 , #0
cmp r9 , r10 @ skip spurious interrupt 1023
beq o u t
movw r10 , #0x3fe @ ...and 1022
cmp r9 , r10
beq o u t
str r9 , [ r8 , #G I C C _ E O I R ] @ a c k n o w l e d g e t h e i n t e r r u p t
dsb
@ Compute CPU number
lsr r9 , r9 , #10
and r9 , r9 , #0xf
movw r8 , #( S U N 7 I _ C P U C F G _ B A S E & 0 x f f f f )
movt r8 , #( S U N 7 I _ C P U C F G _ B A S E > > 1 6 )
@ Wait for the core to enter WFI
lsl r11 , r9 , #6 @ x64
add r11 , r11 , r8
1 : ldr r10 , [ r11 , #0x48 ]
tst r10 , #( 1 < < 2 )
bne 2 f
timer_ w a i t r10 , O N E _ M S
b 1 b
@ Reset CPU
2 : mov r10 , #0
str r10 , [ r11 , #0x40 ]
@ Lock CPU
mov r10 , #1
lsl r9 , r10 , r9 @ r9 is now CPU mask
ldr r10 , [ r8 , #0x1e4 ]
bic r10 , r10 , r9
str r10 , [ r8 , #0x1e4 ]
@ Set power gating
ldr r10 , [ r8 , #0x1b4 ]
orr r10 , r10 , #1
str r10 , [ r8 , #0x1b4 ]
timer_ w a i t r10 , O N E _ M S
@ Activate power clamp
mov r10 , #1
1 : str r10 , [ r8 , #0x1b0 ]
lsl r10 , r10 , #1
orr r10 , r10 , #1
tst r10 , #0x100
beq 1 b
@ Restore security level
out : mcr p15 , 0 , r7 , c1 , c1 , 0
pop { r0 - r12 }
subs p c , l r , #4
@ r1 = target CPU
@ r2 = target PC
.globl psci_cpu_on
@ -144,6 +239,53 @@ psci_cpu_on:
_target_pc :
.word 0
/* Imported from Linux kernel */
v7_flush_dcache_all :
dmb @ ensure ordering with previous memory accesses
mrc p15 , 1 , r0 , c0 , c0 , 1 @ read clidr
ands r3 , r0 , #0x7000000 @ extract loc from clidr
mov r3 , r3 , l s r #23 @ left align loc bit field
beq f i n i s h e d @ if loc is 0, then no need to clean
mov r10 , #0 @ start clean at cache level 0
flush_levels :
add r2 , r10 , r10 , l s r #1 @ work out 3x current cache level
mov r1 , r0 , l s r r2 @ extract cache type bits from clidr
and r1 , r1 , #7 @ mask of the bits for current cache only
cmp r1 , #2 @ see what cache we have at this level
blt s k i p @ skip if no cache, or just i-cache
mrs r9 , c p s r @ make cssr&csidr read atomic
mcr p15 , 2 , r10 , c0 , c0 , 0 @ select current cache level in cssr
isb @ isb to sych the new cssr&csidr
mrc p15 , 1 , r1 , c0 , c0 , 0 @ read the new csidr
msr c p s r _ c , r9
and r2 , r1 , #7 @ extract the length of the cache lines
add r2 , r2 , #4 @ add 4 (line length offset)
ldr r4 , =0x3ff
ands r4 , r4 , r1 , l s r #3 @ find maximum number on the way size
clz r5 , r4 @ find bit position of way size increment
ldr r7 , =0x7fff
ands r7 , r7 , r1 , l s r #13 @ extract max number of the index size
loop1 :
mov r9 , r7 @ create working copy of max index
loop2 :
orr r11 , r10 , r4 , l s l r5 @ factor way and cache number into r11
orr r11 , r11 , r9 , l s l r2 @ factor index number into r11
mcr p15 , 0 , r11 , c7 , c14 , 2 @ clean & invalidate by set/way
subs r9 , r9 , #1 @ decrement the index
bge l o o p2
subs r4 , r4 , #1 @ decrement the way
bge l o o p1
skip :
add r10 , r10 , #2 @ increment cache number
cmp r3 , r10
bgt f l u s h _ l e v e l s
finished :
mov r10 , #0 @ swith back to cache level 0
mcr p15 , 2 , r10 , c0 , c0 , 0 @ select current cache level in cssr
dsb s t
isb
bx l r
_sunxi_cpu_entry :
@ Set SMP bit
mrc p15 , 0 , r0 , c1 , c0 , 1
@ -158,5 +300,34 @@ _sunxi_cpu_entry:
ldr r0 , [ r0 ]
b _ d o _ n o n s e c _ e n t r y
.globl psci_cpu_off
psci_cpu_off :
mrc p15 , 0 , r0 , c1 , c0 , 0 @ SCTLR
bic r0 , r0 , #( 1 < < 2 ) @ Clear C bit
mcr p15 , 0 , r0 , c1 , c0 , 0 @ SCTLR
isb
dsb
bl v7 _ f l u s h _ d c a c h e _ a l l
clrex @ Why???
mrc p15 , 0 , r0 , c1 , c0 , 1 @ ACTLR
bic r0 , r0 , #( 1 < < 6 ) @ Clear SMP bit
mcr p15 , 0 , r0 , c1 , c0 , 1 @ ACTLR
isb
dsb
@ Ask CPU0 to pull the rug...
movw r0 , #( G I C D _ B A S E & 0xffff )
movt r0 , #( G I C D _ B A S E > > 16 )
movw r1 , #15 @ SGI15
movt r1 , #1 @ Target is CPU0
str r1 , [ r0 , #G I C D _ S G I R ]
dsb
1 : wfi
b 1 b
text_end :
.popsection