aboutsummaryrefslogtreecommitdiff
path: root/arch/blackfin/mach-common
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-10-16 12:45:08 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-16 12:45:08 -0700
commit1b821bfb034c5db5af62b463e3001243905179ba (patch)
treea5c1090f41716a6912742c9bc960dc2d3ae82899 /arch/blackfin/mach-common
parenta45fbc33137b11e479ea8b7d478a1d7e6488971b (diff)
parent1390da4ee75168b6e4d8354e93e3b5f0a0291f2f (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/blackfin-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/blackfin-2.6: Blackfin arch: make sure cycles is marked as volatile so gcc doesnt reorder on us Blackfin arch: disable CONFIG_HW_RANDOM and CONFIG_DAB in defconfig files Blackfin arch: update cache flush prototypes with argument names to make them less mysterious Blackfin arch: move bfin_addr_dcachable() and friends into the cacheflush header where it belongs Blackfin arch: use the new bfin_addr_dcachable() function Blackfin arch: fix bug - build kernel failed at head.S when reprogram clock on all platforms Blackfin arch: unify/cleanup cache code Blackfin arch: update AD7879 platform resources in board file Blackfin arch: Zero out bss region in L1/L2 memory. Blackfin arch: add read/write IO accessor functions to Blackfin Blackfin arch: fix bug - some serial header files set RTS to an input when they should all be outputs
Diffstat (limited to 'arch/blackfin/mach-common')
-rw-r--r--arch/blackfin/mach-common/cache.S173
-rw-r--r--arch/blackfin/mach-common/head.S54
2 files changed, 112 insertions, 115 deletions
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
index 85f8c79b3c3..db532181fbd 100644
--- a/arch/blackfin/mach-common/cache.S
+++ b/arch/blackfin/mach-common/cache.S
@@ -1,148 +1,91 @@
/*
- * File: arch/blackfin/mach-common/cache.S
- * Based on:
- * Author: LG Soft India
+ * Blackfin cache control code
*
- * Created:
- * Description: cache control support
+ * Copyright 2004-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
+ * Enter bugs at http://blackfin.uclinux.org/
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/linkage.h>
-#include <asm/cplb.h>
-#include <asm/entry.h>
#include <asm/blackfin.h>
#include <asm/cache.h>
+#include <asm/page.h>
.text
-/*
- * blackfin_cache_flush_range(start, end)
- * Invalidate all cache lines assocoiated with this
- * area of memory.
+/* Since all L1 caches work the same way, we use the same method for flushing
+ * them. Only the actual flush instruction differs. We write this in asm as
+ * GCC can be hard to coax into writing nice hardware loops.
*
- * start: Start address
- * end: End address
+ * Also, we assume the following register setup:
+ * R0 = start address
+ * R1 = end address
*/
-ENTRY(_blackfin_icache_flush_range)
+.macro do_flush flushins:req optflushins optnopins label
+
+ /* end = ((end - 1) & -L1_CACHE_BYTES) + L1_CACHE_BYTES; */
+ R1 += -1;
R2 = -L1_CACHE_BYTES;
- R2 = R0 & R2;
- P0 = R2;
- P1 = R1;
- CSYNC(R3);
- IFLUSH [P0];
+ R1 = R1 & R2;
+ R1 += L1_CACHE_BYTES;
+
+ /* count = (end - start) >> L1_CACHE_SHIFT */
+ R2 = R1 - R0;
+ R2 >>= L1_CACHE_SHIFT;
+ P1 = R2;
+
+.ifnb \label
+\label :
+.endif
+ P0 = R0;
+ LSETUP (1f, 2f) LC1 = P1;
1:
- IFLUSH [P0++];
- CC = P0 < P1 (iu);
- IF CC JUMP 1b (bp);
- IFLUSH [P0];
- SSYNC(R3);
+.ifnb \optflushins
+ \optflushins [P0];
+.endif
+.ifb \optnopins
+2:
+.endif
+ \flushins [P0++];
+.ifnb \optnopins
+2: \optnopins;
+.endif
+
RTS;
-ENDPROC(_blackfin_icache_flush_range)
+.endm
-/*
- * blackfin_icache_dcache_flush_range(start, end)
- * FLUSH all cache lines assocoiated with this
- * area of memory.
- *
- * start: Start address
- * end: End address
- */
+/* Invalidate all instruction cache lines assocoiated with this memory area */
+ENTRY(_blackfin_icache_flush_range)
+ do_flush IFLUSH, , nop
+ENDPROC(_blackfin_icache_flush_range)
+/* Flush all cache lines assocoiated with this area of memory. */
ENTRY(_blackfin_icache_dcache_flush_range)
- R2 = -L1_CACHE_BYTES;
- R2 = R0 & R2;
- P0 = R2;
- P1 = R1;
- CSYNC(R3);
- IFLUSH [P0];
-1:
- FLUSH [P0];
- IFLUSH [P0++];
- CC = P0 < P1 (iu);
- IF CC JUMP 1b (bp);
- IFLUSH [P0];
- FLUSH [P0];
- SSYNC(R3);
- RTS;
+ do_flush IFLUSH, FLUSH
ENDPROC(_blackfin_icache_dcache_flush_range)
/* Throw away all D-cached data in specified region without any obligation to
- * write them back. However, we must clean the D-cached entries around the
- * boundaries of the start and/or end address is not cache aligned.
- *
- * Start: start address,
- * end : end address.
+ * write them back. Since the Blackfin ISA does not have an "invalidate"
+ * instruction, we use flush/invalidate. Perhaps as a speed optimization we
+ * could bang on the DTEST MMRs ...
*/
-
ENTRY(_blackfin_dcache_invalidate_range)
- R2 = -L1_CACHE_BYTES;
- R2 = R0 & R2;
- P0 = R2;
- P1 = R1;
- CSYNC(R3);
- FLUSHINV[P0];
-1:
- FLUSHINV[P0++];
- CC = P0 < P1 (iu);
- IF CC JUMP 1b (bp);
-
- /* If the data crosses a cache line, then we'll be pointing to
- * the last cache line, but won't have flushed/invalidated it yet,
- * so do one more.
- */
- FLUSHINV[P0];
- SSYNC(R3);
- RTS;
+ do_flush FLUSHINV
ENDPROC(_blackfin_dcache_invalidate_range)
+/* Flush all data cache lines assocoiated with this memory area */
ENTRY(_blackfin_dcache_flush_range)
- R2 = -L1_CACHE_BYTES;
- R2 = R0 & R2;
- P0 = R2;
- P1 = R1;
- CSYNC(R3);
- FLUSH[P0];
-1:
- FLUSH[P0++];
- CC = P0 < P1 (iu);
- IF CC JUMP 1b (bp);
-
- /* If the data crosses a cache line, then we'll be pointing to
- * the last cache line, but won't have flushed it yet, so do
- * one more.
- */
- FLUSH[P0];
- SSYNC(R3);
- RTS;
+ do_flush FLUSH, , , .Ldfr
ENDPROC(_blackfin_dcache_flush_range)
+/* Our headers convert the page structure to an address, so just need to flush
+ * its contents like normal. We know the start address is page aligned (which
+ * greater than our cache alignment), as is the end address. So just jump into
+ * the middle of the dcache flush function.
+ */
ENTRY(_blackfin_dflush_page)
P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT);
- P0 = R0;
- CSYNC(R3);
- FLUSH[P0];
- LSETUP (.Lfl1, .Lfl1) LC0 = P1;
-.Lfl1: FLUSH [P0++];
- SSYNC(R3);
- RTS;
+ jump .Ldfr;
ENDPROC(_blackfin_dflush_page)
diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S
index 3069df58072..f123a62e245 100644
--- a/arch/blackfin/mach-common/head.S
+++ b/arch/blackfin/mach-common/head.S
@@ -206,6 +206,60 @@ ENTRY(_real_start)
w[p0] = r0;
ssync;
+#if L1_DATA_A_LENGTH > 0
+ r1.l = __sbss_l1;
+ r1.h = __sbss_l1;
+ r2.l = __ebss_l1;
+ r2.h = __ebss_l1;
+ r0 = 0 (z);
+ r2 = r2 - r1;
+ cc = r2 == 0;
+ if cc jump .L_a_l1_done;
+ r2 >>= 2;
+ p1 = r1;
+ p2 = r2;
+ lsetup (.L_clear_a_l1, .L_clear_a_l1 ) lc0 = p2;
+.L_clear_a_l1:
+ [p1++] = r0;
+.L_a_l1_done:
+#endif
+
+#if L1_DATA_B_LENGTH > 0
+ r1.l = __sbss_b_l1;
+ r1.h = __sbss_b_l1;
+ r2.l = __ebss_b_l1;
+ r2.h = __ebss_b_l1;
+ r0 = 0 (z);
+ r2 = r2 - r1;
+ cc = r2 == 0;
+ if cc jump .L_b_l1_done;
+ r2 >>= 2;
+ p1 = r1;
+ p2 = r2;
+ lsetup (.L_clear_b_l1, .L_clear_b_l1 ) lc0 = p2;
+.L_clear_b_l1:
+ [p1++] = r0;
+.L_b_l1_done:
+#endif
+
+#if L2_LENGTH > 0
+ r1.l = __sbss_l2;
+ r1.h = __sbss_l2;
+ r2.l = __ebss_l2;
+ r2.h = __ebss_l2;
+ r0 = 0 (z);
+ r2 = r2 - r1;
+ cc = r2 == 0;
+ if cc jump .L_l2_done;
+ r2 >>= 2;
+ p1 = r1;
+ p2 = r2;
+ lsetup (.L_clear_l2, .L_clear_l2 ) lc0 = p2;
+.L_clear_l2:
+ [p1++] = r0;
+.L_l2_done:
+#endif
+
/* Zero out the bss region
* Note: this will fail if bss is 0 bytes ...
*/