Annotation of sys/arch/sh/sh/cache_sh4.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: cache_sh4.c,v 1.3 2007/03/19 20:12:43 miod Exp $ */
! 2: /* $NetBSD: cache_sh4.c,v 1.15 2005/12/24 23:24:02 perry Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2002 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by UCHIYAMA Yasushi.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/param.h>
! 41: #include <sys/systm.h>
! 42:
! 43: #include <sh/cache.h>
! 44: #include <sh/cache_sh4.h>
! 45:
! 46: #define round_line(x) (((x) + 31) & ~31)
! 47: #define trunc_line(x) ((x) & ~31)
! 48:
! 49: void sh4_icache_sync_all(void);
! 50: void sh4_icache_sync_range(vaddr_t, vsize_t);
! 51: void sh4_icache_sync_range_index(vaddr_t, vsize_t);
! 52: void sh4_dcache_wbinv_all(void);
! 53: void sh4_dcache_wbinv_range(vaddr_t, vsize_t);
! 54: void sh4_dcache_wbinv_range_index(vaddr_t, vsize_t);
! 55: void sh4_dcache_inv_range(vaddr_t, vsize_t);
! 56: void sh4_dcache_wb_range(vaddr_t, vsize_t);
! 57:
! 58: /* EMODE */
! 59: void sh4_emode_icache_sync_all(void);
! 60: void sh4_emode_icache_sync_range_index(vaddr_t, vsize_t);
! 61: void sh4_emode_dcache_wbinv_all(void);
! 62: void sh4_emode_dcache_wbinv_range_index(vaddr_t, vsize_t);
! 63:
! 64: /* must be inlined. */
! 65: static inline void cache_sh4_op_line_32(vaddr_t, vaddr_t, uint32_t,
! 66: uint32_t);
! 67: static inline void cache_sh4_op_8lines_32(vaddr_t, vaddr_t, uint32_t,
! 68: uint32_t);
! 69: static inline void cache_sh4_emode_op_line_32(vaddr_t, vaddr_t,
! 70: uint32_t, uint32_t, uint32_t);
! 71: static inline void cache_sh4_emode_op_8lines_32(vaddr_t, vaddr_t,
! 72: uint32_t, uint32_t, uint32_t);
! 73:
! 74: void
! 75: sh4_cache_config(void)
! 76: {
! 77: int icache_size;
! 78: int dcache_size;
! 79: int ways;
! 80: uint32_t r;
! 81:
! 82: /* Determine cache size */
! 83: switch (cpu_product) {
! 84: default:
! 85: /* FALLTHROUGH */
! 86: case CPU_PRODUCT_7750:
! 87: case CPU_PRODUCT_7750S:
! 88: case CPU_PRODUCT_7751:
! 89: #if defined(SH4_CACHE_DISABLE_EMODE)
! 90: case CPU_PRODUCT_7750R:
! 91: case CPU_PRODUCT_7751R:
! 92: #endif
! 93: icache_size = SH4_ICACHE_SIZE;
! 94: dcache_size = SH4_DCACHE_SIZE;
! 95: ways = 1;
! 96: r = SH4_CCR_ICE|SH4_CCR_OCE|SH4_CCR_WT;
! 97: break;
! 98:
! 99: #if !defined(SH4_CACHE_DISABLE_EMODE)
! 100: case CPU_PRODUCT_7750R:
! 101: case CPU_PRODUCT_7751R:
! 102: icache_size = SH4_EMODE_ICACHE_SIZE;
! 103: dcache_size = SH4_EMODE_DCACHE_SIZE;
! 104: ways = 2;
! 105: r = SH4_CCR_EMODE|SH4_CCR_ICE|SH4_CCR_OCE|SH4_CCR_WT;
! 106: break;
! 107: #endif
! 108: }
! 109: #if defined(SH4_CACHE_DISABLE_ICACHE)
! 110: r &= ~SH4_CCR_ICE;
! 111: #endif
! 112: #if defined(SH4_CACHE_DISABLE_DCACHE)
! 113: r &= ~SH4_CCR_OCE;
! 114: #endif
! 115: #if !defined (SH4_CACHE_WT)
! 116: #define SH4_CACHE_WB_U0_P0_P3
! 117: #define SH4_CACHE_WB_P1
! 118: #endif
! 119: #if defined(SH4_CACHE_WB_U0_P0_P3)
! 120: r &= ~SH4_CCR_WT;
! 121: #endif
! 122: #if defined(SH4_CACHE_WB_P1)
! 123: r |= SH4_CCR_CB;
! 124: #endif
! 125:
! 126: sh4_icache_sync_all();
! 127: RUN_P2;
! 128: _reg_write_4(SH4_CCR, SH4_CCR_ICI|SH4_CCR_OCI);
! 129: _reg_write_4(SH4_CCR, r);
! 130: RUN_P1;
! 131:
! 132: r = _reg_read_4(SH4_CCR);
! 133:
! 134: sh_cache_unified = 0;
! 135: sh_cache_enable_icache = (r & SH4_CCR_ICE);
! 136: sh_cache_enable_dcache = (r & SH4_CCR_OCE);
! 137: sh_cache_ways = ways;
! 138: sh_cache_line_size = SH4_CACHE_LINESZ;
! 139: sh_cache_prefer_mask = (dcache_size / ways - 1);
! 140: sh_cache_write_through_p0_u0_p3 = (r & SH4_CCR_WT);
! 141: sh_cache_write_through_p1 = !(r & SH4_CCR_CB);
! 142: sh_cache_write_through = sh_cache_write_through_p0_u0_p3 &&
! 143: sh_cache_write_through_p1;
! 144: sh_cache_ram_mode = (r & SH4_CCR_ORA);
! 145: sh_cache_index_mode_icache = (r & SH4_CCR_IIX);
! 146: sh_cache_index_mode_dcache = (r & SH4_CCR_OIX);
! 147:
! 148: sh_cache_size_dcache = dcache_size;
! 149: if (sh_cache_ram_mode)
! 150: sh_cache_size_dcache /= 2;
! 151: sh_cache_size_icache = icache_size;
! 152:
! 153: sh_cache_ops._icache_sync_all = sh4_icache_sync_all;
! 154: sh_cache_ops._icache_sync_range = sh4_icache_sync_range;
! 155: sh_cache_ops._icache_sync_range_index = sh4_icache_sync_range_index;
! 156:
! 157: sh_cache_ops._dcache_wbinv_all = sh4_dcache_wbinv_all;
! 158: sh_cache_ops._dcache_wbinv_range = sh4_dcache_wbinv_range;
! 159: sh_cache_ops._dcache_wbinv_range_index = sh4_dcache_wbinv_range_index;
! 160: sh_cache_ops._dcache_inv_range = sh4_dcache_inv_range;
! 161: sh_cache_ops._dcache_wb_range = sh4_dcache_wb_range;
! 162:
! 163: switch (cpu_product) {
! 164: case CPU_PRODUCT_7750R:
! 165: case CPU_PRODUCT_7751R:
! 166: if (!(r & SH4_CCR_EMODE)) {
! 167: break;
! 168: }
! 169: sh_cache_ops._icache_sync_all = sh4_emode_icache_sync_all;
! 170: sh_cache_ops._icache_sync_range_index = sh4_emode_icache_sync_range_index;
! 171: sh_cache_ops._dcache_wbinv_all = sh4_emode_dcache_wbinv_all;
! 172: sh_cache_ops._dcache_wbinv_range_index = sh4_emode_dcache_wbinv_range_index;
! 173: break;
! 174: }
! 175: }
! 176:
! 177: /*
! 178: * cache_sh4_op_line_32: (index-operation)
! 179: *
! 180: * Clear the specified bits on single 32-byte cache line.
! 181: */
! 182: static inline void
! 183: cache_sh4_op_line_32(vaddr_t va, vaddr_t base, uint32_t mask, uint32_t bits)
! 184: {
! 185: vaddr_t cca;
! 186:
! 187: cca = base | (va & mask);
! 188: _reg_bclr_4(cca, bits);
! 189: }
! 190:
! 191: /*
! 192: * cache_sh4_op_8lines_32: (index-operation)
! 193: *
! 194: * Clear the specified bits on 8 32-byte cache lines.
! 195: */
! 196: static inline void
! 197: cache_sh4_op_8lines_32(vaddr_t va, vaddr_t base, uint32_t mask, uint32_t bits)
! 198: {
! 199: volatile uint32_t *cca = (volatile uint32_t *)
! 200: (base | (va & mask));
! 201:
! 202: cca[ 0] &= ~bits;
! 203: cca[ 8] &= ~bits;
! 204: cca[16] &= ~bits;
! 205: cca[24] &= ~bits;
! 206: cca[32] &= ~bits;
! 207: cca[40] &= ~bits;
! 208: cca[48] &= ~bits;
! 209: cca[56] &= ~bits;
! 210: }
! 211:
! 212: void
! 213: sh4_icache_sync_all(void)
! 214: {
! 215: vaddr_t va = 0;
! 216: vaddr_t eva = SH4_ICACHE_SIZE;
! 217:
! 218: sh4_dcache_wbinv_all();
! 219:
! 220: RUN_P2;
! 221: while (va < eva) {
! 222: cache_sh4_op_8lines_32(va, SH4_CCIA, CCIA_ENTRY_MASK, CCIA_V);
! 223: va += 32 * 8;
! 224: }
! 225: RUN_P1;
! 226: }
! 227:
! 228: void
! 229: sh4_icache_sync_range(vaddr_t va, vsize_t sz)
! 230: {
! 231: vaddr_t ccia;
! 232: vaddr_t eva = round_line(va + sz);
! 233: va = trunc_line(va);
! 234:
! 235: sh4_dcache_wbinv_range(va, (eva - va));
! 236:
! 237: RUN_P2;
! 238: while (va < eva) {
! 239: /* CCR.IIX has no effect on this entry specification */
! 240: ccia = SH4_CCIA | CCIA_A | (va & CCIA_ENTRY_MASK);
! 241: _reg_write_4(ccia, va & CCIA_TAGADDR_MASK); /* V = 0 */
! 242: va += 32;
! 243: }
! 244: RUN_P1;
! 245: }
! 246:
! 247: void
! 248: sh4_icache_sync_range_index(vaddr_t va, vsize_t sz)
! 249: {
! 250: vaddr_t eva = round_line(va + sz);
! 251: va = trunc_line(va);
! 252:
! 253: sh4_dcache_wbinv_range_index(va, eva - va);
! 254:
! 255: RUN_P2;
! 256: while ((eva - va) >= (8 * 32)) {
! 257: cache_sh4_op_8lines_32(va, SH4_CCIA, CCIA_ENTRY_MASK, CCIA_V);
! 258: va += 32 * 8;
! 259: }
! 260:
! 261: while (va < eva) {
! 262: cache_sh4_op_line_32(va, SH4_CCIA, CCIA_ENTRY_MASK, CCIA_V);
! 263: va += 32;
! 264: }
! 265: RUN_P1;
! 266: }
! 267:
! 268: void
! 269: sh4_dcache_wbinv_all(void)
! 270: {
! 271: vaddr_t va = 0;
! 272: vaddr_t eva = SH4_DCACHE_SIZE;
! 273:
! 274: RUN_P2;
! 275: while (va < eva) {
! 276: cache_sh4_op_8lines_32(va, SH4_CCDA, CCDA_ENTRY_MASK,
! 277: (CCDA_U | CCDA_V));
! 278: va += 32 * 8;
! 279: }
! 280: RUN_P1;
! 281: }
! 282:
! 283: void
! 284: sh4_dcache_wbinv_range(vaddr_t va, vsize_t sz)
! 285: {
! 286: vaddr_t eva = round_line(va + sz);
! 287: va = trunc_line(va);
! 288:
! 289: while (va < eva) {
! 290: __asm volatile("ocbp @%0" : : "r"(va));
! 291: va += 32;
! 292: }
! 293: }
! 294:
! 295: void
! 296: sh4_dcache_wbinv_range_index(vaddr_t va, vsize_t sz)
! 297: {
! 298: vaddr_t eva = round_line(va + sz);
! 299: va = trunc_line(va);
! 300:
! 301: RUN_P2;
! 302: while ((eva - va) >= (8 * 32)) {
! 303: cache_sh4_op_8lines_32(va, SH4_CCDA, CCDA_ENTRY_MASK,
! 304: (CCDA_U | CCDA_V));
! 305: va += 32 * 8;
! 306: }
! 307:
! 308: while (va < eva) {
! 309: cache_sh4_op_line_32(va, SH4_CCDA, CCDA_ENTRY_MASK,
! 310: (CCDA_U | CCDA_V));
! 311: va += 32;
! 312: }
! 313: RUN_P1;
! 314: }
! 315:
! 316: void
! 317: sh4_dcache_inv_range(vaddr_t va, vsize_t sz)
! 318: {
! 319: vaddr_t eva = round_line(va + sz);
! 320: va = trunc_line(va);
! 321:
! 322: while (va < eva) {
! 323: __asm volatile("ocbi @%0" : : "r"(va));
! 324: va += 32;
! 325: }
! 326: }
! 327:
! 328: void
! 329: sh4_dcache_wb_range(vaddr_t va, vsize_t sz)
! 330: {
! 331: vaddr_t eva = round_line(va + sz);
! 332: va = trunc_line(va);
! 333:
! 334: while (va < eva) {
! 335: __asm volatile("ocbwb @%0" : : "r"(va));
! 336: va += 32;
! 337: }
! 338: }
! 339:
! 340: /*
! 341: * EMODE operation
! 342: */
! 343: /*
! 344: * cache_sh4_emode_op_line_32: (index-operation)
! 345: *
! 346: * Clear the specified bits on single 32-byte cache line. 2-ways.
! 347: */
! 348: static inline void
! 349: cache_sh4_emode_op_line_32(vaddr_t va, vaddr_t base, uint32_t mask,
! 350: uint32_t bits, uint32_t way_shift)
! 351: {
! 352: vaddr_t cca;
! 353:
! 354: /* extract entry # */
! 355: va &= mask;
! 356:
! 357: /* operate for each way */
! 358: cca = base | (0 << way_shift) | va;
! 359: _reg_bclr_4(cca, bits);
! 360:
! 361: cca = base | (1 << way_shift) | va;
! 362: _reg_bclr_4(cca, bits);
! 363: }
! 364:
! 365: /*
! 366: * cache_sh4_emode_op_8lines_32: (index-operation)
! 367: *
! 368: * Clear the specified bits on 8 32-byte cache lines. 2-ways.
! 369: */
! 370: static inline void
! 371: cache_sh4_emode_op_8lines_32(vaddr_t va, vaddr_t base, uint32_t mask,
! 372: uint32_t bits, uint32_t way_shift)
! 373: {
! 374: volatile uint32_t *cca;
! 375:
! 376: /* extract entry # */
! 377: va &= mask;
! 378:
! 379: /* operate for each way */
! 380: cca = (volatile uint32_t *)(base | (0 << way_shift) | va);
! 381: cca[ 0] &= ~bits;
! 382: cca[ 8] &= ~bits;
! 383: cca[16] &= ~bits;
! 384: cca[24] &= ~bits;
! 385: cca[32] &= ~bits;
! 386: cca[40] &= ~bits;
! 387: cca[48] &= ~bits;
! 388: cca[56] &= ~bits;
! 389:
! 390: cca = (volatile uint32_t *)(base | (1 << way_shift) | va);
! 391: cca[ 0] &= ~bits;
! 392: cca[ 8] &= ~bits;
! 393: cca[16] &= ~bits;
! 394: cca[24] &= ~bits;
! 395: cca[32] &= ~bits;
! 396: cca[40] &= ~bits;
! 397: cca[48] &= ~bits;
! 398: cca[56] &= ~bits;
! 399: }
! 400:
! 401: void
! 402: sh4_emode_icache_sync_all(void)
! 403: {
! 404: vaddr_t va = 0;
! 405: vaddr_t eva = SH4_EMODE_ICACHE_SIZE;
! 406:
! 407: sh4_emode_dcache_wbinv_all();
! 408:
! 409: RUN_P2;
! 410: while (va < eva) {
! 411: cache_sh4_emode_op_8lines_32(va, SH4_CCIA, CCIA_ENTRY_MASK,
! 412: CCIA_V, 13);
! 413: va += 32 * 8;
! 414: }
! 415: RUN_P1;
! 416: }
! 417:
! 418: void
! 419: sh4_emode_icache_sync_range_index(vaddr_t va, vsize_t sz)
! 420: {
! 421: vaddr_t eva = round_line(va + sz);
! 422: va = trunc_line(va);
! 423:
! 424: sh4_emode_dcache_wbinv_range_index(va, eva - va);
! 425:
! 426: RUN_P2;
! 427: while ((eva - va) >= (8 * 32)) {
! 428: cache_sh4_emode_op_8lines_32(va, SH4_CCIA, CCIA_ENTRY_MASK,
! 429: CCIA_V, 13);
! 430: va += 32 * 8;
! 431: }
! 432:
! 433: while (va < eva) {
! 434: cache_sh4_emode_op_line_32(va, SH4_CCIA, CCIA_ENTRY_MASK,
! 435: CCIA_V, 13);
! 436: va += 32;
! 437: }
! 438: RUN_P1;
! 439: }
! 440:
! 441: void
! 442: sh4_emode_dcache_wbinv_all(void)
! 443: {
! 444: vaddr_t va = 0;
! 445: vaddr_t eva = SH4_EMODE_DCACHE_SIZE;
! 446:
! 447: RUN_P2;
! 448: while (va < eva) {
! 449: cache_sh4_emode_op_8lines_32(va, SH4_CCDA, CCDA_ENTRY_MASK,
! 450: (CCDA_U | CCDA_V), 14);
! 451: va += 32 * 8;
! 452: }
! 453: RUN_P1;
! 454: }
! 455:
! 456: void
! 457: sh4_emode_dcache_wbinv_range_index(vaddr_t va, vsize_t sz)
! 458: {
! 459: vaddr_t eva = round_line(va + sz);
! 460: va = trunc_line(va);
! 461:
! 462: RUN_P2;
! 463: while ((eva - va) >= (8 * 32)) {
! 464: cache_sh4_emode_op_8lines_32(va, SH4_CCDA, CCDA_ENTRY_MASK,
! 465: (CCDA_U | CCDA_V), 14);
! 466: va += 32 * 8;
! 467: }
! 468:
! 469: while (va < eva) {
! 470: cache_sh4_emode_op_line_32(va, SH4_CCDA, CCDA_ENTRY_MASK,
! 471: (CCDA_U | CCDA_V), 14);
! 472: va += 32;
! 473: }
! 474: RUN_P1;
! 475: }
CVSweb