Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 905a09d5 authored by Eric Miao's avatar Eric Miao Committed by Russell King
Browse files

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



(20072fd0 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: default avatarLothar WaÃ&lt;9f&gt;mann <LW@KARO-electronics.de>
Signed-off-by: default avatarLennert Buytenhek <buytenh@marvell.com>
Signed-off-by: default avatarEric Miao <eric.miao@marvell.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent e76e3ac6
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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.
+182 −0
Original line number Diff line number Diff line
/*
 * 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);
+0 −22
Original line number Diff line number Diff line
@@ -51,11 +51,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
@@ -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