1276336Sian/*- 2276336Sian * Copyright 2014 Svatopluk Kraus <onwahe@gmail.com> 3276336Sian * Copyright 2014 Michal Meloun <meloun@miracle.cz> 4276336Sian * All rights reserved. 5276336Sian * 6276336Sian * Redistribution and use in source and binary forms, with or without 7276336Sian * modification, are permitted provided that the following conditions 8276336Sian * are met: 9276336Sian * 1. Redistributions of source code must retain the above copyright 10276336Sian * notice, this list of conditions and the following disclaimer. 11276336Sian * 2. Redistributions in binary form must reproduce the above copyright 12276336Sian * notice, this list of conditions and the following disclaimer in the 13276336Sian * documentation and/or other materials provided with the distribution. 14276336Sian * 15276336Sian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16276336Sian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17276336Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18276336Sian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19276336Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20276336Sian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21276336Sian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22276336Sian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23276336Sian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24276336Sian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25276336Sian * SUCH DAMAGE. 26276336Sian * 27276336Sian * $FreeBSD$ 28276336Sian */ 29283947Sian#include "assym.s" 30276336Sian 31276336Sian#include <machine/asm.h> 32276336Sian#include <machine/asmacros.h> 33276336Sian#include <machine/armreg.h> 34276336Sian#include <machine/sysreg.h> 35276336Sian 36283947Sian#define GET_PCB(tmp) \ 37295920Sskra mrc CP15_TPIDRPRW(tmp); \ 38295920Sskra add tmp, tmp, #(TD_PCB) 39283947Sian 40283366Sandrew/* 41276336Sian * Define cache functions used by startup code, which counts on the fact that 42276350Sian * only r0-r3,r12 (ip) are modified and no stack space is used. These functions 43283366Sandrew * must be called with interrupts disabled. Moreover, these work only with 44276350Sian * caches integrated to CPU (accessible via CP15); systems with an external L2 45276350Sian * cache controller such as a PL310 need separate calls to that device driver 46276350Sian * to affect L2 caches. This is not a factor during early kernel startup, as 47276350Sian * any external L2 cache controller has not been enabled yet. 48276336Sian */ 49276336Sian 50276336Sian/* Invalidate D cache to PoC. (aka all cache levels)*/ 51276350SianASENTRY_NP(dcache_inv_poc_all) 52276394Sian#if __ARM_ARCH == 6 53276394Sian mcr CP15_DCIALL 54276394Sian DSB 55276394Sian bx lr 56276394Sian#else 57276336Sian mrc CP15_CLIDR(r0) 58276336Sian ands r0, r0, #0x07000000 59276394Sian mov r0, r0, lsr #23 /* Get LoC 'naturally' aligned for */ 60276394Sian beq 4f /* use in the CSSELR register below */ 61276336Sian 62276394Sian1: sub r0, #2 63276394Sian mcr CP15_CSSELR(r0) /* set cache level */ 64276336Sian isb 65276336Sian mrc CP15_CCSIDR(r0) /* read CCSIDR */ 66276336Sian 67276336Sian ubfx r2, r0, #13, #15 /* get num sets - 1 from CCSIDR */ 68276336Sian ubfx r3, r0, #3, #10 /* get num ways - 1 from CCSIDR */ 69276336Sian clz r1, r3 /* number of bits to MSB of way */ 70276336Sian lsl r3, r3, r1 /* shift into position */ 71276336Sian mov ip, #1 72276336Sian lsl ip, ip, r1 /* ip now contains the way decr */ 73276336Sian 74276336Sian ubfx r0, r0, #0, #3 /* get linesize from CCSIDR */ 75276336Sian add r0, r0, #4 /* apply bias */ 76276336Sian lsl r2, r2, r0 /* shift sets by log2(linesize) */ 77276336Sian add r3, r3, r2 /* merge numsets - 1 with numways - 1 */ 78276336Sian sub ip, ip, r2 /* subtract numsets - 1 from way decr */ 79276336Sian mov r1, #1 80276336Sian lsl r1, r1, r0 /* r1 now contains the set decr */ 81276336Sian mov r2, ip /* r2 now contains set way decr */ 82276336Sian 83276336Sian /* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */ 84276336Sian2: mcr CP15_DCISW(r3) /* invalidate line */ 85276336Sian movs r0, r3 /* get current way/set */ 86276336Sian beq 3f /* at 0 means we are done */ 87276336Sian movs r0, r0, lsl #10 /* clear way bits leaving only set bits*/ 88276336Sian subne r3, r3, r1 /* non-zero?, decrement set */ 89276336Sian subeq r3, r3, r2 /* zero?, decrement way and restore set count */ 90276336Sian b 2b 91276336Sian 92276336Sian3: 93276336Sian mrc CP15_CSSELR(r0) /* get cache level */ 94276394Sian teq r0, #0 95276394Sian bne 1b 96276336Sian 97276336Sian4: dsb /* wait for stores to finish */ 98276336Sian mov r0, #0 99276336Sian mcr CP15_CSSELR(r0) 100276336Sian isb 101276336Sian bx lr 102276394Sian#endif /* __ARM_ARCH == 6 */ 103276336SianEND(dcache_inv_poc_all) 104276336Sian 105276336Sian/* Invalidate D cache to PoU. (aka L1 cache only)*/ 106276350SianASENTRY_NP(dcache_inv_pou_all) 107276394Sian#if __ARM_ARCH == 6 108276394Sian mcr CP15_DCIALL 109276394Sian DSB 110276394Sian bx lr 111276394Sian#else 112276336Sian mrc CP15_CLIDR(r0) 113276444Sian ands r0, r0, #0x38000000 114276336Sian mov r0, r0, lsr #26 /* Get LoUU (naturally aligned) */ 115276336Sian beq 4f 116276336Sian 117276394Sian1: sub r0, #2 118276394Sian mcr CP15_CSSELR(r0) /* set cache level */ 119276336Sian isb 120276336Sian mrc CP15_CCSIDR(r0) /* read CCSIDR */ 121276336Sian 122276336Sian ubfx r2, r0, #13, #15 /* get num sets - 1 from CCSIDR */ 123276336Sian ubfx r3, r0, #3, #10 /* get num ways - 1 from CCSIDR */ 124276336Sian clz r1, r3 /* number of bits to MSB of way */ 125276336Sian lsl r3, r3, r1 /* shift into position */ 126276336Sian mov ip, #1 127276336Sian lsl ip, ip, r1 /* ip now contains the way decr */ 128276336Sian 129276336Sian ubfx r0, r0, #0, #3 /* get linesize from CCSIDR */ 130276336Sian add r0, r0, #4 /* apply bias */ 131276336Sian lsl r2, r2, r0 /* shift sets by log2(linesize) */ 132276336Sian add r3, r3, r2 /* merge numsets - 1 with numways - 1 */ 133276336Sian sub ip, ip, r2 /* subtract numsets - 1 from way decr */ 134276336Sian mov r1, #1 135276336Sian lsl r1, r1, r0 /* r1 now contains the set decr */ 136276336Sian mov r2, ip /* r2 now contains set way decr */ 137276336Sian 138276336Sian /* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */ 139276394Sian2: mcr CP15_DCISW(r3) /* invalidate line */ 140276336Sian movs r0, r3 /* get current way/set */ 141276336Sian beq 3f /* at 0 means we are done */ 142276336Sian movs r0, r0, lsl #10 /* clear way bits leaving only set bits*/ 143276336Sian subne r3, r3, r1 /* non-zero?, decrement set */ 144276336Sian subeq r3, r3, r2 /* zero?, decrement way and restore set count */ 145276336Sian b 2b 146276336Sian 147276336Sian3: 148276336Sian mrc CP15_CSSELR(r0) /* get cache level */ 149276394Sian teq r0, #0 150276394Sian bne 1b 151276336Sian 152276336Sian4: dsb /* wait for stores to finish */ 153276336Sian mov r0, #0 154276336Sian mcr CP15_CSSELR(r0) 155276336Sian bx lr 156276394Sian#endif 157276336SianEND(dcache_inv_pou_all) 158276336Sian 159276336Sian/* Write back and Invalidate D cache to PoC. */ 160276350SianASENTRY_NP(dcache_wbinv_poc_all) 161276394Sian#if __ARM_ARCH == 6 162276394Sian mcr CP15_DCCIALL 163276394Sian DSB 164276394Sian bx lr 165276394Sian#else 166276336Sian mrc CP15_CLIDR(r0) 167276336Sian ands r0, r0, #0x07000000 168276336Sian beq 4f 169276394Sian mov r0, #0 /* Clean from inner to outer levels */ 170276336Sian 171276336Sian1: mcr CP15_CSSELR(r0) /* set cache level */ 172276336Sian isb 173276336Sian mrc CP15_CCSIDR(r0) /* read CCSIDR */ 174276336Sian 175276336Sian ubfx r2, r0, #13, #15 /* get num sets - 1 from CCSIDR */ 176276336Sian ubfx r3, r0, #3, #10 /* get num ways - 1 from CCSIDR */ 177276336Sian clz r1, r3 /* number of bits to MSB of way */ 178276336Sian lsl r3, r3, r1 /* shift into position */ 179276336Sian mov ip, #1 180276336Sian lsl ip, ip, r1 /* ip now contains the way decr */ 181276336Sian 182276336Sian ubfx r0, r0, #0, #3 /* get linesize from CCSIDR */ 183276336Sian add r0, r0, #4 /* apply bias */ 184276336Sian lsl r2, r2, r0 /* shift sets by log2(linesize) */ 185276336Sian add r3, r3, r2 /* merge numsets - 1 with numways - 1 */ 186276336Sian sub ip, ip, r2 /* subtract numsets - 1 from way decr */ 187276336Sian mov r1, #1 188276336Sian lsl r1, r1, r0 /* r1 now contains the set decr */ 189276336Sian mov r2, ip /* r2 now contains set way decr */ 190276336Sian 191276336Sian /* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */ 192276394Sian2: mcr CP15_DCCISW(r3) /* clean and invalidate line */ 193276336Sian movs r0, r3 /* get current way/set */ 194276336Sian beq 3f /* at 0 means we are done */ 195276336Sian movs r0, r0, lsl #10 /* clear way bits leaving only set bits*/ 196276336Sian subne r3, r3, r1 /* non-zero?, decrement set */ 197276336Sian subeq r3, r3, r2 /* zero?, decrement way and restore set count */ 198276336Sian b 2b 199276336Sian 200276336Sian3: 201276336Sian mrc CP15_CSSELR(r0) /* get cache level */ 202276336Sian add r0, r0, #2 /* next level */ 203276336Sian mrc CP15_CLIDR(r1) 204276336Sian ands r1, r1, #0x07000000 205276336Sian mov r1, r1, lsr #23 /* Get LoC (naturally aligned) */ 206276336Sian cmp r1, r0 207276394Sian bne 1b 208276336Sian 209276336Sian4: dsb /* wait for stores to finish */ 210276336Sian mov r0, #0 211276336Sian mcr CP15_CSSELR(r0) 212276336Sian bx lr 213276394Sian#endif /* __ARM_ARCH == 6 */ 214276336SianEND(dcache_wbinv_poc_all) 215283947Sian 216283947SianASENTRY_NP(dcache_wb_pou_checked) 217283947Sian ldr ip, .Lcpuinfo 218283947Sian ldr ip, [ip, #DCACHE_LINE_SIZE] 219283947Sian 220283947Sian GET_PCB(r2) 221283947Sian ldr r2, [r2] 222283947Sian 223283947Sian adr r3, _C_LABEL(cachebailout) 224283947Sian str r3, [r2, #PCB_ONFAULT] 225283947Sian1: 226283947Sian mcr CP15_DCCMVAC(r0) 227283947Sian add r0, r0, ip 228283947Sian subs r1, r1, ip 229283947Sian bhi 1b 230283947Sian DSB 231283947Sian mov r0, #0 232283947Sian str r0, [r2, #PCB_ONFAULT] 233283947Sian mov r0, #1 /* cannot be faulting address */ 234283947Sian RET 235283947Sian 236283947Sian.Lcpuinfo: 237283947Sian .word cpuinfo 238283947SianEND(dcache_wb_pou_checked) 239283947Sian 240283947SianASENTRY_NP(icache_inv_pou_checked) 241283947Sian ldr ip, .Lcpuinfo 242283947Sian ldr ip, [ip, #ICACHE_LINE_SIZE] 243283947Sian 244283947Sian GET_PCB(r2) 245283947Sian ldr r2, [r2] 246283947Sian 247283947Sian adr r3, _C_LABEL(cachebailout) 248283947Sian str r3, [r2, #PCB_ONFAULT] 249283947Sian 250283947Sian1: 251283947Sian mcr CP15_ICIMVAU(r0) 252283947Sian add r0, r0, ip 253283947Sian subs r1, r1, ip 254283947Sian bhi 1b 255283947Sian DSB 256283947Sian ISB 257283947Sian mov r0, #0 258283947Sian str r0, [r2, #PCB_ONFAULT] 259283947Sian mov r0, #1 /* cannot be faulting address */ 260283947Sian RET 261283947SianEND(icache_inv_pou_checked) 262283947Sian 263283947Sian/* label must be global as trap-v6.c references it */ 264283947Sian .global _C_LABEL(cachebailout) 265283947Sian_C_LABEL(cachebailout): 266283947Sian DSB 267283947Sian ISB 268283947Sian mov r1, #0 269283947Sian str r1, [r2, #PCB_ONFAULT] 270283947Sian RET 271