1/* 2 * Blackfin cache control code 3 * 4 * Copyright 2004-2008 Analog Devices Inc. 5 * 6 * Licensed under the GPL-2 or later. 7 */ 8 9#include <linux/linkage.h> 10#include <asm/blackfin.h> 11#include <asm/cache.h> 12#include <asm/page.h> 13 14#ifdef CONFIG_CACHE_FLUSH_L1 15.section .l1.text 16#else 17.text 18#endif 19 20/* 05000443 - IFLUSH cannot be last instruction in hardware loop */ 21#if ANOMALY_05000443 22# define BROK_FLUSH_INST "IFLUSH" 23#else 24# define BROK_FLUSH_INST "no anomaly! yeah!" 25#endif 26 27/* Since all L1 caches work the same way, we use the same method for flushing 28 * them. Only the actual flush instruction differs. We write this in asm as 29 * GCC can be hard to coax into writing nice hardware loops. 30 * 31 * Also, we assume the following register setup: 32 * R0 = start address 33 * R1 = end address 34 */ 35.macro do_flush flushins:req label 36 37 R2 = -L1_CACHE_BYTES; 38 39 /* start = (start & -L1_CACHE_BYTES) */ 40 R0 = R0 & R2; 41 42 /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */ 43 R1 += -1; 44 R1 = R1 & R2; 45 R1 += L1_CACHE_BYTES; 46 47 /* count = (end - start) >> L1_CACHE_SHIFT */ 48 R2 = R1 - R0; 49 R2 >>= L1_CACHE_SHIFT; 50 P1 = R2; 51 52.ifnb \label 53\label : 54.endif 55 P0 = R0; 56 57 LSETUP (1f, 2f) LC1 = P1; 581: 59.ifeqs "\flushins", BROK_FLUSH_INST 60 \flushins [P0++]; 612: nop; 62.else 632: \flushins [P0++]; 64.endif 65 66 RTS; 67.endm 68 69/* Invalidate all instruction cache lines assocoiated with this memory area */ 70ENTRY(_blackfin_icache_flush_range) 71 do_flush IFLUSH 72ENDPROC(_blackfin_icache_flush_range) 73 74/* Throw away all D-cached data in specified region without any obligation to 75 * write them back. Since the Blackfin ISA does not have an "invalidate" 76 * instruction, we use flush/invalidate. Perhaps as a speed optimization we 77 * could bang on the DTEST MMRs ... 78 */ 79ENTRY(_blackfin_dcache_invalidate_range) 80 do_flush FLUSHINV 81ENDPROC(_blackfin_dcache_invalidate_range) 82 83/* Flush all data cache lines assocoiated with this memory area */ 84ENTRY(_blackfin_dcache_flush_range) 85 do_flush FLUSH, .Ldfr 86ENDPROC(_blackfin_dcache_flush_range) 87 88/* Our headers convert the page structure to an address, so just need to flush 89 * its contents like normal. We know the start address is page aligned (which 90 * greater than our cache alignment), as is the end address. So just jump into 91 * the middle of the dcache flush function. 92 */ 93ENTRY(_blackfin_dflush_page) 94 P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); 95 jump .Ldfr; 96ENDPROC(_blackfin_dflush_page) 97