1/* 2 * cortex arm arch v7 cache flushing and invalidation 3 * shared by l.s and rebootcode.s 4 */ 5 6TEXT cacheiinv(SB), $-4 /* I invalidate */ 7 MOVW $0, R0 8 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvi), CpCACHEall /* ok on cortex */ 9 ISB 10 RET 11 12/* 13 * set/way operators, passed a suitable set/way value in R0. 14 */ 15TEXT cachedwb_sw(SB), $-4 16 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEsi 17 RET 18 19TEXT cachedwbinv_sw(SB), $-4 20 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEsi 21 RET 22 23TEXT cachedinv_sw(SB), $-4 24 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEsi 25 RET 26 27 /* set cache size select */ 28TEXT setcachelvl(SB), $-4 29 MCR CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0 30 ISB 31 RET 32 33 /* return cache sizes */ 34TEXT getwayssets(SB), $-4 35 MRC CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0 36 RET 37 38/* 39 * l1 cache operations. 40 * l1 and l2 ops are intended to be called from C, thus need save no 41 * caller's regs, only those we need to preserve across calls. 42 */ 43 44TEXT cachedwb(SB), $-4 45 MOVW.W R14, -8(R13) 46 MOVW $cachedwb_sw(SB), R0 47 MOVW $1, R8 48 BL wholecache(SB) 49 MOVW.P 8(R13), R15 50 51TEXT cachedwbinv(SB), $-4 52 MOVW.W R14, -8(R13) 53 MOVW $cachedwbinv_sw(SB), R0 54 MOVW $1, R8 55 BL wholecache(SB) 56 MOVW.P 8(R13), R15 57 58TEXT cachedinv(SB), $-4 59 MOVW.W R14, -8(R13) 60 MOVW $cachedinv_sw(SB), R0 61 MOVW $1, R8 62 BL wholecache(SB) 63 MOVW.P 8(R13), R15 64 65TEXT cacheuwbinv(SB), $-4 66 MOVM.DB.W [R14], (R13) /* save lr on stack */ 67 MOVW CPSR, R1 68 CPSID /* splhi */ 69 70 MOVM.DB.W [R1], (R13) /* save R1 on stack */ 71 72 BL cachedwbinv(SB) 73 BL cacheiinv(SB) 74 75 MOVM.IA.W (R13), [R1] /* restore R1 (saved CPSR) */ 76 MOVW R1, CPSR 77 MOVM.IA.W (R13), [R14] /* restore lr */ 78 RET 79 80/* 81 * l2 cache operations 82 */ 83 84TEXT l2cacheuwb(SB), $-4 85 MOVW.W R14, -8(R13) 86 MOVW $cachedwb_sw(SB), R0 87 MOVW $2, R8 88 BL wholecache(SB) 89 MOVW.P 8(R13), R15 90 91TEXT l2cacheuwbinv(SB), $-4 92 MOVW.W R14, -8(R13) 93 MOVW CPSR, R1 94 CPSID /* splhi */ 95 96 MOVM.DB.W [R1], (R13) /* save R1 on stack */ 97 98 MOVW $cachedwbinv_sw(SB), R0 99 MOVW $2, R8 100 BL wholecache(SB) 101 BL l2cacheuinv(SB) 102 103 MOVM.IA.W (R13), [R1] /* restore R1 (saved CPSR) */ 104 MOVW R1, CPSR 105 MOVW.P 8(R13), R15 106 107TEXT l2cacheuinv(SB), $-4 108 MOVW.W R14, -8(R13) 109 MOVW $cachedinv_sw(SB), R0 110 MOVW $2, R8 111 BL wholecache(SB) 112 MOVW.P 8(R13), R15 113 114/* 115 * these shift values are for the Cortex-A8 L1 cache (A=2, L=6) and 116 * the Cortex-A8 L2 cache (A=3, L=6). 117 * A = log2(# of ways), L = log2(bytes per cache line). 118 * see armv7 arch ref p. 1403. 119 */ 120#define L1WAYSH 30 121#define L1SETSH 6 122#define L2WAYSH 29 123#define L2SETSH 6 124 125/* 126 * callers are assumed to be the above l1 and l2 ops. 127 * R0 is the function to call in the innermost loop. 128 * R8 is the cache level (one-origin: 1 or 2). 129 * 130 * initial translation by 5c, then massaged by hand. 131 */ 132TEXT wholecache+0(SB), $-4 133 MOVW R0, R1 /* save argument for inner loop in R1 */ 134 SUB $1, R8 /* convert cache level to zero origin */ 135 136 /* we may not have the MMU on yet, so map R1 to PC's space */ 137 BIC $KSEGM, R1 /* strip segment from address */ 138 MOVW PC, R2 /* get PC's segment ... */ 139 AND $KSEGM, R2 140 CMP $0, R2 /* PC segment should be non-zero on omap */ 141 BEQ buggery 142 ORR R2, R1 /* combine them */ 143 144 /* drain write buffers */ 145 BARRIERS 146 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait 147 ISB 148 149 MOVW CPSR, R2 150 MOVM.DB.W [R2,R14], (SP) /* save regs on stack */ 151 CPSID /* splhi to make entire op atomic */ 152 153 /* get cache sizes */ 154 SLL $1, R8, R0 /* R0 = (cache - 1) << 1 */ 155 MCR CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0 /* set cache size select */ 156 ISB 157 MRC CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0 /* get cache sizes */ 158 159 /* compute # of ways and sets for this cache level */ 160 SRA $3, R0, R5 /* R5 (ways) = R0 >> 3 */ 161 AND $1023, R5 /* R5 = (R0 >> 3) & MASK(10) */ 162 ADD $1, R5 /* R5 (ways) = ((R0 >> 3) & MASK(10)) + 1 */ 163 164 SRA $13, R0, R2 /* R2 = R0 >> 13 */ 165 AND $32767, R2 /* R2 = (R0 >> 13) & MASK(15) */ 166 ADD $1, R2 /* R2 (sets) = ((R0 >> 13) & MASK(15)) + 1 */ 167 168 /* precompute set/way shifts for inner loop */ 169 CMP $0, R8 /* cache == 1? */ 170 MOVW.EQ $L1WAYSH, R3 /* yes */ 171 MOVW.EQ $L1SETSH, R4 172 MOVW.NE $L2WAYSH, R3 /* no */ 173 MOVW.NE $L2SETSH, R4 174 175 /* iterate over ways */ 176 MOVW $0, R7 /* R7: way */ 177outer: 178 /* iterate over sets */ 179 MOVW $0, R6 /* R6: set */ 180inner: 181 /* compute set/way register contents */ 182 SLL R3, R7, R0 /* R0 = way << R3 (L?WAYSH) */ 183 ORR R8<<1, R0 /* R0 = way << L?WAYSH | (cache - 1) << 1 */ 184 ORR R6<<R4, R0 /* R0 = way<<L?WAYSH | (cache-1)<<1 |set<<R4 */ 185 186 BL (R1) /* call set/way operation with R0 */ 187 188 ADD $1, R6 /* set++ */ 189 CMP R2, R6 /* set >= sets? */ 190 BLT inner /* no, do next set */ 191 192 ADD $1, R7 /* way++ */ 193 CMP R5, R7 /* way >= ways? */ 194 BLT outer /* no, do next way */ 195 196 MOVM.IA.W (SP), [R2,R14] /* restore regs */ 197 MOVW R2, CPSR /* splx */ 198 199 /* drain write buffers */ 200 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait 201 ISB 202 RET 203 204buggery: 205PUTC('?') 206 MOVW PC, R0 207// B pczeroseg(SB) 208 RET 209