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/* 19 * The maximum number of pages we support up to when doing ranged dcache 20 * flushing. Anything exceeding this will simply flush the dcache in its 21 * entirety. 22 */ 23#define MAX_OCACHE_PAGES 32 24#define MAX_ICACHE_PAGES 32 25 26#ifdef CONFIG_CACHE_WRITEBACK 27static void sh2a_flush_oc_line(unsigned long v, int way) 28{ 29 unsigned long addr = (v & 0x000007f0) | (way << 11); 30 unsigned long data; 31 32 data = __raw_readl(CACHE_OC_ADDRESS_ARRAY | addr); 33 if ((data & CACHE_PHYSADDR_MASK) == (v & CACHE_PHYSADDR_MASK)) { 34 data &= ~SH_CACHE_UPDATED; 35 __raw_writel(data, CACHE_OC_ADDRESS_ARRAY | addr); 36 } 37} 38#endif 39 40static void sh2a_invalidate_line(unsigned long cache_addr, unsigned long v) 41{ 42 /* Set associative bit to hit all ways */ 43 unsigned long addr = (v & 0x000007f0) | SH_CACHE_ASSOC; 44 __raw_writel((addr & CACHE_PHYSADDR_MASK), cache_addr | addr); 45} 46 47/* 48 * Write back the dirty D-caches, but not invalidate them. 49 */ 50static void sh2a__flush_wback_region(void *start, int size) 51{ 52#ifdef CONFIG_CACHE_WRITEBACK 53 unsigned long v; 54 unsigned long begin, end; 55 unsigned long flags; 56 int nr_ways; 57 58 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 59 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 60 & ~(L1_CACHE_BYTES-1); 61 nr_ways = current_cpu_data.dcache.ways; 62 63 local_irq_save(flags); 64 jump_to_uncached(); 65 66 /* If there are too many pages then flush the entire cache */ 67 if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) { 68 begin = CACHE_OC_ADDRESS_ARRAY; 69 end = begin + (nr_ways * current_cpu_data.dcache.way_size); 70 71 for (v = begin; v < end; v += L1_CACHE_BYTES) { 72 unsigned long data = __raw_readl(v); 73 if (data & SH_CACHE_UPDATED) 74 __raw_writel(data & ~SH_CACHE_UPDATED, v); 75 } 76 } else { 77 int way; 78 for (way = 0; way < nr_ways; way++) { 79 for (v = begin; v < end; v += L1_CACHE_BYTES) 80 sh2a_flush_oc_line(v, way); 81 } 82 } 83 84 back_to_cached(); 85 local_irq_restore(flags); 86#endif 87} 88 89/* 90 * Write back the dirty D-caches and invalidate them. 91 */ 92static void sh2a__flush_purge_region(void *start, int size) 93{ 94 unsigned long v; 95 unsigned long begin, end; 96 unsigned long flags; 97 98 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 99 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 100 & ~(L1_CACHE_BYTES-1); 101 102 local_irq_save(flags); 103 jump_to_uncached(); 104 105 for (v = begin; v < end; v+=L1_CACHE_BYTES) { 106#ifdef CONFIG_CACHE_WRITEBACK 107 int way; 108 int nr_ways = current_cpu_data.dcache.ways; 109 for (way = 0; way < nr_ways; way++) 110 sh2a_flush_oc_line(v, way); 111#endif 112 sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v); 113 } 114 115 back_to_cached(); 116 local_irq_restore(flags); 117} 118 119/* 120 * Invalidate the D-caches, but no write back please 121 */ 122static void sh2a__flush_invalidate_region(void *start, int size) 123{ 124 unsigned long v; 125 unsigned long begin, end; 126 unsigned long flags; 127 128 begin = (unsigned long)start & ~(L1_CACHE_BYTES-1); 129 end = ((unsigned long)start + size + L1_CACHE_BYTES-1) 130 & ~(L1_CACHE_BYTES-1); 131 132 local_irq_save(flags); 133 jump_to_uncached(); 134 135 /* If there are too many pages then just blow the cache */ 136 if (((end - begin) >> PAGE_SHIFT) >= MAX_OCACHE_PAGES) { 137 __raw_writel(__raw_readl(SH_CCR) | CCR_OCACHE_INVALIDATE, 138 SH_CCR); 139 } else { 140 for (v = begin; v < end; v += L1_CACHE_BYTES) 141 sh2a_invalidate_line(CACHE_OC_ADDRESS_ARRAY, v); 142 } 143 144 back_to_cached(); 145 local_irq_restore(flags); 146} 147 148/* 149 * Write back the range of D-cache, and purge the I-cache. 150 */ 151static void sh2a_flush_icache_range(void *args) 152{ 153 struct flusher_data *data = args; 154 unsigned long start, end; 155 unsigned long v; 156 unsigned long flags; 157 158 start = data->addr1 & ~(L1_CACHE_BYTES-1); 159 end = (data->addr2 + L1_CACHE_BYTES-1) & ~(L1_CACHE_BYTES-1); 160 161#ifdef CONFIG_CACHE_WRITEBACK 162 sh2a__flush_wback_region((void *)start, end-start); 163#endif 164 165 local_irq_save(flags); 166 jump_to_uncached(); 167 168 /* I-Cache invalidate */ 169 /* If there are too many pages then just blow the cache */ 170 if (((end - start) >> PAGE_SHIFT) >= MAX_ICACHE_PAGES) { 171 __raw_writel(__raw_readl(SH_CCR) | CCR_ICACHE_INVALIDATE, 172 SH_CCR); 173 } else { 174 for (v = start; v < end; v += L1_CACHE_BYTES) 175 sh2a_invalidate_line(CACHE_IC_ADDRESS_ARRAY, v); 176 } 177 178 back_to_cached(); 179 local_irq_restore(flags); 180} 181 182void __init sh2a_cache_init(void) 183{ 184 local_flush_icache_range = sh2a_flush_icache_range; 185 186 __flush_wback_region = sh2a__flush_wback_region; 187 __flush_purge_region = sh2a__flush_purge_region; 188 __flush_invalidate_region = sh2a__flush_invalidate_region; 189} 190