/* * cortex arm arch v7 cache flushing and invalidation * shared by l.s and rebootcode.s */ TEXT cacheiinv(SB), $-4 /* I invalidate */ MOVW $0, R0 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvi), CpCACHEall /* ok on cortex */ ISB RET /* * set/way operators, passed a suitable set/way value in R0. */TEXT cachedwb_sw(SB), $-4 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEsi RET TEXT cachedwbinv_sw(SB), $-4 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEsi RET TEXT cachedinv_sw(SB), $-4 MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEsi RET /* set cache size select */TEXT setcachelvl(SB), $-4 MCR CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0 ISB RET /* return cache sizes */TEXT getwayssets(SB), $-4 MRC CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0 RET /* * l1 cache operations. * l1 and l2 ops are intended to be called from C, thus need save no * caller's regs, only those we need to preserve across calls. */ TEXT cachedwb(SB), $-4 MOVW.W R14, -8(R13) MOVW $cachedwb_sw(SB), R0 MOVW $1, R8 BL wholecache(SB) MOVW.P 8(R13), R15 TEXT cachedwbinv(SB), $-4 MOVW.W R14, -8(R13) MOVW $cachedwbinv_sw(SB), R0 MOVW $1, R8 BL wholecache(SB) MOVW.P 8(R13), R15 TEXT cachedinv(SB), $-4 MOVW.W R14, -8(R13) MOVW $cachedinv_sw(SB), R0 MOVW $1, R8 BL wholecache(SB) MOVW.P 8(R13), R15 TEXT cacheuwbinv(SB), $-4 MOVM.DB.W [R14], (R13) /* save lr on stack */ MOVW CPSR, R1 CPSID /* splhi */ MOVM.DB.W [R1], (R13) /* save R1 on stack */ BL cachedwbinv(SB) BL cacheiinv(SB) MOVM.IA.W (R13), [R1] /* restore R1 (saved CPSR) */ MOVW R1, CPSR MOVM.IA.W (R13), [R14] /* restore lr */ RET /* * l2 cache operations */ TEXT l2cacheuwb(SB), $-4 MOVW.W R14, -8(R13) MOVW $cachedwb_sw(SB), R0 MOVW $2, R8 BL wholecache(SB) MOVW.P 8(R13), R15 TEXT l2cacheuwbinv(SB), $-4 MOVW.W R14, -8(R13) MOVW CPSR, R1 CPSID /* splhi */ MOVM.DB.W [R1], (R13) /* save R1 on stack */ MOVW $cachedwbinv_sw(SB), R0 MOVW $2, R8 BL wholecache(SB) BL l2cacheuinv(SB) MOVM.IA.W (R13), [R1] /* restore R1 (saved CPSR) */ MOVW R1, CPSR MOVW.P 8(R13), R15 TEXT l2cacheuinv(SB), $-4 MOVW.W R14, -8(R13) MOVW $cachedinv_sw(SB), R0 MOVW $2, R8 BL wholecache(SB) MOVW.P 8(R13), R15 /* * these shift values are for the Cortex-A8 L1 cache (A=2, L=6) and * the Cortex-A8 L2 cache (A=3, L=6). * A = log2(# of ways), L = log2(bytes per cache line). * see armv7 arch ref p. 1403. */#define L1WAYSH 30#define L1SETSH 6#define L2WAYSH 29#define L2SETSH 6 /* * callers are assumed to be the above l1 and l2 ops. * R0 is the function to call in the innermost loop. * R8 is the cache level (one-origin: 1 or 2). * * initial translation by 5c, then massaged by hand. */TEXT wholecache+0(SB), $-4 MOVW R0, R1 /* save argument for inner loop in R1 */ SUB $1, R8 /* convert cache level to zero origin */ /* we may not have the MMU on yet, so map R1 to PC's space */ BIC $KSEGM, R1 /* strip segment from address */ MOVW PC, R2 /* get PC's segment ... */ AND $KSEGM, R2 CMP $0, R2 /* PC segment should be non-zero on omap */ BEQ buggery ORR R2, R1 /* combine them */ /* drain write buffers */ BARRIERS MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait ISB MOVW CPSR, R2 MOVM.DB.W [R2,R14], (SP) /* save regs on stack */ CPSID /* splhi to make entire op atomic */ /* get cache sizes */ SLL $1, R8, R0 /* R0 = (cache - 1) << 1 */ MCR CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0 /* set cache size select */ ISB MRC CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0 /* get cache sizes */ /* compute # of ways and sets for this cache level */ SRA $3, R0, R5 /* R5 (ways) = R0 >> 3 */ AND $1023, R5 /* R5 = (R0 >> 3) & MASK(10) */ ADD $1, R5 /* R5 (ways) = ((R0 >> 3) & MASK(10)) + 1 */ SRA $13, R0, R2 /* R2 = R0 >> 13 */ AND $32767, R2 /* R2 = (R0 >> 13) & MASK(15) */ ADD $1, R2 /* R2 (sets) = ((R0 >> 13) & MASK(15)) + 1 */ /* precompute set/way shifts for inner loop */ CMP $0, R8 /* cache == 1? */ MOVW.EQ $L1WAYSH, R3 /* yes */ MOVW.EQ $L1SETSH, R4 MOVW.NE $L2WAYSH, R3 /* no */ MOVW.NE $L2SETSH, R4 /* iterate over ways */ MOVW $0, R7 /* R7: way */outer: /* iterate over sets */ MOVW $0, R6 /* R6: set */inner: /* compute set/way register contents */ SLL R3, R7, R0 /* R0 = way << R3 (L?WAYSH) */ ORR R8<<1, R0 /* R0 = way << L?WAYSH | (cache - 1) << 1 */ ORR R6<<R4, R0 /* R0 = way<<L?WAYSH | (cache-1)<<1 |set<<R4 */ BL (R1) /* call set/way operation with R0 */ ADD $1, R6 /* set++ */ CMP R2, R6 /* set >= sets? */ BLT inner /* no, do next set */ ADD $1, R7 /* way++ */ CMP R5, R7 /* way >= ways? */ BLT outer /* no, do next way */ MOVM.IA.W (SP), [R2,R14] /* restore regs */ MOVW R2, CPSR /* splx */ /* drain write buffers */ MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait ISB RET buggery:PUTC('?') MOVW PC, R0// B pczeroseg(SB) RET
/*
* cortex arm arch v7 cache flushing and invalidation
* shared by l.s and rebootcode.s
*/
TEXT cacheiinv(SB), $-4 /* I invalidate */
MOVW $0, R0
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvi), CpCACHEall /* ok on cortex */
ISB
RET
/*
* set/way operators, passed a suitable set/way value in R0.
*/
TEXT cachedwb_sw(SB), $-4
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEsi
RET
TEXT cachedwbinv_sw(SB), $-4
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwbi), CpCACHEsi
RET
TEXT cachedinv_sw(SB), $-4
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEinvd), CpCACHEsi
RET
/* set cache size select */
TEXT setcachelvl(SB), $-4
MCR CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0
ISB
RET
/* return cache sizes */
TEXT getwayssets(SB), $-4
MRC CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0
RET
/*
* l1 cache operations.
* l1 and l2 ops are intended to be called from C, thus need save no
* caller's regs, only those we need to preserve across calls.
*/
TEXT cachedwb(SB), $-4
MOVW.W R14, -8(R13)
MOVW $cachedwb_sw(SB), R0
MOVW $1, R8
BL wholecache(SB)
MOVW.P 8(R13), R15
TEXT cachedwbinv(SB), $-4
MOVW.W R14, -8(R13)
MOVW $cachedwbinv_sw(SB), R0
MOVW $1, R8
BL wholecache(SB)
MOVW.P 8(R13), R15
TEXT cachedinv(SB), $-4
MOVW.W R14, -8(R13)
MOVW $cachedinv_sw(SB), R0
MOVW $1, R8
BL wholecache(SB)
MOVW.P 8(R13), R15
TEXT cacheuwbinv(SB), $-4
MOVM.DB.W [R14], (R13) /* save lr on stack */
MOVW CPSR, R1
CPSID /* splhi */
MOVM.DB.W [R1], (R13) /* save R1 on stack */
BL cachedwbinv(SB)
BL cacheiinv(SB)
MOVM.IA.W (R13), [R1] /* restore R1 (saved CPSR) */
MOVW R1, CPSR
MOVM.IA.W (R13), [R14] /* restore lr */
RET
/*
* l2 cache operations
*/
TEXT l2cacheuwb(SB), $-4
MOVW.W R14, -8(R13)
MOVW $cachedwb_sw(SB), R0
MOVW $2, R8
BL wholecache(SB)
MOVW.P 8(R13), R15
TEXT l2cacheuwbinv(SB), $-4
MOVW.W R14, -8(R13)
MOVW CPSR, R1
CPSID /* splhi */
MOVM.DB.W [R1], (R13) /* save R1 on stack */
MOVW $cachedwbinv_sw(SB), R0
MOVW $2, R8
BL wholecache(SB)
BL l2cacheuinv(SB)
MOVM.IA.W (R13), [R1] /* restore R1 (saved CPSR) */
MOVW R1, CPSR
MOVW.P 8(R13), R15
TEXT l2cacheuinv(SB), $-4
MOVW.W R14, -8(R13)
MOVW $cachedinv_sw(SB), R0
MOVW $2, R8
BL wholecache(SB)
MOVW.P 8(R13), R15
/*
* these shift values are for the Cortex-A8 L1 cache (A=2, L=6) and
* the Cortex-A8 L2 cache (A=3, L=6).
* A = log2(# of ways), L = log2(bytes per cache line).
* see armv7 arch ref p. 1403.
*/
#define L1WAYSH 30
#define L1SETSH 6
#define L2WAYSH 29
#define L2SETSH 6
/*
* callers are assumed to be the above l1 and l2 ops.
* R0 is the function to call in the innermost loop.
* R8 is the cache level (one-origin: 1 or 2).
*
* initial translation by 5c, then massaged by hand.
*/
TEXT wholecache+0(SB), $-4
MOVW R0, R1 /* save argument for inner loop in R1 */
SUB $1, R8 /* convert cache level to zero origin */
/* we may not have the MMU on yet, so map R1 to PC's space */
BIC $KSEGM, R1 /* strip segment from address */
MOVW PC, R2 /* get PC's segment ... */
AND $KSEGM, R2
CMP $0, R2 /* PC segment should be non-zero on omap */
BEQ buggery
ORR R2, R1 /* combine them */
/* drain write buffers */
BARRIERS
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait
ISB
MOVW CPSR, R2
MOVM.DB.W [R2,R14], (SP) /* save regs on stack */
CPSID /* splhi to make entire op atomic */
/* get cache sizes */
SLL $1, R8, R0 /* R0 = (cache - 1) << 1 */
MCR CpSC, CpIDcssel, R0, C(CpID), C(CpIDidct), 0 /* set cache size select */
ISB
MRC CpSC, CpIDcsize, R0, C(CpID), C(CpIDidct), 0 /* get cache sizes */
/* compute # of ways and sets for this cache level */
SRA $3, R0, R5 /* R5 (ways) = R0 >> 3 */
AND $1023, R5 /* R5 = (R0 >> 3) & MASK(10) */
ADD $1, R5 /* R5 (ways) = ((R0 >> 3) & MASK(10)) + 1 */
SRA $13, R0, R2 /* R2 = R0 >> 13 */
AND $32767, R2 /* R2 = (R0 >> 13) & MASK(15) */
ADD $1, R2 /* R2 (sets) = ((R0 >> 13) & MASK(15)) + 1 */
/* precompute set/way shifts for inner loop */
CMP $0, R8 /* cache == 1? */
MOVW.EQ $L1WAYSH, R3 /* yes */
MOVW.EQ $L1SETSH, R4
MOVW.NE $L2WAYSH, R3 /* no */
MOVW.NE $L2SETSH, R4
/* iterate over ways */
MOVW $0, R7 /* R7: way */
outer:
/* iterate over sets */
MOVW $0, R6 /* R6: set */
inner:
/* compute set/way register contents */
SLL R3, R7, R0 /* R0 = way << R3 (L?WAYSH) */
ORR R8<<1, R0 /* R0 = way << L?WAYSH | (cache - 1) << 1 */
ORR R6<<R4, R0 /* R0 = way<<L?WAYSH | (cache-1)<<1 |set<<R4 */
BL (R1) /* call set/way operation with R0 */
ADD $1, R6 /* set++ */
CMP R2, R6 /* set >= sets? */
BLT inner /* no, do next set */
ADD $1, R7 /* way++ */
CMP R5, R7 /* way >= ways? */
BLT outer /* no, do next way */
MOVM.IA.W (SP), [R2,R14] /* restore regs */
MOVW R2, CPSR /* splx */
/* drain write buffers */
MCR CpSC, 0, R0, C(CpCACHE), C(CpCACHEwb), CpCACHEwait
ISB
RET
buggery:
PUTC('?')
MOVW PC, R0
// B pczeroseg(SB)
RET