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/* 05000443 - IFLUSH cannot be last instruction in hardware loop */ 15#if ANOMALY_05000443 16# define BROK_FLUSH_INST "IFLUSH" 17#else 18# define BROK_FLUSH_INST "no anomaly! yeah!" 19#endif 20 21/* Since all L1 caches work the same way, we use the same method for flushing 22 * them. Only the actual flush instruction differs. We write this in asm as 23 * GCC can be hard to coax into writing nice hardware loops. 24 * 25 * Also, we assume the following register setup: 26 * R0 = start address 27 * R1 = end address 28 */ 29.macro do_flush flushins:req label 30 31 R2 = -L1_CACHE_BYTES; 32 33 /* start = (start & -L1_CACHE_BYTES) */ 34 R0 = R0 & R2; 35 36 /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */ 37 R1 += -1; 38 R1 = R1 & R2; 39 R1 += L1_CACHE_BYTES; 40 41 /* count = (end - start) >> L1_CACHE_SHIFT */ 42 R2 = R1 - R0; 43 R2 >>= L1_CACHE_SHIFT; 44 P1 = R2; 45 46.ifnb \label 47\label : 48.endif 49 P0 = R0; 50 51 LSETUP (1f, 2f) LC1 = P1; 521: 53.ifeqs "\flushins", BROK_FLUSH_INST 54 \flushins [P0++]; 55 nop; 56 nop; 572: nop; 58.else 592: \flushins [P0++]; 60.endif 61 62 RTS; 63.endm 64 65#ifdef CONFIG_ICACHE_FLUSH_L1 66.section .l1.text 67#else 68.text 69#endif 70 71/* Invalidate all instruction cache lines assocoiated with this memory area */ 72#ifdef CONFIG_SMP 73# define _blackfin_icache_flush_range _blackfin_icache_flush_range_l1 74#endif 75ENTRY(_blackfin_icache_flush_range) 76 do_flush IFLUSH 77ENDPROC(_blackfin_icache_flush_range) 78 79#ifdef CONFIG_SMP 80.text 81# undef _blackfin_icache_flush_range 82ENTRY(_blackfin_icache_flush_range) 83 p0.L = LO(DSPID); 84 p0.H = HI(DSPID); 85 r3 = [p0]; 86 r3 = r3.b (z); 87 p2 = r3; 88 p0.L = _blackfin_iflush_l1_entry; 89 p0.H = _blackfin_iflush_l1_entry; 90 p0 = p0 + (p2 << 2); 91 p1 = [p0]; 92 jump (p1); 93ENDPROC(_blackfin_icache_flush_range) 94#endif 95 96#ifdef CONFIG_DCACHE_FLUSH_L1 97.section .l1.text 98#else 99.text 100#endif 101 102/* Throw away all D-cached data in specified region without any obligation to 103 * write them back. Since the Blackfin ISA does not have an "invalidate" 104 * instruction, we use flush/invalidate. Perhaps as a speed optimization we 105 * could bang on the DTEST MMRs ... 106 */ 107ENTRY(_blackfin_dcache_invalidate_range) 108 do_flush FLUSHINV 109ENDPROC(_blackfin_dcache_invalidate_range) 110 111/* Flush all data cache lines assocoiated with this memory area */ 112ENTRY(_blackfin_dcache_flush_range) 113 do_flush FLUSH, .Ldfr 114ENDPROC(_blackfin_dcache_flush_range) 115 116/* Our headers convert the page structure to an address, so just need to flush 117 * its contents like normal. We know the start address is page aligned (which 118 * greater than our cache alignment), as is the end address. So just jump into 119 * the middle of the dcache flush function. 120 */ 121ENTRY(_blackfin_dflush_page) 122 P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); 123 jump .Ldfr; 124ENDPROC(_blackfin_dflush_page) 125