1/* $NetBSD: cache_sh3.c,v 1.15 2009/04/30 05:20:30 nonaka Exp $ */ 2 3/*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD: cache_sh3.c,v 1.15 2009/04/30 05:20:30 nonaka Exp $"); 34 35#include "opt_cache.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39 40#include <sh3/cache.h> 41#include <sh3/cache_sh3.h> 42 43#define round_line(x) (((x) + 15) & ~15) 44#define trunc_line(x) ((x) & ~15) 45 46void sh3_cache_wbinv_all(void); 47void sh3_cache_wbinv_range(vaddr_t, vsize_t); 48void sh3_cache_wbinv_range_index(vaddr_t, vsize_t); 49void sh3_cache_panic(vaddr_t, vsize_t); 50void sh3_cache_nop(vaddr_t, vsize_t); 51 52int sh_cache_way_size; 53int sh_cache_way_shift; 54int sh_cache_entry_mask; 55 56static inline void cache_sh3_op_line_16_nway(int, vaddr_t, uint32_t); 57static inline void cache_sh3_op_8lines_16_nway(int, vaddr_t, uint32_t); 58 59void 60sh3_cache_config(void) 61{ 62 size_t cache_size; 63 uint32_t r; 64 65 /* Determine cache size */ 66 switch (cpu_product) { 67 default: 68 /* FALLTHROUGH */ 69 case CPU_PRODUCT_7708: 70 /* FALLTHROUGH */ 71 case CPU_PRODUCT_7708S: 72 /* FALLTHROUGH */ 73 case CPU_PRODUCT_7708R: 74 cache_size = 8 * 1024; 75 break; 76 case CPU_PRODUCT_7709: 77 cache_size = 8 * 1024; 78 break; 79 case CPU_PRODUCT_7709A: 80 /* FALLTHROUGH */ 81 case CPU_PRODUCT_7706: 82 cache_size = 16 * 1024; 83 break; 84 } 85 86 r = _reg_read_4(SH3_CCR); 87 88 sh_cache_unified = 1; 89 sh_cache_enable_unified = (r & SH3_CCR_CE); 90 sh_cache_line_size = 16; 91 sh_cache_write_through_p0_u0_p3 = r & SH3_CCR_WT; 92 sh_cache_write_through_p1 = !(r & SH3_CCR_CB); 93 sh_cache_write_through = sh_cache_write_through_p0_u0_p3 && 94 sh_cache_write_through_p1; 95 96 sh_cache_ram_mode = r & SH3_CCR_RA; 97 if (sh_cache_ram_mode) { 98 /* 99 * In RAM-mode, way 2 and 3 are used as RAM. 100 */ 101 sh_cache_ways = 2; 102 sh_cache_size_unified = cache_size / 2; 103 } else { 104 sh_cache_ways = 4; 105 sh_cache_size_unified = cache_size; 106 } 107 108 /* size enough to access foreach entries */ 109 sh_cache_way_size = sh_cache_size_unified / 4/*way*/; 110 /* mask for extracting entry select */ 111 sh_cache_entry_mask = (sh_cache_way_size - 1) & ~15/*line-mask*/; 112 /* shift for way selection (16KB/8KB) */ 113 sh_cache_way_shift = 114 /* entry bits */ 115 ffs(sh_cache_size_unified / (4/*way*/ * 16/*line-size*/)) - 1 116 /* line bits */ 117 + 4; 118 119 sh_cache_ops._icache_sync_all = sh3_cache_wbinv_all; 120 sh_cache_ops._icache_sync_range = sh3_cache_wbinv_range; 121 sh_cache_ops._icache_sync_range_index = sh3_cache_wbinv_range_index; 122 sh_cache_ops._dcache_wbinv_all = sh3_cache_wbinv_all; 123 sh_cache_ops._dcache_wbinv_range = sh3_cache_wbinv_range; 124 sh_cache_ops._dcache_wbinv_range_index = sh3_cache_wbinv_range_index; 125 /* SH3 can't invalidate without write-back */ 126 sh_cache_ops._dcache_inv_range = sh3_cache_panic; 127 if (sh_cache_write_through) { 128 sh_cache_ops._dcache_wb_range = sh3_cache_nop; 129 } else { 130 /* SH3 can't write-back without invalidate */ 131 sh_cache_ops._dcache_wb_range = sh3_cache_wbinv_range; 132 } 133} 134 135/* 136 * cache_sh3_op_line_16_nway: (index-operation) 137 * 138 * Clear the specified bits on single 16-byte cache line. n-ways. 139 * 140 */ 141static inline void 142cache_sh3_op_line_16_nway(int n, vaddr_t va, uint32_t bits) 143{ 144 vaddr_t cca; 145 int way; 146 147 /* extract entry # */ 148 va &= sh_cache_entry_mask; 149 150 /* operate for each way */ 151 for (way = 0; way < n; way++) { 152 cca = (SH3_CCA | way << sh_cache_way_shift | va); 153 _reg_bclr_4(cca, bits); 154 } 155} 156 157/* 158 * cache_sh3_op_8lines_16_nway: (index-operation) 159 * 160 * Clear the specified bits on 8 16-byte cache lines, n-ways. 161 * 162 */ 163static inline void 164cache_sh3_op_8lines_16_nway(int n, vaddr_t va, uint32_t bits) 165{ 166 volatile uint32_t *cca; 167 int way; 168 169 /* extract entry # */ 170 va &= sh_cache_entry_mask; 171 172 /* operate for each way */ 173 for (way = 0; way < n; way++) { 174 cca = (volatile uint32_t *) 175 (SH3_CCA | way << sh_cache_way_shift | va); 176 cca[ 0] &= ~bits; 177 cca[ 4] &= ~bits; 178 cca[ 8] &= ~bits; 179 cca[12] &= ~bits; 180 cca[16] &= ~bits; 181 cca[20] &= ~bits; 182 cca[24] &= ~bits; 183 cca[28] &= ~bits; 184 } 185} 186 187void 188sh3_cache_wbinv_all(void) 189{ 190 vaddr_t va; 191 192 for (va = 0; va < sh_cache_way_size; va += 16 * 8) 193 cache_sh3_op_8lines_16_nway(sh_cache_ways, va, CCA_U | CCA_V); 194} 195 196void 197sh3_cache_wbinv_range_index(vaddr_t va, vsize_t sz) 198{ 199 vaddr_t eva = round_line(va + sz); 200 201 va = trunc_line(va); 202 203 while ((eva - va) >= (8 * 16)) { 204 cache_sh3_op_8lines_16_nway(sh_cache_ways, va, CCA_U | CCA_V); 205 va += 16 * 8; 206 } 207 208 while (va < eva) { 209 cache_sh3_op_line_16_nway(sh_cache_ways, va, CCA_U | CCA_V); 210 va += 16; 211 } 212} 213 214void 215sh3_cache_wbinv_range(vaddr_t va, vsize_t sz) 216{ 217 vaddr_t eva = round_line(va + sz); 218 vaddr_t cca; 219 220 va = trunc_line(va); 221 222 while (va < eva) { 223 cca = SH3_CCA | CCA_A | (va & sh_cache_entry_mask); 224 /* 225 * extract virtual tag-address. 226 * MMU translates it to physical address tag, 227 * and write to address-array. 228 * implicitly specified U = 0, V = 0. 229 */ 230 _reg_write_4(cca, va & CCA_TAGADDR_MASK); 231 va += 16; 232 } 233} 234 235void 236sh3_cache_panic(vaddr_t va, vsize_t size) 237{ 238 239 panic("SH3 can't invalidate without write-back"); 240} 241 242void 243sh3_cache_nop(vaddr_t va, vsize_t sz) 244{ 245 /* NO-OP */ 246} 247