Commit cce2d453e4940d3fccd42a6917d01027148e11c3

Authored by Yoshinori Sato
Committed by Paul Mundt
1 parent 1af446edfe

SH2(A) cache update

Includes:
- SH2 (7619) Writeback support.
- SH2A cache handling fix.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

Showing 7 changed files with 213 additions and 16 deletions Side-by-side Diff

arch/sh/include/cpu-sh2/cpu/cache.h
... ... @@ -21,11 +21,11 @@
21 21 #define CCR 0xffffffec
22 22  
23 23 #define CCR_CACHE_CE 0x01 /* Cache enable */
24   -#define CCR_CACHE_WT 0x06 /* CCR[bit1=1,bit2=1] */
  24 +#define CCR_CACHE_WT 0x02 /* CCR[bit1=1,bit2=1] */
25 25 /* 0x00000000-0x7fffffff: Write-through */
26 26 /* 0x80000000-0x9fffffff: Write-back */
27 27 /* 0xc0000000-0xdfffffff: Write-through */
28   -#define CCR_CACHE_CB 0x00 /* CCR[bit1=0,bit2=0] */
  28 +#define CCR_CACHE_CB 0x04 /* CCR[bit1=0,bit2=0] */
29 29 /* 0x00000000-0x7fffffff: Write-back */
30 30 /* 0x80000000-0x9fffffff: Write-through */
31 31 /* 0xc0000000-0xdfffffff: Write-back */
... ... @@ -36,6 +36,8 @@
36 36  
37 37 #define CCR_CACHE_ENABLE CCR_CACHE_CE
38 38 #define CCR_CACHE_INVALIDATE CCR_CACHE_CF
  39 +#define CACHE_PHYSADDR_MASK 0x1ffffc00
  40 +
39 41 #endif
40 42  
41 43 #endif /* __ASM_CPU_SH2_CACHE_H */
arch/sh/include/cpu-sh2a/cpu/cache.h
... ... @@ -36,6 +36,9 @@
36 36  
37 37 #define CCR_CACHE_ENABLE (CCR_CACHE_OCE | CCR_CACHE_ICE)
38 38 #define CCR_CACHE_INVALIDATE (CCR_CACHE_OCI | CCR_CACHE_ICI)
  39 +#define CCR_ICACHE_INVALIDATE CCR_CACHE_ICI
  40 +#define CCR_OCACHE_INVALIDATE CCR_CACHE_OCI
  41 +#define CACHE_PHYSADDR_MASK 0x1ffffc00
39 42  
40 43 #endif /* __ASM_CPU_SH2A_CACHE_H */
arch/sh/include/cpu-sh2a/cpu/cacheflush.h
  1 +#ifndef __ASM_CPU_SH2A_CACHEFLUSH_H
  2 +#define __ASM_CPU_SH2A_CACHEFLUSH_H
  3 +
  4 +/*
  5 + * Cache flushing:
  6 + *
  7 + * - flush_cache_all() flushes entire cache
  8 + * - flush_cache_mm(mm) flushes the specified mm context's cache lines
  9 + * - flush_cache_dup mm(mm) handles cache flushing when forking
  10 + * - flush_cache_page(mm, vmaddr, pfn) flushes a single page
  11 + * - flush_cache_range(vma, start, end) flushes a range of pages
  12 + *
  13 + * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
  14 + * - flush_icache_range(start, end) flushes(invalidates) a range for icache
  15 + * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache
  16 + *
  17 + * Caches are indexed (effectively) by physical address on SH-2, so
  18 + * we don't need them.
  19 + */
  20 +#define flush_cache_all() do { } while (0)
  21 +#define flush_cache_mm(mm) do { } while (0)
  22 +#define flush_cache_dup_mm(mm) do { } while (0)
  23 +#define flush_cache_range(vma, start, end) do { } while (0)
  24 +#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
  25 +#define flush_dcache_page(page) do { } while (0)
  26 +#define flush_dcache_mmap_lock(mapping) do { } while (0)
  27 +#define flush_dcache_mmap_unlock(mapping) do { } while (0)
  28 +void flush_icache_range(unsigned long start, unsigned long end);
  29 +#define flush_icache_page(vma,pg) do { } while (0)
  30 +#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
  31 +#define flush_cache_sigtramp(vaddr) do { } while (0)
  32 +
  33 +#define p3_cache_init() do { } while (0)
  34 +#endif /* __ASM_CPU_SH2A_CACHEFLUSH_H */
... ... @@ -237,7 +237,6 @@
237 237  
238 238 config CACHE_WRITEBACK
239 239 bool "Write-back"
240   - depends on CPU_SH2A || CPU_SH3 || CPU_SH4 || CPU_SH5
241 240  
242 241 config CACHE_WRITETHROUGH
243 242 bool "Write-through"
arch/sh/mm/Makefile_32
... ... @@ -5,11 +5,14 @@
5 5 obj-y := init.o extable_32.o consistent.o
6 6  
7 7 ifndef CONFIG_CACHE_OFF
8   -obj-$(CONFIG_CPU_SH2) += cache-sh2.o
9   -obj-$(CONFIG_CPU_SH3) += cache-sh3.o
10   -obj-$(CONFIG_CPU_SH4) += cache-sh4.o
11   -obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
  8 +cache-$(CONFIG_CPU_SH2) := cache-sh2.o
  9 +cache-$(CONFIG_CPU_SH2A) := cache-sh2a.o
  10 +cache-$(CONFIG_CPU_SH3) := cache-sh3.o
  11 +cache-$(CONFIG_CPU_SH4) := cache-sh4.o
  12 +cache-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
12 13 endif
  14 +
  15 +obj-y += $(cache-y)
13 16  
14 17 mmu-y := tlb-nommu.o pg-nommu.o
15 18 mmu-$(CONFIG_MMU) := fault_32.o tlbflush_32.o ioremap_32.o
arch/sh/mm/cache-sh2.c
... ... @@ -2,6 +2,7 @@
2 2 * arch/sh/mm/cache-sh2.c
3 3 *
4 4 * Copyright (C) 2002 Paul Mundt
  5 + * Copyright (C) 2008 Yoshinori Sato
5 6 *
6 7 * Released under the terms of the GNU GPL v2.0.
7 8 */
... ... @@ -24,8 +25,15 @@
24 25 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
25 26 & ~(L1_CACHE_BYTES-1);
26 27 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
27   - /* FIXME cache purge */
28   - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
  28 + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0);
  29 + int way;
  30 + for (way = 0; way < 4; way++) {
  31 + unsigned long data = ctrl_inl(addr | (way << 12));
  32 + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
  33 + data &= ~SH_CACHE_UPDATED;
  34 + ctrl_outl(data, addr | (way << 12));
  35 + }
  36 + }
29 37 }
30 38 }
31 39  
32 40  
33 41  
... ... @@ -37,21 +45,41 @@
37 45 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
38 46 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
39 47 & ~(L1_CACHE_BYTES-1);
40   - for (v = begin; v < end; v+=L1_CACHE_BYTES) {
41   - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
42   - }
  48 +
  49 + for (v = begin; v < end; v+=L1_CACHE_BYTES)
  50 + ctrl_outl((v & CACHE_PHYSADDR_MASK),
  51 + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008);
43 52 }
44 53  
45 54 void __flush_invalidate_region(void *start, int size)
46 55 {
  56 +#ifdef CONFIG_CACHE_WRITEBACK
  57 + /*
  58 + * SH-2 does not support individual line invalidation, only a
  59 + * global invalidate.
  60 + */
  61 + unsigned long ccr;
  62 + unsigned long flags;
  63 + local_irq_save(flags);
  64 + jump_to_uncached();
  65 +
  66 + ccr = ctrl_inl(CCR);
  67 + ccr |= CCR_CACHE_INVALIDATE;
  68 + ctrl_outl(ccr, CCR);
  69 +
  70 + back_to_cached();
  71 + local_irq_restore(flags);
  72 +#else
47 73 unsigned long v;
48 74 unsigned long begin, end;
49 75  
50 76 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
51 77 end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
52 78 & ~(L1_CACHE_BYTES-1);
53   - for (v = begin; v < end; v+=L1_CACHE_BYTES) {
54   - ctrl_outl((v & 0x1ffffc00), (v & 0x00000ff0) | 0x00000008);
55   - }
  79 +
  80 + for (v = begin; v < end; v+=L1_CACHE_BYTES)
  81 + ctrl_outl((v & CACHE_PHYSADDR_MASK),
  82 + CACHE_OC_ADDRESS_ARRAY | (v & 0x00000ff0) | 0x00000008);
  83 +#endif
56 84 }
arch/sh/mm/cache-sh2a.c
  1 +/*
  2 + * arch/sh/mm/cache-sh2a.c
  3 + *
  4 + * Copyright (C) 2008 Yoshinori Sato
  5 + *
  6 + * Released under the terms of the GNU GPL v2.0.
  7 + */
  8 +
  9 +#include <linux/init.h>
  10 +#include <linux/mm.h>
  11 +
  12 +#include <asm/cache.h>
  13 +#include <asm/addrspace.h>
  14 +#include <asm/processor.h>
  15 +#include <asm/cacheflush.h>
  16 +#include <asm/io.h>
  17 +
  18 +void __flush_wback_region(void *start, int size)
  19 +{
  20 + unsigned long v;
  21 + unsigned long begin, end;
  22 + unsigned long flags;
  23 +
  24 + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  25 + end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  26 + & ~(L1_CACHE_BYTES-1);
  27 +
  28 + local_irq_save(flags);
  29 + jump_to_uncached();
  30 +
  31 + for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  32 + unsigned long addr = CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0);
  33 + int way;
  34 + for (way = 0; way < 4; way++) {
  35 + unsigned long data = ctrl_inl(addr | (way << 11));
  36 + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
  37 + data &= ~SH_CACHE_UPDATED;
  38 + ctrl_outl(data, addr | (way << 11));
  39 + }
  40 + }
  41 + }
  42 +
  43 + back_to_cached();
  44 + local_irq_restore(flags);
  45 +}
  46 +
  47 +void __flush_purge_region(void *start, int size)
  48 +{
  49 + unsigned long v;
  50 + unsigned long begin, end;
  51 + unsigned long flags;
  52 +
  53 + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  54 + end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  55 + & ~(L1_CACHE_BYTES-1);
  56 +
  57 + local_irq_save(flags);
  58 + jump_to_uncached();
  59 +
  60 + for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  61 + ctrl_outl((v & CACHE_PHYSADDR_MASK),
  62 + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008);
  63 + }
  64 + back_to_cached();
  65 + local_irq_restore(flags);
  66 +}
  67 +
  68 +void __flush_invalidate_region(void *start, int size)
  69 +{
  70 + unsigned long v;
  71 + unsigned long begin, end;
  72 + unsigned long flags;
  73 +
  74 + begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  75 + end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  76 + & ~(L1_CACHE_BYTES-1);
  77 + local_irq_save(flags);
  78 + jump_to_uncached();
  79 +
  80 +#ifdef CONFIG_CACHE_WRITEBACK
  81 + ctrl_outl(ctrl_inl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
  82 + /* I-cache invalidate */
  83 + for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  84 + ctrl_outl((v & CACHE_PHYSADDR_MASK),
  85 + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008);
  86 + }
  87 +#else
  88 + for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  89 + ctrl_outl((v & CACHE_PHYSADDR_MASK),
  90 + CACHE_IC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008);
  91 + ctrl_outl((v & CACHE_PHYSADDR_MASK),
  92 + CACHE_OC_ADDRESS_ARRAY | (v & 0x000003f0) | 0x00000008);
  93 + }
  94 +#endif
  95 + back_to_cached();
  96 + local_irq_restore(flags);
  97 +}
  98 +
  99 +/* WBack O-Cache and flush I-Cache */
  100 +void flush_icache_range(unsigned long start, unsigned long end)
  101 +{
  102 + unsigned long v;
  103 + unsigned long flags;
  104 +
  105 + start = start & ~(L1_CACHE_BYTES-1);
  106 + end = (end + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1);
  107 +
  108 + local_irq_save(flags);
  109 + jump_to_uncached();
  110 +
  111 + for (v = start; v < end; v+=L1_CACHE_BYTES) {
  112 + unsigned long addr = (v & 0x000007f0);
  113 + int way;
  114 + /* O-Cache writeback */
  115 + for (way = 0; way < 4; way++) {
  116 + unsigned long data = ctrl_inl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
  117 + if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
  118 + data &= ~SH_CACHE_UPDATED;
  119 + ctrl_outl(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
  120 + }
  121 + }
  122 + /* I-Cache invalidate */
  123 + ctrl_outl(addr,
  124 + CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008);
  125 + }
  126 +
  127 + back_to_cached();
  128 + local_irq_restore(flags);
  129 +}