mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 10:57:46 +00:00
[ARM] pxa: add support for L2 outer cache on XScale3 (attempt 2)
(20072fd0c9
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>
This commit is contained in:
parent
e76e3ac69e
commit
905a09d57a
3 changed files with 190 additions and 22 deletions
|
@ -742,3 +742,11 @@ config CACHE_L2X0
|
||||||
select OUTER_CACHE
|
select OUTER_CACHE
|
||||||
help
|
help
|
||||||
This option enables the L2x0 PrimeCell.
|
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
arch/arm/mm/cache-xsc3l2.c
Normal file
182
arch/arm/mm/cache-xsc3l2.c
Normal file
|
@ -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);
|
|
@ -51,11 +51,6 @@
|
||||||
*/
|
*/
|
||||||
#define CACHESIZE 32768
|
#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
|
* 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
|
* have to ensure that the last operation to the coprocessor was
|
||||||
|
@ -265,12 +260,9 @@ ENTRY(xsc3_dma_inv_range)
|
||||||
tst r0, #CACHELINESIZE - 1
|
tst r0, #CACHELINESIZE - 1
|
||||||
bic r0, r0, #CACHELINESIZE - 1
|
bic r0, r0, #CACHELINESIZE - 1
|
||||||
mcrne p15, 0, r0, c7, c10, 1 @ clean L1 D line
|
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
|
tst r1, #CACHELINESIZE - 1
|
||||||
mcrne p15, 0, r1, c7, c10, 1 @ clean L1 D line
|
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
|
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
|
add r0, r0, #CACHELINESIZE
|
||||||
cmp r0, r1
|
cmp r0, r1
|
||||||
blo 1b
|
blo 1b
|
||||||
|
@ -288,7 +280,6 @@ ENTRY(xsc3_dma_inv_range)
|
||||||
ENTRY(xsc3_dma_clean_range)
|
ENTRY(xsc3_dma_clean_range)
|
||||||
bic r0, r0, #CACHELINESIZE - 1
|
bic r0, r0, #CACHELINESIZE - 1
|
||||||
1: mcr p15, 0, r0, c7, c10, 1 @ clean L1 D line
|
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
|
add r0, r0, #CACHELINESIZE
|
||||||
cmp r0, r1
|
cmp r0, r1
|
||||||
blo 1b
|
blo 1b
|
||||||
|
@ -306,8 +297,6 @@ ENTRY(xsc3_dma_clean_range)
|
||||||
ENTRY(xsc3_dma_flush_range)
|
ENTRY(xsc3_dma_flush_range)
|
||||||
bic r0, r0, #CACHELINESIZE - 1
|
bic r0, r0, #CACHELINESIZE - 1
|
||||||
1: mcr p15, 0, r0, c7, c14, 1 @ clean/invalidate L1 D line
|
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
|
add r0, r0, #CACHELINESIZE
|
||||||
cmp r0, r1
|
cmp r0, r1
|
||||||
blo 1b
|
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, c5, 0 @ invalidate L1 I cache and BTB
|
||||||
mcr p15, 0, ip, c7, c10, 4 @ data write barrier
|
mcr p15, 0, ip, c7, c10, 4 @ data write barrier
|
||||||
mcr p15, 0, ip, c7, c5, 4 @ prefetch flush
|
mcr p15, 0, ip, c7, c5, 4 @ prefetch flush
|
||||||
#ifdef L2_CACHE_ENABLE
|
|
||||||
orr r0, r0, #0x18 @ cache the page table in L2
|
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, r0, c2, c0, 0 @ load page table pointer
|
||||||
mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs
|
mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs
|
||||||
cpwait_ret lr, ip
|
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
|
orreq r2, r2, #PTE_EXT_AP_UNO_SRW @ yes -> user n/a, system r/w
|
||||||
@ combined with user -> user r/w
|
@ combined with user -> user r/w
|
||||||
|
|
||||||
#if L2_CACHE_ENABLE
|
|
||||||
@ If it's cacheable, it needs to be in L2 also.
|
@ If it's cacheable, it needs to be in L2 also.
|
||||||
eor ip, r1, #L_PTE_CACHEABLE
|
eor ip, r1, #L_PTE_CACHEABLE
|
||||||
tst ip, #L_PTE_CACHEABLE
|
tst ip, #L_PTE_CACHEABLE
|
||||||
orreq r2, r2, #PTE_EXT_TEX(0x5)
|
orreq r2, r2, #PTE_EXT_TEX(0x5)
|
||||||
#endif
|
|
||||||
|
|
||||||
tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young?
|
tst r3, #L_PTE_PRESENT | L_PTE_YOUNG @ present and young?
|
||||||
movne r2, #0 @ no -> fault
|
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, c10, 4 @ data write barrier
|
||||||
mcr p15, 0, ip, c7, c5, 4 @ prefetch flush
|
mcr p15, 0, ip, c7, c5, 4 @ prefetch flush
|
||||||
mcr p15, 0, ip, c8, c7, 0 @ invalidate I and D TLBs
|
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
|
orr r4, r4, #0x18 @ cache the page table in L2
|
||||||
#endif
|
|
||||||
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
|
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
|
||||||
|
|
||||||
mov r0, #0 @ don't allow CP access
|
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
|
mrc p15, 0, r0, c1, c0, 1 @ get auxiliary control reg
|
||||||
and r0, r0, #2 @ preserve bit P bit setting
|
and r0, r0, #2 @ preserve bit P bit setting
|
||||||
#if L2_CACHE_ENABLE
|
|
||||||
orr r0, r0, #(1 << 10) @ enable L2 for LLR cache
|
orr r0, r0, #(1 << 10) @ enable L2 for LLR cache
|
||||||
#endif
|
|
||||||
mcr p15, 0, r0, c1, c0, 1 @ set auxiliary control reg
|
mcr p15, 0, r0, c1, c0, 1 @ set auxiliary control reg
|
||||||
|
|
||||||
adr r5, xsc3_crval
|
adr r5, xsc3_crval
|
||||||
|
@ -429,9 +410,6 @@ __xsc3_setup:
|
||||||
bic r0, r0, r5 @ ..V. ..R. .... ..A.
|
bic r0, r0, r5 @ ..V. ..R. .... ..A.
|
||||||
orr r0, r0, r6 @ ..VI Z..S .... .C.M (mmu)
|
orr r0, r0, r6 @ ..VI Z..S .... .C.M (mmu)
|
||||||
@ ...I Z..S .... .... (uc)
|
@ ...I Z..S .... .... (uc)
|
||||||
#if L2_CACHE_ENABLE
|
|
||||||
orr r0, r0, #0x04000000 @ L2 enable
|
|
||||||
#endif
|
|
||||||
mov pc, lr
|
mov pc, lr
|
||||||
|
|
||||||
.size __xsc3_setup, . - __xsc3_setup
|
.size __xsc3_setup, . - __xsc3_setup
|
||||||
|
|
Loading…
Reference in a new issue