1*4882a593Smuzhiyun/* 2*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+ 3*4882a593Smuzhiyun */ 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun#include <config.h> 6*4882a593Smuzhiyun#include <linux/linkage.h> 7*4882a593Smuzhiyun#include <linux/sizes.h> 8*4882a593Smuzhiyun#include <asm/system.h> 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD) 11*4882a593Smuzhiyun#define ARM(x...) 12*4882a593Smuzhiyun#define THUMB(x...) x 13*4882a593Smuzhiyun#else 14*4882a593Smuzhiyun#define ARM(x...) x 15*4882a593Smuzhiyun#define THUMB(x...) 16*4882a593Smuzhiyun#endif 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun/* 19*4882a593Smuzhiyun * v7_flush_dcache_all() 20*4882a593Smuzhiyun * 21*4882a593Smuzhiyun * Flush the whole D-cache. 22*4882a593Smuzhiyun * 23*4882a593Smuzhiyun * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) 24*4882a593Smuzhiyun * 25*4882a593Smuzhiyun * Note: copied from arch/arm/mm/cache-v7.S of Linux 4.4 26*4882a593Smuzhiyun */ 27*4882a593SmuzhiyunENTRY(__v7_flush_dcache_all) 28*4882a593Smuzhiyun dmb @ ensure ordering with previous memory accesses 29*4882a593Smuzhiyun mrc p15, 1, r0, c0, c0, 1 @ read clidr 30*4882a593Smuzhiyun mov r3, r0, lsr #23 @ move LoC into position 31*4882a593Smuzhiyun ands r3, r3, #7 << 1 @ extract LoC*2 from clidr 32*4882a593Smuzhiyun beq finished @ if loc is 0, then no need to clean 33*4882a593Smuzhiyunstart_flush_levels: 34*4882a593Smuzhiyun mov r10, #0 @ start clean at cache level 0 35*4882a593Smuzhiyunflush_levels: 36*4882a593Smuzhiyun add r2, r10, r10, lsr #1 @ work out 3x current cache level 37*4882a593Smuzhiyun mov r1, r0, lsr r2 @ extract cache type bits from clidr 38*4882a593Smuzhiyun and r1, r1, #7 @ mask of the bits for current cache only 39*4882a593Smuzhiyun cmp r1, #2 @ see what cache we have at this level 40*4882a593Smuzhiyun blt skip @ skip if no cache, or just i-cache 41*4882a593Smuzhiyun mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr 42*4882a593Smuzhiyun isb @ isb to sych the new cssr&csidr 43*4882a593Smuzhiyun mrc p15, 1, r1, c0, c0, 0 @ read the new csidr 44*4882a593Smuzhiyun and r2, r1, #7 @ extract the length of the cache lines 45*4882a593Smuzhiyun add r2, r2, #4 @ add 4 (line length offset) 46*4882a593Smuzhiyun movw r4, #0x3ff 47*4882a593Smuzhiyun ands r4, r4, r1, lsr #3 @ find maximum number on the way size 48*4882a593Smuzhiyun clz r5, r4 @ find bit position of way size increment 49*4882a593Smuzhiyun movw r7, #0x7fff 50*4882a593Smuzhiyun ands r7, r7, r1, lsr #13 @ extract max number of the index size 51*4882a593Smuzhiyunloop1: 52*4882a593Smuzhiyun mov r9, r7 @ create working copy of max index 53*4882a593Smuzhiyunloop2: 54*4882a593Smuzhiyun ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11 55*4882a593Smuzhiyun THUMB( lsl r6, r4, r5 ) 56*4882a593Smuzhiyun THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 57*4882a593Smuzhiyun ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11 58*4882a593Smuzhiyun THUMB( lsl r6, r9, r2 ) 59*4882a593Smuzhiyun THUMB( orr r11, r11, r6 ) @ factor index number into r11 60*4882a593Smuzhiyun mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way 61*4882a593Smuzhiyun subs r9, r9, #1 @ decrement the index 62*4882a593Smuzhiyun bge loop2 63*4882a593Smuzhiyun subs r4, r4, #1 @ decrement the way 64*4882a593Smuzhiyun bge loop1 65*4882a593Smuzhiyunskip: 66*4882a593Smuzhiyun add r10, r10, #2 @ increment cache number 67*4882a593Smuzhiyun cmp r3, r10 68*4882a593Smuzhiyun bgt flush_levels 69*4882a593Smuzhiyunfinished: 70*4882a593Smuzhiyun mov r10, #0 @ swith back to cache level 0 71*4882a593Smuzhiyun mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr 72*4882a593Smuzhiyun dsb st 73*4882a593Smuzhiyun isb 74*4882a593Smuzhiyun bx lr 75*4882a593SmuzhiyunENDPROC(__v7_flush_dcache_all) 76*4882a593Smuzhiyun 77*4882a593SmuzhiyunENTRY(v7_flush_dcache_all) 78*4882a593Smuzhiyun ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) 79*4882a593Smuzhiyun THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) 80*4882a593Smuzhiyun bl __v7_flush_dcache_all 81*4882a593Smuzhiyun ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) 82*4882a593Smuzhiyun THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) 83*4882a593Smuzhiyun bx lr 84*4882a593SmuzhiyunENDPROC(v7_flush_dcache_all) 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun/* 87*4882a593Smuzhiyun * v7_invalidate_dcache_all() 88*4882a593Smuzhiyun * 89*4882a593Smuzhiyun * Invalidate the whole D-cache. 90*4882a593Smuzhiyun * 91*4882a593Smuzhiyun * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode) 92*4882a593Smuzhiyun * 93*4882a593Smuzhiyun * Note: copied from __v7_flush_dcache_all above with 94*4882a593Smuzhiyun * mcr p15, 0, r11, c7, c14, 2 95*4882a593Smuzhiyun * Replaced with: 96*4882a593Smuzhiyun * mcr p15, 0, r11, c7, c6, 2 97*4882a593Smuzhiyun */ 98*4882a593SmuzhiyunENTRY(__v7_invalidate_dcache_all) 99*4882a593Smuzhiyun dmb @ ensure ordering with previous memory accesses 100*4882a593Smuzhiyun mrc p15, 1, r0, c0, c0, 1 @ read clidr 101*4882a593Smuzhiyun mov r3, r0, lsr #23 @ move LoC into position 102*4882a593Smuzhiyun ands r3, r3, #7 << 1 @ extract LoC*2 from clidr 103*4882a593Smuzhiyun beq inval_finished @ if loc is 0, then no need to clean 104*4882a593Smuzhiyun mov r10, #0 @ start clean at cache level 0 105*4882a593Smuzhiyuninval_levels: 106*4882a593Smuzhiyun add r2, r10, r10, lsr #1 @ work out 3x current cache level 107*4882a593Smuzhiyun mov r1, r0, lsr r2 @ extract cache type bits from clidr 108*4882a593Smuzhiyun and r1, r1, #7 @ mask of the bits for current cache only 109*4882a593Smuzhiyun cmp r1, #2 @ see what cache we have at this level 110*4882a593Smuzhiyun blt inval_skip @ skip if no cache, or just i-cache 111*4882a593Smuzhiyun mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr 112*4882a593Smuzhiyun isb @ isb to sych the new cssr&csidr 113*4882a593Smuzhiyun mrc p15, 1, r1, c0, c0, 0 @ read the new csidr 114*4882a593Smuzhiyun and r2, r1, #7 @ extract the length of the cache lines 115*4882a593Smuzhiyun add r2, r2, #4 @ add 4 (line length offset) 116*4882a593Smuzhiyun movw r4, #0x3ff 117*4882a593Smuzhiyun ands r4, r4, r1, lsr #3 @ find maximum number on the way size 118*4882a593Smuzhiyun clz r5, r4 @ find bit position of way size increment 119*4882a593Smuzhiyun movw r7, #0x7fff 120*4882a593Smuzhiyun ands r7, r7, r1, lsr #13 @ extract max number of the index size 121*4882a593Smuzhiyuninval_loop1: 122*4882a593Smuzhiyun mov r9, r7 @ create working copy of max index 123*4882a593Smuzhiyuninval_loop2: 124*4882a593Smuzhiyun ARM( orr r11, r10, r4, lsl r5 ) @ factor way and cache number into r11 125*4882a593Smuzhiyun THUMB( lsl r6, r4, r5 ) 126*4882a593Smuzhiyun THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 127*4882a593Smuzhiyun ARM( orr r11, r11, r9, lsl r2 ) @ factor index number into r11 128*4882a593Smuzhiyun THUMB( lsl r6, r9, r2 ) 129*4882a593Smuzhiyun THUMB( orr r11, r11, r6 ) @ factor index number into r11 130*4882a593Smuzhiyun mcr p15, 0, r11, c7, c6, 2 @ invalidate by set/way 131*4882a593Smuzhiyun subs r9, r9, #1 @ decrement the index 132*4882a593Smuzhiyun bge inval_loop2 133*4882a593Smuzhiyun subs r4, r4, #1 @ decrement the way 134*4882a593Smuzhiyun bge inval_loop1 135*4882a593Smuzhiyuninval_skip: 136*4882a593Smuzhiyun add r10, r10, #2 @ increment cache number 137*4882a593Smuzhiyun cmp r3, r10 138*4882a593Smuzhiyun bgt inval_levels 139*4882a593Smuzhiyuninval_finished: 140*4882a593Smuzhiyun mov r10, #0 @ swith back to cache level 0 141*4882a593Smuzhiyun mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr 142*4882a593Smuzhiyun dsb st 143*4882a593Smuzhiyun isb 144*4882a593Smuzhiyun bx lr 145*4882a593SmuzhiyunENDPROC(__v7_invalidate_dcache_all) 146*4882a593Smuzhiyun 147*4882a593SmuzhiyunENTRY(v7_invalidate_dcache_all) 148*4882a593Smuzhiyun ARM( stmfd sp!, {r4-r5, r7, r9-r11, lr} ) 149*4882a593Smuzhiyun THUMB( stmfd sp!, {r4-r7, r9-r11, lr} ) 150*4882a593Smuzhiyun bl __v7_invalidate_dcache_all 151*4882a593Smuzhiyun ARM( ldmfd sp!, {r4-r5, r7, r9-r11, lr} ) 152*4882a593Smuzhiyun THUMB( ldmfd sp!, {r4-r7, r9-r11, lr} ) 153*4882a593Smuzhiyun bx lr 154*4882a593SmuzhiyunENDPROC(v7_invalidate_dcache_all) 155