Path: blob/master/arch/blackfin/mach-common/cache.S
10817 views
/*1* Blackfin cache control code2*3* Copyright 2004-2008 Analog Devices Inc.4*5* Licensed under the GPL-2 or later.6*/78#include <linux/linkage.h>9#include <asm/blackfin.h>10#include <asm/cache.h>11#include <asm/page.h>1213/* 05000443 - IFLUSH cannot be last instruction in hardware loop */14#if ANOMALY_0500044315# define BROK_FLUSH_INST "IFLUSH"16#else17# define BROK_FLUSH_INST "no anomaly! yeah!"18#endif1920/* Since all L1 caches work the same way, we use the same method for flushing21* them. Only the actual flush instruction differs. We write this in asm as22* GCC can be hard to coax into writing nice hardware loops.23*24* Also, we assume the following register setup:25* R0 = start address26* R1 = end address27*/28.macro do_flush flushins:req label2930R2 = -L1_CACHE_BYTES;3132/* start = (start & -L1_CACHE_BYTES) */33R0 = R0 & R2;3435/* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */36R1 += -1;37R1 = R1 & R2;38R1 += L1_CACHE_BYTES;3940/* count = (end - start) >> L1_CACHE_SHIFT */41R2 = R1 - R0;42R2 >>= L1_CACHE_SHIFT;43P1 = R2;4445.ifnb \label46\label :47.endif48P0 = R0;4950LSETUP (1f, 2f) LC1 = P1;511:52.ifeqs "\flushins", BROK_FLUSH_INST53\flushins [P0++];54nop;55nop;562: nop;57.else582: \flushins [P0++];59.endif6061RTS;62.endm6364#ifdef CONFIG_ICACHE_FLUSH_L165.section .l1.text66#else67.text68#endif6970/* Invalidate all instruction cache lines assocoiated with this memory area */71#ifdef CONFIG_SMP72# define _blackfin_icache_flush_range _blackfin_icache_flush_range_l173#endif74ENTRY(_blackfin_icache_flush_range)75do_flush IFLUSH76ENDPROC(_blackfin_icache_flush_range)7778#ifdef CONFIG_SMP79.text80# undef _blackfin_icache_flush_range81ENTRY(_blackfin_icache_flush_range)82p0.L = LO(DSPID);83p0.H = HI(DSPID);84r3 = [p0];85r3 = r3.b (z);86p2 = r3;87p0.L = _blackfin_iflush_l1_entry;88p0.H = _blackfin_iflush_l1_entry;89p0 = p0 + (p2 << 2);90p1 = [p0];91jump (p1);92ENDPROC(_blackfin_icache_flush_range)93#endif9495#ifdef CONFIG_DCACHE_FLUSH_L196.section .l1.text97#else98.text99#endif100101/* Throw away all D-cached data in specified region without any obligation to102* write them back. Since the Blackfin ISA does not have an "invalidate"103* instruction, we use flush/invalidate. Perhaps as a speed optimization we104* could bang on the DTEST MMRs ...105*/106ENTRY(_blackfin_dcache_invalidate_range)107do_flush FLUSHINV108ENDPROC(_blackfin_dcache_invalidate_range)109110/* Flush all data cache lines assocoiated with this memory area */111ENTRY(_blackfin_dcache_flush_range)112do_flush FLUSH, .Ldfr113ENDPROC(_blackfin_dcache_flush_range)114115/* Our headers convert the page structure to an address, so just need to flush116* its contents like normal. We know the start address is page aligned (which117* greater than our cache alignment), as is the end address. So just jump into118* the middle of the dcache flush function.119*/120ENTRY(_blackfin_dflush_page)121P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);122jump .Ldfr;123ENDPROC(_blackfin_dflush_page)124125126