[ARM] pxa: add support for L2 outer cache on XScale3 (attempt 2)

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Linux Kernel Mailing List
Date: Monday, August 4, 2008 - 10:59 am

Gitweb:     http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=905a09...
Commit:     905a09d57afcc49511de18a95605c11ad9c88649
Parent:     e76e3ac69e62d3f93e935526bc9afa371e7f38ba
Author:     Eric Miao <eric.miao@marvell.com>
AuthorDate: Fri Jun 6 16:34:03 2008 +0800
Committer:  Russell King <rmk+kernel@arm.linux.org.uk>
CommitDate: Mon Jul 28 23:13:09 2008 +0100

    [ARM] pxa: add support for L2 outer cache on XScale3 (attempt 2)
    
    (20072fd0c93349e19527dd2fa9588b4335960e62 lost most of its changes
    somehow, came from a mbox archive applied with git-am.  No idea
    what happened.  This puts back the missing bits.  --rmk)
    
    The initial patch from Lothar, and Lennert make it into a cleaner
    one, modified and tested on PXA320 by Eric Miao.
    
    This patch moves the L2 cache operations out of proc-xsc3.S into
    dedicated outer cache support code.
    
    CACHE_XSC3L2 can be deselected so no L2 cache specific code will be
    linked in, and that L2 enable bit will not be set, this applies to
    the following cases:
    
        a. _only_ PXA300/PXA310 support included and no L2 cache wanted
        b. PXA320 support included, but want L2 be disabled
    
    So the enabling of L2 depends on two things:
    
        - CACHE_XSC3L2 is selected
        - and L2 cache is present
    
    Where the latter is only a safeguard (previous testing shows it works
    OK even when this bit is turned on).
    
    IXP series of processors with XScale3 cannot disable L2 cache for the
    moment since they depend on the L2 cache for its coherent memory, so
    IXP may always select CACHE_XSC3L2.
    
    Other L2 relevant bits are always turned on (i.e. the original code
    enclosed by #if L2_CACHE_ENABLED .. #endif), as they showed no side
    effects. Specifically, these bits are:
    
       - OC bits in TTBASE register (table walk outer cache attributes)
       - LLR Outer Cache Attributes (OC) in Auxiliary Control Register
    
    Signed-off-by: Lothar WaÃ<9f>mann <LW@KARO-electronics.de>
    Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
    Signed-off-by: Eric Miao <eric.miao@marvell.com>
    Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/mm/Kconfig        |    8 ++
 arch/arm/mm/cache-xsc3l2.c |  182 ++++++++++++++++++++++++++++++++++++++++++++
 arch/arm/mm/proc-xsc3.S    |   22 -----
 3 files changed, 190 insertions(+), 22 deletions(-)

diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 399d1d6..ed15f87 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -742,3 +742,11 @@ config CACHE_L2X0
 	select OUTER_CACHE
 	help
 	  This option enables the L2x0 PrimeCell.
+
+config CACHE_XSC3L2
+	bool "Enable the L2 cache on XScale3"
+	depends on CPU_XSC3
+	default y
+	select OUTER_CACHE
+	help
+	  This option enables the L2 cache on XScale3.
diff --git a/arch/arm/mm/cache-xsc3l2.c b/arch/arm/mm/cache-xsc3l2.c
new file mode 100644
index 0000000..158bd96
--- /dev/null
+++ b/arch/arm/mm/cache-xsc3l2.c
@@ -0,0 +1,182 @@
+/*
+ * arch/arm/mm/cache-xsc3l2.c - XScale3 L2 cache controller support
+ *
+ * Copyright (C) 2007 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <asm/system.h>
+#include <asm/cacheflush.h>
+#include <asm/io.h>
+
+#define CR_L2	(1 << 26)
+
+#define CACHE_LINE_SIZE		32
+#define CACHE_LINE_SHIFT	5
+#define CACHE_WAY_PER_SET	8
+
+#define CACHE_WAY_SIZE(l2ctype)	(8192 << (((l2ctype) >> 8) & 0xf))
+#define CACHE_SET_SIZE(l2ctype)	(CACHE_WAY_SIZE(l2ctype) >> CACHE_LINE_SHIFT)
+
+static inline int xsc3_l2_present(void)
+{
+	unsigned long l2ctype;
+
+	__asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
+
+	return !!(l2ctype & 0xf8);
+}
+
+static inline void xsc3_l2_clean_mva(unsigned long addr)
+{
+	__asm__("mcr p15, 1, %0, c7, c11, 1" : : "r" (addr));
+}
+
+static inline void xsc3_l2_clean_pa(unsigned long addr)
+{
+	xsc3_l2_clean_mva(__phys_to_virt(addr));
+}
+
+static inline void xsc3_l2_inv_mva(unsigned long addr)
+{
+	__asm__("mcr p15, 1, %0, c7, c7, 1" : : "r" (addr));
+}
+
+static inline void xsc3_l2_inv_pa(unsigned long addr)
+{
+	xsc3_l2_inv_mva(__phys_to_virt(addr));
+}
+
+static inline void xsc3_l2_inv_all(void)
+{
+	unsigned long l2ctype, set_way;
+	int set, way;
+
+	__asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
+
+	for (set = 0; set < CACHE_SET_SIZE(l2ctype); set++) {
+		for (way = 0; way < CACHE_WAY_PER_SET; way++) {
+			set_way = (way << 29) | (set << 5);
+			__asm__("mcr p15, 1, %0, c7, c11, 2" : : "r"(set_way));
+		}
+	}
+
+	dsb();
+}
+
+static void xsc3_l2_inv_range(unsigned long start, unsigned long end)
+{
+	if (start == 0 && end == -1ul) {
+		xsc3_l2_inv_all();
+		return;
+	}
+
+	/*
+	 * Clean and invalidate partial first cache line.
+	 */
+	if (start & (CACHE_LINE_SIZE - 1)) {
+		xsc3_l2_clean_pa(start & ~(CACHE_LINE_SIZE - 1));
+		xsc3_l2_inv_pa(start & ~(CACHE_LINE_SIZE - 1));
+		start = (start | (CACHE_LINE_SIZE - 1)) + 1;
+	}
+
+	/*
+	 * Clean and invalidate partial last cache line.
+	 */
+	if (end & (CACHE_LINE_SIZE - 1)) {
+		xsc3_l2_clean_pa(end & ~(CACHE_LINE_SIZE - 1));
+		xsc3_l2_inv_pa(end & ~(CACHE_LINE_SIZE - 1));
+		end &= ~(CACHE_LINE_SIZE - 1);
+	}
+
+	/*
+	 * Invalidate all full cache lines between 'start' and 'end'.
+	 */
+	while (start != end) {
+		xsc3_l2_inv_pa(start);
+		start += CACHE_LINE_SIZE;
+	}
+
+	dsb();
+}
+
+static void xsc3_l2_clean_range(unsigned long start, unsigned long end)
+{
+	start &= ~(CACHE_LINE_SIZE - 1);
+	while (start < end) {
+		xsc3_l2_clean_pa(start);
+		start += CACHE_LINE_SIZE;
+	}
+
+	dsb();
+}
+
+/*
+ * optimize L2 flush all operation by set/way format
+ */
+static inline void xsc3_l2_flush_all(void)
+{
+	unsigned long l2ctype, set_way;
+	int set, way;
+
+	__asm__("mrc p15, 1, %0, c0, c0, 1" : "=r" (l2ctype));
+
+	for (set = 0; set < CACHE_SET_SIZE(l2ctype); set++) {
+		for (way = 0; way < CACHE_WAY_PER_SET; way++) {
+			set_way = (way << 29) | (set << 5);
+			__asm__("mcr p15, 1, %0, c7, c15, 2" : : "r"(set_way));
+		}
+	}
+
+	dsb();
+}
+
+static void xsc3_l2_flush_range(unsigned long start, unsigned long end)
+{
+	if (start == 0 && end == -1ul) {
+		xsc3_l2_flush_all();
+		return;
+	}
+
+	start &= ~(CACHE_LINE_SIZE - 1);
+	while (start < end) {
+		xsc3_l2_clean_pa(start);
+		xsc3_l2_inv_pa(start);
+		start += CACHE_LINE_SIZE;
+	}
+
+	dsb();
+}
+
+static int __init xsc3_l2_init(void)
+{
+	if (!cpu_is_xsc3() || !xsc3_l2_present())
+		return 0;
+
+	if (!(get_cr() & CR_L2)) {
+		pr_info("XScale3 L2 cache enabled.\n");
+		adjust_cr(CR_L2, CR_L2);
+		xsc3_l2_inv_all();
+	}
+
+	outer_cache.inv_range = xsc3_l2_inv_range;
+	outer_cache.clean_range = xsc3_l2_clean_range;
+	outer_cache.flush_range = xsc3_l2_flush_range;
+
+	return 0;
+}
+core_initcall(xsc3_l2_init);
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 3533741..6ff53c2 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -52,11 +52,6 @@
 #define CACHESIZE	32768
 
 /*
- * Run with L2 enabled.
- */
-#define L2_CACHE_ENABLE	1
-
-/*
  * This macro is used to wait for a CP15 write and is needed when we
  * have to ensure that the last operation to the coprocessor was
  * completed before continuing with operation.
@@ -265,12 +260,9 @@ ENTRY(xsc3_dma_inv_range)
 	tst	r0, #CACHELINESIZE - 1
 	bic	r0, r0, #CACHELINESIZE - 1
 	mcrne	p15, 0, r0, c7, c10, 1		@ clean L1 D line
-	mcrne	p15, 1, r0, c7, c11, 1		@ clean L2 line
 	tst	r1, #CACHELINESIZE - 1
 	mcrne	p15, 0, r1, c7, c10, 1		@ clean L1 D line
-	mcrne	p15, 1, r1, c7, c11, 1		@ clean L2 line
 1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate L1 D line
-	mcr	p15, 1, r0, c7, c7, 1		@ invalidate L2 line
 	add	r0, r0, #CACHELINESIZE
 	cmp	r0, r1
 	blo	1b
@@ -288,7 +280,6 @@ ENTRY(xsc3_dma_inv_range)
 ENTRY(xsc3_dma_clean_range)
 	bic	r0, r0, #CACHELINESIZE - 1
 1:	mcr	p15, 0, r0, c7, c10, 1		@ clean L1 D line
-	mcr	p15, 1, r0, c7, c11, 1		@ clean L2 line
 	add	r0, r0, #CACHELINESIZE
 	cmp	r0, r1
 	blo	1b
@@ -306,8 +297,6 @@ ENTRY(xsc3_dma_clean_range)
 ENTRY(xsc3_dma_flush_range)
 	bic	r0, r0, #CACHELINESIZE - 1
 1:	mcr	p15, 0, r0, c7, c14, 1		@ clean/invalidate L1 D line
-	mcr	p15, 1, r0, c7, c11, 1		@ clean L2 line
-	mcr	p15, 1, r0, c7, c7, 1		@ invalidate L2 line
 	add	r0, r0, #CACHELINESIZE
 	cmp	r0, r1
 	blo	1b
@@ -347,9 +336,7 @@ ENTRY(cpu_xsc3_switch_mm)
 	mcr	p15, 0, ip, c7, c5, 0		@ invalidate L1 I cache and BTB
 	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
 	mcr	p15, 0, ip, c7, c5, 4		@ prefetch flush
-#ifdef L2_CACHE_ENABLE
 	orr	r0, r0, #0x18			@ cache the page table in L2
-#endif
 	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
 	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I and D TLBs
 	cpwait_ret lr, ip
@@ -378,12 +365,10 @@ ENTRY(cpu_xsc3_set_pte_ext)
 	orreq	r2, r2, #PTE_EXT_AP_UNO_SRW	@ yes -> user n/a, system r/w
 						@ combined with user -> user r/w
 
-#if L2_CACHE_ENABLE
 	@ If it's cacheable, it needs to be in L2 also.
 	eor	ip, r1, #L_PTE_CACHEABLE
 	tst	ip, #L_PTE_CACHEABLE
 	orreq	r2, r2, #PTE_EXT_TEX(0x5)
-#endif
 
 	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ present and young?
 	movne	r2, #0				@ no -> fault
@@ -408,9 +393,7 @@ __xsc3_setup:
 	mcr	p15, 0, ip, c7, c10, 4		@ data write barrier
 	mcr	p15, 0, ip, c7, c5, 4		@ prefetch flush
 	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I and D TLBs
-#if L2_CACHE_ENABLE
 	orr	r4, r4, #0x18			@ cache the page table in L2
-#endif
 	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
 
 	mov	r0, #0				@ don't allow CP access
@@ -418,9 +401,7 @@ __xsc3_setup:
 
 	mrc	p15, 0, r0, c1, c0, 1		@ get auxiliary control reg
 	and	r0, r0, #2			@ preserve bit P bit setting
-#if L2_CACHE_ENABLE
 	orr	r0, r0, #(1 << 10)		@ enable L2 for LLR cache
-#endif
 	mcr	p15, 0, r0, c1, c0, 1		@ set auxiliary control reg
 
 	adr	r5, xsc3_crval
@@ -429,9 +410,6 @@ __xsc3_setup:
 	bic	r0, r0, r5			@ ..V. ..R. .... ..A.
 	orr	r0, r0, r6			@ ..VI Z..S .... .C.M (mmu)
 						@ ...I Z..S .... .... (uc)
-#if L2_CACHE_ENABLE
-	orr 	r0, r0, #0x04000000		@ L2 enable
-#endif
 	mov	pc, lr
 
 	.size	__xsc3_setup, . - __xsc3_setup
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[ARM] pxa: add support for L2 outer cache on XScale3 (atte ..., Linux Kernel Mailing ..., (Mon Aug 4, 10:59 am)