blob: 1f51225426a2124e9dcd9ef4769fa4cb9e73272e [file] [log] [blame]
Yoshinori Satocce2d452008-08-04 16:33:47 +09001/*
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
Paul Mundta58e1a22009-08-15 12:38:29 +090018static void sh2a__flush_wback_region(void *start, int size)
Yoshinori Satocce2d452008-08-04 16:33:47 +090019{
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++) {
Paul Mundt9d56dd32010-01-26 12:58:40 +090035 unsigned long data = __raw_readl(addr | (way << 11));
Yoshinori Satocce2d452008-08-04 16:33:47 +090036 if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
37 data &= ~SH_CACHE_UPDATED;
Paul Mundt9d56dd32010-01-26 12:58:40 +090038 __raw_writel(data, addr | (way << 11));
Yoshinori Satocce2d452008-08-04 16:33:47 +090039 }
40 }
41 }
42
43 back_to_cached();
44 local_irq_restore(flags);
45}
46
Paul Mundta58e1a22009-08-15 12:38:29 +090047static void sh2a__flush_purge_region(void *start, int size)
Yoshinori Satocce2d452008-08-04 16:33:47 +090048{
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) {
Paul Mundt9d56dd32010-01-26 12:58:40 +090061 __raw_writel((v & CACHE_PHYSADDR_MASK),
Yoshihiro Shimoda216813a2008-08-07 13:54:59 +090062 CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
Yoshinori Satocce2d452008-08-04 16:33:47 +090063 }
64 back_to_cached();
65 local_irq_restore(flags);
66}
67
Paul Mundta58e1a22009-08-15 12:38:29 +090068static void sh2a__flush_invalidate_region(void *start, int size)
Yoshinori Satocce2d452008-08-04 16:33:47 +090069{
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
Paul Mundt9d56dd32010-01-26 12:58:40 +090081 __raw_writel(__raw_readl(CCR) | CCR_OCACHE_INVALIDATE, CCR);
Yoshinori Satocce2d452008-08-04 16:33:47 +090082 /* I-cache invalidate */
83 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
Paul Mundt9d56dd32010-01-26 12:58:40 +090084 __raw_writel((v & CACHE_PHYSADDR_MASK),
Yoshihiro Shimoda216813a2008-08-07 13:54:59 +090085 CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
Yoshinori Satocce2d452008-08-04 16:33:47 +090086 }
87#else
88 for (v = begin; v < end; v+=L1_CACHE_BYTES) {
Paul Mundt9d56dd32010-01-26 12:58:40 +090089 __raw_writel((v & CACHE_PHYSADDR_MASK),
Yoshihiro Shimoda216813a2008-08-07 13:54:59 +090090 CACHE_IC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
Paul Mundt9d56dd32010-01-26 12:58:40 +090091 __raw_writel((v & CACHE_PHYSADDR_MASK),
Yoshihiro Shimoda216813a2008-08-07 13:54:59 +090092 CACHE_OC_ADDRESS_ARRAY | (v & 0x000007f0) | 0x00000008);
Yoshinori Satocce2d452008-08-04 16:33:47 +090093 }
94#endif
95 back_to_cached();
96 local_irq_restore(flags);
97}
98
99/* WBack O-Cache and flush I-Cache */
Paul Mundtf26b2a52009-08-21 17:23:14 +0900100static void sh2a_flush_icache_range(void *args)
Yoshinori Satocce2d452008-08-04 16:33:47 +0900101{
Paul Mundtf26b2a52009-08-21 17:23:14 +0900102 struct flusher_data *data = args;
103 unsigned long start, end;
Yoshinori Satocce2d452008-08-04 16:33:47 +0900104 unsigned long v;
Paul Mundt983f4c52009-09-01 21:12:55 +0900105 unsigned long flags;
Yoshinori Satocce2d452008-08-04 16:33:47 +0900106
Paul Mundtf26b2a52009-08-21 17:23:14 +0900107 start = data->addr1 & ~(L1_CACHE_BYTES-1);
108 end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1);
Yoshinori Satocce2d452008-08-04 16:33:47 +0900109
Paul Mundt983f4c52009-09-01 21:12:55 +0900110 local_irq_save(flags);
Yoshinori Satocce2d452008-08-04 16:33:47 +0900111 jump_to_uncached();
112
113 for (v = start; v < end; v+=L1_CACHE_BYTES) {
114 unsigned long addr = (v & 0x000007f0);
115 int way;
116 /* O-Cache writeback */
117 for (way = 0; way < 4; way++) {
Paul Mundt9d56dd32010-01-26 12:58:40 +0900118 unsigned long data = __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
Yoshinori Satocce2d452008-08-04 16:33:47 +0900119 if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) {
120 data &= ~SH_CACHE_UPDATED;
Paul Mundt9d56dd32010-01-26 12:58:40 +0900121 __raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr | (way << 11));
Yoshinori Satocce2d452008-08-04 16:33:47 +0900122 }
123 }
124 /* I-Cache invalidate */
Paul Mundt9d56dd32010-01-26 12:58:40 +0900125 __raw_writel(addr,
Paul Mundt983f4c52009-09-01 21:12:55 +0900126 CACHE_IC_ADDRESS_ARRAY | addr | 0x00000008);
Yoshinori Satocce2d452008-08-04 16:33:47 +0900127 }
128
129 back_to_cached();
Paul Mundt983f4c52009-09-01 21:12:55 +0900130 local_irq_restore(flags);
Yoshinori Satocce2d452008-08-04 16:33:47 +0900131}
Paul Mundta58e1a22009-08-15 12:38:29 +0900132
133void __init sh2a_cache_init(void)
134{
Paul Mundtf26b2a52009-08-21 17:23:14 +0900135 local_flush_icache_range = sh2a_flush_icache_range;
Paul Mundta58e1a22009-08-15 12:38:29 +0900136
137 __flush_wback_region = sh2a__flush_wback_region;
138 __flush_purge_region = sh2a__flush_purge_region;
139 __flush_invalidate_region = sh2a__flush_invalidate_region;
140}