1 1.1 jmcneill /*- 2 1.1 jmcneill * Copyright (c) 2010 Per Odlund <per.odlund (at) armagedon.se> 3 1.1 jmcneill * 4 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 5 1.1 jmcneill * modification, are permitted provided that the following conditions 6 1.1 jmcneill * are met: 7 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 8 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 9 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 10 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 11 1.1 jmcneill * documentation and/or other materials provided with the distribution. 12 1.1 jmcneill * 13 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 14 1.1 jmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 15 1.1 jmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 1.1 jmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 17 1.1 jmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 1.1 jmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 1.1 jmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 1.1 jmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 1.1 jmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 1.1 jmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 1.1 jmcneill * POSSIBILITY OF SUCH DAMAGE. 24 1.1 jmcneill */ 25 1.1 jmcneill 26 1.1 jmcneill /* ARMv7 assembly functions for manipulating caches and other core functions. 27 1.1 jmcneill * Based on cpufuncs for v6 and xscale. 28 1.1 jmcneill */ 29 1.1 jmcneill 30 1.1 jmcneill #include <machine/asm.h> 31 1.1 jmcneill 32 1.1 jmcneill .arch armv7a 33 1.1 jmcneill 34 1.1 jmcneill /* LINTSTUB: void armv7_dcache_wbinv_range(vaddr_t, vsize_t); */ 35 1.1 jmcneill ENTRY(armv7_dcache_wbinv_range) 36 1.1 jmcneill mov ip, #0 37 1.1 jmcneill mcr p15, 2, ip, c0, c0, 0 @ set cache level to L1 38 1.1 jmcneill mrc p15, 1, r2, c0, c0, 0 @ read CCSIDR 39 1.1 jmcneill and r2, r2, #7 @ get line size (log2(size)-4, 0=16) 40 1.1 jmcneill mov ip, #16 @ make a bit mask 41 1.1 jmcneill lsl r2, ip, r2 @ and shift into position 42 1.1 jmcneill sub ip, r2, #1 @ make into a mask 43 1.1 jmcneill and r3, r0, ip @ get offset into cache line 44 1.1 jmcneill add r1, r1, r3 @ add to length 45 1.1 jmcneill bic r0, r0, ip @ clear offset from start. 46 1.1 jmcneill dsb 47 1.1 jmcneill 1: 48 1.1 jmcneill mcr p15, 0, r0, c7, c14, 1 @ wb and inv the D-Cache line to PoC 49 1.1 jmcneill add r0, r0, r2 50 1.1 jmcneill subs r1, r1, r2 51 1.1 jmcneill bhi 1b 52 1.1 jmcneill dsb @ data synchronization barrier 53 1.1 jmcneill bx lr 54 1.1 jmcneill END(armv7_dcache_wbinv_range) 55 1.1 jmcneill 56 1.2 skrll /* LINTSTUB: void armv7_dcache_wbinv_all(void); */ 57 1.2 skrll ENTRY_NP(armv7_dcache_wbinv_all) 58 1.2 skrll mrc p15, 1, r0, c0, c0, 1 @ read CLIDR 59 1.2 skrll tst r0, #0x07000000 60 1.2 skrll bxeq lr 61 1.2 skrll mov r3, #0 @ start with L1 62 1.2 skrll 63 1.2 skrll .Lstart_wbinv: 64 1.2 skrll add r2, r3, r3, lsr #1 @ r2 = level * 3 / 2 65 1.2 skrll mov r1, r0, lsr r2 @ r1 = cache type 66 1.2 skrll tst r1, #6 @ is it unified or data? 67 1.2 skrll beq .Lnext_level_wbinv @ nope, skip level 68 1.2 skrll 69 1.2 skrll mcr p15, 2, r3, c0, c0, 0 @ select cache level 70 1.2 skrll isb 71 1.2 skrll mrc p15, 1, r0, c0, c0, 0 @ read CCSIDR 72 1.2 skrll 73 1.2 skrll ubfx ip, r0, #0, #3 @ get linesize from CCSIDR 74 1.2 skrll add ip, ip, #4 @ apply bias 75 1.2 skrll ubfx r2, r0, #13, #15 @ get numsets - 1 from CCSIDR 76 1.2 skrll lsl r2, r2, ip @ shift to set position 77 1.2 skrll orr r3, r3, r2 @ merge set into way/set/level 78 1.2 skrll mov r1, #1 79 1.2 skrll lsl r1, r1, ip @ r1 = set decr 80 1.2 skrll 81 1.2 skrll ubfx ip, r0, #3, #10 @ get numways - 1 from [to be discarded] CCSIDR 82 1.2 skrll clz r2, ip @ number of bits to MSB of way 83 1.2 skrll lsl ip, ip, r2 @ shift by that into way position 84 1.2 skrll mov r0, #1 @ 85 1.2 skrll lsl r2, r0, r2 @ r2 now contains the way decr 86 1.2 skrll mov r0, r3 @ get sets/level (no way yet) 87 1.2 skrll orr r3, r3, ip @ merge way into way/set/level 88 1.2 skrll bfc r0, #0, #4 @ clear low 4 bits (level) to get numset - 1 89 1.2 skrll sub r2, r2, r0 @ subtract from way decr 90 1.2 skrll 91 1.2 skrll /* r3 = ways/sets/level, r2 = way decr, r1 = set decr, r0 and ip are free */ 92 1.2 skrll 1: mcr p15, 0, r3, c7, c14, 2 @ DCCISW (data cache clean and invalidate by set/way) 93 1.2 skrll cmp r3, #15 @ are we done with this level (way/set == 0) 94 1.2 skrll bls .Lnext_level_wbinv @ yes, go to next level 95 1.2 skrll ubfx r0, r3, #4, #18 @ extract set bits 96 1.2 skrll cmp r0, #0 @ compare 97 1.2 skrll subne r3, r3, r1 @ non-zero?, decrement set # 98 1.2 skrll subeq r3, r3, r2 @ zero?, decrement way # and restore set count 99 1.2 skrll b 1b 100 1.2 skrll 101 1.2 skrll .Lnext_level_wbinv: 102 1.2 skrll dsb 103 1.2 skrll mrc p15, 1, r0, c0, c0, 1 @ read CLIDR 104 1.2 skrll ubfx ip, r0, #24, #3 @ narrow to LoC 105 1.2 skrll add r3, r3, #2 @ go to next level 106 1.2 skrll cmp r3, ip, lsl #1 @ compare 107 1.2 skrll blt .Lstart_wbinv @ not done, next level (r0 == CLIDR) 108 1.2 skrll 109 1.2 skrll .Ldone_wbinv: 110 1.2 skrll mov r0, #0 @ default back to cache level 0 111 1.2 skrll mcr p15, 2, r0, c0, c0, 0 @ select cache level 112 1.2 skrll dsb 113 1.2 skrll isb 114 1.2 skrll bx lr 115 1.2 skrll END(armv7_dcache_wbinv_all) 116 1.2 skrll 117 1.1 jmcneill /* * LINTSTUB: void armv7_icache_inv_all(void); */ 118 1.1 jmcneill ENTRY_NP(armv7_icache_inv_all) 119 1.1 jmcneill mov r0, #0 120 1.1 jmcneill mcr p15, 2, r0, c0, c0, 0 @ set cache level to L1 121 1.1 jmcneill mrc p15, 1, r0, c0, c0, 0 @ read CCSIDR 122 1.1 jmcneill 123 1.1 jmcneill ubfx r2, r0, #13, #15 @ get num sets - 1 from CCSIDR 124 1.1 jmcneill ubfx r3, r0, #3, #10 @ get numways - 1 from CCSIDR 125 1.1 jmcneill clz r1, r3 @ number of bits to MSB of way 126 1.1 jmcneill lsl r3, r3, r1 @ shift into position 127 1.1 jmcneill mov ip, #1 @ 128 1.1 jmcneill lsl ip, ip, r1 @ ip now contains the way decr 129 1.1 jmcneill 130 1.1 jmcneill ubfx r0, r0, #0, #3 @ get linesize from CCSIDR 131 1.1 jmcneill add r0, r0, #4 @ apply bias 132 1.1 jmcneill lsl r2, r2, r0 @ shift sets by log2(linesize) 133 1.1 jmcneill add r3, r3, r2 @ merge numsets - 1 with numways - 1 134 1.1 jmcneill sub ip, ip, r2 @ subtract numsets - 1 from way decr 135 1.1 jmcneill mov r1, #1 136 1.1 jmcneill lsl r1, r1, r0 @ r1 now contains the set decr 137 1.1 jmcneill mov r2, ip @ r2 now contains set way decr 138 1.1 jmcneill 139 1.1 jmcneill /* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */ 140 1.1 jmcneill 1: mcr p15, 0, r3, c7, c6, 2 @ DCISW (data cache invalidate by set/way) 141 1.1 jmcneill movs r0, r3 @ get current way/set 142 1.1 jmcneill beq 2f @ at 0 means we are done. 143 1.1 jmcneill lsls r0, r0, #10 @ clear way bits leaving only set bits 144 1.1 jmcneill subne r3, r3, r1 @ non-zero?, decrement set # 145 1.1 jmcneill subeq r3, r3, r2 @ zero?, decrement way # and restore set count 146 1.1 jmcneill b 1b 147 1.1 jmcneill 148 1.1 jmcneill 2: dsb @ wait for stores to finish 149 1.1 jmcneill mov r0, #0 @ and ... 150 1.1 jmcneill mcr p15, 0, r0, c7, c5, 0 @ invalidate L1 cache 151 1.1 jmcneill isb @ instruction sync barrier 152 1.1 jmcneill bx lr @ return 153 1.1 jmcneill END(armv7_icache_inv_all) 154 1.1 jmcneill 155 1.1 jmcneill ENTRY_NP(armv7_exec_kernel) 156 1.1 jmcneill mov r4, r0 @ kernel entry 157 1.1 jmcneill mov r5, r1 @ fdt address 158 1.1 jmcneill 159 1.1 jmcneill /* Disable MMU and cache */ 160 1.1 jmcneill mrc p15, 0, r0, c1, c0, 0 @ SCTLR read 161 1.1 jmcneill bic r0, r0, #5 @ disable dcache and MMU 162 1.1 jmcneill mcr p15, 0, r0, c1, c0, 0 @ SCTLR write 163 1.1 jmcneill 164 1.1 jmcneill /* Invalidate TLB */ 165 1.1 jmcneill dsb 166 1.1 jmcneill mov r0, #0 167 1.1 jmcneill mcr p15, 0, r0, c8, c7, 0 @ flush I+D TLB 168 1.1 jmcneill dsb 169 1.1 jmcneill isb 170 1.1 jmcneill 171 1.1 jmcneill /* Setup kernel args */ 172 1.1 jmcneill mov r0, #0 173 1.1 jmcneill mov r1, #0 174 1.1 jmcneill mov r2, r5 175 1.1 jmcneill mov r3, #0 176 1.1 jmcneill 177 1.1 jmcneill /* Jump to kernel */ 178 1.1 jmcneill bx r4 179 1.1 jmcneill END(armv7_exec_kernel) 180